From 08d62080c1421802f4408f6b3476b700bd55fb5f Mon Sep 17 00:00:00 2001 From: Stephen Adamson Date: Mon, 22 Jun 2026 12:55:32 +0100 Subject: [PATCH] feat(frontend): add out_of_hours booking type and timeSlots utils Add optional out_of_hours field to Booking interface and TimeSlotGroup. Add debug logging to timeSlot generation utilities for easier development. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- frontend/src/lib/types/booking.ts | 1 + frontend/src/lib/utils/timeSlots.ts | 57 +++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/frontend/src/lib/types/booking.ts b/frontend/src/lib/types/booking.ts index a5fb3a4..699aa45 100644 --- a/frontend/src/lib/types/booking.ts +++ b/frontend/src/lib/types/booking.ts @@ -118,6 +118,7 @@ export interface Booking { updated_at: string; created_by?: string; created_by_name?: string; + out_of_hours?: boolean; // Deposit fields deposit_required: boolean; diff --git a/frontend/src/lib/utils/timeSlots.ts b/frontend/src/lib/utils/timeSlots.ts index 14b3905..ca48e95 100644 --- a/frontend/src/lib/utils/timeSlots.ts +++ b/frontend/src/lib/utils/timeSlots.ts @@ -11,6 +11,7 @@ export interface TimeSlotGroup { startTime: string; endTime: string; isGrouped?: boolean; + outOfHours?: boolean; } export interface DayHours { @@ -111,7 +112,16 @@ export function generateAvailableTimeSlots( const dateStr = date.toString(); const dayWH = workingHours[dateStr]; const dayAH = availableHours[dateStr]; - if (!dayWH?.isOpen || !dayAH?.slots) return []; + if (!dayWH?.isOpen || !dayAH?.slots) { + console.log('[DEBUG] generateAvailableTimeSlots - early return', { + dateStr, + hasDayWH: !!dayWH, + dayWH_isOpen: dayWH?.isOpen, + hasDayAH: !!dayAH, + dayAH_slots: dayAH?.slots?.length + }); + return []; + } const slots: string[] = []; const now = new SvelteDate(); @@ -140,6 +150,16 @@ export function generateAvailableTimeSlots( } } } + console.log('[DEBUG] generateAvailableTimeSlots result', { + dateStr, + duration, + dayWH_startTime: dayWH.startTime, + dayWH_endTime: dayWH.endTime, + dayAH_slots_raw: dayAH.slots, + isToday, + generatedSlotsCount: slots.length, + generatedSlots: slots.slice(0, 20) + (slots.length > 20 ? `... (${slots.length} total)` : '') + }); return slots; } @@ -150,10 +170,25 @@ export function generateGroupedTimeSlots( duration: number, protection: Map ): TimeSlotGroup[] { - if (!workingHours) return []; + if (!workingHours) { + console.log('[DEBUG] generateGroupedTimeSlots - no workingHours'); + return []; + } const dateStr = date.toString(); const dayWH = workingHours[dateStr]; - if (!dayWH || !dayWH.isOpen) return []; + if (!dayWH || !dayWH.isOpen) { + console.log('[DEBUG] generateGroupedTimeSlots - day not open', { dateStr, dayWH }); + return []; + } + + console.log('[DEBUG] generateGroupedTimeSlots - inputs', { + dateStr, + duration, + startTime: dayWH.startTime, + endTime: dayWH.endTime, + isOpen: dayWH.isOpen, + source: (dayWH as any).source + }); const grouped: TimeSlotGroup[] = []; const [startHour, startMinute] = dayWH.startTime.split(':').map(Number); @@ -175,6 +210,15 @@ export function generateGroupedTimeSlots( duration, protection ); + + console.log('[DEBUG] generateGroupedTimeSlots - availableSlots', { + availableSlotsCount: availableSlots.length, + availableSlots: availableSlots.slice(0, 30) + (availableSlots.length > 30 ? `... (${availableSlots.length} total)` : ''), + dayRange: `${dayWH.startTime}-${dayWH.endTime}`, + startTotalMinutes, + endTotalMinutes + }); + let currentUnavailableStart: string | null = null; let lastAvailableEndTime: string | null = null; @@ -222,5 +266,12 @@ export function generateGroupedTimeSlots( } } + console.log('[DEBUG] generateGroupedTimeSlots - final result', { + availableCount: grouped.filter(s => s.type === 'available').length, + unavailableCount: grouped.filter(s => s.type === 'unavailable').length, + availableTimes: grouped.filter(s => s.type === 'available').map(s => s.startTime + '-' + s.endTime).slice(0, 20), + unavailableRanges: grouped.filter(s => s.type === 'unavailable').map(s => s.startTime + '-' + s.endTime) + }); + return grouped; }