126 lines
3.9 KiB
TypeScript
126 lines
3.9 KiB
TypeScript
import { zodResolver } from "@hookform/resolvers/zod";
|
|
import { useRef, useEffect } from "react";
|
|
import { useForm } from "react-hook-form";
|
|
import { z } from "zod";
|
|
|
|
import type { EventLocationType } from "@calcom/app-store/locations";
|
|
import { useBookerStore } from "@calcom/features/bookings/Booker/store";
|
|
import getBookingResponsesSchema from "@calcom/features/bookings/lib/getBookingResponsesSchema";
|
|
import type { BookerEvent } from "@calcom/features/bookings/types";
|
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|
|
|
import { useInitialFormValues } from "./useInitialFormValues";
|
|
|
|
export interface IUseBookingForm {
|
|
event?: Pick<BookerEvent, "bookingFields"> | null;
|
|
sessionEmail?: string | null;
|
|
sessionName?: string | null;
|
|
sessionUsername?: string | null;
|
|
hasSession: boolean;
|
|
extraOptions: Record<string, string | string[]>;
|
|
prefillFormParams: {
|
|
guests: string[];
|
|
name: string | null;
|
|
};
|
|
}
|
|
|
|
export type UseBookingFormReturnType = ReturnType<typeof useBookingForm>;
|
|
|
|
export const useBookingForm = ({
|
|
event,
|
|
sessionEmail,
|
|
sessionName,
|
|
sessionUsername,
|
|
hasSession,
|
|
extraOptions,
|
|
prefillFormParams,
|
|
}: IUseBookingForm) => {
|
|
const rescheduleUid = useBookerStore((state) => state.rescheduleUid);
|
|
const bookingData = useBookerStore((state) => state.bookingData);
|
|
const { t } = useLocale();
|
|
const bookerFormErrorRef = useRef<HTMLDivElement>(null);
|
|
|
|
const bookingFormSchema = z
|
|
.object({
|
|
responses: event
|
|
? getBookingResponsesSchema({
|
|
bookingFields: event.bookingFields,
|
|
view: rescheduleUid ? "reschedule" : "booking",
|
|
})
|
|
: // Fallback until event is loaded.
|
|
z.object({}),
|
|
})
|
|
.passthrough();
|
|
|
|
type BookingFormValues = {
|
|
locationType?: EventLocationType["type"];
|
|
responses: z.infer<typeof bookingFormSchema>["responses"] | null;
|
|
// Key is not really part of form values, but only used to have a key
|
|
// to set generic error messages on. Needed until RHF has implemented root error keys.
|
|
globalError: undefined;
|
|
};
|
|
const isRescheduling = !!rescheduleUid && !!bookingData;
|
|
|
|
const { initialValues, key } = useInitialFormValues({
|
|
eventType: event,
|
|
rescheduleUid,
|
|
isRescheduling,
|
|
email: sessionEmail,
|
|
name: sessionName,
|
|
username: sessionUsername,
|
|
hasSession,
|
|
extraOptions,
|
|
prefillFormParams,
|
|
});
|
|
|
|
const bookingForm = useForm<BookingFormValues>({
|
|
defaultValues: initialValues,
|
|
resolver: zodResolver(
|
|
// Since this isn't set to strict we only validate the fields in the schema
|
|
bookingFormSchema,
|
|
{},
|
|
{
|
|
// bookingFormSchema is an async schema, so inform RHF to do async validation.
|
|
mode: "async",
|
|
}
|
|
),
|
|
});
|
|
|
|
useEffect(() => {
|
|
// initialValues would be null initially as the async schema parsing is happening. Let's show the form in first render without any prefill values
|
|
// But ensure that when initialValues is available, the form is reset and rerendered with the prefill values
|
|
bookingForm.reset(initialValues);
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [key]);
|
|
|
|
const email = bookingForm.watch("responses.email");
|
|
const name = bookingForm.watch("responses.name");
|
|
|
|
const beforeVerifyEmail = () => {
|
|
bookingForm.clearErrors();
|
|
|
|
// It shouldn't be possible that this method is fired without having event data,
|
|
// but since in theory (looking at the types) it is possible, we still handle that case.
|
|
if (!event) {
|
|
bookingForm.setError("globalError", { message: t("error_booking_event") });
|
|
return;
|
|
}
|
|
};
|
|
|
|
const errors = {
|
|
hasFormErrors: Boolean(bookingForm.formState.errors["globalError"]),
|
|
formErrors: bookingForm.formState.errors["globalError"],
|
|
};
|
|
|
|
return {
|
|
bookingForm,
|
|
bookerFormErrorRef,
|
|
key,
|
|
formEmail: email,
|
|
formName: name,
|
|
beforeVerifyEmail,
|
|
formErrors: errors,
|
|
errors,
|
|
};
|
|
};
|