, rows: array}>, times: string[]} */ public function build(Carbon $start, Carbon $now, bool $applyShortNotice): array { $end = $start->copy()->addDays(6); $weekdays = [1,2,3,4,5]; // Mon..Fri $times = ['09:00:00','10:00:00','11:00:00','14:00:00','15:00:00','16:00:00']; // Get all slots with bookings in the visible week $slots = Slot::with(['bookings' => function ($q) use ($start, $end) { $q->whereBetween('date', [$start->toDateString(), $end->toDateString()]); }])->get(); // Map slots by weekday/time for O(1) lookup in the loop $map = []; foreach ($slots as $s) { $map[(int)$s->weekday][$s->time] = $s; } // Column headers $headers = []; for ($i = 0; $i < 5; $i++) { $d = $start->copy()->addDays($i); $headers[] = [ 'date' => $d->toDateString(), 'label' => $d->format('D d M'), ]; } // Rows (each time) $rows = []; foreach ($times as $time) { $cells = []; foreach ($weekdays as $wd) { $date = $start->copy()->addDays($wd - 1)->toDateString(); $slot = $map[$wd][$time] ?? null; $booking = $slot ? $slot->bookings->firstWhere('date', $date) : null; // Compute short-notice closure only when required (students) $sessionStart = Carbon::createFromFormat('Y-m-d H:i:s', "{$date} {$time}", $now->timezone); $minutesUntil = $now->diffInMinutes($sessionStart, false); $tooSoon = $applyShortNotice ? ($minutesUntil <= 120) : false; // Decide status + cell class $status = 'closed'; $class = 'bg-gray-100'; $name = null; if ($booking) { if ($booking->status === 'booked') { $status = 'booked'; $class = 'bg-red-200'; } elseif ($booking->status === 'blocked') { $status = 'blocked'; $class = 'bg-yellow-200'; } } elseif (!$slot) { $status = 'not_seeded'; // slot wasn’t seeded for this weekday/time } elseif ($minutesUntil < 0 || $tooSoon) { $status = 'closed'; } else { $status = 'free'; $class = 'bg-green-100'; } if ($booking && $booking->student_name) { $name = $booking->student_name; } $cells[] = [ 'date' => $date, 'time' => $time, 'slot' => $slot?->id, 'status' => $status, // free | booked | blocked | closed | not_seeded 'class' => $class, 'name' => $name, ]; } $rows[] = [ 'time' => $time, 'label' => substr($time, 0, 5), 'cells' => $cells, ]; } return [ 'headers' => $headers, 'rows' => $rows, 'times' => $times, ]; } }