Files
cal.diy/packages/features/bookings/Booker/components/hooks/useBookingForm.ts
T
Lauris SkraucisandMorgan 0072aba55d refactor: v2 event-types (#15457)
* refactor: UserAvatarGroupWithOrg.tsx remove unecessary profile prop

* chore: define event-type types in platform/types

* feat: event-type transformes in lib and re-exported through platform-libraries

* chore: define user types in platform/types

* chore: add users endpoint to platform-constants

* refactor: app-store use narrowed down booker event type

* chore: version old event-types module

* fix: old event-types e2e test

* fix: libraries add missing export

* fix: reset libraries version to 0

* feat: new event-types module and users endpoints

* feat: make booker atom work with v2 event-types

* updating event type

* refactor: remove guard for get event-types

* refactor: move private hook to public

* Revert "refactor: remove guard for get event-types"

This reverts commit d41204069f1d5bb1305b388ce53399f9175f4249.

* Revert "refactor: move private hook to public"

This reverts commit 09322e8fba102e57104959f79ed6bfa9a677dc9d.

* refactor: get by username and slug in /event-types

* remove console log

* feat: locations handle displayEventPublicly

* test e2e event-types

* revert: user output from types

* refactor: event-types hooks have private and public folders

* refactor: require event-type.slug in input

* refactor: demand that all labels of booking fields are unique

* refactor: remove unused import

* refactor: only have email and name by default in booker

* refactor: add booking field slug

* fix: display event-type location publicly / hide it in booker

* fix: display event-type location publicly / hide it in booker

* fix: packages/lib tests

* fix: typescript in e2e test

* fix: dynamic event types input

* refactor: use IsIn instead of IsEnum

* refactor: simplify getEventTypes

* fix: use ApiAuthGuard instead of AccessTokenGuard

* chore: export more stuff from libraries

* refactor: SchedulingTypeEnum and Type

---------

Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
2024-06-21 10:49:12 +00:00

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,
};
};