Initial commit

This commit is contained in:
Richard Jolley committed 2026-01-14 00:54:08 +00:00
commit c909d539bc
7178 files changed
+756624

No files matched your search

+136
View File
@@ -0,0 +1,136 @@
<link rel="stylesheet" href="{{ asset('css/custom.css') }}">
@php
use App\Services\BusyWindowService;
use Carbon\Carbon;
// Load all external busy windows with ±40 min buffer
$busyWindows = BusyWindowService::getBusyRanges();
@endphp
@include('partials.flash')
<x-app-layout>
<div class="container mx-auto my-6">
<div class="flex justify-between items-center mb-4">
<h2 class="text-2xl font-semibold">
Calendar: {{ $start->toFormattedDateString() }} – {{ $end->toFormattedDateString() }}
</h2>
<div class="space-x-2">
<a href="{{ route('admin.calendar', ['week' => $weekOffset - 1]) }}"
class="px-3 py-1 bg-gray-200 rounded hover:bg-gray-300">← Previous</a>
<a href="{{ route('admin.calendar') }}"
class="px-3 py-1 bg-blue-200 rounded hover:bg-blue-300">This Week</a>
<a href="{{ route('admin.calendar', ['week' => $weekOffset + 1]) }}"
class="px-3 py-1 bg-gray-200 rounded hover:bg-gray-300">Next →</a>
</div>
</div>
<div class="mb-3 text-sm">
<span class="inline-block px-2 py-1 rounded bg-green-100 border">Free</span>
<span class="inline-block px-2 py-1 rounded bg-red-200 border ml-2">Booked</span>
<span class="inline-block px-2 py-1 rounded bg-yellow-200 border ml-2">Closed (Admin)</span>
<span class="inline-block px-2 py-1 rounded bg-amber-200 border ml-2">Busy (External)</span>
<span class="inline-block px-2 py-1 rounded bg-gray-100 border ml-2">Closed (Past/≤ 2h)</span>
</div>
@php
$times = ['09:00:00','10:00:00','11:00:00','14:00:00','15:00:00','16:00:00'];
@endphp
<table class="w-full border-collapse border border-gray-300">
<thead>
<tr class="bg-gray-100">
<th class="border p-2">Time</th>
@for ($i = 0; $i < 5; $i++) {{-- Mon–Fri --}}
<th class="border p-2">
{{ $start->copy()->addDays($i)->format('D d M') }}
</th>
@endfor
</tr>
</thead>
<tbody>
@foreach ($times as $time)
<tr>
<td class="border p-2 font-medium">{{ substr($time, 0, 5) }}</td>
@for ($weekday = 1; $weekday <= 5; $weekday++) {{-- 1=Mon . 5=Fri --}}
@php
$date = $start->copy()->addDays($weekday - 1)->toDateString();
// Find the recurring slot for this weekday+time
$slot = $slots->first(function($s) use ($weekday, $time) {
return (int)$s->weekday === $weekday && $s->time === $time;
});
// Existing booking for that visible date?
$booking = $slot ? $slot->bookings->firstWhere('date', $date) : null;
// 2-hour rule
$sessionStart = Carbon::createFromFormat('Y-m-d H:i:s', $date.' '.$time, $now->timezone);
$minutesUntil = $now->diffInMinutes($sessionStart, false);
$tooSoon = $minutesUntil <= 120;
// External busy window check (±40 min buffer already applied)
$isExternalBusy = BusyWindowService::isInBusyWindow($sessionStart, $busyWindows);
// Assign background class
$class = 'border p-2 text-center ';
if ($booking?->status === 'booked') $class .= 'bg-red-200';
elseif ($booking?->status === 'blocked') $class .= 'bg-yellow-200';
elseif ($isExternalBusy) $class .= 'bg-amber-200';
elseif ($slot && !$booking && !$tooSoon) $class .= 'bg-green-100';
else $class .= 'bg-gray-100';
@endphp
<td class="{{ $class }}">
@if ($isExternalBusy)
Busy (External)
@elseif ($booking)
{{ $booking->status === 'blocked' ? 'Closed' : 'Booked' }}
@if ($booking->status === 'booked' && $booking->student_name)
<br><span class="text-xs">{{ $booking->student_name }}</span>
@endif
@elseif (!$slot)
Not seeded
@elseif ($tooSoon || $minutesUntil < 0)
Closed
@else
@php $isStudent = isset($viewer) && $viewer === 'student'; @endphp
@if ($slot)
@if ($isStudent)
<div class="flex items-center justify-center gap-3">
<a href="{{ route('student.bookings.create', ['date' => $date, 'slot_id' => $slot->id]) }}"
class="underline text-blue-700 hover:text-blue-900">
Book
</a>
<a href="{{ route('student.bookings.series.create', ['date' => $date, 'slot_id' => $slot->id, 'weeks' => 6]) }}"
class="underline text-purple-700 hover:text-purple-900">
Book series
</a>
</div>
@else
<div class="flex items-center justify-center gap-3">
<a href="{{ route('admin.bookings.create', ['date' => $date, 'slot_id' => $slot->id]) }}"
class="underline text-blue-700 hover:text-blue-900">Book</a>
<a href="{{ route('admin.bookings.block.create', ['date' => $date, 'slot_id' => $slot->id]) }}"
class="underline text-amber-700 hover:text-amber-900">Close</a>
<a href="{{ route('admin.bookings.series.create', ['date' => $date, 'slot_id' => $slot->id, 'weeks' => 6]) }}"
class="underline text-purple-700 hover:text-purple-900">Block booking</a>
</div>
@endif
@else
Free
@endif
@endif
</td>
@endfor
</tr>
@endforeach
</tbody>
</table>
</div>
</x-app-layout>