import clsx from "clsx"; import { useTranslation } from "next-i18next"; import * as React from "react"; import { Controller, useForm } from "react-hook-form"; import { getBrowserTimeZone } from "../../../utils/date-time-utils"; import FullPageLoader from "../../full-page-loader"; import Calendar from "../../icons/calendar.svg"; import Table from "../../icons/table.svg"; import { useModal } from "../../modal"; import TimeZonePicker from "../../time-zone-picker"; import { PollFormProps } from "../types"; import { DateTimeOption } from "./types"; const WeekCalendar = React.lazy(() => import("./week-calendar")); const MonthCalendar = React.lazy(() => import("./month-calendar")); export type PollOptionsData = { navigationDate: string; // used to navigate to the right part of the calendar duration: number; // duration of the event in minutes timeZone: string; view: string; options: DateTimeOption[]; }; const PollOptionsForm: React.VoidFunctionComponent< PollFormProps & { title?: string } > = ({ name, defaultValues, onSubmit, onChange, title, className }) => { const { t } = useTranslation("app"); const { control, handleSubmit, watch, setValue, formState } = useForm({ defaultValues: { options: [], duration: 30, timeZone: "", navigationDate: new Date().toISOString(), ...defaultValues, }, resolver: (values) => { return { values, errors: values.options.length === 0 ? { options: true, } : {}, }; }, }); const views = React.useMemo(() => { const res = [ { label: "Month view", value: "month", Component: MonthCalendar, }, { label: "Week view", value: "week", Component: WeekCalendar, }, ]; return res; }, []); const watchView = watch("view"); const selectedView = React.useMemo( () => views.find((view) => view.value === watchView) ?? views[0], [views, watchView], ); const watchOptions = watch("options"); const watchDuration = watch("duration"); const watchTimeZone = watch("timeZone"); const datesOnly = watchOptions.every((option) => option.type === "date"); const [dateOrTimeRangeModal, openDateOrTimeRangeModal] = useModal({ title: "Wait a minute… šŸ¤”", description: "You can't have both time and date options in the same poll. Which would you like to keep?", okText: "Keep time options", onOk: () => { setValue( "options", watchOptions.filter((option) => option.type === "timeSlot"), ); if (!watchTimeZone) { setValue("timeZone", getBrowserTimeZone()); } }, cancelText: "Keep date options", onCancel: () => { setValue( "options", watchOptions.filter((option) => option.type === "date"), ); setValue("timeZone", ""); }, }); React.useEffect(() => { if (onChange) { const subscription = watch(({ options = [], ...rest }) => { // Watch returns a deep partial here which is not really accurate and messes up // the types a bit. Repackaging it to keep the types sane. onChange({ options: options as DateTimeOption[], ...rest }); }); return () => { subscription.unsubscribe(); }; } }, [watch, onChange]); React.useEffect(() => { if (watchOptions.length > 1) { const optionType = watchOptions[0].type; // all options needs to be the same type if (watchOptions.some((option) => option.type !== optionType)) { openDateOrTimeRangeModal(); } } }, [watchOptions, openDateOrTimeRangeModal]); const watchNavigationDate = watch("navigationDate"); const navigationDate = new Date(watchNavigationDate); const [calendarHelpModal, openHelpModal] = useModal({ overlayClosable: true, title: "Forget something?", description: t("calendarHelp"), okText: t("ok"), }); return (
{calendarHelpModal} {dateOrTimeRangeModal}
( { setValue("timeZone", timeZone, { shouldTouch: true }); }} disabled={datesOnly} /> )} />