refactor: booker component
This commit is contained in:
parent
138dbd52d3
commit
556d6ea25b
|
@ -15,7 +15,7 @@ import { BookerLayouts } from "@calcom/prisma/zod-utils";
|
|||
|
||||
import { VerifyCodeDialog } from "../components/VerifyCodeDialog";
|
||||
import { AvailableTimeSlots } from "./components/AvailableTimeSlots";
|
||||
import { BookEventContainer, BookEventForm } from "./components/BookEventForm";
|
||||
import { BookEventForm } from "./components/BookEventForm";
|
||||
import { BookFormAsModal } from "./components/BookEventForm/BookFormAsModal";
|
||||
import { EventMeta } from "./components/EventMeta";
|
||||
import { Header } from "./components/Header";
|
||||
|
@ -76,7 +76,7 @@ const BookerComponent = ({
|
|||
duration,
|
||||
});
|
||||
const event = useEvent();
|
||||
const { selectedTimeslot, setSelectedTimeslot, handleRemoveSlot, handleReserveSlot } = useSlots(event);
|
||||
const { selectedTimeslot, setSelectedTimeslot } = useSlots(event);
|
||||
const {
|
||||
shouldShowFormInDialog,
|
||||
hasDarkBackground,
|
||||
|
@ -208,43 +208,38 @@ const BookerComponent = ({
|
|||
return null;
|
||||
}
|
||||
|
||||
const BookEventWizard = (
|
||||
<BookEventContainer
|
||||
onRemoveSelectedSlot={handleRemoveSlot}
|
||||
onReserveSlot={handleReserveSlot}
|
||||
event={event.data}>
|
||||
<BookEventForm
|
||||
key={key}
|
||||
onCancel={() => {
|
||||
setSelectedTimeslot(null);
|
||||
if (seatedEventData.bookingUid) {
|
||||
setSeatedEventData({ ...seatedEventData, bookingUid: undefined, attendees: undefined });
|
||||
}
|
||||
}}
|
||||
onSubmit={renderConfirmNotVerifyEmailButtonCond ? handleBookEvent : handleVerifyEmail}
|
||||
errorRef={bookerFormErrorRef}
|
||||
errors={errors}
|
||||
loadingStates={loadingStates}
|
||||
renderConfirmNotVerifyEmailButtonCond={renderConfirmNotVerifyEmailButtonCond}
|
||||
bookingForm={bookingForm as unknown as UseFormReturn<FieldValues, any>}
|
||||
eventQuery={event}
|
||||
rescheduleUid={rescheduleUid}>
|
||||
<>
|
||||
<VerifyCodeDialog
|
||||
isOpenDialog={isEmailVerificationModalVisible}
|
||||
setIsOpenDialog={setEmailVerificationModalVisible}
|
||||
email={formEmail}
|
||||
onSuccess={() => {
|
||||
setVerifiedEmail(formEmail);
|
||||
setEmailVerificationModalVisible(false);
|
||||
handleBookEvent();
|
||||
}}
|
||||
isUserSessionRequiredToVerify={false}
|
||||
/>
|
||||
<RedirectToInstantMeetingModal hasInstantMeetingTokenExpired={hasInstantMeetingTokenExpired} />
|
||||
</>
|
||||
</BookEventForm>
|
||||
</BookEventContainer>
|
||||
const EventBooker = (
|
||||
<BookEventForm
|
||||
key={key}
|
||||
onCancel={() => {
|
||||
setSelectedTimeslot(null);
|
||||
if (seatedEventData.bookingUid) {
|
||||
setSeatedEventData({ ...seatedEventData, bookingUid: undefined, attendees: undefined });
|
||||
}
|
||||
}}
|
||||
onSubmit={renderConfirmNotVerifyEmailButtonCond ? handleBookEvent : handleVerifyEmail}
|
||||
errorRef={bookerFormErrorRef}
|
||||
errors={errors}
|
||||
loadingStates={loadingStates}
|
||||
renderConfirmNotVerifyEmailButtonCond={renderConfirmNotVerifyEmailButtonCond}
|
||||
bookingForm={bookingForm as unknown as UseFormReturn<FieldValues, any>}
|
||||
eventQuery={event}
|
||||
rescheduleUid={rescheduleUid}>
|
||||
<>
|
||||
<VerifyCodeDialog
|
||||
isOpenDialog={isEmailVerificationModalVisible}
|
||||
setIsOpenDialog={setEmailVerificationModalVisible}
|
||||
email={formEmail}
|
||||
onSuccess={() => {
|
||||
setVerifiedEmail(formEmail);
|
||||
setEmailVerificationModalVisible(false);
|
||||
handleBookEvent();
|
||||
}}
|
||||
isUserSessionRequiredToVerify={false}
|
||||
/>
|
||||
<RedirectToInstantMeetingModal hasInstantMeetingTokenExpired={hasInstantMeetingTokenExpired} />
|
||||
</>
|
||||
</BookEventForm>
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -307,7 +302,7 @@ const BookerComponent = ({
|
|||
"bg-default dark:bg-muted sticky top-0 z-10"
|
||||
)}>
|
||||
<Header
|
||||
username={username}
|
||||
isMyLink={Boolean(username === event?.data?.owner?.username)}
|
||||
eventSlug={eventSlug}
|
||||
enabledLayouts={bookerLayouts.enabledLayouts}
|
||||
extraDays={layout === BookerLayouts.COLUMN_VIEW ? columnViewExtraDays.current : extraDays}
|
||||
|
@ -342,7 +337,7 @@ const BookerComponent = ({
|
|||
className="border-subtle sticky top-0 ml-[-1px] h-full p-6 md:w-[var(--booker-main-width)] md:border-l"
|
||||
{...fadeInLeft}
|
||||
visible={bookerState === "booking" && !shouldShowFormInDialog}>
|
||||
{BookEventWizard}
|
||||
{EventBooker}
|
||||
</BookerSection>
|
||||
|
||||
<BookerSection
|
||||
|
@ -406,7 +401,7 @@ const BookerComponent = ({
|
|||
<BookFormAsModal
|
||||
onCancel={() => setSelectedTimeslot(null)}
|
||||
visible={bookerState === "booking" && shouldShowFormInDialog}>
|
||||
{BookEventWizard}
|
||||
{EventBooker}
|
||||
</BookFormAsModal>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -3,11 +3,10 @@ import type {
|
|||
IUseBookingFormLoadingStates,
|
||||
} from "bookings/Booker/components/hooks/useBookingForm";
|
||||
import type { TFunction } from "next-i18next";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import type { FieldError } from "react-hook-form";
|
||||
import type { UseFormReturn, FieldValues } from "react-hook-form";
|
||||
|
||||
import { MINUTES_TO_BOOK } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery";
|
||||
import { Alert, Button, EmptyScreen, Form } from "@calcom/ui";
|
||||
|
@ -29,38 +28,6 @@ type BookEventFormProps = {
|
|||
renderConfirmNotVerifyEmailButtonCond: boolean;
|
||||
};
|
||||
|
||||
type BookEventContainerProps = {
|
||||
onReserveSlot: () => void;
|
||||
onRemoveSelectedSlot: () => void;
|
||||
event: useEventReturnType["data"];
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
export const BookEventContainer = ({
|
||||
onReserveSlot,
|
||||
onRemoveSelectedSlot,
|
||||
event,
|
||||
children,
|
||||
}: BookEventContainerProps) => {
|
||||
const timeslot = useBookerStore((state) => state.selectedTimeslot);
|
||||
|
||||
useEffect(() => {
|
||||
onReserveSlot();
|
||||
|
||||
const interval = setInterval(() => {
|
||||
onReserveSlot();
|
||||
}, parseInt(MINUTES_TO_BOOK) * 60 * 1000 - 2000);
|
||||
|
||||
return () => {
|
||||
onRemoveSelectedSlot();
|
||||
clearInterval(interval);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [event?.id, timeslot]);
|
||||
|
||||
return <div className="flex h-full flex-col">{children}</div>;
|
||||
};
|
||||
|
||||
export const BookEventForm = ({
|
||||
onCancel,
|
||||
eventQuery,
|
||||
|
|
|
@ -1 +1 @@
|
|||
export { BookEventContainer, BookEventForm } from "./BookEventForm";
|
||||
export { BookEventForm } from "./BookEventForm";
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { shallow } from "zustand/shallow";
|
||||
|
||||
|
@ -20,20 +19,17 @@ export function Header({
|
|||
isMobile,
|
||||
enabledLayouts,
|
||||
nextSlots,
|
||||
username,
|
||||
eventSlug,
|
||||
ownerName,
|
||||
isMyLink,
|
||||
}: {
|
||||
extraDays: number;
|
||||
isMobile: boolean;
|
||||
enabledLayouts: BookerLayouts[];
|
||||
nextSlots: number;
|
||||
username: string;
|
||||
eventSlug: string;
|
||||
ownerName?: string;
|
||||
isMyLink: boolean;
|
||||
}) {
|
||||
const { t, i18n } = useLocale();
|
||||
const session = useSession();
|
||||
|
||||
const [layout, setLayout] = useBookerStore((state) => [state.layout, state.setLayout], shallow);
|
||||
const selectedDateString = useBookerStore((state) => state.selectedDate);
|
||||
|
@ -64,7 +60,6 @@ export function Header({
|
|||
<LayoutToggle onLayoutToggle={onLayoutToggle} layout={layout} enabledLayouts={enabledLayouts} />
|
||||
);
|
||||
};
|
||||
const isMyLink = username === session?.data?.user.username; // TODO: check for if the user is the owner of the link
|
||||
|
||||
// In month view we only show the layout toggle.
|
||||
if (isMonthView) {
|
||||
|
|
|
@ -119,7 +119,7 @@ export function OverlayCalendarContainer() {
|
|||
shallow
|
||||
);
|
||||
|
||||
const { data: session, status: sessionStatus } = useSession();
|
||||
const { data: session } = useSession();
|
||||
const setOverlayBusyDates = useOverlayCalendarStore((state) => state.setOverlayBusyDates);
|
||||
const switchEnabled =
|
||||
searchParams?.get("overlayCalendar") === "true" ||
|
||||
|
|
|
@ -66,7 +66,6 @@ export const useBookingForm = ({ event, hashedLink }: IUseBookingForm) => {
|
|||
const username = useBookerStore((state) => state.username);
|
||||
const routerQuery = useRouterQuery();
|
||||
const searchParams = useSearchParams();
|
||||
const verifiedEmail = useBookerStore((state) => state.verifiedEmail);
|
||||
|
||||
const bookingFormSchema = z
|
||||
.object({
|
||||
|
@ -307,9 +306,11 @@ export const useBookingForm = ({ event, hashedLink }: IUseBookingForm) => {
|
|||
createInstantBookingMutation.error,
|
||||
};
|
||||
|
||||
// A redirect is triggered on mutation success, so keep the loading state while it is happening.
|
||||
const loadingStates = {
|
||||
creatingBooking: createBookingMutation.isLoading,
|
||||
creatingRecurringBooking: createRecurringBookingMutation.isLoading,
|
||||
creatingBooking: createBookingMutation.isLoading || createBookingMutation.isSuccess,
|
||||
creatingRecurringBooking:
|
||||
createRecurringBookingMutation.isLoading || createRecurringBookingMutation.isSuccess,
|
||||
creatingInstantBooking: createInstantBookingMutation.isLoading,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { useEffect } from "react";
|
||||
import { shallow } from "zustand/shallow";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { useBookerStore } from "@calcom/features/bookings/Booker/store";
|
||||
import { useSlotReservationId } from "@calcom/features/bookings/Booker/useSlotReservationId";
|
||||
import type { useEventReturnType } from "@calcom/features/bookings/Booker/utils/event";
|
||||
import { MINUTES_TO_BOOK } from "@calcom/lib/constants";
|
||||
import { trpc } from "@calcom/trpc";
|
||||
|
||||
export const useSlots = (event: useEventReturnType) => {
|
||||
|
@ -45,6 +47,22 @@ export const useSlots = (event: useEventReturnType) => {
|
|||
}
|
||||
};
|
||||
|
||||
const timeslot = useBookerStore((state) => state.selectedTimeslot);
|
||||
|
||||
useEffect(() => {
|
||||
handleReserveSlot();
|
||||
|
||||
const interval = setInterval(() => {
|
||||
handleReserveSlot();
|
||||
}, parseInt(MINUTES_TO_BOOK) * 60 * 1000 - 2000);
|
||||
|
||||
return () => {
|
||||
handleRemoveSlot();
|
||||
clearInterval(interval);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [event?.data?.id, timeslot]);
|
||||
|
||||
return {
|
||||
selectedTimeslot,
|
||||
setSelectedTimeslot,
|
||||
|
|
Loading…
Reference in New Issue
Block a user