import { useMemo } from "react"; import { shallow } from "zustand/shallow"; import type { Dayjs } from "@calcom/dayjs"; import dayjs from "@calcom/dayjs"; import { classNames } from "@calcom/lib"; import { OutOfOfficeInSlots } from "../../../../bookings/Booker/components/OutOfOfficeInSlots"; import { useBookerTime } from "../../../../bookings/Booker/components/hooks/useBookerTime"; import { useCalendarStore } from "../../state/store"; import type { CalendarAvailableTimeslots } from "../../types/state"; import type { GridCellToDateProps } from "../../utils"; import { gridCellToDateTime } from "../../utils"; type EmptyCellProps = GridCellToDateProps & { isDisabled?: boolean; topOffsetMinutes?: number; }; export function EmptyCell(props: EmptyCellProps) { const cellToDate = gridCellToDateTime({ day: props.day, gridCellIdx: props.gridCellIdx, totalGridCells: props.totalGridCells, selectionLength: props.selectionLength, startHour: props.startHour, timezone: props.timezone, }); const minutesFromStart = (cellToDate.hour() - props.startHour) * 60 + cellToDate.minute(); return ; } type AvailableCellProps = { availableSlots: CalendarAvailableTimeslots; day: GridCellToDateProps["day"]; startHour: GridCellToDateProps["startHour"]; }; export function AvailableCellsForDay({ availableSlots, day, startHour }: AvailableCellProps) { const { timezone } = useBookerTime(); const date = dayjs(day); const dateFormatted = date.format("YYYY-MM-DD"); const slotsForToday = availableSlots && availableSlots[dateFormatted]; const slots = useMemo(() => { const calculatedSlots: { slot: CalendarAvailableTimeslots[string][number]; topOffsetMinutes: number; firstSlot?: CalendarAvailableTimeslots[string][number]; timezone?: string; }[] = []; // first and last slot for ooo to display range correctly in week view let firstSlotIndex = -1; let lastSlotIndex = -1; let areAllSlotsAway = true; let startEndTimeDuration = 0; slotsForToday?.forEach((slot, index) => { const startTime = dayjs(slot.start).tz(timezone); const topOffsetMinutes = (startTime.hour() - startHour) * 60 + startTime.minute(); calculatedSlots.push({ slot, topOffsetMinutes }); if (!slot.away) { areAllSlotsAway = false; } else { if (firstSlotIndex === -1) { firstSlotIndex = index; } lastSlotIndex = index; } }); if (areAllSlotsAway && firstSlotIndex !== -1) { const firstSlot = slotsForToday[firstSlotIndex]; const lastSlot = slotsForToday[lastSlotIndex]; startEndTimeDuration = dayjs(lastSlot.end).diff(dayjs(firstSlot.start), "minutes"); if (firstSlot.toUser == null) { return null; } // This will return null if all slots are away and the first slot has no user return { slots: calculatedSlots, startEndTimeDuration, firstSlot, timezone, }; } return { slots: calculatedSlots, startEndTimeDuration }; }, [slotsForToday, startHour, timezone]); if (slots === null) return null; if (slots.startEndTimeDuration) { const { firstSlot, startEndTimeDuration } = slots; return ( ); } return ( <> {slots.slots.map((slot, index) => ( ))} ); } type CellProps = { isDisabled?: boolean; topOffsetMinutes?: number; timeSlot: Dayjs; }; function Cell({ isDisabled, topOffsetMinutes, timeSlot }: CellProps) { const { timeFormat } = useBookerTime(); const { onEmptyCellClick, hoverEventDuration } = useCalendarStore( (state) => ({ onEmptyCellClick: state.onEmptyCellClick, hoverEventDuration: state.hoverEventDuration, }), shallow ); return (
{ onEmptyCellClick && onEmptyCellClick(timeSlot.toDate()); }}> {!isDisabled && hoverEventDuration !== 0 && ( )}
); } function CustomCell({ timeSlot, children, topOffsetMinutes, startEndTimeDuration, }: CellProps & { children: React.ReactNode; startEndTimeDuration?: number }) { return (
{children}
); }