"use client"; import { useSession } from "next-auth/react"; import { useState } from "react"; import { Controller, useForm } from "react-hook-form"; import SectionBottomActions from "@calcom/features/settings/SectionBottomActions"; import { classNames } from "@calcom/lib"; import { formatLocalizedDateTime } from "@calcom/lib/date-fns"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { localeOptions } from "@calcom/lib/i18n"; import { nameOfDay } from "@calcom/lib/weekday"; import type { RouterOutputs } from "@calcom/trpc/react"; import { trpc } from "@calcom/trpc/react"; import { Button, Form, Label, Select, showToast, SkeletonButton, SkeletonContainer, SkeletonText, TimezoneSelect, SettingsToggle, } from "@calcom/ui"; import TravelScheduleModal from "@components/settings/TravelScheduleModal"; export type FormValues = { locale: { value: string; label: string; }; timeZone: string; timeFormat: { value: number; label: string | number; }; weekStart: { value: string; label: string; }; travelSchedules: { id?: number; startDate: Date; endDate?: Date; timeZone: string; }[]; }; const SkeletonLoader = () => { return (
); }; interface GeneralViewProps { localeProp: string; user: RouterOutputs["viewer"]["me"]; travelSchedules: RouterOutputs["viewer"]["getTravelSchedules"]; revalidatePage: GeneralQueryViewProps["revalidatePage"]; } type GeneralQueryViewProps = { revalidatePage: () => Promise; }; const GeneralQueryView = ({ revalidatePage }: GeneralQueryViewProps) => { const { t } = useLocale(); const { data: user, isPending } = trpc.viewer.me.useQuery(); const { data: travelSchedules, isPending: isPendingTravelSchedules } = trpc.viewer.getTravelSchedules.useQuery(); if (isPending || isPendingTravelSchedules) return ; if (!user) { throw new Error(t("something_went_wrong")); } return ( ); }; const GeneralView = ({ localeProp, user, travelSchedules, revalidatePage }: GeneralViewProps) => { const utils = trpc.useContext(); const { t, i18n: { language }, } = useLocale(); const { update } = useSession(); const [isUpdateBtnLoading, setIsUpdateBtnLoading] = useState(false); const [isTZScheduleOpen, setIsTZScheduleOpen] = useState(false); const mutation = trpc.viewer.updateProfile.useMutation({ onSuccess: async (res) => { await utils.viewer.me.invalidate(); reset(getValues()); showToast(t("settings_updated_successfully"), "success"); await update(res); if (res.locale) { window.calNewLocale = res.locale; document.cookie = `calNewLocale=${res.locale}; path=/`; } await revalidatePage(); }, onError: () => { showToast(t("error_updating_settings"), "error"); }, onSettled: async () => { await utils.viewer.me.invalidate(); setIsUpdateBtnLoading(false); }, }); const timeFormatOptions = [ { value: 12, label: t("12_hour") }, { value: 24, label: t("24_hour") }, ]; const weekStartOptions = [ { value: "Sunday", label: nameOfDay(localeProp, 0) }, { value: "Monday", label: nameOfDay(localeProp, 1) }, { value: "Tuesday", label: nameOfDay(localeProp, 2) }, { value: "Wednesday", label: nameOfDay(localeProp, 3) }, { value: "Thursday", label: nameOfDay(localeProp, 4) }, { value: "Friday", label: nameOfDay(localeProp, 5) }, { value: "Saturday", label: nameOfDay(localeProp, 6) }, ]; const formMethods = useForm({ defaultValues: { locale: { value: localeProp || "", label: localeOptions.find((option) => option.value === localeProp)?.label || "", }, timeZone: user.timeZone || "", timeFormat: { value: user.timeFormat || 12, label: timeFormatOptions.find((option) => option.value === user.timeFormat)?.label || 12, }, weekStart: { value: user.weekStart, label: nameOfDay(localeProp, user.weekStart === "Sunday" ? 0 : 1), }, travelSchedules: travelSchedules.map((schedule) => { return { id: schedule.id, startDate: schedule.startDate, endDate: schedule.endDate ?? undefined, timeZone: schedule.timeZone, }; }) || [], }, }); const { formState: { isDirty, isSubmitting }, reset, getValues, } = formMethods; const isDisabled = isSubmitting || !isDirty; const [isAllowDynamicBookingChecked, setIsAllowDynamicBookingChecked] = useState( !!user.allowDynamicBooking ); const [isAllowSEOIndexingChecked, setIsAllowSEOIndexingChecked] = useState( user.organizationSettings?.allowSEOIndexing === false ? !!user.organizationSettings?.allowSEOIndexing : !!user.allowSEOIndexing ); const [isReceiveMonthlyDigestEmailChecked, setIsReceiveMonthlyDigestEmailChecked] = useState( !!user.receiveMonthlyDigestEmail ); const watchedTzSchedules = formMethods.watch("travelSchedules"); return (
{ setIsUpdateBtnLoading(true); mutation.mutate({ ...values, locale: values.locale.value, timeFormat: values.timeFormat.value, weekStart: values.weekStart.value, }); }}>
( <> className="capitalize" options={localeOptions} value={value} onChange={onChange} /> )} /> ( <> { if (event) formMethods.setValue("timeZone", event.value, { shouldDirty: true }); }} /> )} /> {!watchedTzSchedules.length ? ( ) : (
{watchedTzSchedules.map((schedule, index) => { return (
{`${formatLocalizedDateTime( schedule.startDate, { day: "numeric", month: "long" }, language )} ${ schedule.endDate ? `- ${formatLocalizedDateTime( schedule.endDate, { day: "numeric", month: "long" }, language )}` : `` }`}
{schedule.timeZone.replace(/_/g, " ")}
); })}
)} ( <> { if (event) formMethods.setValue("weekStart", { ...event }, { shouldDirty: true }); }} /> )} />
{ setIsAllowDynamicBookingChecked(checked); mutation.mutate({ allowDynamicBooking: checked }); }} switchContainerClassName="mt-6" /> { setIsAllowSEOIndexingChecked(checked); mutation.mutate({ allowSEOIndexing: checked }); }} switchContainerClassName="mt-6" /> { setIsReceiveMonthlyDigestEmailChecked(checked); mutation.mutate({ receiveMonthlyDigestEmail: checked }); }} switchContainerClassName="mt-6" /> setIsTZScheduleOpen(false)} setValue={formMethods.setValue} existingSchedules={formMethods.getValues("travelSchedules") ?? []} />
); }; export default GeneralQueryView;