From 5ccf5e6be81be915867a55510c63307473681dd9 Mon Sep 17 00:00:00 2001 From: Benny Joo Date: Tue, 14 Jan 2025 18:48:41 -0500 Subject: [PATCH] chore: migrate /team booking pages (#18656) * wip * remove pages/team/[slug] * fix tests * fix tests 2 --- apps/web/app/_utils.tsx | 23 +++++++- .../future/team/[slug]/[type]/embed/page.tsx | 11 ---- .../app/future/team/[slug]/[type]/page.tsx | 44 -------------- .../web/app/future/team/[slug]/embed/page.tsx | 11 ---- apps/web/app/future/team/[slug]/page.tsx | 28 --------- apps/web/app/team/[slug]/[type]/page.tsx | 58 +++++++++++++++++++ apps/web/app/team/[slug]/page.tsx | 52 +++++++++++++++++ apps/web/middleware.ts | 1 + apps/web/modules/team/type-view.tsx | 48 ++++++++------- apps/web/pages/org/[orgSlug]/index.ts | 1 - .../[slug].tsx => org/[orgSlug]/index.tsx} | 0 .../pages/org/[orgSlug]/team/[slug]/[type].ts | 1 - .../[orgSlug]}/team/[slug]/[type].tsx | 5 +- .../pages/org/[orgSlug]/team/[slug]/index.ts | 2 +- .../organization/organization-settings.e2e.ts | 13 ++++- 15 files changed, 173 insertions(+), 125 deletions(-) delete mode 100644 apps/web/app/future/team/[slug]/[type]/embed/page.tsx delete mode 100644 apps/web/app/future/team/[slug]/[type]/page.tsx delete mode 100644 apps/web/app/future/team/[slug]/embed/page.tsx delete mode 100644 apps/web/app/future/team/[slug]/page.tsx create mode 100644 apps/web/app/team/[slug]/[type]/page.tsx create mode 100644 apps/web/app/team/[slug]/page.tsx delete mode 100644 apps/web/pages/org/[orgSlug]/index.ts rename apps/web/pages/{team/[slug].tsx => org/[orgSlug]/index.tsx} (100%) delete mode 100644 apps/web/pages/org/[orgSlug]/team/[slug]/[type].ts rename apps/web/pages/{ => org/[orgSlug]}/team/[slug]/[type].tsx (85%) diff --git a/apps/web/app/_utils.tsx b/apps/web/app/_utils.tsx index f5b13fe1ac..18acce789d 100644 --- a/apps/web/app/_utils.tsx +++ b/apps/web/app/_utils.tsx @@ -3,8 +3,8 @@ import i18next from "i18next"; import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import { headers } from "next/headers"; -import type { AppImageProps } from "@calcom/lib/OgImages"; -import { constructGenericImage, constructAppImage } from "@calcom/lib/OgImages"; +import type { AppImageProps, MeetingImageProps } from "@calcom/lib/OgImages"; +import { constructGenericImage, constructAppImage, constructMeetingImage } from "@calcom/lib/OgImages"; import { IS_CALCOM, WEBAPP_URL, APP_NAME, SEO_IMG_OGIMG, CAL_URL } from "@calcom/lib/constants"; import { buildCanonical } from "@calcom/lib/next-seo.config"; import { truncateOnWord } from "@calcom/lib/text"; @@ -125,3 +125,22 @@ export const generateAppMetadata = async ( }, }; }; + +export const generateMeetingMetadata = async ( + meeting: MeetingImageProps, + getTitle: (t: TFunction) => string, + getDescription: (t: TFunction) => string, + hideBranding?: boolean, + origin?: string +) => { + const metadata = await _generateMetadataWithoutImage(getTitle, getDescription, hideBranding, origin); + const image = SEO_IMG_OGIMG + constructMeetingImage(meeting); + + return { + ...metadata, + openGraph: { + ...metadata.openGraph, + images: [image], + }, + }; +}; diff --git a/apps/web/app/future/team/[slug]/[type]/embed/page.tsx b/apps/web/app/future/team/[slug]/[type]/embed/page.tsx deleted file mode 100644 index 3430e611a7..0000000000 --- a/apps/web/app/future/team/[slug]/[type]/embed/page.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import withEmbedSsrAppDir from "app/WithEmbedSSR"; -import { WithLayout } from "app/layoutHOC"; - -import { getServerSideProps } from "@lib/team/[slug]/[type]/getServerSideProps"; - -import type { PageProps } from "~/team/type-view"; -import LegacyPage from "~/team/type-view"; - -const getEmbedData = withEmbedSsrAppDir(getServerSideProps); - -export default WithLayout({ getLayout: null, getData: getEmbedData, Page: LegacyPage })<"P">; diff --git a/apps/web/app/future/team/[slug]/[type]/page.tsx b/apps/web/app/future/team/[slug]/[type]/page.tsx deleted file mode 100644 index debf7575b8..0000000000 --- a/apps/web/app/future/team/[slug]/[type]/page.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { withAppDirSsr } from "app/WithAppDirSsr"; -import type { PageProps } from "app/_types"; -import { _generateMetadata } from "app/_utils"; -import { WithLayout } from "app/layoutHOC"; -import { cookies, headers } from "next/headers"; - -import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains"; -import { EventRepository } from "@calcom/lib/server/repository/event"; - -import { buildLegacyCtx } from "@lib/buildLegacyCtx"; -import { getServerSideProps } from "@lib/team/[slug]/[type]/getServerSideProps"; - -import LegacyPage, { type PageProps as LegacyPageProps } from "~/team/type-view"; - -export const generateMetadata = async ({ params, searchParams }: PageProps) => { - const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams); - const props = await getData(legacyCtx); - const { user: username, slug: eventSlug, booking } = props; - const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(legacyCtx.req, legacyCtx.params?.orgSlug); - - const event = await EventRepository.getPublicEvent({ - username, - eventSlug, - isTeamEvent: true, - org: isValidOrgDomain ? currentOrgDomain : null, - fromRedirectOfNonOrgLink: legacyCtx.query.orgRedirection === "true", - }); - - const profileName = event?.profile?.name ?? ""; - const title = event?.title ?? ""; - - return await _generateMetadata( - (t) => `${booking?.uid && !!booking ? t("reschedule") : ""} ${title} | ${profileName}`, - (t) => `${booking?.uid ? t("reschedule") : ""} ${title}` - ); -}; -const getData = withAppDirSsr(getServerSideProps); - -export default WithLayout({ - Page: LegacyPage, - getData, - getLayout: null, - isBookingPage: true, -})<"P">; diff --git a/apps/web/app/future/team/[slug]/embed/page.tsx b/apps/web/app/future/team/[slug]/embed/page.tsx deleted file mode 100644 index 5145f0ed0f..0000000000 --- a/apps/web/app/future/team/[slug]/embed/page.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import withEmbedSsrAppDir from "app/WithEmbedSSR"; -import { WithLayout } from "app/layoutHOC"; - -import { getServerSideProps } from "@lib/team/[slug]/getServerSideProps"; - -import type { PageProps } from "~/team/team-view"; -import LegacyPage from "~/team/team-view"; - -const getEmbedData = withEmbedSsrAppDir(getServerSideProps); - -export default WithLayout({ getLayout: null, getData: getEmbedData, Page: LegacyPage })<"P">; diff --git a/apps/web/app/future/team/[slug]/page.tsx b/apps/web/app/future/team/[slug]/page.tsx deleted file mode 100644 index 8cd056fe22..0000000000 --- a/apps/web/app/future/team/[slug]/page.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { withAppDirSsr } from "app/WithAppDirSsr"; -import type { PageProps as _PageProps } from "app/_types"; -import { _generateMetadata } from "app/_utils"; -import { WithLayout } from "app/layoutHOC"; -import { cookies, headers } from "next/headers"; - -import { buildLegacyCtx } from "@lib/buildLegacyCtx"; -import { getServerSideProps } from "@lib/team/[slug]/getServerSideProps"; - -import type { PageProps } from "~/team/team-view"; -import LegacyPage from "~/team/team-view"; - -export const generateMetadata = async ({ params, searchParams }: _PageProps) => { - const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); - - return await _generateMetadata( - (t) => props.team.name || t("nameless_team"), - (t) => props.team.name || t("nameless_team") - ); -}; - -const getData = withAppDirSsr(getServerSideProps); - -export default WithLayout({ - Page: LegacyPage, - getData, - getLayout: null, -})<"P">; diff --git a/apps/web/app/team/[slug]/[type]/page.tsx b/apps/web/app/team/[slug]/[type]/page.tsx new file mode 100644 index 0000000000..25815f8bfc --- /dev/null +++ b/apps/web/app/team/[slug]/[type]/page.tsx @@ -0,0 +1,58 @@ +import { withAppDirSsr } from "app/WithAppDirSsr"; +import type { PageProps } from "app/_types"; +import { generateMeetingMetadata } from "app/_utils"; +import { WithLayout } from "app/layoutHOC"; +import { cookies, headers } from "next/headers"; + +import { getOrgFullOrigin } from "@calcom/features/ee/organizations/lib/orgDomains"; + +import { buildLegacyCtx } from "@lib/buildLegacyCtx"; +import { getServerSideProps } from "@lib/team/[slug]/[type]/getServerSideProps"; + +import LegacyPage from "~/team/type-view"; +import type { PageProps as LegacyPageProps } from "~/team/type-view"; + +export const generateMetadata = async ({ params, searchParams }: PageProps) => { + const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams); + const props = await getData(legacyCtx); + const { booking, isSEOIndexable, eventData, isBrandingHidden } = props; + + const profileName = eventData?.profile?.name ?? ""; + const profileImage = eventData?.profile.image; + const title = eventData?.title ?? ""; + const meeting = { + title, + profile: { name: profileName, image: profileImage }, + users: [ + ...(eventData?.users || []).map((user) => ({ + name: `${user.name}`, + username: `${user.username}`, + })), + ], + }; + + const metadata = await generateMeetingMetadata( + meeting, + (t) => `${booking?.uid && !!booking ? t("reschedule") : ""} ${title} | ${profileName}`, + (t) => `${booking?.uid ? t("reschedule") : ""} ${title}`, + isBrandingHidden, + getOrgFullOrigin(eventData.entity.orgSlug ?? null) + ); + + return { + ...metadata, + robots: { + follow: !(eventData?.hidden || !isSEOIndexable), + index: !(eventData?.hidden || !isSEOIndexable), + }, + }; +}; + +const getData = withAppDirSsr(getServerSideProps); + +export default WithLayout({ + Page: LegacyPage, + getData, + getLayout: null, + isBookingPage: true, +})<"P">; diff --git a/apps/web/app/team/[slug]/page.tsx b/apps/web/app/team/[slug]/page.tsx new file mode 100644 index 0000000000..cba4c5d3a7 --- /dev/null +++ b/apps/web/app/team/[slug]/page.tsx @@ -0,0 +1,52 @@ +import { withAppDirSsr } from "app/WithAppDirSsr"; +import type { PageProps as _PageProps } from "app/_types"; +import { generateMeetingMetadata } from "app/_utils"; +import { WithLayout } from "app/layoutHOC"; +import { cookies, headers } from "next/headers"; + +import { getOrgFullOrigin } from "@calcom/features/ee/organizations/lib/orgDomains"; +import { getOrgOrTeamAvatar } from "@calcom/lib/defaultAvatarImage"; + +import { buildLegacyCtx } from "@lib/buildLegacyCtx"; +import { getServerSideProps } from "@lib/team/[slug]/getServerSideProps"; + +import type { PageProps } from "~/team/team-view"; +import LegacyPage from "~/team/team-view"; + +export const generateMetadata = async ({ params, searchParams }: _PageProps) => { + const { team, markdownStrippedBio, isSEOIndexable, currentOrgDomain } = await getData( + buildLegacyCtx(headers(), cookies(), params, searchParams) + ); + + const meeting = { + title: markdownStrippedBio ?? "", + profile: { + name: `${team.name}`, + image: getOrgOrTeamAvatar(team), + }, + }; + + const metadata = await generateMeetingMetadata( + meeting, + (t) => team.name || t("nameless_team"), + (t) => team.name || t("nameless_team"), + false, + getOrgFullOrigin(currentOrgDomain ?? null) + ); + return { + ...metadata, + robots: { + follow: isSEOIndexable, + index: isSEOIndexable, + }, + }; +}; + +const getData = withAppDirSsr(getServerSideProps); + +export default WithLayout({ + Page: LegacyPage, + getData, + getLayout: null, + isBookingPage: true, +})<"P">; diff --git a/apps/web/middleware.ts b/apps/web/middleware.ts index 44d95ab66b..485f77355f 100644 --- a/apps/web/middleware.ts +++ b/apps/web/middleware.ts @@ -186,6 +186,7 @@ export const config = { "/availability/:path*", "/booking/:path*", "/routing-forms/:path*", + "/team/:path*", ], }; diff --git a/apps/web/modules/team/type-view.tsx b/apps/web/modules/team/type-view.tsx index 221d697a55..8bbfba6057 100644 --- a/apps/web/modules/team/type-view.tsx +++ b/apps/web/modules/team/type-view.tsx @@ -4,6 +4,7 @@ import type { EmbedProps } from "app/WithEmbedSSR"; import { useSearchParams } from "next/navigation"; import { Booker } from "@calcom/atoms/monorepo"; +import { getBookerWrapperClasses } from "@calcom/features/bookings/Booker/utils/getBookerWrapperClasses"; import type { getServerSideProps } from "@lib/team/[slug]/[type]/getServerSideProps"; import type { inferSSRProps } from "@lib/types/inferSSRProps"; @@ -31,32 +32,35 @@ function Type({ teamMemberEmail, crmOwnerRecordType, crmAppSlug, + isEmbed, }: PageProps) { const searchParams = useSearchParams(); return ( - +
+ +
); } diff --git a/apps/web/pages/org/[orgSlug]/index.ts b/apps/web/pages/org/[orgSlug]/index.ts deleted file mode 100644 index a29283de79..0000000000 --- a/apps/web/pages/org/[orgSlug]/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { getServerSideProps, default } from "@pages/team/[slug]"; diff --git a/apps/web/pages/team/[slug].tsx b/apps/web/pages/org/[orgSlug]/index.tsx similarity index 100% rename from apps/web/pages/team/[slug].tsx rename to apps/web/pages/org/[orgSlug]/index.tsx diff --git a/apps/web/pages/org/[orgSlug]/team/[slug]/[type].ts b/apps/web/pages/org/[orgSlug]/team/[slug]/[type].ts deleted file mode 100644 index 85e0b39d1a..0000000000 --- a/apps/web/pages/org/[orgSlug]/team/[slug]/[type].ts +++ /dev/null @@ -1 +0,0 @@ -export { getServerSideProps, default } from "@pages/team/[slug]/[type]"; diff --git a/apps/web/pages/team/[slug]/[type].tsx b/apps/web/pages/org/[orgSlug]/team/[slug]/[type].tsx similarity index 85% rename from apps/web/pages/team/[slug]/[type].tsx rename to apps/web/pages/org/[orgSlug]/team/[slug]/[type].tsx index 67f3987cac..160c0ec36c 100644 --- a/apps/web/pages/team/[slug]/[type].tsx +++ b/apps/web/pages/org/[orgSlug]/team/[slug]/[type].tsx @@ -1,4 +1,3 @@ -import { getBookerWrapperClasses } from "@calcom/features/bookings/Booker/utils/getBookerWrapperClasses"; import { BookerSeo } from "@calcom/features/bookings/components/BookerSeo"; import PageWrapper from "@components/PageWrapper"; @@ -11,7 +10,7 @@ const Page = (props: PageProps) => { const { profile, users, hidden, title } = eventData; return ( -
+ <> { isSEOIndexable={isSEOIndexable} /> -
+ ); }; Page.isBookingPage = true; diff --git a/apps/web/pages/org/[orgSlug]/team/[slug]/index.ts b/apps/web/pages/org/[orgSlug]/team/[slug]/index.ts index a29283de79..602e114448 100644 --- a/apps/web/pages/org/[orgSlug]/team/[slug]/index.ts +++ b/apps/web/pages/org/[orgSlug]/team/[slug]/index.ts @@ -1 +1 @@ -export { getServerSideProps, default } from "@pages/team/[slug]"; +export { getServerSideProps, default } from "@pages/org/[orgSlug]/index"; diff --git a/apps/web/playwright/organization/organization-settings.e2e.ts b/apps/web/playwright/organization/organization-settings.e2e.ts index e24b1baf88..4987da8bdb 100644 --- a/apps/web/playwright/organization/organization-settings.e2e.ts +++ b/apps/web/playwright/organization/organization-settings.e2e.ts @@ -68,7 +68,18 @@ async function verifyRobotsMetaTag({ page, orgSlug, urls, expectedContent }: Ver const { url } = await goToUrlWithErrorHandling(relativeUrl); const metaTag = await page.locator('head > meta[name="robots"]'); const metaTagValue = await metaTag.getAttribute("content"); - expect(metaTagValue).toEqual(expectedContent); + expect(metaTagValue).not.toBeNull(); + expect( + metaTagValue + ?.split(",") + .map((s) => s.trim()) + .join(",") + ).toEqual( + expectedContent + .split(",") + .map((s) => s.trim()) + .join(",") + ); } }); }