import { useMemo, useState, useEffect } from "react"; import { Controller, useFieldArray, useForm, useWatch } from "react-hook-form"; import dayjs from "@calcom/dayjs"; import { DateOverrideInputDialog, DateOverrideList } from "@calcom/features/schedules"; import WebSchedule, { ScheduleComponent as PlatformSchedule, } from "@calcom/features/schedules/components/Schedule"; import WebShell from "@calcom/features/shell/Shell"; import { availabilityAsString } from "@calcom/lib/availability"; import classNames from "@calcom/lib/classNames"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { sortAvailabilityStrings } from "@calcom/lib/weekstart"; import type { RouterOutputs } from "@calcom/trpc/react"; import type { TimeRange, WorkingHours } from "@calcom/types/schedule"; import { Button, ConfirmationDialogContent, EditableHeading, Form, SkeletonText, Dialog, DialogTrigger, Label, SelectSkeletonLoader, Skeleton, Switch, TimezoneSelect as WebTimezoneSelect, Tooltip, VerticalDivider, } from "@calcom/ui"; import { Icon } from "@calcom/ui"; import { Shell as PlatformShell } from "../src/components/ui/shell"; import { cn } from "../src/lib/utils"; import { Timezone as PlatformTimzoneSelect } from "../timezone/index"; import type { AvailabilityFormValues } from "./types"; export type Schedule = { id: number; startTime: Date; endTime: Date; userId: number | null; eventTypeId: number | null; date: Date | null; scheduleId: number | null; days: number[]; }; export type CustomClassNames = { containerClassName?: string; ctaClassName?: string; editableHeadingClassName?: string; formClassName?: string; timezoneSelectClassName?: string; subtitlesClassName?: string; scheduleClassNames?: { scheduleContainer?: string; scheduleDay?: string; dayRanges?: string; timeRanges?: string; labelAndSwitchContainer?: string; }; }; export type Availability = Pick; type AvailabilitySettingsProps = { skeletonLabel?: string; schedule: { name: string; id: number; availability: TimeRange[][]; isLastSchedule: boolean; isDefault: boolean; workingHours: WorkingHours[]; dateOverrides: { ranges: TimeRange[] }[]; timeZone: string; schedule: Availability[]; }; travelSchedules?: RouterOutputs["viewer"]["getTravelSchedules"]; handleDelete: () => void; isDeleting: boolean; isSaving: boolean; isLoading: boolean; timeFormat: number | null; weekStart: string; backPath: string | boolean; handleSubmit: (data: AvailabilityFormValues) => Promise; isPlatform?: boolean; customClassNames?: CustomClassNames; disableEditableHeading?: boolean; enableOverrides?: boolean; }; const DeleteDialogButton = ({ disabled, buttonClassName, isPending, onDeleteConfirmed, handleDelete, }: { disabled?: boolean; onDeleteConfirmed?: () => void; buttonClassName: string; handleDelete: () => void; isPending: boolean; }) => { const { t } = useLocale(); return ( ); }; const useExcludedDates = () => { const watchValues = useWatch({ name: "dateOverrides" }) as { ranges: TimeRange[]; }[]; return useMemo(() => { return watchValues?.map((field) => dayjs(field.ranges[0].start).utc().format("YYYY-MM-DD")); }, [watchValues]); }; const DateOverride = ({ workingHours, userTimeFormat, travelSchedules, weekStart, }: { workingHours: WorkingHours[]; userTimeFormat: number | null; travelSchedules?: RouterOutputs["viewer"]["getTravelSchedules"]; weekStart: 0 | 1 | 2 | 3 | 4 | 5 | 6; }) => { const { append, replace, fields } = useFieldArray({ name: "dateOverrides", }); const excludedDates = useExcludedDates(); const { t } = useLocale(); return (

{t("date_overrides")}{" "}

{t("date_overrides_subtitle")}

ranges.forEach((range) => append({ ranges: [range] }))} userTimeFormat={userTimeFormat} weekStart={weekStart} Trigger={ } />
); }; // Simplify logic by assuming this will never be opened on a large screen const SmallScreenSideBar = ({ open, children }: { open: boolean; children: JSX.Element }) => { return (
{open ? children : null}
); }; export function AvailabilitySettings({ schedule, travelSchedules, handleDelete, isDeleting, isLoading, isSaving, timeFormat, weekStart, backPath, handleSubmit, isPlatform = false, customClassNames, disableEditableHeading = false, enableOverrides = false, }: AvailabilitySettingsProps) { const [openSidebar, setOpenSidebar] = useState(false); const { t, i18n } = useLocale(); const form = useForm({ defaultValues: { ...schedule, schedule: schedule.availability || [], }, }); useEffect(() => { const subscription = form.watch( (value, { name }) => { if (!!name && name.split(".")[0] !== "schedule" && name !== "name") handleSubmit(value as AvailabilityFormValues); }, { ...schedule, schedule: schedule.availability || [], } ); return () => subscription.unsubscribe(); }, [form.watch]); const [Shell, Schedule, TimezoneSelect] = useMemo(() => { return isPlatform ? [PlatformShell, PlatformSchedule, PlatformTimzoneSelect] : [WebShell, WebSchedule, WebTimezoneSelect]; }, [isPlatform]); return ( ( )} /> } subtitle={ schedule ? ( schedule.schedule .filter((availability) => !!availability.days.length) .map((availability) => availabilityAsString(availability, { locale: i18n.language, hour12: timeFormat === 12, }) ) // sort the availability strings as per user's weekstart (settings) .sort(sortAvailabilityStrings(i18n.language, weekStart)) .map((availabilityString, index) => ( {availabilityString}
)) ) : ( ) } CTA={
{!openSidebar ? ( <> {t("set_to_default")} ( )} /> ) : null}
<>
{t("name")} ( )} />
{t("set_to_default")} ( )} />
{t("timezone")} value ? ( onChange(timezone.value)} /> ) : ( ) } />
{!isPlatform && ( <>
{t("something_doesnt_look_right")}
{t("launch_troubleshooter")}
)}
}>
{ handleSubmit(props); }} className={cn(customClassNames?.formClassName, "flex flex-col sm:mx-0 xl:flex-row xl:space-x-6")}>
{typeof weekStart === "string" && ( )}
{enableOverrides && ( )}
{t("timezone")} value ? ( onChange(timezone.value)} /> ) : ( ) } />
{isPlatform ? ( <> ) : ( <>
{t("something_doesnt_look_right")}
{t("launch_troubleshooter")}
)}
); }