diff --git a/apps/web/app/(use-page-wrapper)/[user]/[type]/page.tsx b/apps/web/app/(use-page-wrapper)/[user]/[type]/page.tsx new file mode 100644 index 0000000000..1e19cd0d50 --- /dev/null +++ b/apps/web/app/(use-page-wrapper)/[user]/[type]/page.tsx @@ -0,0 +1,59 @@ +import { withAppDirSsr } from "app/WithAppDirSsr"; +import type { PageProps } from "app/_types"; +import { generateMeetingMetadata } from "app/_utils"; +import { headers, cookies } from "next/headers"; + +import { getOrgFullOrigin } from "@calcom/features/ee/organizations/lib/orgDomains"; + +import { buildLegacyCtx } from "@lib/buildLegacyCtx"; + +import { getServerSideProps } from "@server/lib/[user]/[type]/getServerSideProps"; + +import type { PageProps as LegacyPageProps } from "~/users/views/users-type-public-view"; +import LegacyPage from "~/users/views/users-type-public-view"; + +export const generateMetadata = async ({ params, searchParams }: PageProps) => { + const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams); + const props = await getData(legacyCtx); + + const { booking, isSEOIndexable = true, eventData, isBrandingHidden } = props; + const rescheduleUid = booking?.uid; + 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) => `${rescheduleUid && !!booking ? t("reschedule") : ""} ${title} | ${profileName}`, + (t) => `${rescheduleUid ? t("reschedule") : ""} ${title}`, + isBrandingHidden, + getOrgFullOrigin(eventData?.entity.orgSlug ?? null) + ); + + return { + ...metadata, + robots: { + follow: !(eventData?.hidden || !isSEOIndexable), + index: !(eventData?.hidden || !isSEOIndexable), + }, + }; +}; +const getData = withAppDirSsr(getServerSideProps); + +const ServerPage = async ({ params, searchParams }: PageProps) => { + const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams); + const props = await getData(legacyCtx); + + return ; +}; + +export default ServerPage; diff --git a/apps/web/app/(use-page-wrapper)/[user]/page.tsx b/apps/web/app/(use-page-wrapper)/[user]/page.tsx new file mode 100644 index 0000000000..8bc97b02b4 --- /dev/null +++ b/apps/web/app/(use-page-wrapper)/[user]/page.tsx @@ -0,0 +1,52 @@ +import { withAppDirSsr } from "app/WithAppDirSsr"; +import type { PageProps } from "app/_types"; +import { generateMeetingMetadata } from "app/_utils"; +import { headers, cookies } from "next/headers"; + +import { getOrgFullOrigin } from "@calcom/features/ee/organizations/lib/orgDomains"; + +import { buildLegacyCtx } from "@lib/buildLegacyCtx"; + +import { getServerSideProps } from "@server/lib/[user]/getServerSideProps"; + +import type { PageProps as LegacyPageProps } from "~/users/views/users-public-view"; +import LegacyPage from "~/users/views/users-public-view"; + +export const generateMetadata = async ({ params, searchParams }: PageProps) => { + const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + + const { profile, markdownStrippedBio, isOrgSEOIndexable, entity } = props; + const isOrg = !!profile?.organization; + const allowSEOIndexing = + (!isOrg && profile.allowSEOIndexing) || (isOrg && isOrgSEOIndexable && profile.allowSEOIndexing); + + const meeting = { + title: markdownStrippedBio, + profile: { name: `${profile.name}`, image: profile.image }, + users: [{ username: `${profile.username}`, name: `${profile.name}` }], + }; + const metadata = await generateMeetingMetadata( + meeting, + () => profile.name, + () => markdownStrippedBio, + false, + getOrgFullOrigin(entity.orgSlug ?? null) + ); + + return { + ...metadata, + robots: { + follow: allowSEOIndexing, + index: allowSEOIndexing, + }, + }; +}; + +const getData = withAppDirSsr(getServerSideProps); +const ServerPage = async ({ params, searchParams }: PageProps) => { + const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + + return ; +}; + +export default ServerPage; diff --git a/apps/web/app/future/[user]/[type]/page.tsx b/apps/web/app/future/[user]/[type]/page.tsx deleted file mode 100644 index 3a61c20e5b..0000000000 --- a/apps/web/app/future/[user]/[type]/page.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { withAppDirSsr } from "app/WithAppDirSsr"; -import type { PageProps } from "app/_types"; -import { _generateMetadata } from "app/_utils"; -import { WithLayout } from "app/layoutHOC"; -import { headers, cookies } 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 "@server/lib/[user]/[type]/getServerSideProps"; - -import type { PageProps as LegacyPageProps } from "~/users/views/users-type-public-view"; -import LegacyPage from "~/users/views/users-type-public-view"; - -export const generateMetadata = async ({ params, searchParams }: PageProps) => { - const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams); - const props = await getData(legacyCtx); - - const { booking, user: username, slug: eventSlug } = props; - const rescheduleUid = booking?.uid; - const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(legacyCtx.req, legacyCtx.params?.orgSlug); - - const event = await EventRepository.getPublicEvent({ - username, - eventSlug, - isTeamEvent: false, - org: isValidOrgDomain ? currentOrgDomain : null, - fromRedirectOfNonOrgLink: legacyCtx.query.orgRedirection === "true", - }); - - 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]/page.tsx b/apps/web/app/future/[user]/page.tsx deleted file mode 100644 index 1a05b75cd1..0000000000 --- a/apps/web/app/future/[user]/page.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { withAppDirSsr } from "app/WithAppDirSsr"; -import type { PageProps } from "app/_types"; -import { _generateMetadata } from "app/_utils"; -import { WithLayout } from "app/layoutHOC"; -import { headers, cookies } from "next/headers"; - -import { buildLegacyCtx } from "@lib/buildLegacyCtx"; - -import { getServerSideProps } from "@server/lib/[user]/getServerSideProps"; - -import type { PageProps as LegacyPageProps } from "~/users/views/users-public-view"; -import LegacyPage from "~/users/views/users-public-view"; - -export const generateMetadata = async ({ params, searchParams }: PageProps) => { - const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); - - const { profile, markdownStrippedBio } = props; - return await _generateMetadata( - () => profile.name, - () => markdownStrippedBio - ); -}; - -const getData = withAppDirSsr(getServerSideProps); -export default WithLayout({ getData, Page: LegacyPage })<"P">; diff --git a/apps/web/app/org/[orgSlug]/[user]/[type]/page.tsx b/apps/web/app/org/[orgSlug]/[user]/[type]/page.tsx index 144e5f1f88..48d621d737 100644 --- a/apps/web/app/org/[orgSlug]/[user]/[type]/page.tsx +++ b/apps/web/app/org/[orgSlug]/[user]/[type]/page.tsx @@ -21,7 +21,7 @@ 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 { booking, isSEOIndexable = true, eventData, isBrandingHidden } = props; const rescheduleUid = booking?.uid; const profileName = eventData?.profile?.name ?? ""; diff --git a/apps/web/lib/org/[orgSlug]/[user]/getServerSideProps.tsx b/apps/web/lib/org/[orgSlug]/[user]/getServerSideProps.tsx index 4fce1e1edd..6b5c35d4a4 100644 --- a/apps/web/lib/org/[orgSlug]/[user]/getServerSideProps.tsx +++ b/apps/web/lib/org/[orgSlug]/[user]/getServerSideProps.tsx @@ -1,4 +1,3 @@ -import { getServerSideProps as GSSUserPage } from "@pages/[user]"; import type { GetServerSidePropsContext } from "next"; import { getSlugOrRequestedSlug } from "@calcom/features/ee/organizations/lib/orgDomains"; @@ -6,6 +5,8 @@ import prisma from "@calcom/prisma"; import { getServerSideProps as GSSTeamPage } from "@lib/team/[slug]/getServerSideProps"; +import { getServerSideProps as GSSUserPage } from "@server/lib/[user]/getServerSideProps"; + export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { const team = await prisma.team.findFirst({ where: { diff --git a/apps/web/middleware.ts b/apps/web/middleware.ts index 9aa6a85da1..5f748b579e 100644 --- a/apps/web/middleware.ts +++ b/apps/web/middleware.ts @@ -183,6 +183,8 @@ export const config = { "/routing-forms/:path*", "/team/:path*", "/org/:path*", + "/:user/:type/", + "/:user/", ], }; diff --git a/apps/web/modules/users/views/users-public-view.test.tsx b/apps/web/modules/users/views/users-public-view.test.tsx index 605c45c2bc..7cc1c71e7f 100644 --- a/apps/web/modules/users/views/users-public-view.test.tsx +++ b/apps/web/modules/users/views/users-public-view.test.tsx @@ -1,5 +1,5 @@ import { render } from "@testing-library/react"; -import { describe, expect, it, vi } from "vitest"; +import { describe, it, vi } from "vitest"; import { getOrgFullOrigin } from "@calcom/ee/organizations/lib/orgDomains"; import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery"; @@ -71,33 +71,6 @@ describe("UserPage Component", () => { }); render(); - - const expectedDescription = mockData.props.markdownStrippedBio; - const expectedTitle = expectedDescription; - expect(HeadSeo).toHaveBeenCalledWith( - { - origin: `${mockData.props.entity.orgSlug}.cal.local`, - title: `${mockData.props.profile.name}`, - description: expectedDescription, - meeting: { - profile: { - name: mockData.props.profile.name, - image: mockData.props.users[0].avatarUrl, - }, - title: expectedTitle, - users: [ - { - name: mockData.props.users[0].name, - username: mockData.props.users[0].username, - }, - ], - }, - nextSeoProps: { - nofollow: !mockData.props.profile.allowSEOIndexing, - noindex: !mockData.props.profile.allowSEOIndexing, - }, - }, - {} - ); + expect(HeadSeo).not.toHaveBeenCalled(); }); }); diff --git a/apps/web/modules/users/views/users-public-view.tsx b/apps/web/modules/users/views/users-public-view.tsx index aef379fa14..f9aeeab921 100644 --- a/apps/web/modules/users/views/users-public-view.tsx +++ b/apps/web/modules/users/views/users-public-view.tsx @@ -11,18 +11,17 @@ import { useEmbedStyles, useIsEmbed, } from "@calcom/embed-core/embed-iframe"; -import { getOrgFullOrigin } 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 { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery"; import useTheme from "@calcom/lib/hooks/useTheme"; -import { HeadSeo, Icon, UnpublishedEntity, UserAvatar } from "@calcom/ui"; +import { Icon, UnpublishedEntity, UserAvatar } from "@calcom/ui"; import type { getServerSideProps } from "@server/lib/[user]/getServerSideProps"; export type PageProps = InferGetServerSidePropsType; export function UserPage(props: PageProps) { - const { users, profile, eventTypes, markdownStrippedBio, entity, isOrgSEOIndexable } = props; + const { users, profile, eventTypes, entity } = props; const [user] = users; //To be used when we only have a single user, not dynamic group useTheme(profile.theme); @@ -60,29 +59,8 @@ export function UserPage(props: PageProps) { const isEventListEmpty = eventTypes.length === 0; const isOrg = !!user?.profile?.organization; - const allowSEOIndexing = isOrg - ? isOrgSEOIndexable - ? profile.allowSEOIndexing - : false - : profile.allowSEOIndexing; - return ( <> - -
-