import { useRouter } from "next/router"; import { useState } from "react"; import { Controller, useFieldArray, useForm } from "react-hook-form"; import { z } from "zod"; import { DateOverrideInputDialog, DateOverrideList } from "@calcom/features/schedules"; import Schedule from "@calcom/features/schedules/components/Schedule"; import Shell from "@calcom/features/shell/Shell"; import { availabilityAsString } from "@calcom/lib/availability"; import { yyyymmdd } from "@calcom/lib/date-fns"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery"; import { HttpError } from "@calcom/lib/http-error"; import { trpc } from "@calcom/trpc/react"; import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery"; import type { Schedule as ScheduleType, TimeRange, WorkingHours } from "@calcom/types/schedule"; import { Button, Form, Label, showToast, Skeleton, SkeletonText, Switch, TimezoneSelect, Tooltip, Dialog, DialogTrigger, DropdownMenuSeparator, Dropdown, DropdownMenuContent, DropdownItem, DropdownMenuTrigger, ConfirmationDialogContent, VerticalDivider, } from "@calcom/ui"; import { Info, Plus, Trash, MoreHorizontal } from "@calcom/ui/components/icon"; import PageWrapper from "@components/PageWrapper"; import { SelectSkeletonLoader } from "@components/availability/SkeletonLoader"; import EditableHeading from "@components/ui/EditableHeading"; const querySchema = z.object({ schedule: z.coerce.number().positive().optional(), }); type AvailabilityFormValues = { name: string; schedule: ScheduleType; dateOverrides: { ranges: TimeRange[] }[]; timeZone: string; isDefault: boolean; }; const DateOverride = ({ workingHours }: { workingHours: WorkingHours[] }) => { const { remove, append, update, fields } = useFieldArray({ name: "dateOverrides", }); const { t } = useLocale(); return (

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

{t("date_overrides_subtitle")}

yyyymmdd(field.ranges[0].start))} remove={remove} update={update} items={fields} workingHours={workingHours} /> yyyymmdd(field.ranges[0].start))} onChange={(ranges) => append({ ranges })} Trigger={ } />
); }; export default function Availability() { const { t, i18n } = useLocale(); const router = useRouter(); const utils = trpc.useContext(); const me = useMeQuery(); const { data: { schedule: scheduleId }, } = useTypedQuery(querySchema); const { fromEventType } = router.query; const { timeFormat } = me.data || { timeFormat: null }; const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const { data: schedule, isLoading } = trpc.viewer.availability.schedule.get.useQuery( { scheduleId }, { enabled: !!scheduleId, } ); const form = useForm({ values: schedule && { ...schedule, schedule: schedule?.availability || [], }, }); const updateMutation = trpc.viewer.availability.schedule.update.useMutation({ onSuccess: async ({ prevDefaultId, currentDefaultId, ...data }) => { if (prevDefaultId && currentDefaultId) { // check weather the default schedule has been changed by comparing previous default schedule id and current default schedule id. if (prevDefaultId !== currentDefaultId) { // if not equal, invalidate previous default schedule id and refetch previous default schedule id. utils.viewer.availability.schedule.get.invalidate({ scheduleId: prevDefaultId }); utils.viewer.availability.schedule.get.refetch({ scheduleId: prevDefaultId }); } } utils.viewer.availability.schedule.get.invalidate({ scheduleId: data.schedule.id }); utils.viewer.availability.list.invalidate(); showToast( t("availability_updated_successfully", { scheduleName: data.schedule.name, }), "success" ); }, onError: (err) => { if (err instanceof HttpError) { const message = `${err.statusCode}: ${err.message}`; showToast(message, "error"); } }, }); const deleteMutation = trpc.viewer.availability.schedule.delete.useMutation({ onError: (err) => { if (err instanceof HttpError) { const message = `${err.statusCode}: ${err.message}`; showToast(message, "error"); } }, onSettled: () => { utils.viewer.availability.list.invalidate(); }, onSuccess: () => { showToast(t("schedule_deleted_successfully"), "success"); router.push("/availability"); }, }); return ( ( )} /> } subtitle={ schedule ? ( schedule.schedule .filter((availability) => !!availability.days.length) .map((availability) => ( {availabilityAsString(availability, { locale: i18n.language, hour12: timeFormat === 12 })}
)) ) : ( ) } CTA={
{t("set_to_default")} { form.setValue("isDefault", e); }} />
}>
{ scheduleId && updateMutation.mutate({ scheduleId, dateOverrides: dateOverrides.flatMap((override) => override.ranges), ...values, }); }} className="flex flex-col sm:mx-0 xl:flex-row xl:space-x-6">
{typeof me.data?.weekStart === "string" && ( )}
{schedule?.workingHours && }
value ? ( onChange(timezone.value)} /> ) : ( ) } />

{t("something_doesnt_look_right")}

); } Availability.PageWrapper = PageWrapper;