import dayjs from "@calcom/dayjs"; import { useTimePreferences } from "@calcom/features/bookings/lib/timePreferences"; import { TimezoneSelect } from "@calcom/web/modules/timezone/components/TimezoneSelect"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { DatePicker, SettingsToggle } from "@calcom/ui/components/form"; import { DatePickerWithRange as DateRangePicker } from "@calcom/ui/components/form/date-range-picker/DateRangePicker"; import { Button } from "@coss/ui/components/button"; import { Dialog, DialogClose, DialogDescription, DialogFooter, DialogHeader, DialogPanel, DialogPopup, DialogTitle, } from "@coss/ui/components/dialog"; import { Label } from "@coss/ui/components/label"; import { useIsMobile } from "@coss/ui/hooks/use-mobile"; import { useState } from "react"; import type { UseFormSetValue } from "react-hook-form"; import type { FormValues } from "~/settings/my-account/general-view"; interface TravelScheduleModalProps { open: boolean; onOpenChange: (open: boolean) => void; setValue: UseFormSetValue; existingSchedules: FormValues["travelSchedules"]; } const TravelScheduleModal = ({ open, onOpenChange, setValue, existingSchedules, }: TravelScheduleModalProps) => { const { t } = useLocale(); const { timezone: preferredTimezone } = useTimePreferences(); const isMobile = useIsMobile(); const [startDate, setStartDate] = useState(new Date()); const [endDate, setEndDate] = useState(new Date()); const [selectedTimeZone, setSelectedTimeZone] = useState(preferredTimezone); const [isNoEndDate, setIsNoEndDate] = useState(false); const [isDateRangeOpen, setIsDateRangeOpen] = useState(false); const [errorMessage, setErrorMessage] = useState(""); const isOverlapping = (newSchedule: { startDate: Date; endDate?: Date }) => { const newStart = dayjs(newSchedule.startDate); const newEnd = newSchedule.endDate ? dayjs(newSchedule.endDate) : null; for (const schedule of existingSchedules) { const start = dayjs(schedule.startDate); const end = schedule.endDate ? dayjs(schedule.endDate) : null; if (!newEnd) { // if the start date is after or on the existing schedule's start date and before the existing schedule's end date (if it has one) if (newStart.isSame(start) || newStart.isAfter(start)) { if (!end || newStart.isSame(end) || newStart.isBefore(end)) return true; } } else { // For schedules with an end date, check for any overlap if (newStart.isSame(end) || newStart.isBefore(end) || end === null) { if (newEnd.isSame(start) || newEnd.isAfter(start)) { return true; } } } } }; const resetValues = () => { setStartDate(new Date()); setEndDate(new Date()); setSelectedTimeZone(preferredTimezone); setIsNoEndDate(false); setIsDateRangeOpen(false); }; const createNewSchedule = () => { const newSchedule = { startDate, endDate, timeZone: selectedTimeZone, }; if (!isOverlapping(newSchedule)) { setValue("travelSchedules", existingSchedules.concat(newSchedule), { shouldDirty: true }); onOpenChange(false); resetValues(); } else { setErrorMessage(t("overlaps_with_existing_schedule")); } }; return ( { onOpenChange(nextOpen); if (!nextOpen) { setIsDateRangeOpen(false); } }}> {t("travel_schedule")} {t("travel_schedule_description")}
{!isNoEndDate ? ( <> { // If newStartDate does become undefined - we resort back to to-todays date setStartDate(newStartDate ?? new Date()); setEndDate(newEndDate); setErrorMessage(""); }} /> ) : ( <> { setStartDate(newDate); setErrorMessage(""); }} /> )}
{errorMessage}
{ setEndDate(!checked ? startDate : undefined); setIsNoEndDate(checked); if (checked) { setIsDateRangeOpen(false); } setErrorMessage(""); }} />
setSelectedTimeZone(value)} menuPortalTarget={typeof document === "undefined" ? undefined : document.body} menuPlacement={isMobile ? "top" : "auto"} styles={{ menuPortal: (base) => Object.assign({}, base, { zIndex: 9999 }) }} className="mb-11 mt-2 w-full rounded-md text-sm" />
}>{t("cancel")}
); }; export default TravelScheduleModal;