Initial commit
This commit is contained in:
commit
c909d539bc
7178 files changed
+756624
No files matched your search
@@ -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>
|
||||
Reference in new issue
Block a user