chore: [app-router-migration 29] Migrate /team/* page group (#13102)
This commit is contained in:
@@ -2,6 +2,7 @@ import CategoryPage from "@pages/apps/categories/[category]";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
import { type GetServerSidePropsContext } from "next";
|
||||
import { notFound } from "next/navigation";
|
||||
import z from "zod";
|
||||
|
||||
@@ -38,8 +39,8 @@ const querySchema = z.object({
|
||||
category: z.nativeEnum(AppCategories),
|
||||
});
|
||||
|
||||
const getPageProps = async ({ params }: { params: Record<string, string | string[]> }) => {
|
||||
const p = querySchema.safeParse(params);
|
||||
const getPageProps = async (context: GetServerSidePropsContext) => {
|
||||
const p = querySchema.safeParse(context.params);
|
||||
|
||||
if (!p.success) {
|
||||
return notFound();
|
||||
@@ -66,6 +67,5 @@ const getPageProps = async ({ params }: { params: Record<string, string | string
|
||||
};
|
||||
};
|
||||
|
||||
// @ts-expect-error getData arg
|
||||
export default WithLayout({ getData: getPageProps, Page: CategoryPage })<"P">;
|
||||
export default WithLayout({ getData: getPageProps, Page: CategoryPage, getLayout: null })<"P">;
|
||||
export const dynamic = "force-static";
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import LegacyPage from "@pages/team/[slug]/[type]/embed";
|
||||
import withEmbedSsrAppDir from "app/WithEmbedSSR";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
|
||||
import { getData } from "../page";
|
||||
|
||||
const getEmbedData = withEmbedSsrAppDir(getData);
|
||||
|
||||
export default WithLayout({ getLayout: null, getData: getEmbedData, Page: LegacyPage })<"P">;
|
||||
@@ -0,0 +1,35 @@
|
||||
import LegacyPage, { type PageProps, getServerSideProps } from "@pages/team/[slug]/[type]";
|
||||
import { withAppDir } from "app/AppDirSSRHOC";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
import { type GetServerSidePropsContext } from "next";
|
||||
import { cookies, headers } from "next/headers";
|
||||
|
||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||
|
||||
export const generateMetadata = async ({ params }: { params: Record<string, string | string[]> }) => {
|
||||
const legacyCtx = buildLegacyCtx(headers(), cookies(), params);
|
||||
const props = await getData(legacyCtx as unknown as GetServerSidePropsContext);
|
||||
const { entity, user, slug, booking } = props;
|
||||
const { trpc } = await import("@calcom/trpc");
|
||||
const { data: event } = trpc.viewer.public.event.useQuery(
|
||||
{ username: user, eventSlug: slug, isTeamEvent: false, org: entity.orgSlug ?? null },
|
||||
{ refetchOnWindowFocus: false }
|
||||
);
|
||||
|
||||
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}`
|
||||
);
|
||||
};
|
||||
export const getData = withAppDir<PageProps>(getServerSideProps);
|
||||
|
||||
export default WithLayout({
|
||||
Page: LegacyPage,
|
||||
getData,
|
||||
getLayout: null,
|
||||
isBookingPage: true,
|
||||
})<"P">;
|
||||
@@ -0,0 +1,9 @@
|
||||
import LegacyPage from "@pages/team/[slug]/embed";
|
||||
import withEmbedSsrAppDir from "app/WithEmbedSSR";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
|
||||
import { getData } from "../page";
|
||||
|
||||
const getEmbedData = withEmbedSsrAppDir(getData);
|
||||
|
||||
export default WithLayout({ getLayout: null, getData: getEmbedData, Page: LegacyPage })<"P">;
|
||||
@@ -0,0 +1,29 @@
|
||||
import LegacyPage, { type PageProps, getServerSideProps } from "@pages/team/[slug]";
|
||||
import { withAppDir } from "app/AppDirSSRHOC";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
import { type GetServerSidePropsContext } from "next";
|
||||
import { cookies, headers } from "next/headers";
|
||||
|
||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||
|
||||
export const generateMetadata = async ({ params }: { params: Record<string, string | string[]> }) => {
|
||||
const props = await getData(
|
||||
buildLegacyCtx(headers(), cookies(), params) as unknown as GetServerSidePropsContext
|
||||
);
|
||||
const teamName = props.team.name || "Nameless Team";
|
||||
|
||||
return await _generateMetadata(
|
||||
() => teamName,
|
||||
() => teamName
|
||||
);
|
||||
};
|
||||
|
||||
export const getData = withAppDir<PageProps>(getServerSideProps);
|
||||
|
||||
export default WithLayout({
|
||||
Page: LegacyPage,
|
||||
getData,
|
||||
getLayout: null,
|
||||
isBookingPage: true,
|
||||
})<"P">;
|
||||
@@ -0,0 +1,137 @@
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
|
||||
import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains";
|
||||
import { getFeatureFlagMap } from "@calcom/features/flags/server/utils";
|
||||
import { getBookerBaseUrlSync } from "@calcom/lib/getBookerUrl/client";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
|
||||
import { getTeamWithMembers } from "@calcom/lib/server/queries/teams";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
import { stripMarkdown } from "@calcom/lib/stripMarkdown";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { RedirectType } from "@calcom/prisma/client";
|
||||
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import { getTemporaryOrgRedirect } from "@lib/getTemporaryOrgRedirect";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
const log = logger.getSubLogger({ prefix: ["team/[slug]"] });
|
||||
|
||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||
const slug = Array.isArray(context.query?.slug) ? context.query.slug.pop() : context.query.slug;
|
||||
const { isValidOrgDomain, currentOrgDomain } = orgDomainConfig(context.req, context.params?.orgSlug);
|
||||
const isOrgContext = isValidOrgDomain && currentOrgDomain;
|
||||
|
||||
// Provided by Rewrite from next.config.js
|
||||
const isOrgProfile = context.query?.isOrgProfile === "1";
|
||||
const flags = await getFeatureFlagMap(prisma);
|
||||
const isOrganizationFeatureEnabled = flags["organizations"];
|
||||
|
||||
log.debug("getServerSideProps", {
|
||||
isOrgProfile,
|
||||
isOrganizationFeatureEnabled,
|
||||
isValidOrgDomain,
|
||||
currentOrgDomain,
|
||||
});
|
||||
|
||||
const team = await getTeamWithMembers({
|
||||
slug: slugify(slug ?? ""),
|
||||
orgSlug: currentOrgDomain,
|
||||
isTeamView: true,
|
||||
isOrgView: isValidOrgDomain && isOrgProfile,
|
||||
});
|
||||
|
||||
if (!isOrgContext && slug) {
|
||||
const redirect = await getTemporaryOrgRedirect({
|
||||
slugs: slug,
|
||||
redirectType: RedirectType.Team,
|
||||
eventTypeSlug: null,
|
||||
currentQuery: context.query,
|
||||
});
|
||||
|
||||
if (redirect) {
|
||||
return redirect;
|
||||
}
|
||||
}
|
||||
|
||||
const ssr = await ssrInit(context);
|
||||
const metadata = teamMetadataSchema.parse(team?.metadata ?? {});
|
||||
|
||||
// Taking care of sub-teams and orgs
|
||||
if (
|
||||
(!isValidOrgDomain && team?.parent) ||
|
||||
(!isValidOrgDomain && !!metadata?.isOrganization) ||
|
||||
!isOrganizationFeatureEnabled
|
||||
) {
|
||||
return { notFound: true } as const;
|
||||
}
|
||||
|
||||
if (!team || (team.parent && !team.parent.slug)) {
|
||||
const unpublishedTeam = await prisma.team.findFirst({
|
||||
where: {
|
||||
...(team?.parent
|
||||
? { id: team.parent.id }
|
||||
: {
|
||||
metadata: {
|
||||
path: ["requestedSlug"],
|
||||
equals: slug,
|
||||
},
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
if (!unpublishedTeam) return { notFound: true } as const;
|
||||
|
||||
return {
|
||||
props: {
|
||||
isUnpublished: true,
|
||||
team: { ...unpublishedTeam, createdAt: null },
|
||||
trpcState: ssr.dehydrate(),
|
||||
},
|
||||
} as const;
|
||||
}
|
||||
|
||||
team.eventTypes =
|
||||
team.eventTypes?.map((type) => ({
|
||||
...type,
|
||||
users: type.users.map((user) => ({
|
||||
...user,
|
||||
avatar: `/${user.username}/avatar.png`,
|
||||
})),
|
||||
descriptionAsSafeHTML: markdownToSafeHTML(type.description),
|
||||
})) ?? null;
|
||||
|
||||
const safeBio = markdownToSafeHTML(team.bio) || "";
|
||||
|
||||
const members = !team.isPrivate
|
||||
? team.members.map((member) => {
|
||||
return {
|
||||
name: member.name,
|
||||
id: member.id,
|
||||
bio: member.bio,
|
||||
subteams: member.subteams,
|
||||
username: member.username,
|
||||
accepted: member.accepted,
|
||||
organizationId: member.organizationId,
|
||||
safeBio: markdownToSafeHTML(member.bio || ""),
|
||||
bookerUrl: getBookerBaseUrlSync(member.organization?.slug || ""),
|
||||
};
|
||||
})
|
||||
: [];
|
||||
|
||||
const markdownStrippedBio = stripMarkdown(team?.bio || "");
|
||||
|
||||
const { inviteToken: _inviteToken, ...serializableTeam } = team;
|
||||
|
||||
return {
|
||||
props: {
|
||||
team: { ...serializableTeam, safeBio, members, metadata },
|
||||
themeBasis: serializableTeam.slug,
|
||||
trpcState: ssr.dehydrate(),
|
||||
markdownStrippedBio,
|
||||
isValidOrgDomain,
|
||||
currentOrgDomain,
|
||||
},
|
||||
} as const;
|
||||
};
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
// This route is reachable by
|
||||
// 1. /team/[slug]
|
||||
// 2. / (when on org domain e.g. http://calcom.cal.com/. This is through a rewrite from next.config.js)
|
||||
@@ -5,45 +7,32 @@
|
||||
// 1. org/[orgSlug]/team/[slug]
|
||||
// 2. org/[orgSlug]/[user]/[type]
|
||||
import classNames from "classnames";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import { sdkActionManager, useIsEmbed } from "@calcom/embed-core/embed-iframe";
|
||||
import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains";
|
||||
import EventTypeDescription from "@calcom/features/eventtypes/components/EventTypeDescription";
|
||||
import { getFeatureFlagMap } from "@calcom/features/flags/server/utils";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { getBookerBaseUrlSync } from "@calcom/lib/getBookerUrl/client";
|
||||
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 { getTeamWithMembers } from "@calcom/lib/server/queries/teams";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
import { stripMarkdown } from "@calcom/lib/stripMarkdown";
|
||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { RedirectType } from "@calcom/prisma/client";
|
||||
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
import { Avatar, Button, HeadSeo, UnpublishedEntity } from "@calcom/ui";
|
||||
import { ArrowRight } from "@calcom/ui/components/icon";
|
||||
|
||||
import { useToggleQuery } from "@lib/hooks/useToggleQuery";
|
||||
import { getServerSideProps } from "@lib/team/[slug]/getServerSideProps";
|
||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
|
||||
import PageWrapper from "@components/PageWrapper";
|
||||
import Team from "@components/team/screens/Team";
|
||||
import { UserAvatarGroup } from "@components/ui/avatar/UserAvatarGroup";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
import { getTemporaryOrgRedirect } from "../../lib/getTemporaryOrgRedirect";
|
||||
export { getServerSideProps };
|
||||
|
||||
export type PageProps = inferSSRProps<typeof getServerSideProps>;
|
||||
const log = logger.getSubLogger({ prefix: ["team/[slug]"] });
|
||||
function TeamPage({
|
||||
team,
|
||||
isUnpublished,
|
||||
@@ -268,124 +257,6 @@ function TeamPage({
|
||||
);
|
||||
}
|
||||
|
||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||
const slug = Array.isArray(context.query?.slug) ? context.query.slug.pop() : context.query.slug;
|
||||
const { isValidOrgDomain, currentOrgDomain } = orgDomainConfig(context.req, context.params?.orgSlug);
|
||||
const isOrgContext = isValidOrgDomain && currentOrgDomain;
|
||||
|
||||
// Provided by Rewrite from next.config.js
|
||||
const isOrgProfile = context.query?.isOrgProfile === "1";
|
||||
const flags = await getFeatureFlagMap(prisma);
|
||||
const isOrganizationFeatureEnabled = flags["organizations"];
|
||||
|
||||
log.debug("getServerSideProps", {
|
||||
isOrgProfile,
|
||||
isOrganizationFeatureEnabled,
|
||||
isValidOrgDomain,
|
||||
currentOrgDomain,
|
||||
});
|
||||
|
||||
const team = await getTeamWithMembers({
|
||||
slug: slugify(slug ?? ""),
|
||||
orgSlug: currentOrgDomain,
|
||||
isTeamView: true,
|
||||
isOrgView: isValidOrgDomain && isOrgProfile,
|
||||
});
|
||||
|
||||
if (!isOrgContext && slug) {
|
||||
const redirect = await getTemporaryOrgRedirect({
|
||||
slugs: slug,
|
||||
redirectType: RedirectType.Team,
|
||||
eventTypeSlug: null,
|
||||
currentQuery: context.query,
|
||||
});
|
||||
|
||||
if (redirect) {
|
||||
return redirect;
|
||||
}
|
||||
}
|
||||
|
||||
const ssr = await ssrInit(context);
|
||||
const metadata = teamMetadataSchema.parse(team?.metadata ?? {});
|
||||
|
||||
// Taking care of sub-teams and orgs
|
||||
if (
|
||||
(!isValidOrgDomain && team?.parent) ||
|
||||
(!isValidOrgDomain && !!metadata?.isOrganization) ||
|
||||
!isOrganizationFeatureEnabled
|
||||
) {
|
||||
return { notFound: true } as const;
|
||||
}
|
||||
|
||||
if (!team || (team.parent && !team.parent.slug)) {
|
||||
const unpublishedTeam = await prisma.team.findFirst({
|
||||
where: {
|
||||
...(team?.parent
|
||||
? { id: team.parent.id }
|
||||
: {
|
||||
metadata: {
|
||||
path: ["requestedSlug"],
|
||||
equals: slug,
|
||||
},
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
if (!unpublishedTeam) return { notFound: true } as const;
|
||||
|
||||
return {
|
||||
props: {
|
||||
isUnpublished: true,
|
||||
team: { ...unpublishedTeam, createdAt: null },
|
||||
trpcState: ssr.dehydrate(),
|
||||
},
|
||||
} as const;
|
||||
}
|
||||
|
||||
team.eventTypes =
|
||||
team.eventTypes?.map((type) => ({
|
||||
...type,
|
||||
users: type.users.map((user) => ({
|
||||
...user,
|
||||
avatar: `/${user.username}/avatar.png`,
|
||||
})),
|
||||
descriptionAsSafeHTML: markdownToSafeHTML(type.description),
|
||||
})) ?? null;
|
||||
|
||||
const safeBio = markdownToSafeHTML(team.bio) || "";
|
||||
|
||||
const members = !team.isPrivate
|
||||
? team.members.map((member) => {
|
||||
return {
|
||||
name: member.name,
|
||||
id: member.id,
|
||||
bio: member.bio,
|
||||
subteams: member.subteams,
|
||||
username: member.username,
|
||||
accepted: member.accepted,
|
||||
organizationId: member.organizationId,
|
||||
safeBio: markdownToSafeHTML(member.bio || ""),
|
||||
bookerUrl: getBookerBaseUrlSync(member.organization?.slug || ""),
|
||||
};
|
||||
})
|
||||
: [];
|
||||
|
||||
const markdownStrippedBio = stripMarkdown(team?.bio || "");
|
||||
|
||||
const { inviteToken: _inviteToken, ...serializableTeam } = team;
|
||||
|
||||
return {
|
||||
props: {
|
||||
team: { ...serializableTeam, safeBio, members, metadata },
|
||||
themeBasis: serializableTeam.slug,
|
||||
trpcState: ssr.dehydrate(),
|
||||
markdownStrippedBio,
|
||||
isValidOrgDomain,
|
||||
currentOrgDomain,
|
||||
},
|
||||
} as const;
|
||||
};
|
||||
|
||||
TeamPage.isBookingPage = true;
|
||||
TeamPage.PageWrapper = PageWrapper;
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import withEmbedSsr from "@lib/withEmbedSsr";
|
||||
|
||||
import { getServerSideProps as _getServerSideProps } from "../[type]";
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import withEmbedSsr from "@lib/withEmbedSsr";
|
||||
|
||||
import { getServerSideProps as _getServerSideProps } from "../../team/[slug]";
|
||||
|
||||
Reference in New Issue
Block a user