From caaecf2f94de838d462a26df85b24e482afb6a33 Mon Sep 17 00:00:00 2001 From: Benny Joo Date: Wed, 26 Feb 2025 05:50:27 -0500 Subject: [PATCH] chore: migrate /user embed pages (#19149) * add user pages to config.matcher in middleware * add app router user booking pages * remove HeadSeo from users-public-view component * remove pages router user booking pages * fix type check * fix embed * fix test * chore: remove BookerSEO from users-type-public-view * fix * migrate all /user embed pages to app router * remove /future routes * fix prefill not working with preload * move to (booking-page-wrapper) route group --------- Co-authored-by: Hariom Balhara --- .../[user]/[type]/embed/page.tsx | 19 +++++ .../[user]/embed/page.tsx | 19 +++++ apps/web/pages/[user]/[type]/embed.tsx | 16 ----- apps/web/pages/[user]/embed.tsx | 15 ---- .../Booker/components/hooks/useBookingForm.ts | 2 +- .../components/hooks/useInitialFormValues.ts | 69 +++++++++++++++---- 6 files changed, 95 insertions(+), 45 deletions(-) create mode 100644 apps/web/app/(booking-page-wrapper)/[user]/[type]/embed/page.tsx create mode 100644 apps/web/app/(booking-page-wrapper)/[user]/embed/page.tsx delete mode 100644 apps/web/pages/[user]/[type]/embed.tsx delete mode 100644 apps/web/pages/[user]/embed.tsx diff --git a/apps/web/app/(booking-page-wrapper)/[user]/[type]/embed/page.tsx b/apps/web/app/(booking-page-wrapper)/[user]/[type]/embed/page.tsx new file mode 100644 index 0000000000..0e78ce9f45 --- /dev/null +++ b/apps/web/app/(booking-page-wrapper)/[user]/[type]/embed/page.tsx @@ -0,0 +1,19 @@ +import withEmbedSsrAppDir from "app/WithEmbedSSR"; +import type { PageProps as ServerPageProps } from "app/_types"; +import { cookies, headers } from "next/headers"; + +import { buildLegacyCtx } from "@lib/buildLegacyCtx"; + +import { getServerSideProps } from "@server/lib/[user]/[type]/getServerSideProps"; + +import TypePage, { type PageProps as ClientPageProps } from "~/users/views/users-type-public-view"; + +const getData = withEmbedSsrAppDir(getServerSideProps); + +const ServerPage = async ({ params, searchParams }: ServerPageProps) => { + const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const props = await getData(context); + return ; +}; + +export default ServerPage; diff --git a/apps/web/app/(booking-page-wrapper)/[user]/embed/page.tsx b/apps/web/app/(booking-page-wrapper)/[user]/embed/page.tsx new file mode 100644 index 0000000000..df9491b2e9 --- /dev/null +++ b/apps/web/app/(booking-page-wrapper)/[user]/embed/page.tsx @@ -0,0 +1,19 @@ +import withEmbedSsrAppDir from "app/WithEmbedSSR"; +import type { PageProps as ServerPageProps } from "app/_types"; +import { cookies, headers } from "next/headers"; + +import { buildLegacyCtx } from "@lib/buildLegacyCtx"; + +import { getServerSideProps } from "@server/lib/[user]/getServerSideProps"; + +import User, { type PageProps as ClientPageProps } from "~/users/views/users-public-view"; + +const getData = withEmbedSsrAppDir(getServerSideProps); + +const ServerPage = async ({ params, searchParams }: ServerPageProps) => { + const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const props = await getData(context); + return ; +}; + +export default ServerPage; diff --git a/apps/web/pages/[user]/[type]/embed.tsx b/apps/web/pages/[user]/[type]/embed.tsx deleted file mode 100644 index c0c99d663e..0000000000 --- a/apps/web/pages/[user]/[type]/embed.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import withEmbedSsr from "@lib/withEmbedSsr"; - -import PageWrapper from "@components/PageWrapper"; - -import { getServerSideProps as _getServerSideProps } from "@server/lib/[user]/[type]/getServerSideProps"; - -import type { PageProps } from "~/users/views/users-type-public-view"; -import TypePage from "~/users/views/users-type-public-view"; - -export const getServerSideProps = withEmbedSsr(_getServerSideProps); - -const Type = (props: PageProps) => ; - -Type.PageWrapper = PageWrapper; - -export default Type; diff --git a/apps/web/pages/[user]/embed.tsx b/apps/web/pages/[user]/embed.tsx deleted file mode 100644 index abf2228e49..0000000000 --- a/apps/web/pages/[user]/embed.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import withEmbedSsr from "@lib/withEmbedSsr"; - -import PageWrapper from "@components/PageWrapper"; - -import { getServerSideProps as _getServerSideProps } from "@server/lib/[user]/getServerSideProps"; - -import User, { type PageProps } from "~/users/views/users-public-view"; - -export const getServerSideProps = withEmbedSsr(_getServerSideProps); - -const UserPage = (props: PageProps) => ; - -UserPage.PageWrapper = PageWrapper; - -export default UserPage; diff --git a/packages/features/bookings/Booker/components/hooks/useBookingForm.ts b/packages/features/bookings/Booker/components/hooks/useBookingForm.ts index 65711da11e..0191e71c9b 100644 --- a/packages/features/bookings/Booker/components/hooks/useBookingForm.ts +++ b/packages/features/bookings/Booker/components/hooks/useBookingForm.ts @@ -64,7 +64,7 @@ export const useBookingForm = ({ }; const isRescheduling = !!rescheduleUid && !!bookingData; - const { initialValues, key } = useInitialFormValues({ + const { values: initialValues, key } = useInitialFormValues({ eventType: event, rescheduleUid, isRescheduling, diff --git a/packages/features/bookings/Booker/components/hooks/useInitialFormValues.ts b/packages/features/bookings/Booker/components/hooks/useInitialFormValues.ts index 434b4aed74..143f424485 100644 --- a/packages/features/bookings/Booker/components/hooks/useInitialFormValues.ts +++ b/packages/features/bookings/Booker/components/hooks/useInitialFormValues.ts @@ -24,6 +24,34 @@ type UseInitialFormValuesProps = { lastBookingResponse?: Record; }; +// Add this stable hash function +function getStableHash(obj: Record) { + return Object.entries(obj) + .sort(([keyA], [keyB]) => keyA.localeCompare(keyB)) + .map(([key, value]) => { + if (Array.isArray(value)) { + return `${key}:${value.sort().join(",")}`; + } + return `${key}:${value}`; + }) + .join("|"); +} + +const buildKey = ({ + values, + hasSession, + stableHashExtraOptions, +}: { + values: Record; + hasSession: boolean; + stableHashExtraOptions: string; +}) => { + // We could think about removing specific items like values.length, hasSession and bookingId and instead use a stableHash maybe . + return `${Object.keys(values).length}_${hasSession ? 1 : 0}_${ + values.bookingId ?? 0 + }_${stableHashExtraOptions}`; +}; + export function useInitialFormValues({ eventType, rescheduleUid, @@ -36,16 +64,27 @@ export function useInitialFormValues({ prefillFormParams, lastBookingResponse, }: UseInitialFormValuesProps) { - const [initialValues, setDefaultValues] = useState<{ - responses?: Partial>>; - bookingId?: number; - }>({}); + const stableHashExtraOptions = getStableHash(extraOptions); + + const [initialValuesState, setInitialValuesState] = useState<{ + values: { + responses?: Partial>>; + bookingId?: number; + }; + key: string; + }>({ + values: {}, + key: "", + }); const bookingData = useBookerStore((state) => state.bookingData); const formValues = useBookerStore((state) => state.formValues); useEffect(() => { (async function () { if (Object.keys(formValues).length) { - setDefaultValues(formValues); + setInitialValuesState({ + values: formValues, + key: buildKey({ values: formValues, hasSession, stableHashExtraOptions }), + }); return; } @@ -99,7 +138,10 @@ export function useInitialFormValues({ email: defaultUserValues.email ?? "", }; - setDefaultValues(defaults); + setInitialValuesState({ + values: defaults, + key: buildKey({ values: defaults, hasSession, stableHashExtraOptions }), + }); } if (!rescheduleUid && !bookingData) { @@ -124,9 +166,12 @@ export function useInitialFormValues({ name: defaultUserValues.name, email: defaultUserValues.email ?? "", }; - setDefaultValues(defaults); + setInitialValuesState({ + values: defaults, + key: buildKey({ values: defaults, hasSession, stableHashExtraOptions }), + }); })(); - // do not add extraOptions as a dependency, it will cause infinite loop + // TODO: Remove it. It was initially added so that we don't add extraOptions in deps but that is handled using stableHashExtraOptions now. // eslint-disable-next-line react-hooks/exhaustive-deps }, [ eventType?.bookingFields, @@ -139,11 +184,9 @@ export function useInitialFormValues({ name, username, prefillFormParams, + // We need to have extraOptions as a dep so that any change in query params can update the form values, but extraOptions itself isn't stable and changes reference on every render + stableHashExtraOptions, ]); - // When initialValues is available(after doing async schema parsing) or session is available(so that we can prefill logged-in user email and name), we need to reset the form with the initialValues - // We also need the key to change if the bookingId changes, so that the form is reset and rerendered with the new initialValues - const key = `${Object.keys(initialValues).length}_${hasSession ? 1 : 0}_${initialValues?.bookingId ?? 0}`; - - return { initialValues, key }; + return initialValuesState; }