import { useMemo, useRef, useEffect } from "react"; import dayjs from "@calcom/dayjs"; import { useIsEmbed } from "@calcom/embed-core/embed-iframe"; import { AvailableTimes, AvailableTimesSkeleton } from "@calcom/features/bookings"; import { useSlotsForMultipleDates } from "@calcom/features/schedules/lib/use-schedule/useSlotsForDate"; import { classNames } from "@calcom/lib"; import useMediaQuery from "@calcom/lib/hooks/useMediaQuery"; import { useBookerStore } from "../store"; import { useEvent, useScheduleForEvent } from "../utils/event"; type AvailableTimeSlotsProps = { extraDays?: number; limitHeight?: boolean; seatsPerTimeSlot?: number | null; }; /** * Renders available time slots for a given date. * It will extract the date from the booker store. * Next to that you can also pass in the `extraDays` prop, this * will also fetch the next `extraDays` days and show multiple days * in columns next to each other. */ export const AvailableTimeSlots = ({ extraDays, limitHeight, seatsPerTimeSlot }: AvailableTimeSlotsProps) => { const isMobile = useMediaQuery("(max-width: 768px)"); const selectedDate = useBookerStore((state) => state.selectedDate); const setSelectedTimeslot = useBookerStore((state) => state.setSelectedTimeslot); const setSeatedEventData = useBookerStore((state) => state.setSeatedEventData); const isEmbed = useIsEmbed(); const event = useEvent(); const date = selectedDate || dayjs().format("YYYY-MM-DD"); const containerRef = useRef(null); const onTimeSelect = ( time: string, attendees: number, seatsPerTimeSlot?: number | null, bookingUid?: string ) => { setSelectedTimeslot(time); if (seatsPerTimeSlot) { setSeatedEventData({ seatsPerTimeSlot, attendees, bookingUid, }); if (seatsPerTimeSlot && seatsPerTimeSlot - attendees > 1) { return; } } if (!event.data) return; }; const schedule = useScheduleForEvent({ prefetchNextMonth: !!extraDays && dayjs(date).month() !== dayjs(date).add(extraDays, "day").month(), }); // Creates an array of dates to fetch slots for. // If `extraDays` is passed in, we will extend the array with the next `extraDays` days. const dates = useMemo( () => !extraDays ? [date] : [ // If NO date is selected yet, we show by default the upcomming `nextDays` days. date, ...Array.from({ length: extraDays }).map((_, index) => dayjs(date) .add(index + 1, "day") .format("YYYY-MM-DD") ), ], [date, extraDays] ); const isMultipleDates = dates.length > 1; const slotsPerDay = useSlotsForMultipleDates(dates, schedule?.data?.slots); useEffect(() => { if (isEmbed) return; if (containerRef.current && !schedule.isLoading && isMobile) { containerRef.current.scrollIntoView({ behavior: "smooth", block: "center" }); } }, [containerRef, schedule.isLoading, isEmbed, isMobile]); return (
{schedule.isLoading ? // Shows exact amount of days as skeleton. Array.from({ length: 1 + (extraDays ?? 0) }).map((_, i) => ) : slotsPerDay.length > 0 && slotsPerDay.map((slots) => ( ))}
); };