diff --git a/frontend/app/booking/page.tsx b/frontend/app/booking/page.tsx index 0645519..d129422 100644 --- a/frontend/app/booking/page.tsx +++ b/frontend/app/booking/page.tsx @@ -92,6 +92,12 @@ const pageStyles: Record = { background: "rgba(167, 139, 250, 0.15)", border: "1px solid #a78bfa", }, + dateButtonDisabled: { + opacity: 0.4, + cursor: "not-allowed", + background: "rgba(255, 255, 255, 0.01)", + border: "1px solid rgba(255, 255, 255, 0.04)", + }, dateWeekday: { color: "#fff", fontWeight: 500, @@ -224,6 +230,8 @@ export default function BookingPage() { const [isBooking, setIsBooking] = useState(false); const [error, setError] = useState(null); const [successMessage, setSuccessMessage] = useState(null); + const [datesWithAvailability, setDatesWithAvailability] = useState>(new Set()); + const [isLoadingAvailability, setIsLoadingAvailability] = useState(true); const dates = getDateRange(minAdvanceDays, maxAdvanceDays); @@ -245,6 +253,36 @@ export default function BookingPage() { } }, []); + // Fetch availability for all dates on mount + useEffect(() => { + if (!user || !isAuthorized) return; + + const fetchAllAvailability = async () => { + setIsLoadingAvailability(true); + const availabilitySet = new Set(); + + // Fetch availability for all dates in parallel + const promises = dates.map(async (date) => { + try { + const dateStr = formatDate(date); + const data = await api.get(`/api/booking/slots?date=${dateStr}`); + if (data.slots.length > 0) { + availabilitySet.add(dateStr); + } + } catch (err) { + // Silently fail for individual dates - they'll just be marked as unavailable + console.error(`Failed to fetch availability for ${formatDate(date)}:`, err); + } + }); + + await Promise.all(promises); + setDatesWithAvailability(availabilitySet); + setIsLoadingAvailability(false); + }; + + fetchAllAvailability(); + }, [user, isAuthorized, dates]); + useEffect(() => { if (selectedDate && user && isAuthorized) { fetchSlots(selectedDate); @@ -252,8 +290,12 @@ export default function BookingPage() { }, [selectedDate, user, isAuthorized, fetchSlots]); const handleDateSelect = (date: Date) => { - setSelectedDate(date); - setSuccessMessage(null); + const dateStr = formatDate(date); + // Only allow selection if date has availability + if (datesWithAvailability.has(dateStr)) { + setSelectedDate(date); + setSuccessMessage(null); + } }; const handleSlotSelect = (slot: BookableSlot) => { @@ -329,14 +371,20 @@ export default function BookingPage() {

Select a Date

{dates.map((date) => { - const isSelected = selectedDate && formatDate(selectedDate) === formatDate(date); + const dateStr = formatDate(date); + const isSelected = selectedDate && formatDate(selectedDate) === dateStr; + const hasAvailability = datesWithAvailability.has(dateStr); + const isDisabled = !hasAvailability || isLoadingAvailability; + return (