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 <hariombalhara@gmail.com>
This commit is contained in:
co-authored by
Hariom Balhara
parent
8741714402
commit
caaecf2f94
@@ -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<ClientPageProps>(getServerSideProps);
|
||||||
|
|
||||||
|
const ServerPage = async ({ params, searchParams }: ServerPageProps) => {
|
||||||
|
const context = buildLegacyCtx(headers(), cookies(), params, searchParams);
|
||||||
|
const props = await getData(context);
|
||||||
|
return <TypePage {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ServerPage;
|
||||||
@@ -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<ClientPageProps>(getServerSideProps);
|
||||||
|
|
||||||
|
const ServerPage = async ({ params, searchParams }: ServerPageProps) => {
|
||||||
|
const context = buildLegacyCtx(headers(), cookies(), params, searchParams);
|
||||||
|
const props = await getData(context);
|
||||||
|
return <User {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ServerPage;
|
||||||
@@ -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) => <TypePage {...props} />;
|
|
||||||
|
|
||||||
Type.PageWrapper = PageWrapper;
|
|
||||||
|
|
||||||
export default Type;
|
|
||||||
@@ -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) => <User {...props} />;
|
|
||||||
|
|
||||||
UserPage.PageWrapper = PageWrapper;
|
|
||||||
|
|
||||||
export default UserPage;
|
|
||||||
@@ -64,7 +64,7 @@ export const useBookingForm = ({
|
|||||||
};
|
};
|
||||||
const isRescheduling = !!rescheduleUid && !!bookingData;
|
const isRescheduling = !!rescheduleUid && !!bookingData;
|
||||||
|
|
||||||
const { initialValues, key } = useInitialFormValues({
|
const { values: initialValues, key } = useInitialFormValues({
|
||||||
eventType: event,
|
eventType: event,
|
||||||
rescheduleUid,
|
rescheduleUid,
|
||||||
isRescheduling,
|
isRescheduling,
|
||||||
|
|||||||
@@ -24,6 +24,34 @@ type UseInitialFormValuesProps = {
|
|||||||
lastBookingResponse?: Record<string, string>;
|
lastBookingResponse?: Record<string, string>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Add this stable hash function
|
||||||
|
function getStableHash(obj: Record<string, string | string[]>) {
|
||||||
|
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<string, any>;
|
||||||
|
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({
|
export function useInitialFormValues({
|
||||||
eventType,
|
eventType,
|
||||||
rescheduleUid,
|
rescheduleUid,
|
||||||
@@ -36,16 +64,27 @@ export function useInitialFormValues({
|
|||||||
prefillFormParams,
|
prefillFormParams,
|
||||||
lastBookingResponse,
|
lastBookingResponse,
|
||||||
}: UseInitialFormValuesProps) {
|
}: UseInitialFormValuesProps) {
|
||||||
const [initialValues, setDefaultValues] = useState<{
|
const stableHashExtraOptions = getStableHash(extraOptions);
|
||||||
responses?: Partial<z.infer<ReturnType<typeof getBookingResponsesSchema>>>;
|
|
||||||
bookingId?: number;
|
const [initialValuesState, setInitialValuesState] = useState<{
|
||||||
}>({});
|
values: {
|
||||||
|
responses?: Partial<z.infer<ReturnType<typeof getBookingResponsesSchema>>>;
|
||||||
|
bookingId?: number;
|
||||||
|
};
|
||||||
|
key: string;
|
||||||
|
}>({
|
||||||
|
values: {},
|
||||||
|
key: "",
|
||||||
|
});
|
||||||
const bookingData = useBookerStore((state) => state.bookingData);
|
const bookingData = useBookerStore((state) => state.bookingData);
|
||||||
const formValues = useBookerStore((state) => state.formValues);
|
const formValues = useBookerStore((state) => state.formValues);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async function () {
|
(async function () {
|
||||||
if (Object.keys(formValues).length) {
|
if (Object.keys(formValues).length) {
|
||||||
setDefaultValues(formValues);
|
setInitialValuesState({
|
||||||
|
values: formValues,
|
||||||
|
key: buildKey({ values: formValues, hasSession, stableHashExtraOptions }),
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +138,10 @@ export function useInitialFormValues({
|
|||||||
email: defaultUserValues.email ?? "",
|
email: defaultUserValues.email ?? "",
|
||||||
};
|
};
|
||||||
|
|
||||||
setDefaultValues(defaults);
|
setInitialValuesState({
|
||||||
|
values: defaults,
|
||||||
|
key: buildKey({ values: defaults, hasSession, stableHashExtraOptions }),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rescheduleUid && !bookingData) {
|
if (!rescheduleUid && !bookingData) {
|
||||||
@@ -124,9 +166,12 @@ export function useInitialFormValues({
|
|||||||
name: defaultUserValues.name,
|
name: defaultUserValues.name,
|
||||||
email: defaultUserValues.email ?? "",
|
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
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [
|
}, [
|
||||||
eventType?.bookingFields,
|
eventType?.bookingFields,
|
||||||
@@ -139,11 +184,9 @@ export function useInitialFormValues({
|
|||||||
name,
|
name,
|
||||||
username,
|
username,
|
||||||
prefillFormParams,
|
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
|
return initialValuesState;
|
||||||
// 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 };
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user