import { useState, useEffect, useCallback } from "react"; import { exchangeApi } from "../../api"; import { components } from "../../generated/api"; import { formatDate } from "../../utils/date"; type BookableSlot = components["schemas"]["BookableSlot"]; interface UseAvailableSlotsOptions { /** Whether the user is authenticated and authorized */ enabled?: boolean; /** Dates to check availability for */ dates: Date[]; /** Current wizard step - only fetch when in booking or confirmation step */ wizardStep?: "details" | "booking" | "confirmation"; } interface UseAvailableSlotsResult { /** Available slots for the selected date */ availableSlots: BookableSlot[]; /** Set of date strings that have availability */ datesWithAvailability: Set; /** Whether slots are currently being loaded for a specific date */ isLoadingSlots: boolean; /** Whether availability is being checked for all dates */ isLoadingAvailability: boolean; /** Fetch slots for a specific date */ fetchSlots: (date: Date) => Promise; } /** * Hook for managing available slots and date availability. * Fetches availability for all dates when entering booking/confirmation steps. */ export function useAvailableSlots(options: UseAvailableSlotsOptions): UseAvailableSlotsResult { const { enabled = true, dates, wizardStep } = options; const [availableSlots, setAvailableSlots] = useState([]); const [datesWithAvailability, setDatesWithAvailability] = useState>(new Set()); const [isLoadingSlots, setIsLoadingSlots] = useState(false); const [isLoadingAvailability, setIsLoadingAvailability] = useState(true); const fetchSlots = useCallback( async (date: Date) => { if (!enabled) return; setIsLoadingSlots(true); setAvailableSlots([]); try { const dateStr = formatDate(date); const data = await exchangeApi.getSlots(dateStr); setAvailableSlots(data.slots); } catch (err) { console.error("Failed to fetch slots:", err); } finally { setIsLoadingSlots(false); } }, [enabled] ); // Fetch availability for all dates when entering booking or confirmation step useEffect(() => { if (!enabled || (wizardStep !== "booking" && wizardStep !== "confirmation")) return; const fetchAllAvailability = async () => { setIsLoadingAvailability(true); const availabilitySet = new Set(); const promises = dates.map(async (date) => { try { const dateStr = formatDate(date); const data = await exchangeApi.getSlots(dateStr); if (data.slots.length > 0) { availabilitySet.add(dateStr); } } catch (err) { console.error(`Failed to fetch availability for ${formatDate(date)}:`, err); } }); await Promise.all(promises); setDatesWithAvailability(availabilitySet); setIsLoadingAvailability(false); }; fetchAllAvailability(); }, [enabled, dates, wizardStep]); return { availableSlots, datesWithAvailability, isLoadingSlots, isLoadingAvailability, fetchSlots, }; }