From 3dd312b88b66236c0648037aa95d49dbdb174c48 Mon Sep 17 00:00:00 2001 From: Morgan <33722304+ThyMinimalDev@users.noreply.github.com> Date: Fri, 16 Feb 2024 13:38:12 +0200 Subject: [PATCH] chore: booker web wrapper (#13676) * chore: booker web wrapper * fixup! chore: booker web wrapper * fixup! fixup! chore: booker web wrapper * fixup! fixup! fixup! chore: booker web wrapper * fixup! fixup! fixup! fixup! chore: booker web wrapper * fix: CreateANewOrganizationForm verify dialog * fix: EventBooker not rerendering when it should * fix: init booker store properly * fixup! fix: init booker store properly * fix: useMemo EventBooker * fix: remove unnecessary file --- packages/atoms/booker/Booker.docs.mdx | 2 +- packages/atoms/booker/Booker.stories.tsx | 2 +- packages/atoms/booker/Booker.tsx | 13 - packages/atoms/booker/export.ts | 2 +- packages/atoms/booker/index.ts | 2 +- .../booker/wrappers/BookerWebWrapper.tsx | 195 +++++++++++ packages/atoms/index.ts | 2 +- packages/features/bookings/Booker/Booker.tsx | 309 +++++++----------- .../BookEventForm/BookEventForm.tsx | 12 +- .../Booker/components/InstantBooking.tsx | 4 +- .../Booker/components/LargeCalendar.tsx | 6 +- .../OverlayCalendar/OverlayCalendar.tsx | 22 +- .../OverlayCalendarContinueModal.tsx | 10 +- .../OverlayCalendar/OverlayCalendarSwitch.tsx | 44 +-- .../components/hooks/useBookerLayout.ts | 2 + .../Booker/components/hooks/useBookingForm.ts | 27 +- .../Booker/components/hooks/useBookings.ts | 23 +- .../Booker/components/hooks/useCalendars.ts | 9 +- .../components/hooks/useInitialFormValues.ts | 62 ++-- .../components/hooks/useOverlayCalendar.ts | 2 + .../Booker/components/hooks/useSlots.ts | 2 + .../Booker/components/hooks/useVerifyCode.ts | 74 +++++ .../Booker/components/hooks/useVerifyEmail.ts | 2 +- packages/features/bookings/Booker/types.ts | 35 ++ .../bookings/components/VerifyCodeDialog.tsx | 70 ++-- .../components/CreateANewOrganizationForm.tsx | 28 +- 26 files changed, 591 insertions(+), 370 deletions(-) delete mode 100644 packages/atoms/booker/Booker.tsx create mode 100644 packages/atoms/booker/wrappers/BookerWebWrapper.tsx create mode 100644 packages/features/bookings/Booker/components/hooks/useVerifyCode.ts diff --git a/packages/atoms/booker/Booker.docs.mdx b/packages/atoms/booker/Booker.docs.mdx index f92c09c954..7355e12376 100644 --- a/packages/atoms/booker/Booker.docs.mdx +++ b/packages/atoms/booker/Booker.docs.mdx @@ -1,6 +1,6 @@ import { Meta, Canvas, ArgsTable } from "@storybook/blocks"; import { Title } from "@calcom/storybook/components"; -import { Booker } from "./Booker"; +import { BookerWebWrapper as Booker } from "./wrappers/BookerWebWrapper"; import * as BookerStories from "./Booker.stories"; diff --git a/packages/atoms/booker/Booker.stories.tsx b/packages/atoms/booker/Booker.stories.tsx index ab485daa3f..7ab0111f37 100644 --- a/packages/atoms/booker/Booker.stories.tsx +++ b/packages/atoms/booker/Booker.stories.tsx @@ -1,6 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react"; -import { Booker } from "./Booker"; +import { BookerWebWrapper as Booker } from "./wrappers/BookerWebWrapper"; const meta: Meta = { component: Booker, diff --git a/packages/atoms/booker/Booker.tsx b/packages/atoms/booker/Booker.tsx deleted file mode 100644 index 28e050bace..0000000000 --- a/packages/atoms/booker/Booker.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import type { BookerProps } from "@calcom/features/bookings/Booker"; -import { Booker as BookerComponent } from "@calcom/features/bookings/Booker"; - -import type { AtomsGlobalConfigProps } from "../types"; - -type BookerAtomProps = BookerProps & AtomsGlobalConfigProps; - -/** - * @TODO Before we can turn this into a reusable atom - * * Use the webAppUrl coming from AtomsGlobalConfigProps to make url dynamic - * * Find a solution for translations - */ -export const Booker = (props: BookerAtomProps) => ; diff --git a/packages/atoms/booker/export.ts b/packages/atoms/booker/export.ts index 2bb3a2ac04..3c06badbb9 100644 --- a/packages/atoms/booker/export.ts +++ b/packages/atoms/booker/export.ts @@ -1,5 +1,5 @@ /** Export file is only used for building the dist version of this Atom. */ // import "../globals.css"; -export { Booker } from "./Booker"; +export { BookerWebWrapper as Booker } from "./wrappers/BookerWebWrapper"; export * from "../types"; diff --git a/packages/atoms/booker/index.ts b/packages/atoms/booker/index.ts index 47fb01d585..8f1e66dfa0 100644 --- a/packages/atoms/booker/index.ts +++ b/packages/atoms/booker/index.ts @@ -1 +1 @@ -export { Booker } from "./Booker"; +export { BookerWebWrapper as Booker } from "./wrappers/BookerWebWrapper"; diff --git a/packages/atoms/booker/wrappers/BookerWebWrapper.tsx b/packages/atoms/booker/wrappers/BookerWebWrapper.tsx new file mode 100644 index 0000000000..3fffb53cbb --- /dev/null +++ b/packages/atoms/booker/wrappers/BookerWebWrapper.tsx @@ -0,0 +1,195 @@ +import { useSession } from "next-auth/react"; +import { useSearchParams } from "next/navigation"; +import { usePathname, useRouter } from "next/navigation"; +import { useMemo, useCallback } from "react"; +import { shallow } from "zustand/shallow"; + +import dayjs from "@calcom/dayjs"; +import type { BookerProps } from "@calcom/features/bookings/Booker"; +import { Booker as BookerComponent } from "@calcom/features/bookings/Booker"; +import { useBookerLayout } from "@calcom/features/bookings/Booker/components/hooks/useBookerLayout"; +import { useBookingForm } from "@calcom/features/bookings/Booker/components/hooks/useBookingForm"; +import { useBookings } from "@calcom/features/bookings/Booker/components/hooks/useBookings"; +import { useCalendars } from "@calcom/features/bookings/Booker/components/hooks/useCalendars"; +import { useSlots } from "@calcom/features/bookings/Booker/components/hooks/useSlots"; +import { useVerifyCode } from "@calcom/features/bookings/Booker/components/hooks/useVerifyCode"; +import { useVerifyEmail } from "@calcom/features/bookings/Booker/components/hooks/useVerifyEmail"; +import { useBookerStore, useInitializeBookerStore } from "@calcom/features/bookings/Booker/store"; +import { useEvent, useScheduleForEvent } from "@calcom/features/bookings/Booker/utils/event"; +import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery"; +import { BookerLayouts } from "@calcom/prisma/zod-utils"; + +import type { AtomsGlobalConfigProps } from "../../types"; + +type BookerWebWrapperAtomProps = BookerProps & AtomsGlobalConfigProps; + +export const BookerWebWrapper = (props: BookerWebWrapperAtomProps) => { + const router = useRouter(); + const pathname = usePathname(); + const searchParams = useSearchParams(); + const event = useEvent(); + const bookerLayout = useBookerLayout(event.data); + + const selectedDate = searchParams?.get("date"); + const isRedirect = searchParams?.get("redirected") === "true" || false; + const fromUserNameRedirected = searchParams?.get("username") || ""; + const rescheduleUid = + typeof window !== "undefined" ? new URLSearchParams(window.location.search).get("rescheduleUid") : null; + const bookingUid = + typeof window !== "undefined" ? new URLSearchParams(window.location.search).get("bookingUid") : null; + const date = dayjs(selectedDate).format("YYYY-MM-DD"); + + useInitializeBookerStore({ + ...props, + eventId: event?.data?.id, + rescheduleUid, + bookingUid: bookingUid, + layout: bookerLayout.defaultLayout, + org: props.entity.orgSlug, + }); + + const [bookerState, _] = useBookerStore((state) => [state.state, state.setState], shallow); + const [dayCount] = useBookerStore((state) => [state.dayCount, state.setDayCount], shallow); + const { data: session } = useSession(); + const routerQuery = useRouterQuery(); + const hasSession = !!session; + const firstNameQueryParam = searchParams?.get("firstName"); + const lastNameQueryParam = searchParams?.get("lastName"); + const metadata = Object.keys(routerQuery) + .filter((key) => key.startsWith("metadata")) + .reduce( + (metadata, key) => ({ + ...metadata, + [key.substring("metadata[".length, key.length - 1)]: searchParams?.get(key), + }), + {} + ); + const prefillFormParams = useMemo(() => { + return { + name: + searchParams?.get("name") || + (firstNameQueryParam ? `${firstNameQueryParam} ${lastNameQueryParam}` : null), + guests: searchParams?.getAll("guests") || searchParams?.getAll("guest"), + }; + }, [searchParams, firstNameQueryParam, lastNameQueryParam]); + + const bookerForm = useBookingForm({ + event, + sessionEmail: session?.user.email, + sessionUsername: session?.user.username, + sessionName: session?.user.name, + hasSession, + extraOptions: routerQuery, + prefillFormParams, + }); + const bookings = useBookings({ + event, + hashedLink: props.hashedLink, + bookingForm: bookerForm.bookingForm, + metadata: metadata ?? {}, + }); + const calendars = useCalendars({ hasSession }); + const verifyEmail = useVerifyEmail({ + email: bookerForm.formEmail, + name: bookerForm.formName, + requiresBookerEmailVerification: event?.data?.requiresBookerEmailVerification, + onVerifyEmail: bookerForm.beforeVerifyEmail, + }); + const slots = useSlots(event); + + const prefetchNextMonth = + (bookerLayout.layout === BookerLayouts.WEEK_VIEW && + !!bookerLayout.extraDays && + dayjs(date).month() !== dayjs(date).add(bookerLayout.extraDays, "day").month()) || + (bookerLayout.layout === BookerLayouts.COLUMN_VIEW && + dayjs(date).month() !== dayjs(date).add(bookerLayout.columnViewExtraDays.current, "day").month()); + + const monthCount = + ((bookerLayout.layout !== BookerLayouts.WEEK_VIEW && bookerState === "selecting_time") || + bookerLayout.layout === BookerLayouts.COLUMN_VIEW) && + dayjs(date).add(1, "month").month() !== + dayjs(date).add(bookerLayout.columnViewExtraDays.current, "day").month() + ? 2 + : undefined; + /** + * Prioritize dateSchedule load + * Component will render but use data already fetched from here, and no duplicate requests will be made + * */ + const schedule = useScheduleForEvent({ + prefetchNextMonth, + username: props.username, + monthCount, + dayCount, + eventSlug: props.eventSlug, + month: props.month, + duration: props.duration, + selectedDate, + }); + + const verifyCode = useVerifyCode({ + onSuccess: () => { + verifyEmail.setVerifiedEmail(bookerForm.formEmail); + verifyEmail.setEmailVerificationModalVisible(false); + bookings.handleBookEvent(); + }, + }); + + // Toggle query param for overlay calendar + const onOverlaySwitchStateChange = useCallback( + (state: boolean) => { + const current = new URLSearchParams(Array.from(searchParams?.entries() ?? [])); + if (state) { + current.set("overlayCalendar", "true"); + localStorage.setItem("overlayCalendarSwitchDefault", "true"); + } else { + current.delete("overlayCalendar"); + localStorage.removeItem("overlayCalendarSwitchDefault"); + } + // cast to string + const value = current.toString(); + const query = value ? `?${value}` : ""; + router.push(`${pathname}${query}`); + }, + [searchParams, pathname, router] + ); + + return ( + { + if (pathname) window.location.href = pathname; + }} + onConnectNowInstantMeeting={() => { + const newPath = `${pathname}?isInstantMeeting=true`; + router.push(newPath); + }} + onOverlayClickNoCalendar={() => { + router.push("/apps/categories/calendar"); + }} + onClickOverlayContinue={() => { + const currentUrl = new URL(window.location.href); + currentUrl.pathname = "/login/"; + currentUrl.searchParams.set("callbackUrl", window.location.pathname); + currentUrl.searchParams.set("overlayCalendar", "true"); + router.push(currentUrl.toString()); + }} + onOverlaySwitchStateChange={onOverlaySwitchStateChange} + sessionUsername={session?.user.username} + isRedirect={isRedirect} + fromUserNameRedirected={fromUserNameRedirected} + rescheduleUid={rescheduleUid} + bookingUid={bookingUid} + hasSession={hasSession} + extraOptions={routerQuery} + bookings={bookings} + calendars={calendars} + slots={slots} + verifyEmail={verifyEmail} + bookerForm={bookerForm} + event={event} + bookerLayout={bookerLayout} + schedule={schedule} + verifyCode={verifyCode} + /> + ); +}; diff --git a/packages/atoms/index.ts b/packages/atoms/index.ts index fc1b9f7f9d..07163614f2 100644 --- a/packages/atoms/index.ts +++ b/packages/atoms/index.ts @@ -1,2 +1,2 @@ -export { Booker } from "./booker/Booker"; +export { Booker } from "./booker"; export { CalProvider } from "./cal-provider/index"; diff --git a/packages/features/bookings/Booker/Booker.tsx b/packages/features/bookings/Booker/Booker.tsx index e08a5e3cde..2acb06150c 100644 --- a/packages/features/bookings/Booker/Booker.tsx +++ b/packages/features/bookings/Booker/Booker.tsx @@ -1,8 +1,5 @@ import { LazyMotion, m, AnimatePresence } from "framer-motion"; -import { useSession } from "next-auth/react"; import dynamic from "next/dynamic"; -import { useSearchParams } from "next/navigation"; -import { usePathname, useRouter } from "next/navigation"; import { useEffect, useRef, useMemo } from "react"; import StickyBox from "react-sticky-box"; import { shallow } from "zustand/shallow"; @@ -29,16 +26,9 @@ import { OverlayCalendar } from "./components/OverlayCalendar/OverlayCalendar"; import { RedirectToInstantMeetingModal } from "./components/RedirectToInstantMeetingModal"; import { BookerSection } from "./components/Section"; import { Away, NotFound } from "./components/Unavailable"; -import { useBookerLayout } from "./components/hooks/useBookerLayout"; -import { useBookingForm } from "./components/hooks/useBookingForm"; -import { useBookings } from "./components/hooks/useBookings"; -import { useCalendars } from "./components/hooks/useCalendars"; -import { useSlots } from "./components/hooks/useSlots"; -import { useVerifyEmail } from "./components/hooks/useVerifyEmail"; import { fadeInLeft, getBookerSizeClassNames, useBookerResizeAnimation } from "./config"; -import { useBookerStore, useInitializeBookerStore } from "./store"; -import type { BookerProps } from "./types"; -import { useEvent, useScheduleForEvent } from "./utils/event"; +import { useBookerStore } from "./store"; +import type { BookerProps, WrappedBookerProps } from "./types"; import { useBrandColors } from "./utils/use-brand-colors"; const loadFramerFeatures = () => import("./framer-features").then((res) => res.default); @@ -53,28 +43,32 @@ const DatePicker = dynamic(() => import("./components/DatePicker").then((mod) => const BookerComponent = ({ username, eventSlug, - month, - bookingData, hideBranding = false, - isTeamEvent, entity, - durationConfig, - duration, - hashedLink, isInstantMeeting = false, -}: BookerProps) => { - const router = useRouter(); - const pathname = usePathname(); + onGoBackInstantMeeting, + onConnectNowInstantMeeting, + onOverlayClickNoCalendar, + onClickOverlayContinue, + onOverlaySwitchStateChange, + sessionUsername, + isRedirect, + fromUserNameRedirected, + rescheduleUid, + hasSession, + extraOptions, + bookings, + verifyEmail, + slots, + calendars, + bookerForm, + event, + bookerLayout, + schedule, + verifyCode, +}: BookerProps & WrappedBookerProps) => { const [bookerState, setBookerState] = useBookerStore((state) => [state.state, state.setState], shallow); const selectedDate = useBookerStore((state) => state.selectedDate); - const [seatedEventData, setSeatedEventData] = useBookerStore( - (state) => [state.seatedEventData, state.setSeatedEventData], - shallow - ); - const event = useEvent(); - const session = useSession(); - const { selectedTimeslot, setSelectedTimeslot } = useSlots(event); - const { shouldShowFormInDialog, hasDarkBackground, @@ -82,47 +76,19 @@ const BookerComponent = ({ columnViewExtraDays, isMobile, layout, - defaultLayout, hideEventTypeDetails, isEmbed, bookerLayouts, - } = useBookerLayout(event.data); + } = bookerLayout; + + const [seatedEventData, setSeatedEventData] = useBookerStore( + (state) => [state.seatedEventData, state.setSeatedEventData], + shallow + ); + const { selectedTimeslot, setSelectedTimeslot } = slots; const [dayCount, setDayCount] = useBookerStore((state) => [state.dayCount, state.setDayCount], shallow); - const date = dayjs(selectedDate).format("YYYY-MM-DD"); - - const prefetchNextMonth = - (layout === BookerLayouts.WEEK_VIEW && - !!extraDays && - dayjs(date).month() !== dayjs(date).add(extraDays, "day").month()) || - (layout === BookerLayouts.COLUMN_VIEW && - dayjs(date).month() !== dayjs(date).add(columnViewExtraDays.current, "day").month()); - - const monthCount = - ((layout !== BookerLayouts.WEEK_VIEW && bookerState === "selecting_time") || - layout === BookerLayouts.COLUMN_VIEW) && - dayjs(date).add(1, "month").month() !== dayjs(date).add(columnViewExtraDays.current, "day").month() - ? 2 - : undefined; - - const searchParams = useSearchParams(); - - /** - * Prioritize dateSchedule load - * Component will render but use data already fetched from here, and no duplicate requests will be made - * */ - const schedule = useScheduleForEvent({ - prefetchNextMonth, - username, - monthCount, - dayCount, - eventSlug, - month, - duration, - selectedDate: searchParams?.get("date"), - }); - const nonEmptyScheduleDays = useNonEmptyScheduleDays(schedule?.data?.slots).filter( (slot) => dayjs(selectedDate).diff(slot, "day") <= 0 ); @@ -146,67 +112,24 @@ const BookerComponent = ({ const timeslotsRef = useRef(null); const StickyOnDesktop = isMobile ? "div" : StickyBox; - const rescheduleUid = - typeof window !== "undefined" ? new URLSearchParams(window.location.search).get("rescheduleUid") : null; - const bookingUid = - typeof window !== "undefined" ? new URLSearchParams(window.location.search).get("bookingUid") : null; const { t } = useLocale(); - const isRedirect = searchParams?.get("redirected") === "true" || false; - const fromUserNameRedirected = searchParams?.get("username") || ""; - useBrandColors({ brandColor: event.data?.profile.brandColor ?? DEFAULT_LIGHT_BRAND_COLOR, darkBrandColor: event.data?.profile.darkBrandColor ?? DEFAULT_DARK_BRAND_COLOR, theme: event.data?.profile.theme, }); - useInitializeBookerStore({ - username, - eventSlug, - month, - eventId: event?.data?.id, - rescheduleUid, - bookingUid, - bookingData, - layout: defaultLayout, - isTeamEvent, - org: entity.orgSlug, - durationConfig, - isInstantMeeting, - }); - - const { - bookerFormErrorRef, - key, - formEmail, - formName, - bookingForm, - beforeVerifyEmail, - errors: formErrors, - } = useBookingForm({ - event, - }); - - const { handleBookEvent, hasInstantMeetingTokenExpired, errors, loadingStates, expiryTime } = useBookings({ - event, - hashedLink, - bookingForm, - }); + const { bookerFormErrorRef, key, formEmail, bookingForm, errors: formErrors } = bookerForm; + const { handleBookEvent, hasInstantMeetingTokenExpired, errors, loadingStates, expiryTime } = bookings; const { isEmailVerificationModalVisible, setEmailVerificationModalVisible, handleVerifyEmail, - setVerifiedEmail, renderConfirmNotVerifyEmailButtonCond, - } = useVerifyEmail({ - email: formEmail, - name: formName, - requiresBookerEmailVerification: event?.data?.requiresBookerEmailVerification, - onVerifyEmail: beforeVerifyEmail, - }); + } = verifyEmail; const { overlayBusyDates, @@ -214,7 +137,7 @@ const BookerComponent = ({ connectedCalendars, loadingConnectedCalendar, onToggleCalendar, - } = useCalendars(); + } = calendars; useEffect(() => { if (event.isPending) return setBookerState("loading"); @@ -223,76 +146,81 @@ const BookerComponent = ({ return setBookerState("booking"); }, [event, selectedDate, selectedTimeslot, setBookerState]); - const EventBooker = useMemo( - () => - bookerState === "booking" ? ( - { - setSelectedTimeslot(null); - if (seatedEventData.bookingUid) { - setSeatedEventData({ ...seatedEventData, bookingUid: undefined, attendees: undefined }); - } - }} - onSubmit={renderConfirmNotVerifyEmailButtonCond ? handleBookEvent : handleVerifyEmail} - errorRef={bookerFormErrorRef} - errors={{ ...formErrors, ...errors }} - loadingStates={loadingStates} - renderConfirmNotVerifyEmailButtonCond={renderConfirmNotVerifyEmailButtonCond} - bookingForm={bookingForm} - eventQuery={event} - rescheduleUid={rescheduleUid}> - <> - { - setVerifiedEmail(formEmail); - setEmailVerificationModalVisible(false); - handleBookEvent(); - }} - isUserSessionRequiredToVerify={false} - /> - { - // Prevent null on app directory - if (pathname) window.location.href = pathname; - }} - /> - - - ) : ( - <> - ), - [ - bookerFormErrorRef, - bookerState, - bookingForm, - errors, - event, - formEmail, - formErrors, - handleBookEvent, - handleVerifyEmail, - hasInstantMeetingTokenExpired, - isEmailVerificationModalVisible, - key, - loadingStates, - pathname, - renderConfirmNotVerifyEmailButtonCond, - rescheduleUid, - seatedEventData, - setEmailVerificationModalVisible, - setSeatedEventData, - setSelectedTimeslot, - setVerifiedEmail, - expiryTime, - ] - ); + const EventBooker = useMemo(() => { + return bookerState === "booking" ? ( + { + setSelectedTimeslot(null); + if (seatedEventData.bookingUid) { + setSeatedEventData({ ...seatedEventData, bookingUid: undefined, attendees: undefined }); + } + }} + onSubmit={renderConfirmNotVerifyEmailButtonCond ? handleBookEvent : handleVerifyEmail} + errorRef={bookerFormErrorRef} + errors={{ ...formErrors, ...errors }} + loadingStates={loadingStates} + renderConfirmNotVerifyEmailButtonCond={renderConfirmNotVerifyEmailButtonCond} + bookingForm={bookingForm} + eventQuery={event} + extraOptions={extraOptions} + rescheduleUid={rescheduleUid}> + <> + + { + onGoBackInstantMeeting(); + }} + /> + + + ) : ( + <> + ); + }, [ + bookerFormErrorRef, + bookerState, + bookingForm, + errors, + event, + expiryTime, + extraOptions, + formEmail, + formErrors, + handleBookEvent, + handleVerifyEmail, + hasInstantMeetingTokenExpired, + isEmailVerificationModalVisible, + key, + loadingStates, + onGoBackInstantMeeting, + renderConfirmNotVerifyEmailButtonCond, + rescheduleUid, + seatedEventData, + setEmailVerificationModalVisible, + setSeatedEventData, + setSelectedTimeslot, + verifyCode.error, + verifyCode.isPending, + verifyCode.resetErrors, + verifyCode.setIsPending, + verifyCode.verifyCodeWithSessionNotRequired, + verifyCode.verifyCodeWithSessionRequired, + ]); if (entity.isUnpublished) { return ; @@ -317,8 +245,7 @@ const BookerComponent = ({ { - const newPath = `${pathname}?isInstantMeeting=true`; - router.push(newPath); + onConnectNowInstantMeeting(); }} /> @@ -372,7 +299,7 @@ const BookerComponent = ({ "bg-default dark:bg-muted sticky top-0 z-10" )}>
{ - router.push("/apps/categories/calendar"); + onOverlayClickNoCalendar(); }} /> @@ -444,7 +374,12 @@ const BookerComponent = ({ visible={layout === BookerLayouts.WEEK_VIEW} className="border-subtle sticky top-0 ml-[-1px] h-full md:border-l" {...fadeInLeft}> - + { +export const Booker = (props: BookerProps & WrappedBookerProps) => { if (props.isAway) return ; return ( diff --git a/packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx b/packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx index d6f351168a..5eef9b990e 100644 --- a/packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx +++ b/packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx @@ -7,13 +7,12 @@ import type { FieldError } from "react-hook-form"; import { WEBSITE_URL } from "@calcom/lib/constants"; import getPaymentAppData from "@calcom/lib/getPaymentAppData"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery"; import { Alert, Button, EmptyScreen, Form } from "@calcom/ui"; import { Calendar } from "@calcom/ui/components/icon"; import { useBookerStore } from "../../store"; import type { useEventReturnType } from "../../utils/event"; -import type { useBookingFormReturnType } from "../hooks/useBookingForm"; +import type { UseBookingFormReturnType } from "../hooks/useBookingForm"; import type { IUseBookingErrors, IUseBookingLoadingStates } from "../hooks/useBookings"; import { BookingFields } from "./BookingFields"; import { FormSkeleton } from "./Skeleton"; @@ -22,11 +21,12 @@ type BookEventFormProps = { onCancel?: () => void; onSubmit: () => void; errorRef: React.RefObject; - errors: useBookingFormReturnType["errors"] & IUseBookingErrors; + errors: UseBookingFormReturnType["errors"] & IUseBookingErrors; loadingStates: IUseBookingLoadingStates; children?: React.ReactNode; - bookingForm: useBookingFormReturnType["bookingForm"]; + bookingForm: UseBookingFormReturnType["bookingForm"]; renderConfirmNotVerifyEmailButtonCond: boolean; + extraOptions: Record; }; export const BookEventForm = ({ @@ -40,12 +40,12 @@ export const BookEventForm = ({ renderConfirmNotVerifyEmailButtonCond, bookingForm, children, + extraOptions, }: Omit & { eventQuery: useEventReturnType; rescheduleUid: string | null; }) => { const eventType = eventQuery.data; - const routerQuery = useRouterQuery(); const setFormValues = useBookerStore((state) => state.setFormValues); const bookingData = useBookerStore((state) => state.bookingData); const timeslot = useBookerStore((state) => state.selectedTimeslot); @@ -76,7 +76,7 @@ export const BookEventForm = ({ ); if (!eventType) { - console.warn("No event type found for event", routerQuery); + console.warn("No event type found for event", extraOptions); return ; } diff --git a/packages/features/bookings/Booker/components/InstantBooking.tsx b/packages/features/bookings/Booker/components/InstantBooking.tsx index 3677993dcf..11db897e5a 100644 --- a/packages/features/bookings/Booker/components/InstantBooking.tsx +++ b/packages/features/bookings/Booker/components/InstantBooking.tsx @@ -1,11 +1,11 @@ +import type { useEventReturnType } from "@calcom/features/bookings/Booker/utils/event"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { SchedulingType } from "@calcom/prisma/enums"; -import { type RouterOutputs } from "@calcom/trpc"; import { Button, UserAvatarGroupWithOrg } from "@calcom/ui"; interface IInstantBookingProps { onConnectNow: () => void; - event: NonNullable; + event: NonNullable; } export const InstantBooking = ({ onConnectNow, event }: IInstantBookingProps) => { diff --git a/packages/features/bookings/Booker/components/LargeCalendar.tsx b/packages/features/bookings/Booker/components/LargeCalendar.tsx index 6702b27102..66183d13e3 100644 --- a/packages/features/bookings/Booker/components/LargeCalendar.tsx +++ b/packages/features/bookings/Booker/components/LargeCalendar.tsx @@ -7,8 +7,7 @@ import type { CalendarAvailableTimeslots } from "@calcom/features/calendars/week import { localStorage } from "@calcom/lib/webstorage"; import { useBookerStore } from "../store"; -import type { useScheduleForEventReturnType } from "../utils/event"; -import { useEvent } from "../utils/event"; +import type { useEventReturnType, useScheduleForEventReturnType } from "../utils/event"; import { getQueryParam } from "../utils/query-param"; import { useOverlayCalendarStore } from "./OverlayCalendar/store"; @@ -16,10 +15,12 @@ export const LargeCalendar = ({ extraDays, schedule, isLoading, + event, }: { extraDays: number; schedule?: useScheduleForEventReturnType["data"]; isLoading: boolean; + event: useEventReturnType; }) => { const selectedDate = useBookerStore((state) => state.selectedDate); const setSelectedTimeslot = useBookerStore((state) => state.setSelectedTimeslot); @@ -28,7 +29,6 @@ export const LargeCalendar = ({ const displayOverlay = getQueryParam("overlayCalendar") === "true" || localStorage.getItem("overlayCalendarSwitchDefault"); - const event = useEvent(); const eventDuration = selectedEventDuration || event?.data?.length || 30; const availableSlots = useMemo(() => { diff --git a/packages/features/bookings/Booker/components/OverlayCalendar/OverlayCalendar.tsx b/packages/features/bookings/Booker/components/OverlayCalendar/OverlayCalendar.tsx index f67323315f..ac7ab7b632 100644 --- a/packages/features/bookings/Booker/components/OverlayCalendar/OverlayCalendar.tsx +++ b/packages/features/bookings/Booker/components/OverlayCalendar/OverlayCalendar.tsx @@ -11,7 +11,12 @@ type OverlayCalendarProps = Pick< | "onToggleCalendar" | "loadingConnectedCalendar" | "isOverlayCalendarEnabled" -> & { handleClickNoCalendar: () => void }; +> & { + handleClickNoCalendar: () => void; + hasSession: boolean; + handleClickContinue: () => void; + handleSwitchStateChange: (state: boolean) => void; +}; export const OverlayCalendar = ({ connectedCalendars, @@ -20,6 +25,9 @@ export const OverlayCalendar = ({ isOverlayCalendarEnabled, loadingConnectedCalendar, handleClickNoCalendar, + handleSwitchStateChange, + handleClickContinue, + hasSession, }: OverlayCalendarProps) => { const { handleCloseContinueModal, @@ -31,8 +39,16 @@ export const OverlayCalendar = ({ } = useOverlayCalendar({ connectedCalendars, overlayBusyDates, onToggleCalendar }); return ( <> - - + + void; + onContinue: () => void; } export function OverlayCalendarContinueModal(props: IOverlayCalendarContinueModalProps) { - const router = useRouter(); const { t } = useLocale(); return ( <> @@ -24,12 +23,7 @@ export function OverlayCalendarContinueModal(props: IOverlayCalendarContinueModa