From c839e40a3e90c91619767ccc12789c537e559d1b Mon Sep 17 00:00:00 2001 From: Benny Joo Date: Sat, 27 Jan 2024 10:57:43 +0000 Subject: [PATCH] chore: [app-router-migration 26] Migrate "/[user]" page (#13057) Co-authored-by: zomars --- .../app/future/[user]/[type]/embed/page.tsx | 12 + apps/web/app/future/[user]/[type]/page.tsx | 45 +++ apps/web/app/future/[user]/embed/page.tsx | 12 + apps/web/app/future/[user]/page.tsx | 33 ++ .../[user]/[type]/getServerSideProps.tsx | 3 +- .../users-public-view.getServerSideProps.tsx} | 288 +++--------------- .../modules/users/views/users-public-view.tsx | 195 ++++++++++++ ...s-type-public-view.getServerSideProps.tsx} | 4 + .../users/views/users-type-public-view.tsx} | 12 +- apps/web/pages/[user]/[type]/embed.tsx | 19 +- apps/web/pages/[user]/[type]/index.tsx | 16 + apps/web/pages/[user]/embed.tsx | 15 +- apps/web/pages/[user]/index.tsx | 16 + .../org/[orgSlug]/[user]/[type]/embed.tsx | 4 +- .../[user]/{[type].tsx => [type]/index.tsx} | 9 +- apps/web/pages/org/[orgSlug]/[user]/index.tsx | 5 +- apps/web/playwright/booking-pages.e2e.ts | 19 +- 17 files changed, 428 insertions(+), 279 deletions(-) create mode 100644 apps/web/app/future/[user]/[type]/embed/page.tsx create mode 100644 apps/web/app/future/[user]/[type]/page.tsx create mode 100644 apps/web/app/future/[user]/embed/page.tsx create mode 100644 apps/web/app/future/[user]/page.tsx rename apps/web/{pages/[user].tsx => modules/users/views/users-public-view.getServerSideProps.tsx} (51%) create mode 100644 apps/web/modules/users/views/users-public-view.tsx rename apps/web/{lib/[user]/[type]/getServerSideProps.tsx => modules/users/views/users-type-public-view.getServerSideProps.tsx} (96%) rename apps/web/{pages/[user]/[type].tsx => modules/users/views/users-type-public-view.tsx} (80%) create mode 100644 apps/web/pages/[user]/[type]/index.tsx create mode 100644 apps/web/pages/[user]/index.tsx rename apps/web/pages/org/[orgSlug]/[user]/{[type].tsx => [type]/index.tsx} (60%) diff --git a/apps/web/app/future/[user]/[type]/embed/page.tsx b/apps/web/app/future/[user]/[type]/embed/page.tsx new file mode 100644 index 0000000000..22db0557c9 --- /dev/null +++ b/apps/web/app/future/[user]/[type]/embed/page.tsx @@ -0,0 +1,12 @@ +import { withAppDirSsr } from "app/WithAppDirSsr"; +import withEmbedSsrAppDir from "app/WithEmbedSSR"; +import { WithLayout } from "app/layoutHOC"; + +import LegacyPage from "~/users/views/users-type-public-view"; +import { getServerSideProps, type PageProps } from "~/users/views/users-type-public-view.getServerSideProps"; + +const getData = withAppDirSsr(getServerSideProps); + +const getEmbedData = withEmbedSsrAppDir(getData); + +export default WithLayout({ getLayout: null, getData: getEmbedData, Page: LegacyPage })<"P">; diff --git a/apps/web/app/future/[user]/[type]/page.tsx b/apps/web/app/future/[user]/[type]/page.tsx new file mode 100644 index 0000000000..1ac9364f4f --- /dev/null +++ b/apps/web/app/future/[user]/[type]/page.tsx @@ -0,0 +1,45 @@ +import { withAppDirSsr } from "app/WithAppDirSsr"; +import { _generateMetadata } from "app/_utils"; +import { WithLayout } from "app/layoutHOC"; +import { type GetServerSidePropsContext } from "next"; +import { headers, cookies } from "next/headers"; + +import { buildLegacyCtx } from "@lib/buildLegacyCtx"; + +import LegacyPage from "~/users/views/users-type-public-view"; +import { getServerSideProps, type PageProps } from "~/users/views/users-type-public-view.getServerSideProps"; + +export const generateMetadata = async ({ + params, + searchParams, +}: { + params: Record; + searchParams: { [key: string]: string | string[] | undefined }; +}) => { + const props = await getData( + buildLegacyCtx(headers(), cookies(), params, searchParams) as unknown as GetServerSidePropsContext + ); + + const { eventData, booking, user, slug } = props; + const rescheduleUid = booking?.uid; + const { trpc } = await import("@calcom/trpc"); + const { data: event } = trpc.viewer.public.event.useQuery( + { username: user, eventSlug: slug, isTeamEvent: false, org: eventData.entity.orgSlug ?? null }, + { refetchOnWindowFocus: false } + ); + + const profileName = event?.profile?.name ?? ""; + const title = event?.title ?? ""; + + return await _generateMetadata( + (t) => `${rescheduleUid && !!booking ? t("reschedule") : ""} ${title} | ${profileName}`, + (t) => `${rescheduleUid ? t("reschedule") : ""} ${title}` + ); +}; +const getData = withAppDirSsr(getServerSideProps); + +export default WithLayout({ + getData, + Page: LegacyPage, + getLayout: null, +})<"P">; diff --git a/apps/web/app/future/[user]/embed/page.tsx b/apps/web/app/future/[user]/embed/page.tsx new file mode 100644 index 0000000000..cb67b98397 --- /dev/null +++ b/apps/web/app/future/[user]/embed/page.tsx @@ -0,0 +1,12 @@ +import { withAppDirSsr } from "app/WithAppDirSsr"; +import withEmbedSsrAppDir from "app/WithEmbedSSR"; +import { WithLayout } from "app/layoutHOC"; + +import LegacyPage from "~/users/views/users-public-view"; +import { getServerSideProps, type UserPageProps } from "~/users/views/users-public-view.getServerSideProps"; + +const getData = withAppDirSsr(getServerSideProps); + +const getEmbedData = withEmbedSsrAppDir(getData); + +export default WithLayout({ getLayout: null, getData: getEmbedData, Page: LegacyPage })<"P">; diff --git a/apps/web/app/future/[user]/page.tsx b/apps/web/app/future/[user]/page.tsx new file mode 100644 index 0000000000..016a383a2e --- /dev/null +++ b/apps/web/app/future/[user]/page.tsx @@ -0,0 +1,33 @@ +import { withAppDirSsr } from "app/WithAppDirSsr"; +import { _generateMetadata } from "app/_utils"; +import { WithLayout } from "app/layoutHOC"; +import { type GetServerSidePropsContext } from "next"; +import { headers, cookies } from "next/headers"; + +import { getLayout } from "@calcom/features/MainLayoutAppDir"; + +import { buildLegacyCtx } from "@lib/buildLegacyCtx"; + +import LegacyPage from "~/users/views/users-public-view"; +import { getServerSideProps, type UserPageProps } from "~/users/views/users-public-view.getServerSideProps"; + +export const generateMetadata = async ({ + params, + searchParams, +}: { + params: Record; + searchParams: { [key: string]: string | string[] | undefined }; +}) => { + const props = await getData( + buildLegacyCtx(headers(), cookies(), params, searchParams) as unknown as GetServerSidePropsContext + ); + + const { profile, markdownStrippedBio } = props; + return await _generateMetadata( + () => profile.name, + () => markdownStrippedBio + ); +}; + +const getData = withAppDirSsr(getServerSideProps); +export default WithLayout({ getLayout, getData, Page: LegacyPage })<"P">; diff --git a/apps/web/lib/org/[orgSlug]/[user]/[type]/getServerSideProps.tsx b/apps/web/lib/org/[orgSlug]/[user]/[type]/getServerSideProps.tsx index 98a5ab0cef..452f5bef6c 100644 --- a/apps/web/lib/org/[orgSlug]/[user]/[type]/getServerSideProps.tsx +++ b/apps/web/lib/org/[orgSlug]/[user]/[type]/getServerSideProps.tsx @@ -5,9 +5,10 @@ import { getSlugOrRequestedSlug } from "@calcom/features/ee/organizations/lib/or import slugify from "@calcom/lib/slugify"; import prisma from "@calcom/prisma"; -import { getServerSideProps as GSSUserTypePage } from "@lib/[user]/[type]/getServerSideProps"; import { getServerSideProps as GSSTeamTypePage } from "@lib/team/[slug]/[type]/getServerSideProps"; +import { getServerSideProps as GSSUserTypePage } from "~/users/views/users-type-public-view.getServerSideProps"; + const paramsSchema = z.object({ orgSlug: z.string().transform((s) => slugify(s)), user: z.string(), diff --git a/apps/web/pages/[user].tsx b/apps/web/modules/users/views/users-public-view.getServerSideProps.tsx similarity index 51% rename from apps/web/pages/[user].tsx rename to apps/web/modules/users/views/users-public-view.getServerSideProps.tsx index 6a274115cc..2373268094 100644 --- a/apps/web/pages/[user].tsx +++ b/apps/web/modules/users/views/users-public-view.getServerSideProps.tsx @@ -1,28 +1,13 @@ import type { DehydratedState } from "@tanstack/react-query"; -import classNames from "classnames"; -import type { GetServerSideProps, InferGetServerSidePropsType } from "next"; -import Link from "next/link"; -import { useSearchParams } from "next/navigation"; +import type { GetServerSideProps } from "next"; import { encode } from "querystring"; -import { Toaster } from "react-hot-toast"; import type { z } from "zod"; -import { - sdkActionManager, - useEmbedNonStylesConfig, - useEmbedStyles, - useIsEmbed, -} from "@calcom/embed-core/embed-iframe"; import { handleUserRedirection } from "@calcom/features/booking-redirect/handle-user"; import { getSlugOrRequestedSlug } from "@calcom/features/ee/organizations/lib/orgDomains"; import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains"; -import { EventTypeDescriptionLazy as EventTypeDescription } from "@calcom/features/eventtypes/components"; -import EmptyPage from "@calcom/features/eventtypes/components/EmptyPage"; import { DEFAULT_DARK_BRAND_COLOR, DEFAULT_LIGHT_BRAND_COLOR } from "@calcom/lib/constants"; import { getUsernameList } from "@calcom/lib/defaultEvents"; -import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery"; -import useTheme from "@calcom/lib/hooks/useTheme"; import logger from "@calcom/lib/logger"; import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML"; import { stripMarkdown } from "@calcom/lib/stripMarkdown"; @@ -30,192 +15,57 @@ import prisma from "@calcom/prisma"; import { RedirectType, type EventType, type User } from "@calcom/prisma/client"; import { baseEventTypeSelect } from "@calcom/prisma/selects"; import { EventTypeMetaDataSchema, teamMetadataSchema } from "@calcom/prisma/zod-utils"; -import { HeadSeo, UnpublishedEntity } from "@calcom/ui"; -import { UserAvatar } from "@calcom/ui"; -import { Verified, ArrowRight } from "@calcom/ui/components/icon"; +import { getTemporaryOrgRedirect } from "@lib/getTemporaryOrgRedirect"; import type { EmbedProps } from "@lib/withEmbedSsr"; -import PageWrapper from "@components/PageWrapper"; - import { ssrInit } from "@server/lib/ssr"; -import { getTemporaryOrgRedirect } from "../lib/getTemporaryOrgRedirect"; +export type UserPageProps = { + trpcState: DehydratedState; + profile: { + name: string; + image: string; + theme: string | null; + brandColor: string; + darkBrandColor: string; + organization: { + requestedSlug: string | null; + slug: string | null; + id: number | null; + }; + allowSEOIndexing: boolean; + username: string | null; + }; + users: Pick[]; + themeBasis: string | null; + markdownStrippedBio: string; + safeBio: string; + entity: { + isUnpublished?: boolean; + orgSlug?: string | null; + name?: string | null; + }; + eventTypes: ({ + descriptionAsSafeHTML: string; + metadata: z.infer; + } & Pick< + EventType, + | "id" + | "title" + | "slug" + | "length" + | "hidden" + | "lockTimeZoneToggleOnBookingPage" + | "requiresConfirmation" + | "requiresBookerEmailVerification" + | "price" + | "currency" + | "recurringEvent" + >)[]; +} & EmbedProps; -export function UserPage(props: InferGetServerSidePropsType) { - const { users, profile, eventTypes, markdownStrippedBio, entity } = props; - const searchParams = useSearchParams(); - - const [user] = users; //To be used when we only have a single user, not dynamic group - useTheme(profile.theme); - const { t } = useLocale(); - - const isBioEmpty = !user.bio || !user.bio.replace("


", "").length; - - const isEmbed = useIsEmbed(props.isEmbed); - const eventTypeListItemEmbedStyles = useEmbedStyles("eventTypeListItem"); - const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left"; - const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed; - const { - // So it doesn't display in the Link (and make tests fail) - user: _user, - orgSlug: _orgSlug, - redirect: _redirect, - ...query - } = useRouterQuery(); - - const isRedirect = searchParams?.get("redirected") === "true" || false; - const fromUserNameRedirected = searchParams?.get("username") || ""; - /* - const telemetry = useTelemetry(); - useEffect(() => { - if (top !== window) { - //page_view will be collected automatically by _middleware.ts - telemetry.event(telemetryEventTypes.embedView, collectPageParameters("/[user]")); - } - }, [telemetry, router.asPath]); */ - - if (entity?.isUnpublished) { - return ( -
- -
- ); - } - - const isEventListEmpty = eventTypes.length === 0; - - return ( - <> - - -
-
- {isRedirect && ( -
-

- {t("user_redirect_title", { - username: fromUserNameRedirected, - })}{" "} - 🏝️ -

-

- {t("user_redirect_description", { - profile: { - username: user.username, - }, - username: fromUserNameRedirected, - })}{" "} - 😄 -

-
- )} -
- -

- {profile.name} - {user.verified && ( - - )} -

- {!isBioEmpty && ( - <> -
- - )} -
- -
- {user.away ? ( -
-
-

😴{` ${t("user_away")}`}

-

{t("user_away_description") as string}

-
-
- ) : ( - eventTypes.map((type) => ( -
- - {/* Don't prefetch till the time we drop the amount of javascript in [user][type] page which is impacting score for [user] page */} -
- { - sdkActionManager?.fire("eventTypeSelected", { - eventType: type, - }); - }} - data-testid="event-type-link"> -
-

{type.title}

-
- - -
-
- )) - )} -
- - {isEventListEmpty && } -
- -
- - ); -} - -UserPage.isBookingPage = true; -UserPage.PageWrapper = PageWrapper; - -const getEventTypesWithHiddenFromDB = async (userId: number) => { +export const getEventTypesWithHiddenFromDB = async (userId: number) => { const eventTypes = await prisma.eventType.findMany({ where: { AND: [ @@ -267,50 +117,6 @@ const getEventTypesWithHiddenFromDB = async (userId: number) => { }, []); }; -export type UserPageProps = { - trpcState: DehydratedState; - profile: { - name: string; - image: string; - theme: string | null; - brandColor: string; - darkBrandColor: string; - organization: { - requestedSlug: string | null; - slug: string | null; - id: number | null; - }; - allowSEOIndexing: boolean; - username: string | null; - }; - users: Pick[]; - themeBasis: string | null; - markdownStrippedBio: string; - safeBio: string; - entity: { - isUnpublished?: boolean; - orgSlug?: string | null; - name?: string | null; - }; - eventTypes: ({ - descriptionAsSafeHTML: string; - metadata: z.infer; - } & Pick< - EventType, - | "id" - | "title" - | "slug" - | "length" - | "hidden" - | "lockTimeZoneToggleOnBookingPage" - | "requiresConfirmation" - | "requiresBookerEmailVerification" - | "price" - | "currency" - | "recurringEvent" - >)[]; -} & EmbedProps; - export const getServerSideProps: GetServerSideProps = async (context) => { const ssr = await ssrInit(context); const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(context.req, context.params?.orgSlug); @@ -484,5 +290,3 @@ export const getServerSideProps: GetServerSideProps = async (cont }, }; }; - -export default UserPage; diff --git a/apps/web/modules/users/views/users-public-view.tsx b/apps/web/modules/users/views/users-public-view.tsx new file mode 100644 index 0000000000..168773945d --- /dev/null +++ b/apps/web/modules/users/views/users-public-view.tsx @@ -0,0 +1,195 @@ +"use client"; + +import classNames from "classnames"; +import type { InferGetServerSidePropsType } from "next"; +import Link from "next/link"; +import { useSearchParams } from "next/navigation"; +import { Toaster } from "react-hot-toast"; + +import { + sdkActionManager, + useEmbedNonStylesConfig, + useEmbedStyles, + useIsEmbed, +} from "@calcom/embed-core/embed-iframe"; +import { EventTypeDescriptionLazy as EventTypeDescription } from "@calcom/features/eventtypes/components"; +import EmptyPage from "@calcom/features/eventtypes/components/EmptyPage"; +import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery"; +import useTheme from "@calcom/lib/hooks/useTheme"; +import { HeadSeo, UnpublishedEntity, UserAvatar } from "@calcom/ui"; +import { ArrowRight, Verified } from "@calcom/ui/components/icon"; + +import { type getServerSideProps } from "./users-public-view.getServerSideProps"; + +export function UserPage(props: InferGetServerSidePropsType) { + const { users, profile, eventTypes, markdownStrippedBio, entity } = props; + const searchParams = useSearchParams(); + + const [user] = users; //To be used when we only have a single user, not dynamic group + useTheme(profile.theme); + const { t } = useLocale(); + + const isBioEmpty = !user.bio || !user.bio.replace("


", "").length; + + const isEmbed = useIsEmbed(props.isEmbed); + const eventTypeListItemEmbedStyles = useEmbedStyles("eventTypeListItem"); + const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left"; + const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed; + const { + // So it doesn't display in the Link (and make tests fail) + user: _user, + orgSlug: _orgSlug, + redirect: _redirect, + ...query + } = useRouterQuery(); + + const isRedirect = searchParams?.get("redirected") === "true" || false; + const fromUserNameRedirected = searchParams?.get("username") || ""; + /* + const telemetry = useTelemetry(); + useEffect(() => { + if (top !== window) { + //page_view will be collected automatically by _middleware.ts + telemetry.event(telemetryEventTypes.embedView, collectPageParameters("/[user]")); + } + }, [telemetry, router.asPath]); */ + + if (entity?.isUnpublished) { + return ( +
+ +
+ ); + } + + const isEventListEmpty = eventTypes.length === 0; + + return ( + <> + + +
+
+ {isRedirect && ( +
+

+ {t("user_redirect_title", { + username: fromUserNameRedirected, + })}{" "} + 🏝️ +

+

+ {t("user_redirect_description", { + profile: { + username: user.username, + }, + username: fromUserNameRedirected, + })}{" "} + 😄 +

+
+ )} +
+ +

+ {profile.name} + {user.verified && ( + + )} +

+ {!isBioEmpty && ( + <> +
+ + )} +
+ +
+ {user.away ? ( +
+
+

😴{` ${t("user_away")}`}

+

{t("user_away_description") as string}

+
+
+ ) : ( + eventTypes.map((type) => ( +
+ + {/* Don't prefetch till the time we drop the amount of javascript in [user][type] page which is impacting score for [user] page */} +
+ { + sdkActionManager?.fire("eventTypeSelected", { + eventType: type, + }); + }} + data-testid="event-type-link"> +
+

{type.title}

+
+ + +
+
+ )) + )} +
+ + {isEventListEmpty && } +
+ +
+ + ); +} + +export default UserPage; diff --git a/apps/web/lib/[user]/[type]/getServerSideProps.tsx b/apps/web/modules/users/views/users-type-public-view.getServerSideProps.tsx similarity index 96% rename from apps/web/lib/[user]/[type]/getServerSideProps.tsx rename to apps/web/modules/users/views/users-type-public-view.getServerSideProps.tsx index 79dedb942b..ddeb02c32b 100644 --- a/apps/web/lib/[user]/[type]/getServerSideProps.tsx +++ b/apps/web/modules/users/views/users-type-public-view.getServerSideProps.tsx @@ -12,6 +12,10 @@ import prisma from "@calcom/prisma"; import { RedirectType } from "@calcom/prisma/client"; import { getTemporaryOrgRedirect } from "@lib/getTemporaryOrgRedirect"; +import { type inferSSRProps } from "@lib/types/inferSSRProps"; +import { type EmbedProps } from "@lib/withEmbedSsr"; + +export type PageProps = inferSSRProps & EmbedProps; async function getDynamicGroupPageProps(context: GetServerSidePropsContext) { const session = await getServerSession(context); diff --git a/apps/web/pages/[user]/[type].tsx b/apps/web/modules/users/views/users-type-public-view.tsx similarity index 80% rename from apps/web/pages/[user]/[type].tsx rename to apps/web/modules/users/views/users-type-public-view.tsx index 5d669e1e57..2c25cffaf8 100644 --- a/apps/web/pages/[user]/[type].tsx +++ b/apps/web/modules/users/views/users-type-public-view.tsx @@ -6,14 +6,7 @@ import { Booker } from "@calcom/atoms"; import { getBookerWrapperClasses } from "@calcom/features/bookings/Booker/utils/getBookerWrapperClasses"; import { BookerSeo } from "@calcom/features/bookings/components/BookerSeo"; -import { getServerSideProps } from "@lib/[user]/[type]/getServerSideProps"; -import type { inferSSRProps } from "@lib/types/inferSSRProps"; -import type { EmbedProps } from "@lib/withEmbedSsr"; - -import PageWrapper from "@components/PageWrapper"; - -export type PageProps = Omit, "trpcState"> & EmbedProps; -export { getServerSideProps }; +import { type PageProps } from "./users-type-public-view.getServerSideProps"; export const getMultipleDurationValue = ( multipleDurationConfig: number[] | undefined, @@ -69,6 +62,3 @@ export default function Type({ ); } - -Type.isBookingPage = true; -Type.PageWrapper = PageWrapper; diff --git a/apps/web/pages/[user]/[type]/embed.tsx b/apps/web/pages/[user]/[type]/embed.tsx index 63fb82b309..1c2fdb4c35 100644 --- a/apps/web/pages/[user]/[type]/embed.tsx +++ b/apps/web/pages/[user]/[type]/embed.tsx @@ -1,11 +1,18 @@ +import { type AppProps } from "@lib/app-providers"; import withEmbedSsr from "@lib/withEmbedSsr"; -import { getServerSideProps as _getServerSideProps } from "../[type]"; +import PageWrapper, { type CalPageWrapper } from "@components/PageWrapper"; -export { default } from "../[type]"; +import TypePage from "~/users/views/users-type-public-view"; +import { getServerSideProps as _getServerSideProps } from "~/users/views/users-type-public-view.getServerSideProps"; -// Somehow these types don't accept the {notFound: true} return type. -// Probably still need to fix this. I don't know why this isn't allowed yet. -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore export const getServerSideProps = withEmbedSsr(_getServerSideProps); + +const Type = TypePage as unknown as CalPageWrapper & { + isBookingPage: AppProps["Component"]["isBookingPage"]; +}; + +Type.isBookingPage = true; +Type.PageWrapper = PageWrapper; + +export default Type; diff --git a/apps/web/pages/[user]/[type]/index.tsx b/apps/web/pages/[user]/[type]/index.tsx new file mode 100644 index 0000000000..8af3eb6372 --- /dev/null +++ b/apps/web/pages/[user]/[type]/index.tsx @@ -0,0 +1,16 @@ +import { type AppProps } from "@lib/app-providers"; + +import PageWrapper, { type CalPageWrapper } from "@components/PageWrapper"; + +import TypePage from "~/users/views/users-type-public-view"; + +export { getServerSideProps } from "~/users/views/users-type-public-view.getServerSideProps"; + +const Type = TypePage as unknown as CalPageWrapper & { + isBookingPage: AppProps["Component"]["isBookingPage"]; +}; + +Type.isBookingPage = true; +Type.PageWrapper = PageWrapper; + +export default Type; diff --git a/apps/web/pages/[user]/embed.tsx b/apps/web/pages/[user]/embed.tsx index 5c62c6117e..c6a9a8de89 100644 --- a/apps/web/pages/[user]/embed.tsx +++ b/apps/web/pages/[user]/embed.tsx @@ -1,7 +1,18 @@ +import { type AppProps } from "@lib/app-providers"; import withEmbedSsr from "@lib/withEmbedSsr"; -import { getServerSideProps as _getServerSideProps } from "../[user]"; +import PageWrapper, { type CalPageWrapper } from "@components/PageWrapper"; -export { default } from "../[user]"; +import User from "~/users/views/users-public-view"; +import { getServerSideProps as _getServerSideProps } from "~/users/views/users-public-view.getServerSideProps"; + +const UserPage = User as unknown as CalPageWrapper & { + isBookingPage: AppProps["Component"]["isBookingPage"]; +}; + +UserPage.isBookingPage = true; +UserPage.PageWrapper = PageWrapper; + +export default UserPage; export const getServerSideProps = withEmbedSsr(_getServerSideProps); diff --git a/apps/web/pages/[user]/index.tsx b/apps/web/pages/[user]/index.tsx new file mode 100644 index 0000000000..da9d511f36 --- /dev/null +++ b/apps/web/pages/[user]/index.tsx @@ -0,0 +1,16 @@ +import { type AppProps } from "@lib/app-providers"; + +import PageWrapper, { type CalPageWrapper } from "@components/PageWrapper"; + +import User from "~/users/views/users-public-view"; + +export { getServerSideProps, type UserPageProps } from "~/users/views/users-public-view.getServerSideProps"; + +const UserPage = User as unknown as CalPageWrapper & { + isBookingPage: AppProps["Component"]["isBookingPage"]; +}; + +UserPage.isBookingPage = true; +UserPage.PageWrapper = PageWrapper; + +export default UserPage; diff --git a/apps/web/pages/org/[orgSlug]/[user]/[type]/embed.tsx b/apps/web/pages/org/[orgSlug]/[user]/[type]/embed.tsx index 63531e5f39..11cb6812ef 100644 --- a/apps/web/pages/org/[orgSlug]/[user]/[type]/embed.tsx +++ b/apps/web/pages/org/[orgSlug]/[user]/[type]/embed.tsx @@ -2,8 +2,8 @@ import withEmbedSsr from "@lib/withEmbedSsr"; -import { getServerSideProps as _getServerSideProps } from "../[type]"; +import { getServerSideProps as _getServerSideProps } from "."; -export { default, type PageProps } from "../[type]"; +export { default, type PageProps } from "."; export const getServerSideProps = withEmbedSsr(_getServerSideProps); diff --git a/apps/web/pages/org/[orgSlug]/[user]/[type].tsx b/apps/web/pages/org/[orgSlug]/[user]/[type]/index.tsx similarity index 60% rename from apps/web/pages/org/[orgSlug]/[user]/[type].tsx rename to apps/web/pages/org/[orgSlug]/[user]/[type]/index.tsx index dcd5a9f3da..c46ab5c6dd 100644 --- a/apps/web/pages/org/[orgSlug]/[user]/[type].tsx +++ b/apps/web/pages/org/[orgSlug]/[user]/[type]/index.tsx @@ -2,10 +2,11 @@ import PageWrapper from "@components/PageWrapper"; -import type { PageProps as UserTypePageProps } from "../../../[user]/[type]"; -import UserTypePage from "../../../[user]/[type]"; -import type { PageProps as TeamTypePageProps } from "../../../team/[slug]/[type]"; -import TeamTypePage from "../../../team/[slug]/[type]"; +import UserTypePage from "~/users/views/users-type-public-view"; +import type { PageProps as UserTypePageProps } from "~/users/views/users-type-public-view.getServerSideProps"; + +import type { PageProps as TeamTypePageProps } from "../../../../team/[slug]/[type]"; +import TeamTypePage from "../../../../team/[slug]/[type]"; export { getServerSideProps } from "@lib/org/[orgSlug]/[user]/[type]/getServerSideProps"; diff --git a/apps/web/pages/org/[orgSlug]/[user]/index.tsx b/apps/web/pages/org/[orgSlug]/[user]/index.tsx index fc2943a4bd..37042a6cdc 100644 --- a/apps/web/pages/org/[orgSlug]/[user]/index.tsx +++ b/apps/web/pages/org/[orgSlug]/[user]/index.tsx @@ -2,8 +2,9 @@ import PageWrapper from "@components/PageWrapper"; -import type { UserPageProps } from "../../../[user]"; -import UserPage from "../../../[user]"; +import UserPage from "~/users/views/users-public-view"; +import { type UserPageProps } from "~/users/views/users-public-view.getServerSideProps"; + import type { PageProps as TeamPageProps } from "../../../team/[slug]"; import TeamPage from "../../../team/[slug]"; diff --git a/apps/web/playwright/booking-pages.e2e.ts b/apps/web/playwright/booking-pages.e2e.ts index a4733ab2a4..abb2e15c90 100644 --- a/apps/web/playwright/booking-pages.e2e.ts +++ b/apps/web/playwright/booking-pages.e2e.ts @@ -5,6 +5,7 @@ import { SchedulingType } from "@calcom/prisma/client"; import type { Schedule, TimeRange } from "@calcom/types/schedule"; import { test } from "./lib/fixtures"; +import { testBothFutureAndLegacyRoutes } from "./lib/future-legacy-routes"; import { bookFirstEvent, bookOptinEvent, @@ -21,7 +22,7 @@ test.afterEach(async ({ users }) => { await users.deleteAll(); }); -test.describe("free user", () => { +testBothFutureAndLegacyRoutes.describe("free user", () => { test.beforeEach(async ({ page, users }) => { const free = await users.create(freeUserObj); await page.goto(`/${free.username}`); @@ -62,7 +63,7 @@ test.describe("free user", () => { }); }); -test.describe("pro user", () => { +testBothFutureAndLegacyRoutes.describe("pro user", () => { test.beforeEach(async ({ page, users }) => { const pro = await users.create(); await page.goto(`/${pro.username}`); @@ -262,7 +263,7 @@ test.describe("pro user", () => { }); }); -test.describe("prefill", () => { +testBothFutureAndLegacyRoutes.describe("prefill", () => { test("logged in", async ({ page, users }) => { const prefill = await users.create({ name: "Prefill User" }); await prefill.apiLogin(); @@ -319,7 +320,7 @@ test.describe("prefill", () => { }); }); -test.describe("Booking on different layouts", () => { +testBothFutureAndLegacyRoutes.describe("Booking on different layouts", () => { test.beforeEach(async ({ page, users }) => { const user = await users.create(); await page.goto(`/${user.username}`); @@ -376,7 +377,7 @@ test.describe("Booking on different layouts", () => { }); }); -test.describe("Booking round robin event", () => { +testBothFutureAndLegacyRoutes.describe("Booking round robin event", () => { test.beforeEach(async ({ page, users }) => { const teamMatesObj = [{ name: "teammate-1" }]; @@ -388,7 +389,7 @@ test.describe("Booking round robin event", () => { const schedule: Schedule = [[], [dateRanges], [dateRanges], [dateRanges], [dateRanges], [dateRanges], []]; const testUser = await users.create( - { username: "test-user", name: "Test User", email: "testuser@example.com", schedule }, + { schedule }, { hasTeam: true, schedulingType: SchedulingType.ROUND_ROBIN, @@ -402,7 +403,7 @@ test.describe("Booking round robin event", () => { test("Does not book round robin host outside availability with date override", async ({ page, users }) => { const [testUser] = users.get(); - testUser.apiLogin(); + await testUser.apiLogin(); const team = await testUser.getFirstTeamMembership(); @@ -429,7 +430,7 @@ test.describe("Booking round robin event", () => { await expect(page.locator("[data-testid=success-page]")).toBeVisible(); - const host = await page.locator('[data-testid="booking-host-name"]'); + const host = page.locator('[data-testid="booking-host-name"]'); const hostName = await host.innerText(); //expect teammate-1 to be booked, test-user is not available at this time @@ -459,7 +460,7 @@ test.describe("Booking round robin event", () => { await expect(page.locator("[data-testid=success-page]")).toBeVisible(); - const hostSecondBooking = await page.locator('[data-testid="booking-host-name"]'); + const hostSecondBooking = page.locator('[data-testid="booking-host-name"]'); const hostNameSecondBooking = await hostSecondBooking.innerText(); expect(hostNameSecondBooking).toBe("teammate-1"); // teammate-1 should be booked again });