Migrate /team/* page group
improve import type Finalize support isBookingPage finalize fix Fix build error fix type errors
This commit is contained in:
parent
0bdc45a1a5
commit
060f2785a9
|
@ -2,7 +2,8 @@ import type { GetServerSideProps, GetServerSidePropsContext } from "next";
|
|||
import { notFound, redirect } from "next/navigation";
|
||||
|
||||
export const withAppDir =
|
||||
(getServerSideProps: GetServerSideProps) => async (context: GetServerSidePropsContext) => {
|
||||
<T extends Record<string, any>>(getServerSideProps: GetServerSideProps<T>) =>
|
||||
async (context: GetServerSidePropsContext): Promise<T> => {
|
||||
const ssrResponse = await getServerSideProps(context);
|
||||
|
||||
if ("redirect" in ssrResponse) {
|
||||
|
@ -13,5 +14,9 @@ export const withAppDir =
|
|||
notFound();
|
||||
}
|
||||
|
||||
return ssrResponse.props;
|
||||
return {
|
||||
...ssrResponse.props,
|
||||
// includes dehydratedState required for future page trpcPropvider
|
||||
...("trpcState" in ssrResponse.props && { dehydratedState: ssrResponse.props.trpcState }),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import LegacyPage from "@pages/apps/categories/index";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { type GetServerSidePropsContext } from "next";
|
||||
|
||||
import { getAppRegistry, getAppRegistryWithCredentials } from "@calcom/app-store/_appRegistry";
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import AppsPage from "@pages/apps";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { type GetServerSidePropsContext } from "next";
|
||||
|
||||
import { getAppRegistry, getAppRegistryWithCredentials } from "@calcom/app-store/_appRegistry";
|
||||
import { getLayout } from "@calcom/features/MainLayoutAppDir";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { type GetServerSidePropsContext } from "next";
|
||||
import { notFound } from "next/navigation";
|
||||
import { z } from "zod";
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import LegacyPage from "@pages/getting-started/[[...step]]";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { cookies, headers } from "next/headers";
|
||||
import { type GetServerSidePropsContext } from "next";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
|
@ -10,10 +9,7 @@ import prisma from "@calcom/prisma";
|
|||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
const getData = async (ctx: GetServerSidePropsContext) => {
|
||||
const req = { headers: headers(), cookies: cookies() };
|
||||
|
||||
//@ts-expect-error Type '{ headers: ReadonlyHeaders; cookies: ReadonlyRequestCookies; }' is not assignable to type 'NextApiRequest
|
||||
const session = await getServerSession({ req });
|
||||
const session = await getServerSession({ req: ctx.req });
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return redirect("/auth/login");
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import { getServerSideProps } from "@pages/team/[slug]/[type]";
|
||||
import { withAppDir } from "app/AppDirSSRHOC";
|
||||
import type { PageProps } from "app/_types";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { cookies, headers } from "next/headers";
|
||||
|
||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||
import withEmbedSsr from "@lib/withEmbedSsr";
|
||||
|
||||
const Page = async ({ params }: PageProps) => {
|
||||
const legacyCtx = buildLegacyCtx(headers(), cookies(), params);
|
||||
|
||||
await withAppDir(withEmbedSsr(getServerSideProps))(legacyCtx as unknown as GetServerSidePropsContext);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default Page;
|
|
@ -0,0 +1,21 @@
|
|||
import LegacyPage, {
|
||||
type PageProps,
|
||||
getServerSideProps as _getServerSideProps,
|
||||
} from "@pages/team/[slug]/[type]";
|
||||
import { withAppDir } from "app/AppDirSSRHOC";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
|
||||
export const generateMetadata = async () =>
|
||||
await _generateMetadata(
|
||||
() => "",
|
||||
() => ""
|
||||
);
|
||||
const getData = withAppDir<PageProps>(_getServerSideProps);
|
||||
|
||||
export default WithLayout({
|
||||
Page: LegacyPage,
|
||||
getData,
|
||||
getLayout: null,
|
||||
isBookingPage: true,
|
||||
})<"P">;
|
|
@ -0,0 +1,18 @@
|
|||
import { getServerSideProps } from "@pages/team/[slug]";
|
||||
import { withAppDir } from "app/AppDirSSRHOC";
|
||||
import type { PageProps } from "app/_types";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { cookies, headers } from "next/headers";
|
||||
|
||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||
import withEmbedSsr from "@lib/withEmbedSsr";
|
||||
|
||||
const Page = async ({ params }: PageProps) => {
|
||||
const legacyCtx = buildLegacyCtx(headers(), cookies(), params);
|
||||
|
||||
await withAppDir(withEmbedSsr(getServerSideProps))(legacyCtx as unknown as GetServerSidePropsContext);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default Page;
|
|
@ -0,0 +1,29 @@
|
|||
import LegacyPage, { type PageProps, getServerSideProps as _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
|
||||
);
|
||||
};
|
||||
|
||||
const getData = withAppDir<PageProps>(_getServerSideProps);
|
||||
|
||||
export default WithLayout({
|
||||
Page: LegacyPage,
|
||||
getData,
|
||||
getLayout: null,
|
||||
isBookingPage: true,
|
||||
})<"P">;
|
|
@ -1,7 +1,7 @@
|
|||
import OldPage from "@pages/teams/index";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { type GetServerSidePropsContext } from "next";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
import { getLayout } from "@calcom/features/MainLayoutAppDir";
|
||||
|
|
|
@ -2,7 +2,7 @@ import OldPage from "@pages/video/[uid]";
|
|||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
import MarkdownIt from "markdown-it";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { type GetServerSidePropsContext } from "next";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
|
|
|
@ -10,9 +10,15 @@ type WithLayoutParams<T extends Record<string, any>> = {
|
|||
getLayout: ((page: React.ReactElement) => React.ReactNode) | null;
|
||||
Page?: (props: T) => React.ReactElement | null;
|
||||
getData?: (arg: GetServerSidePropsContext) => Promise<T>;
|
||||
isBookingPage?: boolean;
|
||||
};
|
||||
|
||||
export function WithLayout<T extends Record<string, any>>({ getLayout, getData, Page }: WithLayoutParams<T>) {
|
||||
export function WithLayout<T extends Record<string, any>>({
|
||||
getLayout,
|
||||
getData,
|
||||
Page,
|
||||
isBookingPage,
|
||||
}: WithLayoutParams<T>) {
|
||||
return async <P extends "P" | "L">(p: P extends "P" ? PageProps : LayoutProps) => {
|
||||
const h = headers();
|
||||
const nonce = h.get("x-nonce") ?? undefined;
|
||||
|
@ -23,7 +29,13 @@ export function WithLayout<T extends Record<string, any>>({ getLayout, getData,
|
|||
const children = "children" in p ? p.children : null;
|
||||
|
||||
return (
|
||||
<PageWrapper getLayout={getLayout} requiresLicense={false} nonce={nonce} themeBasis={null} {...props}>
|
||||
<PageWrapper
|
||||
getLayout={getLayout}
|
||||
requiresLicense={false}
|
||||
nonce={nonce}
|
||||
themeBasis={null}
|
||||
isBookingPage={isBookingPage}
|
||||
{...props}>
|
||||
{Page ? <Page {...props} /> : children}
|
||||
</PageWrapper>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
import type { GetServerSidePropsContext } from "next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import { getBookingForReschedule, getMultipleDurationValue } from "@calcom/features/bookings/lib/get-booking";
|
||||
import type { GetBookingType } from "@calcom/features/bookings/lib/get-booking";
|
||||
import { getSlugOrRequestedSlug } from "@calcom/features/ee/organizations/lib/orgDomains";
|
||||
import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { RedirectType } from "@calcom/prisma/client";
|
||||
|
||||
import { getTemporaryOrgRedirect } from "@lib/getTemporaryOrgRedirect";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
type: z.string().transform((s) => slugify(s)),
|
||||
slug: z.string().transform((s) => slugify(s)),
|
||||
});
|
||||
|
||||
// Booker page fetches a tiny bit of data server side:
|
||||
// 1. Check if team exists, to show 404
|
||||
// 2. If rescheduling, get the booking details
|
||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||
const session = await getServerSession(context);
|
||||
const { slug: teamSlug, type: meetingSlug } = paramsSchema.parse(context.params);
|
||||
const { rescheduleUid, duration: queryDuration, isInstantMeeting: queryIsInstantMeeting } = context.query;
|
||||
const { ssrInit } = await import("@server/lib/ssr");
|
||||
const ssr = await ssrInit(context);
|
||||
const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(context.req, context.params?.orgSlug);
|
||||
const isOrgContext = currentOrgDomain && isValidOrgDomain;
|
||||
|
||||
if (!isOrgContext) {
|
||||
const redirect = await getTemporaryOrgRedirect({
|
||||
slug: teamSlug,
|
||||
redirectType: RedirectType.Team,
|
||||
eventTypeSlug: meetingSlug,
|
||||
currentQuery: context.query,
|
||||
});
|
||||
|
||||
if (redirect) {
|
||||
return redirect;
|
||||
}
|
||||
}
|
||||
|
||||
const team = await prisma.team.findFirst({
|
||||
where: {
|
||||
...getSlugOrRequestedSlug(teamSlug),
|
||||
parent: isValidOrgDomain && currentOrgDomain ? getSlugOrRequestedSlug(currentOrgDomain) : null,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
hideBranding: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!team) {
|
||||
return {
|
||||
notFound: true,
|
||||
} as const;
|
||||
}
|
||||
|
||||
let booking: GetBookingType | null = null;
|
||||
if (rescheduleUid) {
|
||||
booking = await getBookingForReschedule(`${rescheduleUid}`, session?.user?.id);
|
||||
}
|
||||
|
||||
const org = isValidOrgDomain ? currentOrgDomain : null;
|
||||
// We use this to both prefetch the query on the server,
|
||||
// as well as to check if the event exist, so we c an show a 404 otherwise.
|
||||
const eventData = await ssr.viewer.public.event.fetch({
|
||||
username: teamSlug,
|
||||
eventSlug: meetingSlug,
|
||||
isTeamEvent: true,
|
||||
org,
|
||||
});
|
||||
|
||||
if (!eventData) {
|
||||
return {
|
||||
notFound: true,
|
||||
} as const;
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
entity: eventData.entity,
|
||||
duration: getMultipleDurationValue(
|
||||
eventData.metadata?.multipleDuration,
|
||||
queryDuration,
|
||||
eventData.length
|
||||
),
|
||||
booking,
|
||||
away: false,
|
||||
user: teamSlug,
|
||||
teamId: team.id,
|
||||
slug: meetingSlug,
|
||||
trpcState: ssr.dehydrate(),
|
||||
isBrandingHidden: team?.hideBranding,
|
||||
isInstantMeeting: eventData.isInstantEvent && queryIsInstantMeeting ? true : false,
|
||||
themeBasis: null,
|
||||
},
|
||||
};
|
||||
};
|
|
@ -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({
|
||||
slug: 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({
|
||||
slug: 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,27 +1,19 @@
|
|||
import type { GetServerSidePropsContext } from "next";
|
||||
import { z } from "zod";
|
||||
"use client";
|
||||
|
||||
import { Booker } from "@calcom/atoms";
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import { getBookerWrapperClasses } from "@calcom/features/bookings/Booker/utils/getBookerWrapperClasses";
|
||||
import { BookerSeo } from "@calcom/features/bookings/components/BookerSeo";
|
||||
import { getBookingForReschedule, getMultipleDurationValue } from "@calcom/features/bookings/lib/get-booking";
|
||||
import type { GetBookingType } from "@calcom/features/bookings/lib/get-booking";
|
||||
import { getSlugOrRequestedSlug } from "@calcom/features/ee/organizations/lib/orgDomains";
|
||||
import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { RedirectType } from "@calcom/prisma/client";
|
||||
|
||||
import { getServerSideProps } from "@lib/team/[slug]/[type]/getServerSideProps";
|
||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
import type { EmbedProps } from "@lib/withEmbedSsr";
|
||||
|
||||
import PageWrapper from "@components/PageWrapper";
|
||||
|
||||
import { getTemporaryOrgRedirect } from "../../../lib/getTemporaryOrgRedirect";
|
||||
|
||||
export type PageProps = inferSSRProps<typeof getServerSideProps> & EmbedProps;
|
||||
|
||||
export { getServerSideProps };
|
||||
|
||||
export default function Type({
|
||||
slug,
|
||||
user,
|
||||
|
@ -61,92 +53,3 @@ export default function Type({
|
|||
|
||||
Type.PageWrapper = PageWrapper;
|
||||
Type.isBookingPage = true;
|
||||
|
||||
const paramsSchema = z.object({
|
||||
type: z.string().transform((s) => slugify(s)),
|
||||
slug: z.string().transform((s) => slugify(s)),
|
||||
});
|
||||
|
||||
// Booker page fetches a tiny bit of data server side:
|
||||
// 1. Check if team exists, to show 404
|
||||
// 2. If rescheduling, get the booking details
|
||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||
const session = await getServerSession(context);
|
||||
const { slug: teamSlug, type: meetingSlug } = paramsSchema.parse(context.params);
|
||||
const { rescheduleUid, duration: queryDuration, isInstantMeeting: queryIsInstantMeeting } = context.query;
|
||||
const { ssrInit } = await import("@server/lib/ssr");
|
||||
const ssr = await ssrInit(context);
|
||||
const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(context.req, context.params?.orgSlug);
|
||||
const isOrgContext = currentOrgDomain && isValidOrgDomain;
|
||||
|
||||
if (!isOrgContext) {
|
||||
const redirect = await getTemporaryOrgRedirect({
|
||||
slug: teamSlug,
|
||||
redirectType: RedirectType.Team,
|
||||
eventTypeSlug: meetingSlug,
|
||||
currentQuery: context.query,
|
||||
});
|
||||
|
||||
if (redirect) {
|
||||
return redirect;
|
||||
}
|
||||
}
|
||||
|
||||
const team = await prisma.team.findFirst({
|
||||
where: {
|
||||
...getSlugOrRequestedSlug(teamSlug),
|
||||
parent: isValidOrgDomain && currentOrgDomain ? getSlugOrRequestedSlug(currentOrgDomain) : null,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
hideBranding: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!team) {
|
||||
return {
|
||||
notFound: true,
|
||||
} as const;
|
||||
}
|
||||
|
||||
let booking: GetBookingType | null = null;
|
||||
if (rescheduleUid) {
|
||||
booking = await getBookingForReschedule(`${rescheduleUid}`, session?.user?.id);
|
||||
}
|
||||
|
||||
const org = isValidOrgDomain ? currentOrgDomain : null;
|
||||
// We use this to both prefetch the query on the server,
|
||||
// as well as to check if the event exist, so we c an show a 404 otherwise.
|
||||
const eventData = await ssr.viewer.public.event.fetch({
|
||||
username: teamSlug,
|
||||
eventSlug: meetingSlug,
|
||||
isTeamEvent: true,
|
||||
org,
|
||||
});
|
||||
|
||||
if (!eventData) {
|
||||
return {
|
||||
notFound: true,
|
||||
} as const;
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
entity: eventData.entity,
|
||||
duration: getMultipleDurationValue(
|
||||
eventData.metadata?.multipleDuration,
|
||||
queryDuration,
|
||||
eventData.length
|
||||
),
|
||||
booking,
|
||||
away: false,
|
||||
user: teamSlug,
|
||||
teamId: team.id,
|
||||
slug: meetingSlug,
|
||||
trpcState: ssr.dehydrate(),
|
||||
isBrandingHidden: team?.hideBranding,
|
||||
isInstantMeeting: eventData.isInstantEvent && queryIsInstantMeeting ? true : false,
|
||||
themeBasis: null,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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]";
|
||||
|
|
Loading…
Reference in New Issue
Block a user