diff --git a/apps/web/app/AppDirSSRHOC.tsx b/apps/web/app/AppDirSSRHOC.tsx deleted file mode 100644 index 87b419ca49..0000000000 --- a/apps/web/app/AppDirSSRHOC.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import type { GetServerSideProps, GetServerSidePropsContext } from "next"; -import { notFound, redirect } from "next/navigation"; - -export const withAppDir = - (getServerSideProps: GetServerSideProps) => async (context: GetServerSidePropsContext) => { - const ssrResponse = await getServerSideProps(context); - - if ("redirect" in ssrResponse) { - redirect(ssrResponse.redirect.destination); - } - - if ("notFound" in ssrResponse) { - notFound(); - } - - return ssrResponse.props; - }; diff --git a/apps/web/app/WithAppDirSsg.tsx b/apps/web/app/WithAppDirSsg.tsx new file mode 100644 index 0000000000..470e08be10 --- /dev/null +++ b/apps/web/app/WithAppDirSsg.tsx @@ -0,0 +1,26 @@ +import type { GetStaticProps } from "next"; +import { notFound, redirect } from "next/navigation"; + +import type { buildLegacyCtx } from "@lib/buildLegacyCtx"; + +export const withAppDirSsg = + >(getStaticProps: GetStaticProps) => + async (context: ReturnType) => { + const ssgResponse = await getStaticProps(context); + + if ("redirect" in ssgResponse) { + redirect(ssgResponse.redirect.destination); + } + + if ("notFound" in ssgResponse) { + notFound(); + } + + const props = await Promise.resolve(ssgResponse.props); + + return { + ...ssgResponse.props, + // includes dehydratedState required for future page trpcPropvider + ...("trpcState" in props && { dehydratedState: props.trpcState }), + }; + }; diff --git a/apps/web/app/WithAppDirSsr.tsx b/apps/web/app/WithAppDirSsr.tsx new file mode 100644 index 0000000000..3df0c78f16 --- /dev/null +++ b/apps/web/app/WithAppDirSsr.tsx @@ -0,0 +1,24 @@ +import type { GetServerSideProps, GetServerSidePropsContext } from "next"; +import { notFound, redirect } from "next/navigation"; + +export const withAppDirSsr = + >(getServerSideProps: GetServerSideProps) => + async (context: GetServerSidePropsContext) => { + const ssrResponse = await getServerSideProps(context); + + if ("redirect" in ssrResponse) { + redirect(ssrResponse.redirect.destination); + } + + if ("notFound" in ssrResponse) { + notFound(); + } + + const props = await Promise.resolve(ssrResponse.props); + + return { + ...props, + // includes dehydratedState required for future page trpcPropvider + ...("trpcState" in props && { dehydratedState: props.trpcState }), + }; + }; diff --git a/apps/web/app/future/apps/[slug]/layout.tsx b/apps/web/app/future/apps/[slug]/layout.tsx deleted file mode 100644 index dc2fb3468f..0000000000 --- a/apps/web/app/future/apps/[slug]/layout.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { WithLayout } from "app/layoutHOC"; - -export default WithLayout({ getLayout: null })<"L">; diff --git a/apps/web/app/future/apps/[slug]/page.tsx b/apps/web/app/future/apps/[slug]/page.tsx index ec1121c949..e21c2a615e 100644 --- a/apps/web/app/future/apps/[slug]/page.tsx +++ b/apps/web/app/future/apps/[slug]/page.tsx @@ -1,40 +1,27 @@ -import AppPage from "@pages/apps/[slug]/index"; +import Page from "@pages/apps/[slug]/index"; import { Prisma } from "@prisma/client"; +import { withAppDirSsg } from "app/WithAppDirSsg"; import { _generateMetadata } from "app/_utils"; -import fs from "fs"; -import matter from "gray-matter"; -import { notFound } from "next/navigation"; -import path from "path"; -import { z } from "zod"; +import { WithLayout } from "app/layoutHOC"; +import type { InferGetStaticPropsType } from "next"; +import { cookies, headers } from "next/headers"; -import { getAppWithMetadata } from "@calcom/app-store/_appRegistry"; -import { getAppAssetFullPath } from "@calcom/app-store/getAppAssetFullPath"; -import { APP_NAME, IS_PRODUCTION } from "@calcom/lib/constants"; +import { APP_NAME } from "@calcom/lib/constants"; import prisma from "@calcom/prisma"; -const sourceSchema = z.object({ - content: z.string(), - data: z.object({ - description: z.string().optional(), - items: z - .array( - z.union([ - z.string(), - z.object({ - iframe: z.object({ src: z.string() }), - }), - ]) - ) - .optional(), - }), -}); +import { getStaticProps } from "@lib/apps/[slug]/getStaticProps"; +import { buildLegacyCtx } from "@lib/buildLegacyCtx"; + +type Y = InferGetStaticPropsType; +const getData = withAppDirSsg(getStaticProps); export const generateMetadata = async ({ params }: { params: Record }) => { - const { data } = await getPageProps({ params }); + const legacyContext = buildLegacyCtx(headers(), cookies(), params); + const res = await getData(legacyContext); return await _generateMetadata( - () => `${data.name} | ${APP_NAME}`, - () => data.description + () => `${res?.data.name} | ${APP_NAME}`, + () => res?.data.description ?? "" ); }; @@ -53,74 +40,6 @@ export const generateStaticParams = async () => { return []; }; -const getPageProps = async ({ params }: { params: Record }) => { - if (typeof params?.slug !== "string") { - notFound(); - } - - const appMeta = await getAppWithMetadata({ - slug: params?.slug, - }); - - const appFromDb = await prisma.app.findUnique({ - where: { slug: params.slug.toLowerCase() }, - }); - - const isAppAvailableInFileSystem = appMeta; - const isAppDisabled = isAppAvailableInFileSystem && (!appFromDb || !appFromDb.enabled); - - if (!IS_PRODUCTION && isAppDisabled) { - return { - isAppDisabled: true as const, - data: { - ...appMeta, - }, - }; - } - - if (!appFromDb || !appMeta || isAppDisabled) { - notFound(); - } - - const isTemplate = appMeta.isTemplate; - const appDirname = path.join(isTemplate ? "templates" : "", appFromDb.dirName); - const README_PATH = path.join(process.cwd(), "..", "..", `packages/app-store/${appDirname}/DESCRIPTION.md`); - const postFilePath = path.join(README_PATH); - let source = ""; - - try { - source = fs.readFileSync(postFilePath).toString(); - source = source.replace(/{DESCRIPTION}/g, appMeta.description); - } catch (error) { - /* If the app doesn't have a README we fallback to the package description */ - console.log(`No DESCRIPTION.md provided for: ${appDirname}`); - source = appMeta.description; - } - - const result = matter(source); - const { content, data } = sourceSchema.parse({ content: result.content, data: result.data }); - if (data.items) { - data.items = data.items.map((item) => { - if (typeof item === "string") { - return getAppAssetFullPath(item, { - dirName: appMeta.dirName, - isTemplate: appMeta.isTemplate, - }); - } - return item; - }); - } - return { - isAppDisabled: false as const, - source: { content, data }, - data: appMeta, - }; -}; - -export default async function Page({ params }: { params: Record }) { - const pageProps = await getPageProps({ params }); - - return ; -} +export default WithLayout({ getLayout: null, Page, getData }); export const dynamic = "force-static"; diff --git a/apps/web/app/future/apps/[slug]/setup/page.tsx b/apps/web/app/future/apps/[slug]/setup/page.tsx index ce6abc75ba..b62fcfb981 100644 --- a/apps/web/app/future/apps/[slug]/setup/page.tsx +++ b/apps/web/app/future/apps/[slug]/setup/page.tsx @@ -1,8 +1,7 @@ -import SetupPage from "@pages/apps/[slug]/setup"; +import Page from "@pages/apps/[slug]/setup"; +import { withAppDirSsr } from "app/WithAppDirSsr"; import { _generateMetadata } from "app/_utils"; -import type { GetServerSidePropsContext } from "next"; -import { cookies, headers } from "next/headers"; -import { notFound, redirect } from "next/navigation"; +import { WithLayout } from "app/layoutHOC"; import { getServerSideProps } from "@calcom/app-store/_pages/setup/_getServerSideProps"; import { APP_NAME } from "@calcom/lib/constants"; @@ -14,23 +13,4 @@ export const generateMetadata = async ({ params }: { params: Record }) => { - const req = { headers: headers(), cookies: cookies() }; - - const result = await getServerSideProps({ params, req } as unknown as GetServerSidePropsContext); - - if (!result || "notFound" in result) { - notFound(); - } - - if ("redirect" in result) { - redirect(result.redirect.destination); - } - - return result.props; -}; - -export default async function Page({ params }: { params: Record }) { - const pageProps = await getPageProps({ params }); - return ; -} +export default WithLayout({ getLayout: null, Page, getData: withAppDirSsr(getServerSideProps) }); diff --git a/apps/web/app/future/apps/categories/page.tsx b/apps/web/app/future/apps/categories/page.tsx index 0ef5547ee4..8fcb079dbe 100644 --- a/apps/web/app/future/apps/categories/page.tsx +++ b/apps/web/app/future/apps/categories/page.tsx @@ -1,13 +1,11 @@ -import LegacyPage from "@pages/apps/categories/index"; +import Page from "@pages/apps/categories/index"; +import { withAppDirSsr } from "app/WithAppDirSsr"; import { _generateMetadata } from "app/_utils"; import { WithLayout } from "app/layoutHOC"; -import type { GetServerSidePropsContext } from "next"; -import { getAppRegistry, getAppRegistryWithCredentials } from "@calcom/app-store/_appRegistry"; -import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; import { APP_NAME } from "@calcom/lib/constants"; -import { ssrInit } from "@server/lib/ssr"; +import { getServerSideProps } from "@lib/apps/categories/getServerSideProps"; export const generateMetadata = async () => { return await _generateMetadata( @@ -16,29 +14,4 @@ export const generateMetadata = async () => { ); }; -const getData = async (ctx: GetServerSidePropsContext) => { - const ssr = await ssrInit(ctx); - - const session = await getServerSession({ req: ctx.req }); - - let appStore; - if (session?.user?.id) { - appStore = await getAppRegistryWithCredentials(session.user.id); - } else { - appStore = await getAppRegistry(); - } - - const categories = appStore.reduce((c, app) => { - for (const category of app.categories) { - c[category] = c[category] ? c[category] + 1 : 1; - } - return c; - }, {} as Record); - - return { - categories: Object.entries(categories).map(([name, count]) => ({ name, count })), - dehydratedState: ssr.dehydrate(), - }; -}; - -export default WithLayout({ getData, Page: LegacyPage, getLayout: null })<"P">; +export default WithLayout({ getData: withAppDirSsr(getServerSideProps), Page, getLayout: null })<"P">; diff --git a/apps/web/app/future/apps/installed/[category]/layout.tsx b/apps/web/app/future/apps/installed/[category]/layout.tsx deleted file mode 100644 index dc2fb3468f..0000000000 --- a/apps/web/app/future/apps/installed/[category]/layout.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { WithLayout } from "app/layoutHOC"; - -export default WithLayout({ getLayout: null })<"L">; diff --git a/apps/web/app/future/apps/installed/[category]/page.tsx b/apps/web/app/future/apps/installed/[category]/page.tsx index 44b511f0f8..829a6a0e40 100644 --- a/apps/web/app/future/apps/installed/[category]/page.tsx +++ b/apps/web/app/future/apps/installed/[category]/page.tsx @@ -1,14 +1,11 @@ -import LegacyPage from "@pages/apps/installed/[category]"; +import Page from "@pages/apps/installed/[category]"; +import { withAppDirSsr } from "app/WithAppDirSsr"; import { _generateMetadata } from "app/_utils"; -import { notFound } from "next/navigation"; -import { z } from "zod"; +import { WithLayout } from "app/layoutHOC"; import { APP_NAME } from "@calcom/lib/constants"; -import { AppCategories } from "@calcom/prisma/enums"; -const querySchema = z.object({ - category: z.nativeEnum(AppCategories), -}); +import { getServerSideProps } from "@lib/apps/installed/[category]/getServerSideProps"; export const generateMetadata = async () => { return await _generateMetadata( @@ -17,20 +14,6 @@ export const generateMetadata = async () => { ); }; -const getPageProps = async ({ params }: { params: Record }) => { - const p = querySchema.safeParse(params); +const getData = withAppDirSsr(getServerSideProps); - if (!p.success) { - return notFound(); - } - - return { - category: p.data.category, - }; -}; - -export default async function Page({ params }: { params: Record }) { - await getPageProps({ params }); - - return ; -} +export default WithLayout({ getLayout: null, getData, Page }); diff --git a/apps/web/app/future/apps/page.tsx b/apps/web/app/future/apps/page.tsx index cdccef7bdf..4fdd8bea97 100644 --- a/apps/web/app/future/apps/page.tsx +++ b/apps/web/app/future/apps/page.tsx @@ -1,17 +1,12 @@ import AppsPage from "@pages/apps"; +import { withAppDirSsr } from "app/WithAppDirSsr"; import { _generateMetadata } from "app/_utils"; import { WithLayout } from "app/layoutHOC"; -import type { GetServerSidePropsContext } from "next"; -import { getAppRegistry, getAppRegistryWithCredentials } from "@calcom/app-store/_appRegistry"; import { getLayout } from "@calcom/features/MainLayoutAppDir"; -import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; -import type { UserAdminTeams } from "@calcom/features/ee/teams/lib/getUserAdminTeams"; -import getUserAdminTeams from "@calcom/features/ee/teams/lib/getUserAdminTeams"; import { APP_NAME } from "@calcom/lib/constants"; -import type { AppCategories } from "@calcom/prisma/enums"; -import { ssrInit } from "@server/lib/ssr"; +import { getServerSideProps } from "@lib/apps/getServerSideProps"; export const generateMetadata = async () => { return await _generateMetadata( @@ -20,44 +15,4 @@ export const generateMetadata = async () => { ); }; -const getData = async (ctx: GetServerSidePropsContext) => { - const ssr = await ssrInit(ctx); - - const session = await getServerSession({ req: ctx.req }); - - let appStore, userAdminTeams: UserAdminTeams; - if (session?.user?.id) { - userAdminTeams = await getUserAdminTeams({ userId: session.user.id, getUserInfo: true }); - appStore = await getAppRegistryWithCredentials(session.user.id, userAdminTeams); - } else { - appStore = await getAppRegistry(); - userAdminTeams = []; - } - - const categoryQuery = appStore.map(({ categories }) => ({ - categories: categories || [], - })); - - const categories = categoryQuery.reduce((c, app) => { - for (const category of app.categories) { - c[category] = c[category] ? c[category] + 1 : 1; - } - return c; - }, {} as Record); - - return { - categories: Object.entries(categories) - .map(([name, count]): { name: AppCategories; count: number } => ({ - name: name as AppCategories, - count, - })) - .sort(function (a, b) { - return b.count - a.count; - }), - appStore, - userAdminTeams, - dehydratedState: ssr.dehydrate(), - }; -}; - -export default WithLayout({ getLayout, getData, Page: AppsPage }); +export default WithLayout({ getLayout, getData: withAppDirSsr(getServerSideProps), Page: AppsPage }); diff --git a/apps/web/app/future/getting-started/[[...step]]/page.tsx b/apps/web/app/future/getting-started/[[...step]]/page.tsx index 1665eca319..28c8d891e4 100644 --- a/apps/web/app/future/getting-started/[[...step]]/page.tsx +++ b/apps/web/app/future/getting-started/[[...step]]/page.tsx @@ -1,61 +1,7 @@ -import LegacyPage from "@pages/getting-started/[[...step]]"; +import Page from "@pages/getting-started/[[...step]]"; +import { withAppDirSsr } from "app/WithAppDirSsr"; import { WithLayout } from "app/layoutHOC"; -import type { GetServerSidePropsContext } from "next"; -import { cookies, headers } from "next/headers"; -import { redirect } from "next/navigation"; -import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; -import prisma from "@calcom/prisma"; +import { getServerSideProps } from "@lib/getting-started/[[...step]]/getServerSideProps"; -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 }); - - if (!session?.user?.id) { - return redirect("/auth/login"); - } - const ssr = await ssrInit(ctx); - await ssr.viewer.me.prefetch(); - - const user = await prisma.user.findUnique({ - where: { - id: session.user.id, - }, - select: { - completedOnboarding: true, - teams: { - select: { - accepted: true, - team: { - select: { - id: true, - name: true, - logo: true, - }, - }, - }, - }, - }, - }); - - if (!user) { - throw new Error("User from session not found"); - } - - if (user.completedOnboarding) { - redirect("/event-types"); - } - - return { - dehydratedState: ssr.dehydrate(), - hasPendingInvites: user.teams.find((team) => team.accepted === false) ?? false, - requiresLicense: false, - themeBasis: null, - }; -}; - -export default WithLayout({ getLayout: null, getData, Page: LegacyPage }); +export default WithLayout({ getLayout: null, getData: withAppDirSsr(getServerSideProps), Page }); diff --git a/apps/web/app/future/reschedule/[uid]/embed/page.tsx b/apps/web/app/future/reschedule/[uid]/embed/page.tsx index 52bef3e486..00602675e3 100644 --- a/apps/web/app/future/reschedule/[uid]/embed/page.tsx +++ b/apps/web/app/future/reschedule/[uid]/embed/page.tsx @@ -1,5 +1,5 @@ import { getServerSideProps } from "@pages/reschedule/[uid]"; -import { withAppDir } from "app/AppDirSSRHOC"; +import { withAppDirSsr } from "app/WithAppDirSsr"; import type { Params } from "next/dist/shared/lib/router/utils/route-matcher"; import { cookies, headers } from "next/headers"; @@ -12,8 +12,7 @@ type PageProps = Readonly<{ const Page = async ({ params }: PageProps) => { const legacyCtx = buildLegacyCtx(headers(), cookies(), params); - // @ts-expect-error Argument of type '{ query: Params; params: Params; req: { headers: ReadonlyHeaders; cookies: ReadonlyRequestCookies; }; }' - await withAppDir(withEmbedSsr(getServerSideProps))(legacyCtx); + await withAppDirSsr(withEmbedSsr(getServerSideProps))(legacyCtx); return null; }; diff --git a/apps/web/app/future/reschedule/[uid]/page.tsx b/apps/web/app/future/reschedule/[uid]/page.tsx index 40fbf05617..9900ad14d9 100644 --- a/apps/web/app/future/reschedule/[uid]/page.tsx +++ b/apps/web/app/future/reschedule/[uid]/page.tsx @@ -1,5 +1,5 @@ import OldPage, { getServerSideProps as _getServerSideProps } from "@pages/reschedule/[uid]"; -import { withAppDir } from "app/AppDirSSRHOC"; +import { withAppDirSsr } from "app/WithAppDirSsr"; import { _generateMetadata } from "app/_utils"; import type { Params } from "next/dist/shared/lib/router/utils/route-matcher"; import { headers, cookies } from "next/headers"; @@ -16,12 +16,11 @@ type PageProps = Readonly<{ params: Params; }>; -const getData = withAppDir(_getServerSideProps); +const getData = withAppDirSsr(_getServerSideProps); const Page = async ({ params }: PageProps) => { const legacyCtx = buildLegacyCtx(headers(), cookies(), params); - // @ts-expect-error Argument of type '{ query: Params; params: Params; req: { headers: ReadonlyHeaders; cookies: ReadonlyRequestCookies; }; }' await getData(legacyCtx); return ; diff --git a/apps/web/app/future/teams/page.tsx b/apps/web/app/future/teams/page.tsx index 6453ac8e01..2145383bb8 100644 --- a/apps/web/app/future/teams/page.tsx +++ b/apps/web/app/future/teams/page.tsx @@ -1,13 +1,11 @@ -import OldPage from "@pages/teams/index"; +import Page from "@pages/teams/index"; +import { withAppDirSsr } from "app/WithAppDirSsr"; import { _generateMetadata } from "app/_utils"; import { WithLayout } from "app/layoutHOC"; -import type { GetServerSidePropsContext } from "next"; -import { redirect } from "next/navigation"; import { getLayout } from "@calcom/features/MainLayoutAppDir"; -import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; -import { ssrInit } from "@server/lib/ssr"; +import { getServerSideProps } from "@lib/teams/getServerSideProps"; export const generateMetadata = async () => await _generateMetadata( @@ -15,23 +13,4 @@ export const generateMetadata = async () => (t) => t("create_manage_teams_collaborative") ); -async function getData(context: GetServerSidePropsContext) { - const ssr = await ssrInit(context); - - await ssr.viewer.me.prefetch(); - - const session = await getServerSession({ - req: context.req, - }); - - if (!session) { - const token = Array.isArray(context.query.token) ? context.query.token[0] : context.query.token; - - const callbackUrl = token ? `/teams?token=${encodeURIComponent(token)}` : null; - return redirect(callbackUrl ? `/auth/login?callbackUrl=${callbackUrl}` : "/auth/login"); - } - - return { dehydratedState: ssr.dehydrate() }; -} - -export default WithLayout({ getData, getLayout, Page: OldPage })<"P">; +export default WithLayout({ getData: withAppDirSsr(getServerSideProps), getLayout, Page })<"P">; diff --git a/apps/web/app/future/video/[uid]/page.tsx b/apps/web/app/future/video/[uid]/page.tsx index 7625bd0125..1fad8a0470 100644 --- a/apps/web/app/future/video/[uid]/page.tsx +++ b/apps/web/app/future/video/[uid]/page.tsx @@ -1,15 +1,11 @@ -import OldPage from "@pages/video/[uid]"; +import Page from "@pages/video/[uid]"; +import { withAppDirSsr } from "app/WithAppDirSsr"; import { _generateMetadata } from "app/_utils"; import { WithLayout } from "app/layoutHOC"; -import MarkdownIt from "markdown-it"; -import type { GetServerSidePropsContext } from "next"; -import { redirect } from "next/navigation"; -import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; import { APP_NAME } from "@calcom/lib/constants"; -import prisma, { bookingMinimalSelect } from "@calcom/prisma"; -import { ssrInit } from "@server/lib/ssr"; +import { getServerSideProps } from "@lib/video/[uid]/getServerSideProps"; export const generateMetadata = async () => await _generateMetadata( @@ -17,86 +13,6 @@ export const generateMetadata = async () => (t) => t("quick_video_meeting") ); -const md = new MarkdownIt("default", { html: true, breaks: true, linkify: true }); +const getData = withAppDirSsr(getServerSideProps); -async function getData(context: GetServerSidePropsContext) { - const ssr = await ssrInit(context); - - const booking = await prisma.booking.findUnique({ - where: { - uid: context.query.uid as string, - }, - select: { - ...bookingMinimalSelect, - uid: true, - description: true, - isRecorded: true, - user: { - select: { - id: true, - timeZone: true, - name: true, - email: true, - organization: { - select: { - calVideoLogo: true, - }, - }, - }, - }, - references: { - select: { - uid: true, - type: true, - meetingUrl: true, - meetingPassword: true, - }, - where: { - type: "daily_video", - }, - }, - }, - }); - - if (!booking || booking.references.length === 0 || !booking.references[0].meetingUrl) { - return redirect("/video/no-meeting-found"); - } - - //daily.co calls have a 60 minute exit buffer when a user enters a call when it's not available it will trigger the modals - const now = new Date(); - const exitDate = new Date(now.getTime() - 60 * 60 * 1000); - - //find out if the meeting is in the past - const isPast = booking?.endTime <= exitDate; - if (isPast) { - return redirect(`/video/meeting-ended/${booking?.uid}`); - } - - const bookingObj = Object.assign({}, booking, { - startTime: booking.startTime.toString(), - endTime: booking.endTime.toString(), - }); - - const session = await getServerSession({ req: context.req }); - - // set meetingPassword to null for guests - if (session?.user.id !== bookingObj.user?.id) { - bookingObj.references.forEach((bookRef) => { - bookRef.meetingPassword = null; - }); - } - - return { - meetingUrl: bookingObj.references[0].meetingUrl ?? "", - ...(typeof bookingObj.references[0].meetingPassword === "string" && { - meetingPassword: bookingObj.references[0].meetingPassword, - }), - booking: { - ...bookingObj, - ...(bookingObj.description && { description: md.render(bookingObj.description) }), - }, - dehydratedState: ssr.dehydrate(), - }; -} - -export default WithLayout({ getData, Page: OldPage, getLayout: null })<"P">; +export default WithLayout({ getData, Page, getLayout: null })<"P">; diff --git a/apps/web/app/future/video/meeting-ended/[uid]/page.tsx b/apps/web/app/future/video/meeting-ended/[uid]/page.tsx index 9c86ca58bd..68c1744762 100644 --- a/apps/web/app/future/video/meeting-ended/[uid]/page.tsx +++ b/apps/web/app/future/video/meeting-ended/[uid]/page.tsx @@ -1,10 +1,9 @@ -import OldPage from "@pages/video/meeting-ended/[uid]"; +import Page from "@pages/video/meeting-ended/[uid]"; +import { withAppDirSsr } from "app/WithAppDirSsr"; import { _generateMetadata } from "app/_utils"; import { WithLayout } from "app/layoutHOC"; -import { type GetServerSidePropsContext } from "next"; -import { redirect } from "next/navigation"; -import prisma, { bookingMinimalSelect } from "@calcom/prisma"; +import { getServerSideProps } from "@lib/video/meeting-ended/[uid]/getServerSideProps"; export const generateMetadata = async () => await _generateMetadata( @@ -12,41 +11,6 @@ export const generateMetadata = async () => () => "Meeting Unavailable" ); -async function getData(context: Omit) { - const booking = await prisma.booking.findUnique({ - where: { - uid: typeof context?.params?.uid === "string" ? context.params.uid : "", - }, - select: { - ...bookingMinimalSelect, - uid: true, - user: { - select: { - credentials: true, - }, - }, - references: { - select: { - uid: true, - type: true, - meetingUrl: true, - }, - }, - }, - }); +const getData = withAppDirSsr(getServerSideProps); - if (!booking) { - return redirect("/video/no-meeting-found"); - } - - const bookingObj = Object.assign({}, booking, { - startTime: booking.startTime.toString(), - endTime: booking.endTime.toString(), - }); - - return { - booking: bookingObj, - }; -} - -export default WithLayout({ getData, Page: OldPage, getLayout: null })<"P">; +export default WithLayout({ getData, Page, getLayout: null })<"P">; diff --git a/apps/web/app/future/video/meeting-not-started/[uid]/page.tsx b/apps/web/app/future/video/meeting-not-started/[uid]/page.tsx index 3d71a3859d..ade26a9e85 100644 --- a/apps/web/app/future/video/meeting-not-started/[uid]/page.tsx +++ b/apps/web/app/future/video/meeting-not-started/[uid]/page.tsx @@ -1,15 +1,12 @@ -import OldPage from "@pages/video/meeting-not-started/[uid]"; -import { type Params } from "app/_types"; +import Page from "@pages/video/meeting-not-started/[uid]"; +import { withAppDirSsr } from "app/WithAppDirSsr"; +import type { PageProps } from "app/_types"; import { _generateMetadata } from "app/_utils"; import { WithLayout } from "app/layoutHOC"; -import { type GetServerSidePropsContext } from "next"; -import { redirect } from "next/navigation"; import prisma, { bookingMinimalSelect } from "@calcom/prisma"; -type PageProps = Readonly<{ - params: Params; -}>; +import { getServerSideProps } from "@lib/video/meeting-not-started/[uid]/getServerSideProps"; export const generateMetadata = async ({ params }: PageProps) => { const booking = await prisma.booking.findUnique({ @@ -25,26 +22,6 @@ export const generateMetadata = async ({ params }: PageProps) => { ); }; -async function getData(context: Omit) { - const booking = await prisma.booking.findUnique({ - where: { - uid: typeof context?.params?.uid === "string" ? context.params.uid : "", - }, - select: bookingMinimalSelect, - }); +const getData = withAppDirSsr(getServerSideProps); - if (!booking) { - return redirect("/video/no-meeting-found"); - } - - const bookingObj = Object.assign({}, booking, { - startTime: booking.startTime.toString(), - endTime: booking.endTime.toString(), - }); - - return { - booking: bookingObj, - }; -} - -export default WithLayout({ getData, Page: OldPage, getLayout: null })<"P">; +export default WithLayout({ getData, Page, getLayout: null })<"P">; diff --git a/apps/web/app/future/video/no-meeting-found/page.tsx b/apps/web/app/future/video/no-meeting-found/page.tsx index 63d728e96f..9f16119f8b 100644 --- a/apps/web/app/future/video/no-meeting-found/page.tsx +++ b/apps/web/app/future/video/no-meeting-found/page.tsx @@ -1,7 +1,7 @@ import LegacyPage from "@pages/video/no-meeting-found"; import { _generateMetadata } from "app/_utils"; import { WithLayout } from "app/layoutHOC"; -import { type GetServerSidePropsContext } from "next"; +import type { GetServerSidePropsContext } from "next"; import { ssrInit } from "@server/lib/ssr"; @@ -11,6 +11,7 @@ export const generateMetadata = async () => (t) => t("no_meeting_found") ); +// ssr was added by Intuita, legacy page does not have it const getData = async (context: GetServerSidePropsContext) => { const ssr = await ssrInit(context); diff --git a/apps/web/app/layoutHOC.tsx b/apps/web/app/layoutHOC.tsx index fab74cb2d5..40b517e14b 100644 --- a/apps/web/app/layoutHOC.tsx +++ b/apps/web/app/layoutHOC.tsx @@ -9,16 +9,14 @@ import PageWrapper from "@components/PageWrapperAppDir"; type WithLayoutParams> = { getLayout: ((page: React.ReactElement) => React.ReactNode) | null; Page?: (props: T) => React.ReactElement | null; - getData?: (arg: GetServerSidePropsContext) => Promise; + getData?: (arg: GetServerSidePropsContext) => Promise; }; export function WithLayout>({ getLayout, getData, Page }: WithLayoutParams) { return async

(p: P extends "P" ? PageProps : LayoutProps) => { const h = headers(); const nonce = h.get("x-nonce") ?? undefined; - const props = getData - ? await getData(buildLegacyCtx(h, cookies(), p.params) as unknown as GetServerSidePropsContext) - : ({} as T); + const props = getData ? (await getData(buildLegacyCtx(h, cookies(), p.params))) ?? ({} as T) : ({} as T); const children = "children" in p ? p.children : null; diff --git a/apps/web/lib/apps/[slug]/getStaticProps.tsx b/apps/web/lib/apps/[slug]/getStaticProps.tsx new file mode 100644 index 0000000000..9113ba9c4e --- /dev/null +++ b/apps/web/lib/apps/[slug]/getStaticProps.tsx @@ -0,0 +1,94 @@ +import fs from "fs"; +import matter from "gray-matter"; +import MarkdownIt from "markdown-it"; +import type { GetStaticPropsContext } from "next"; +import path from "path"; +import { z } from "zod"; + +import { getAppWithMetadata } from "@calcom/app-store/_appRegistry"; +import { getAppAssetFullPath } from "@calcom/app-store/getAppAssetFullPath"; +import { IS_PRODUCTION } from "@calcom/lib/constants"; +import prisma from "@calcom/prisma"; + +const md = new MarkdownIt("default", { html: true, breaks: true }); + +export const sourceSchema = z.object({ + content: z.string(), + data: z.object({ + description: z.string().optional(), + items: z + .array( + z.union([ + z.string(), + z.object({ + iframe: z.object({ src: z.string() }), + }), + ]) + ) + .optional(), + }), +}); + +export const getStaticProps = async (ctx: GetStaticPropsContext) => { + if (typeof ctx.params?.slug !== "string") return { notFound: true } as const; + + const appMeta = await getAppWithMetadata({ + slug: ctx.params?.slug, + }); + + const appFromDb = await prisma.app.findUnique({ + where: { slug: ctx.params.slug.toLowerCase() }, + }); + + const isAppAvailableInFileSystem = appMeta; + const isAppDisabled = isAppAvailableInFileSystem && (!appFromDb || !appFromDb.enabled); + + if (!IS_PRODUCTION && isAppDisabled) { + return { + props: { + isAppDisabled: true as const, + data: { + ...appMeta, + }, + }, + }; + } + + if (!appFromDb || !appMeta || isAppDisabled) return { notFound: true } as const; + + const isTemplate = appMeta.isTemplate; + const appDirname = path.join(isTemplate ? "templates" : "", appFromDb.dirName); + const README_PATH = path.join(process.cwd(), "..", "..", `packages/app-store/${appDirname}/DESCRIPTION.md`); + const postFilePath = path.join(README_PATH); + let source = ""; + + try { + source = fs.readFileSync(postFilePath).toString(); + source = source.replace(/{DESCRIPTION}/g, appMeta.description); + } catch (error) { + /* If the app doesn't have a README we fallback to the package description */ + console.log(`No DESCRIPTION.md provided for: ${appDirname}`); + source = appMeta.description; + } + + const result = matter(source); + const { content, data } = sourceSchema.parse({ content: result.content, data: result.data }); + if (data.items) { + data.items = data.items.map((item) => { + if (typeof item === "string") { + return getAppAssetFullPath(item, { + dirName: appMeta.dirName, + isTemplate: appMeta.isTemplate, + }); + } + return item; + }); + } + return { + props: { + isAppDisabled: false as const, + source: { content, data }, + data: appMeta, + }, + }; +}; diff --git a/apps/web/lib/apps/categories/[category]/getStaticProps.tsx b/apps/web/lib/apps/categories/[category]/getStaticProps.tsx new file mode 100644 index 0000000000..7afa898b1c --- /dev/null +++ b/apps/web/lib/apps/categories/[category]/getStaticProps.tsx @@ -0,0 +1,31 @@ +import type { GetStaticPropsContext } from "next"; + +import { getAppRegistry } from "@calcom/app-store/_appRegistry"; +import prisma from "@calcom/prisma"; +import type { AppCategories } from "@calcom/prisma/enums"; + +export const getStaticProps = async (context: GetStaticPropsContext) => { + const category = context.params?.category as AppCategories; + + const appQuery = await prisma.app.findMany({ + where: { + categories: { + has: category, + }, + }, + select: { + slug: true, + }, + }); + + const dbAppsSlugs = appQuery.map((category) => category.slug); + + const appStore = await getAppRegistry(); + + const apps = appStore.filter((app) => dbAppsSlugs.includes(app.slug)); + return { + props: { + apps, + }, + }; +}; diff --git a/apps/web/lib/apps/categories/getServerSideProps.tsx b/apps/web/lib/apps/categories/getServerSideProps.tsx new file mode 100644 index 0000000000..80f91be001 --- /dev/null +++ b/apps/web/lib/apps/categories/getServerSideProps.tsx @@ -0,0 +1,35 @@ +import type { GetServerSidePropsContext } from "next"; + +import { getAppRegistry, getAppRegistryWithCredentials } from "@calcom/app-store/_appRegistry"; +import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; + +import { ssrInit } from "@server/lib/ssr"; + +export const getServerSideProps = async (context: GetServerSidePropsContext) => { + const { req, res } = context; + + const ssr = await ssrInit(context); + + const session = await getServerSession({ req, res }); + + let appStore; + if (session?.user?.id) { + appStore = await getAppRegistryWithCredentials(session.user.id); + } else { + appStore = await getAppRegistry(); + } + + const categories = appStore.reduce((c, app) => { + for (const category of app.categories) { + c[category] = c[category] ? c[category] + 1 : 1; + } + return c; + }, {} as Record); + + return { + props: { + categories: Object.entries(categories).map(([name, count]) => ({ name, count })), + trpcState: ssr.dehydrate(), + }, + }; +}; diff --git a/apps/web/lib/apps/getServerSideProps.tsx b/apps/web/lib/apps/getServerSideProps.tsx new file mode 100644 index 0000000000..c0a3e2acc0 --- /dev/null +++ b/apps/web/lib/apps/getServerSideProps.tsx @@ -0,0 +1,52 @@ +import type { GetServerSidePropsContext } from "next"; + +import { getAppRegistry, getAppRegistryWithCredentials } from "@calcom/app-store/_appRegistry"; +import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; +import getUserAdminTeams from "@calcom/features/ee/teams/lib/getUserAdminTeams"; +import type { UserAdminTeams } from "@calcom/features/ee/teams/lib/getUserAdminTeams"; +import type { AppCategories } from "@calcom/prisma/enums"; + +import { ssrInit } from "@server/lib/ssr"; + +export const getServerSideProps = async (context: GetServerSidePropsContext) => { + const { req, res } = context; + + const ssr = await ssrInit(context); + + const session = await getServerSession({ req, res }); + + let appStore, userAdminTeams: UserAdminTeams; + if (session?.user?.id) { + userAdminTeams = await getUserAdminTeams({ userId: session.user.id, getUserInfo: true }); + appStore = await getAppRegistryWithCredentials(session.user.id, userAdminTeams); + } else { + appStore = await getAppRegistry(); + userAdminTeams = []; + } + + const categoryQuery = appStore.map(({ categories }) => ({ + categories: categories || [], + })); + const categories = categoryQuery.reduce((c, app) => { + for (const category of app.categories) { + c[category] = c[category] ? c[category] + 1 : 1; + } + return c; + }, {} as Record); + + return { + props: { + categories: Object.entries(categories) + .map(([name, count]): { name: AppCategories; count: number } => ({ + name: name as AppCategories, + count, + })) + .sort(function (a, b) { + return b.count - a.count; + }), + appStore, + userAdminTeams, + trpcState: ssr.dehydrate(), + }, + }; +}; diff --git a/apps/web/lib/apps/installed/[category]/getServerSideProps.tsx b/apps/web/lib/apps/installed/[category]/getServerSideProps.tsx new file mode 100644 index 0000000000..9be2a03ab1 --- /dev/null +++ b/apps/web/lib/apps/installed/[category]/getServerSideProps.tsx @@ -0,0 +1,43 @@ +import type { GetServerSidePropsContext } from "next"; +import { z } from "zod"; + +import { AppCategories } from "@calcom/prisma/enums"; + +export type querySchemaType = z.infer; + +export const querySchema = z.object({ + category: z.nativeEnum(AppCategories), +}); + +export async function getServerSideProps(ctx: GetServerSidePropsContext) { + // get return-to cookie and redirect if needed + const { cookies } = ctx.req; + + const returnTo = cookies["return-to"]; + + if (cookies && returnTo) { + ctx.res.setHeader("Set-Cookie", "return-to=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"); + const redirect = { + redirect: { + destination: `${returnTo}`, + permanent: false, + }, + } as const; + + return redirect; + } + + const params = querySchema.safeParse(ctx.params); + + if (!params.success) { + const notFound = { notFound: true } as const; + + return notFound; + } + + return { + props: { + category: params.data.category, + }, + }; +} diff --git a/apps/web/lib/apps/installed/getServerSideProps.tsx b/apps/web/lib/apps/installed/getServerSideProps.tsx new file mode 100644 index 0000000000..a43490aea5 --- /dev/null +++ b/apps/web/lib/apps/installed/getServerSideProps.tsx @@ -0,0 +1,3 @@ +export async function getServerSideProps() { + return { redirect: { permanent: false, destination: "/apps/installed/calendar" } }; +} diff --git a/apps/web/lib/buildLegacyCtx.tsx b/apps/web/lib/buildLegacyCtx.tsx index 2dfbf3ff2f..4b78ba8cdc 100644 --- a/apps/web/lib/buildLegacyCtx.tsx +++ b/apps/web/lib/buildLegacyCtx.tsx @@ -1,4 +1,5 @@ import { type Params } from "app/_types"; +import type { GetServerSidePropsContext } from "next"; import { type ReadonlyHeaders } from "next/dist/server/web/spec-extension/adapters/headers"; import { type ReadonlyRequestCookies } from "next/dist/server/web/spec-extension/adapters/request-cookies"; @@ -19,5 +20,5 @@ export const buildLegacyCtx = (headers: ReadonlyHeaders, cookies: ReadonlyReques query: getQuery(headers.get("x-url") ?? "", params), params, req: { headers, cookies }, - }; + } as unknown as GetServerSidePropsContext; }; diff --git a/apps/web/lib/d/[link]/[slug]/getServerSideProps.tsx b/apps/web/lib/d/[link]/[slug]/getServerSideProps.tsx new file mode 100644 index 0000000000..06af51694b --- /dev/null +++ b/apps/web/lib/d/[link]/[slug]/getServerSideProps.tsx @@ -0,0 +1,123 @@ +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 { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains"; +import slugify from "@calcom/lib/slugify"; +import prisma from "@calcom/prisma"; + +import type { inferSSRProps } from "@lib/types/inferSSRProps"; +import type { EmbedProps } from "@lib/withEmbedSsr"; + +export type PageProps = inferSSRProps & EmbedProps; + +async function getUserPageProps(context: GetServerSidePropsContext) { + const session = await getServerSession(context); + const { link, slug } = paramsSchema.parse(context.params); + const { rescheduleUid, duration: queryDuration } = context.query; + const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(context.req); + const org = isValidOrgDomain ? currentOrgDomain : null; + + const { ssrInit } = await import("@server/lib/ssr"); + const ssr = await ssrInit(context); + + const hashedLink = await prisma.hashedLink.findUnique({ + where: { + link, + }, + select: { + eventTypeId: true, + eventType: { + select: { + users: { + select: { + username: true, + }, + }, + team: { + select: { + id: true, + }, + }, + }, + }, + }, + }); + + const username = hashedLink?.eventType.users[0]?.username; + + if (!hashedLink || !username) { + return { + notFound: true, + }; + } + + const user = await prisma.user.findFirst({ + where: { + username, + organization: isValidOrgDomain + ? { + slug: currentOrgDomain, + } + : null, + }, + select: { + away: true, + hideBranding: true, + }, + }); + + if (!user) { + return { + notFound: true, + }; + } + + let booking: GetBookingType | null = null; + if (rescheduleUid) { + booking = await getBookingForReschedule(`${rescheduleUid}`, session?.user?.id); + } + + const isTeamEvent = !!hashedLink.eventType?.team?.id; + + // 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, eventSlug: slug, isTeamEvent, org }); + + if (!eventData) { + return { + notFound: true, + }; + } + + return { + props: { + entity: eventData.entity, + duration: getMultipleDurationValue( + eventData.metadata?.multipleDuration, + queryDuration, + eventData.length + ), + booking, + away: user?.away, + user: username, + slug, + trpcState: ssr.dehydrate(), + isBrandingHidden: user?.hideBranding, + // Sending the team event from the server, because this template file + // is reused for both team and user events. + isTeamEvent, + hashedLink: link, + }, + }; +} + +const paramsSchema = z.object({ link: z.string(), slug: z.string().transform((s) => slugify(s)) }); + +// Booker page fetches a tiny bit of data server side, to determine early +// whether the page should show an away state or dynamic booking not allowed. +export const getServerSideProps = async (context: GetServerSidePropsContext) => { + return await getUserPageProps(context); +}; diff --git a/apps/web/lib/event-types/[type]/getServerSideProps.tsx b/apps/web/lib/event-types/[type]/getServerSideProps.tsx new file mode 100644 index 0000000000..54e527306f --- /dev/null +++ b/apps/web/lib/event-types/[type]/getServerSideProps.tsx @@ -0,0 +1,42 @@ +import type { GetServerSidePropsContext } from "next"; + +import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; + +import { asStringOrThrow } from "@lib/asStringOrNull"; +import type { inferSSRProps } from "@lib/types/inferSSRProps"; + +import { ssrInit } from "@server/lib/ssr"; + +export type PageProps = inferSSRProps; + +export const getServerSideProps = async (context: GetServerSidePropsContext) => { + const { req, res, query } = context; + + const session = await getServerSession({ req, res }); + + const typeParam = parseInt(asStringOrThrow(query.type)); + const ssr = await ssrInit(context); + + if (Number.isNaN(typeParam)) { + return { + notFound: true, + }; + } + + if (!session?.user?.id) { + return { + redirect: { + permanent: false, + destination: "/auth/login", + }, + }; + } + + await ssr.viewer.eventTypes.get.prefetch({ id: typeParam }); + return { + props: { + type: typeParam, + trpcState: ssr.dehydrate(), + }, + }; +}; diff --git a/apps/web/lib/getting-started/[[...step]]/getServerSideProps.tsx b/apps/web/lib/getting-started/[[...step]]/getServerSideProps.tsx new file mode 100644 index 0000000000..e6fa841c67 --- /dev/null +++ b/apps/web/lib/getting-started/[[...step]]/getServerSideProps.tsx @@ -0,0 +1,59 @@ +import type { GetServerSidePropsContext } from "next"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; + +import { getLocale } from "@calcom/features/auth/lib/getLocale"; +import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; +import prisma from "@calcom/prisma"; + +import { ssrInit } from "@server/lib/ssr"; + +export const getServerSideProps = async (context: GetServerSidePropsContext) => { + const { req, res } = context; + + const session = await getServerSession({ req, res }); + + if (!session?.user?.id) { + return { redirect: { permanent: false, destination: "/auth/login" } }; + } + + const ssr = await ssrInit(context); + + await ssr.viewer.me.prefetch(); + + const user = await prisma.user.findUnique({ + where: { + id: session.user.id, + }, + select: { + completedOnboarding: true, + teams: { + select: { + accepted: true, + team: { + select: { + id: true, + name: true, + logo: true, + }, + }, + }, + }, + }, + }); + + if (!user) { + throw new Error("User from session not found"); + } + + if (user.completedOnboarding) { + return { redirect: { permanent: false, destination: "/event-types" } }; + } + const locale = await getLocale(context.req); + return { + props: { + ...(await serverSideTranslations(locale, ["common"])), + trpcState: ssr.dehydrate(), + hasPendingInvites: user.teams.find((team) => team.accepted === false) ?? false, + }, + }; +}; diff --git a/apps/web/lib/teams/getServerSideProps.tsx b/apps/web/lib/teams/getServerSideProps.tsx new file mode 100644 index 0000000000..ae63a5f811 --- /dev/null +++ b/apps/web/lib/teams/getServerSideProps.tsx @@ -0,0 +1,25 @@ +import type { GetServerSidePropsContext } from "next"; + +import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; + +import { ssrInit } from "@server/lib/ssr"; + +export const getServerSideProps = async (context: GetServerSidePropsContext) => { + const ssr = await ssrInit(context); + await ssr.viewer.me.prefetch(); + const session = await getServerSession({ req: context.req, res: context.res }); + const token = Array.isArray(context.query?.token) ? context.query.token[0] : context.query?.token; + + const callbackUrl = token ? `/teams?token=${encodeURIComponent(token)}` : null; + + if (!session) { + return { + redirect: { + destination: callbackUrl ? `/auth/login?callbackUrl=${callbackUrl}` : "/auth/login", + permanent: false, + }, + }; + } + + return { props: { trpcState: ssr.dehydrate() } }; +}; diff --git a/apps/web/lib/video/[uid]/getServerSideProps.tsx b/apps/web/lib/video/[uid]/getServerSideProps.tsx new file mode 100644 index 0000000000..be5cfe1af0 --- /dev/null +++ b/apps/web/lib/video/[uid]/getServerSideProps.tsx @@ -0,0 +1,110 @@ +import MarkdownIt from "markdown-it"; +import type { GetServerSidePropsContext } from "next"; + +import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; +import prisma, { bookingMinimalSelect } from "@calcom/prisma"; + +import { ssrInit } from "@server/lib/ssr"; + +const md = new MarkdownIt("default", { html: true, breaks: true, linkify: true }); + +export async function getServerSideProps(context: GetServerSidePropsContext) { + const { req, res } = context; + + const ssr = await ssrInit(context); + + const booking = await prisma.booking.findUnique({ + where: { + uid: context.query.uid as string, + }, + select: { + ...bookingMinimalSelect, + uid: true, + description: true, + isRecorded: true, + user: { + select: { + id: true, + timeZone: true, + name: true, + email: true, + organization: { + select: { + calVideoLogo: true, + }, + }, + }, + }, + references: { + select: { + uid: true, + type: true, + meetingUrl: true, + meetingPassword: true, + }, + where: { + type: "daily_video", + }, + }, + }, + }); + + if (!booking || booking.references.length === 0 || !booking.references[0].meetingUrl) { + const redirect = { + redirect: { + destination: "/video/no-meeting-found", + permanent: false, + }, + } as const; + + return redirect; + } + + //daily.co calls have a 60 minute exit buffer when a user enters a call when it's not available it will trigger the modals + const now = new Date(); + const exitDate = new Date(now.getTime() - 60 * 60 * 1000); + + //find out if the meeting is in the past + const isPast = booking?.endTime <= exitDate; + if (isPast) { + const redirect = { + redirect: { + destination: `/video/meeting-ended/${booking?.uid}`, + permanent: false, + }, + } as const; + + return redirect; + } + + const bookingObj = Object.assign({}, booking, { + startTime: booking.startTime.toString(), + endTime: booking.endTime.toString(), + }); + + const session = await getServerSession({ req, res }); + + // set meetingPassword to null for guests + if (session?.user.id !== bookingObj.user?.id) { + bookingObj.references.forEach((bookRef) => { + bookRef.meetingPassword = null; + }); + } + + const videoReferences = bookingObj.references.filter((reference) => reference.type.includes("_video")); + const latestVideoReference = videoReferences[videoReferences.length - 1]; + + return { + props: { + meetingUrl: latestVideoReference.meetingUrl ?? "", + ...(typeof latestVideoReference.meetingPassword === "string" && { + meetingPassword: latestVideoReference.meetingPassword, + }), + booking: { + ...bookingObj, + ...(bookingObj.description && { description: md.render(bookingObj.description) }), + }, + trpcState: ssr.dehydrate(), + }, + }; +} diff --git a/apps/web/lib/video/meeting-ended/[uid]/getServerSideProps.tsx b/apps/web/lib/video/meeting-ended/[uid]/getServerSideProps.tsx new file mode 100644 index 0000000000..2995d36bb7 --- /dev/null +++ b/apps/web/lib/video/meeting-ended/[uid]/getServerSideProps.tsx @@ -0,0 +1,49 @@ +import type { GetServerSidePropsContext } from "next"; + +import prisma, { bookingMinimalSelect } from "@calcom/prisma"; + +export async function getServerSideProps(context: GetServerSidePropsContext) { + const booking = await prisma.booking.findUnique({ + where: { + uid: context.query.uid as string, + }, + select: { + ...bookingMinimalSelect, + uid: true, + user: { + select: { + credentials: true, + }, + }, + references: { + select: { + uid: true, + type: true, + meetingUrl: true, + }, + }, + }, + }); + + if (!booking) { + const redirect = { + redirect: { + destination: "/video/no-meeting-found", + permanent: false, + }, + } as const; + + return redirect; + } + + const bookingObj = Object.assign({}, booking, { + startTime: booking.startTime.toString(), + endTime: booking.endTime.toString(), + }); + + return { + props: { + booking: bookingObj, + }, + }; +} diff --git a/apps/web/lib/video/meeting-not-started/[uid]/getServerSideProps.tsx b/apps/web/lib/video/meeting-not-started/[uid]/getServerSideProps.tsx new file mode 100644 index 0000000000..ac2ba3d9cc --- /dev/null +++ b/apps/web/lib/video/meeting-not-started/[uid]/getServerSideProps.tsx @@ -0,0 +1,35 @@ +import type { GetServerSidePropsContext } from "next"; + +import prisma, { bookingMinimalSelect } from "@calcom/prisma"; + +// change the type +export async function getServerSideProps(context: GetServerSidePropsContext) { + const booking = await prisma.booking.findUnique({ + where: { + uid: context.query.uid as string, + }, + select: bookingMinimalSelect, + }); + + if (!booking) { + const redirect = { + redirect: { + destination: "/video/no-meeting-found", + permanent: false, + }, + } as const; + + return redirect; + } + + const bookingObj = Object.assign({}, booking, { + startTime: booking.startTime.toString(), + endTime: booking.endTime.toString(), + }); + + return { + props: { + booking: bookingObj, + }, + }; +} diff --git a/apps/web/pages/apps/[slug]/index.tsx b/apps/web/pages/apps/[slug]/index.tsx index 27bd8dbdfb..8c3cbe4125 100644 --- a/apps/web/pages/apps/[slug]/index.tsx +++ b/apps/web/pages/apps/[slug]/index.tsx @@ -1,19 +1,14 @@ "use client"; import { Prisma } from "@prisma/client"; -import fs from "fs"; -import matter from "gray-matter"; import MarkdownIt from "markdown-it"; -import type { GetStaticPaths, GetStaticPropsContext } from "next"; +import type { GetStaticPaths } from "next"; import Link from "next/link"; -import path from "path"; -import { z } from "zod"; -import { getAppWithMetadata } from "@calcom/app-store/_appRegistry"; -import { getAppAssetFullPath } from "@calcom/app-store/getAppAssetFullPath"; import { IS_PRODUCTION } from "@calcom/lib/constants"; import prisma from "@calcom/prisma"; +import { getStaticProps } from "@lib/apps/[slug]/getStaticProps"; import type { inferSSRProps } from "@lib/types/inferSSRProps"; import PageWrapper from "@components/PageWrapper"; @@ -21,23 +16,6 @@ import App from "@components/apps/App"; const md = new MarkdownIt("default", { html: true, breaks: true }); -const sourceSchema = z.object({ - content: z.string(), - data: z.object({ - description: z.string().optional(), - items: z - .array( - z.union([ - z.string(), - z.object({ - iframe: z.object({ src: z.string() }), - }), - ]) - ) - .optional(), - }), -}); - function SingleAppPage(props: inferSSRProps) { // If it's not production environment, it would be a better idea to inform that the App is disabled. if (props.isAppDisabled) { @@ -113,69 +91,7 @@ export const getStaticPaths: GetStaticPaths<{ slug: string }> = async () => { }; }; -export const getStaticProps = async (ctx: GetStaticPropsContext) => { - if (typeof ctx.params?.slug !== "string") return { notFound: true }; - - const appMeta = await getAppWithMetadata({ - slug: ctx.params?.slug, - }); - - const appFromDb = await prisma.app.findUnique({ - where: { slug: ctx.params.slug.toLowerCase() }, - }); - - const isAppAvailableInFileSystem = appMeta; - const isAppDisabled = isAppAvailableInFileSystem && (!appFromDb || !appFromDb.enabled); - - if (!IS_PRODUCTION && isAppDisabled) { - return { - props: { - isAppDisabled: true as const, - data: { - ...appMeta, - }, - }, - }; - } - - if (!appFromDb || !appMeta || isAppDisabled) return { notFound: true }; - - const isTemplate = appMeta.isTemplate; - const appDirname = path.join(isTemplate ? "templates" : "", appFromDb.dirName); - const README_PATH = path.join(process.cwd(), "..", "..", `packages/app-store/${appDirname}/DESCRIPTION.md`); - const postFilePath = path.join(README_PATH); - let source = ""; - - try { - source = fs.readFileSync(postFilePath).toString(); - source = source.replace(/{DESCRIPTION}/g, appMeta.description); - } catch (error) { - /* If the app doesn't have a README we fallback to the package description */ - console.log(`No DESCRIPTION.md provided for: ${appDirname}`); - source = appMeta.description; - } - - const result = matter(source); - const { content, data } = sourceSchema.parse({ content: result.content, data: result.data }); - if (data.items) { - data.items = data.items.map((item) => { - if (typeof item === "string") { - return getAppAssetFullPath(item, { - dirName: appMeta.dirName, - isTemplate: appMeta.isTemplate, - }); - } - return item; - }); - } - return { - props: { - isAppDisabled: false as const, - source: { content, data }, - data: appMeta, - }, - }; -}; +export { getStaticProps }; SingleAppPage.PageWrapper = PageWrapper; diff --git a/apps/web/pages/apps/categories/[category].tsx b/apps/web/pages/apps/categories/[category].tsx index 0cad97bfa1..7cbbd49e25 100644 --- a/apps/web/pages/apps/categories/[category].tsx +++ b/apps/web/pages/apps/categories/[category].tsx @@ -1,10 +1,9 @@ "use client"; import { Prisma } from "@prisma/client"; -import type { GetStaticPropsContext, InferGetStaticPropsType } from "next"; +import type { InferGetStaticPropsType } from "next"; import Link from "next/link"; -import { getAppRegistry } from "@calcom/app-store/_appRegistry"; import Shell from "@calcom/features/shell/Shell"; import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; import { useLocale } from "@calcom/lib/hooks/useLocale"; @@ -12,6 +11,8 @@ import prisma from "@calcom/prisma"; import { AppCategories } from "@calcom/prisma/enums"; import { AppCard, SkeletonText } from "@calcom/ui"; +import { getStaticProps } from "@lib/apps/categories/[category]/getStaticProps"; + import PageWrapper from "@components/PageWrapper"; export default function Apps({ apps }: InferGetStaticPropsType) { @@ -79,28 +80,4 @@ export const getStaticPaths = async () => { }; }; -export const getStaticProps = async (context: GetStaticPropsContext) => { - const category = context.params?.category as AppCategories; - - const appQuery = await prisma.app.findMany({ - where: { - categories: { - has: category, - }, - }, - select: { - slug: true, - }, - }); - - const dbAppsSlugs = appQuery.map((category) => category.slug); - - const appStore = await getAppRegistry(); - - const apps = appStore.filter((app) => dbAppsSlugs.includes(app.slug)); - return { - props: { - apps, - }, - }; -}; +export { getStaticProps }; diff --git a/apps/web/pages/apps/categories/index.tsx b/apps/web/pages/apps/categories/index.tsx index 1012640fc8..3db426927c 100644 --- a/apps/web/pages/apps/categories/index.tsx +++ b/apps/web/pages/apps/categories/index.tsx @@ -1,19 +1,16 @@ "use client"; -import type { GetServerSidePropsContext } from "next"; import Link from "next/link"; -import { getAppRegistry, getAppRegistryWithCredentials } from "@calcom/app-store/_appRegistry"; -import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; import Shell from "@calcom/features/shell/Shell"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import type { inferSSRProps } from "@calcom/types/inferSSRProps"; import { SkeletonText } from "@calcom/ui"; import { ArrowLeft, ArrowRight } from "@calcom/ui/components/icon"; -import PageWrapper from "@components/PageWrapper"; +import { getServerSideProps } from "@lib/apps/categories/getServerSideProps"; -import { ssrInit } from "@server/lib/ssr"; +import PageWrapper from "@components/PageWrapper"; export default function Apps({ categories }: Omit, "trpcState">) { const { t, isLocaleReady } = useLocale(); @@ -53,31 +50,4 @@ export default function Apps({ categories }: Omit { - const { req, res } = context; - - const ssr = await ssrInit(context); - - const session = await getServerSession({ req, res }); - - let appStore; - if (session?.user?.id) { - appStore = await getAppRegistryWithCredentials(session.user.id); - } else { - appStore = await getAppRegistry(); - } - - const categories = appStore.reduce((c, app) => { - for (const category of app.categories) { - c[category] = c[category] ? c[category] + 1 : 1; - } - return c; - }, {} as Record); - - return { - props: { - categories: Object.entries(categories).map(([name, count]) => ({ name, count })), - trpcState: ssr.dehydrate(), - }, - }; -}; +export { getServerSideProps }; diff --git a/apps/web/pages/apps/index.tsx b/apps/web/pages/apps/index.tsx index 8315bdc4e3..642f98d262 100644 --- a/apps/web/pages/apps/index.tsx +++ b/apps/web/pages/apps/index.tsx @@ -1,17 +1,11 @@ "use client"; -import type { GetServerSidePropsContext } from "next"; import type { ChangeEventHandler } from "react"; import { useState } from "react"; -import { getAppRegistry, getAppRegistryWithCredentials } from "@calcom/app-store/_appRegistry"; import { getLayout } from "@calcom/features/MainLayout"; -import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; -import getUserAdminTeams from "@calcom/features/ee/teams/lib/getUserAdminTeams"; -import type { UserAdminTeams } from "@calcom/features/ee/teams/lib/getUserAdminTeams"; import { classNames } from "@calcom/lib"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import type { AppCategories } from "@calcom/prisma/enums"; import type { inferSSRProps } from "@calcom/types/inferSSRProps"; import type { HorizontalTabItemProps } from "@calcom/ui"; import { @@ -24,11 +18,11 @@ import { } from "@calcom/ui"; import { Search } from "@calcom/ui/components/icon"; +import { getServerSideProps } from "@lib/apps/getServerSideProps"; + import PageWrapper from "@components/PageWrapper"; import AppsLayout from "@components/apps/layouts/AppsLayout"; -import { ssrInit } from "@server/lib/ssr"; - const tabs: HorizontalTabItemProps[] = [ { name: "app_store", @@ -106,48 +100,7 @@ export default function Apps({ ); } +export { getServerSideProps }; + Apps.PageWrapper = PageWrapper; Apps.getLayout = getLayout; - -export const getServerSideProps = async (context: GetServerSidePropsContext) => { - const { req, res } = context; - - const ssr = await ssrInit(context); - - const session = await getServerSession({ req, res }); - - let appStore, userAdminTeams: UserAdminTeams; - if (session?.user?.id) { - userAdminTeams = await getUserAdminTeams({ userId: session.user.id, getUserInfo: true }); - appStore = await getAppRegistryWithCredentials(session.user.id, userAdminTeams); - } else { - appStore = await getAppRegistry(); - userAdminTeams = []; - } - - const categoryQuery = appStore.map(({ categories }) => ({ - categories: categories || [], - })); - const categories = categoryQuery.reduce((c, app) => { - for (const category of app.categories) { - c[category] = c[category] ? c[category] + 1 : 1; - } - return c; - }, {} as Record); - - return { - props: { - categories: Object.entries(categories) - .map(([name, count]): { name: AppCategories; count: number } => ({ - name: name as AppCategories, - count, - })) - .sort(function (a, b) { - return b.count - a.count; - }), - appStore, - userAdminTeams, - trpcState: ssr.dehydrate(), - }, - }; -}; diff --git a/apps/web/pages/apps/installed/[category].tsx b/apps/web/pages/apps/installed/[category].tsx index 5a207ecc13..6f5159c1f8 100644 --- a/apps/web/pages/apps/installed/[category].tsx +++ b/apps/web/pages/apps/installed/[category].tsx @@ -1,14 +1,12 @@ "use client"; import { useReducer } from "react"; -import { z } from "zod"; import DisconnectIntegrationModal from "@calcom/features/apps/components/DisconnectIntegrationModal"; import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { AppCategories } from "@calcom/prisma/enums"; import { trpc } from "@calcom/trpc/react"; -import type { AppGetServerSidePropsContext } from "@calcom/types/AppGetServerSideProps"; import { Button, EmptyScreen, AppSkeletonLoader as SkeletonLoader, ShellSubHeading } from "@calcom/ui"; import type { LucideIcon } from "@calcom/ui/components/icon"; import { @@ -24,6 +22,8 @@ import { } from "@calcom/ui/components/icon"; import { QueryCell } from "@lib/QueryCell"; +import type { querySchemaType } from "@lib/apps/installed/[category]/getServerSideProps"; +import { getServerSideProps } from "@lib/apps/installed/[category]/getServerSideProps"; import PageWrapper from "@components/PageWrapper"; import { AppList } from "@components/apps/AppList"; @@ -111,12 +111,6 @@ const IntegrationsContainer = ({ ); }; -const querySchema = z.object({ - category: z.nativeEnum(AppCategories), -}); - -type querySchemaType = z.infer; - type ModalState = { isOpen: boolean; credentialId: null | number; @@ -173,31 +167,6 @@ export default function InstalledApps() { ); } -// Server side rendering -export async function getServerSideProps(ctx: AppGetServerSidePropsContext) { - // get return-to cookie and redirect if needed - const { cookies } = ctx.req; - if (cookies && cookies["return-to"]) { - const returnTo = cookies["return-to"]; - if (returnTo) { - ctx.res.setHeader("Set-Cookie", "return-to=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"); - return { - redirect: { - destination: `${returnTo}`, - permanent: false, - }, - }; - } - } - const params = querySchema.safeParse(ctx.params); - - if (!params.success) return { notFound: true }; - - return { - props: { - category: params.data.category, - }, - }; -} +export { getServerSideProps }; InstalledApps.PageWrapper = PageWrapper; diff --git a/apps/web/pages/apps/installed/index.tsx b/apps/web/pages/apps/installed/index.tsx index a73184d48a..02786d55a8 100644 --- a/apps/web/pages/apps/installed/index.tsx +++ b/apps/web/pages/apps/installed/index.tsx @@ -1,9 +1,7 @@ +export { getServerSideProps } from "@lib/apps/installed/getServerSideProps"; + function RedirectPage() { return; } -export async function getServerSideProps() { - return { redirect: { permanent: false, destination: "/apps/installed/calendar" } }; -} - export default RedirectPage; diff --git a/apps/web/pages/d/[link]/[slug].tsx b/apps/web/pages/d/[link]/[slug].tsx index 58cae2a8af..4ca71db054 100644 --- a/apps/web/pages/d/[link]/[slug].tsx +++ b/apps/web/pages/d/[link]/[slug].tsx @@ -1,23 +1,11 @@ -import type { GetServerSidePropsContext } from "next"; -import { z } from "zod"; - 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 { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains"; -import slugify from "@calcom/lib/slugify"; -import prisma from "@calcom/prisma"; -import type { inferSSRProps } from "@lib/types/inferSSRProps"; -import type { EmbedProps } from "@lib/withEmbedSsr"; +import { getServerSideProps, type PageProps } from "@lib/d/[link]/[slug]/getServerSideProps"; import PageWrapper from "@components/PageWrapper"; -type PageProps = inferSSRProps & EmbedProps; - export default function Type({ slug, isEmbed, @@ -54,114 +42,7 @@ export default function Type({ ); } +export { getServerSideProps }; + Type.PageWrapper = PageWrapper; Type.isBookingPage = true; - -async function getUserPageProps(context: GetServerSidePropsContext) { - const session = await getServerSession(context); - const { link, slug } = paramsSchema.parse(context.params); - const { rescheduleUid, duration: queryDuration } = context.query; - const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(context.req); - const org = isValidOrgDomain ? currentOrgDomain : null; - - const { ssrInit } = await import("@server/lib/ssr"); - const ssr = await ssrInit(context); - - const hashedLink = await prisma.hashedLink.findUnique({ - where: { - link, - }, - select: { - eventTypeId: true, - eventType: { - select: { - users: { - select: { - username: true, - }, - }, - team: { - select: { - id: true, - }, - }, - }, - }, - }, - }); - - const username = hashedLink?.eventType.users[0]?.username; - - if (!hashedLink || !username) { - return { - notFound: true, - }; - } - - const user = await prisma.user.findFirst({ - where: { - username, - organization: isValidOrgDomain - ? { - slug: currentOrgDomain, - } - : null, - }, - select: { - away: true, - hideBranding: true, - }, - }); - - if (!user) { - return { - notFound: true, - }; - } - - let booking: GetBookingType | null = null; - if (rescheduleUid) { - booking = await getBookingForReschedule(`${rescheduleUid}`, session?.user?.id); - } - - const isTeamEvent = !!hashedLink.eventType?.team?.id; - - // 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, eventSlug: slug, isTeamEvent, org }); - - if (!eventData) { - return { - notFound: true, - }; - } - - return { - props: { - entity: eventData.entity, - duration: getMultipleDurationValue( - eventData.metadata?.multipleDuration, - queryDuration, - eventData.length - ), - booking, - away: user?.away, - user: username, - slug, - trpcState: ssr.dehydrate(), - isBrandingHidden: user?.hideBranding, - // Sending the team event from the server, because this template file - // is reused for both team and user events. - isTeamEvent, - hashedLink: link, - }, - }; -} - -const paramsSchema = z.object({ link: z.string(), slug: z.string().transform((s) => slugify(s)) }); - -// Booker page fetches a tiny bit of data server side, to determine early -// whether the page should show an away state or dynamic booking not allowed. -export const getServerSideProps = async (context: GetServerSidePropsContext) => { - return await getUserPageProps(context); -}; diff --git a/apps/web/pages/event-types/[type]/index.tsx b/apps/web/pages/event-types/[type]/index.tsx index cdad0b5c1c..4125402d8a 100644 --- a/apps/web/pages/event-types/[type]/index.tsx +++ b/apps/web/pages/event-types/[type]/index.tsx @@ -2,7 +2,6 @@ import { useAutoAnimate } from "@formkit/auto-animate/react"; import { zodResolver } from "@hookform/resolvers/zod"; import { isValidPhoneNumber } from "libphonenumber-js"; -import type { GetServerSidePropsContext } from "next"; import dynamic from "next/dynamic"; import { useEffect, useMemo, useState } from "react"; import { useForm } from "react-hook-form"; @@ -12,7 +11,6 @@ import checkForMultiplePaymentApps from "@calcom/app-store/_utils/payments/check import { getEventLocationType } from "@calcom/app-store/locations"; import { validateCustomEventName } from "@calcom/core/event"; import type { EventLocationType } from "@calcom/core/location"; -import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; import type { ChildrenEventType } from "@calcom/features/eventtypes/components/ChildrenEventTypeSelect"; import { validateIntervalLimitOrder } from "@calcom/lib"; import { CAL_URL } from "@calcom/lib/constants"; @@ -34,15 +32,12 @@ import { trpc } from "@calcom/trpc/react"; import type { IntervalLimit, RecurringEvent } from "@calcom/types/Calendar"; import { Form, showToast } from "@calcom/ui"; -import { asStringOrThrow } from "@lib/asStringOrNull"; -import type { inferSSRProps } from "@lib/types/inferSSRProps"; +import { getServerSideProps, type PageProps } from "@lib/event-types/[type]/getServerSideProps"; import PageWrapper from "@components/PageWrapper"; import type { AvailabilityOption } from "@components/eventtype/EventAvailabilityTab"; import { EventTypeSingleLayout } from "@components/eventtype/EventTypeSingleLayout"; -import { ssrInit } from "@server/lib/ssr"; - // These can't really be moved into calcom/ui due to the fact they use infered getserverside props typings; const EventSetupTab = dynamic(() => import("@components/eventtype/EventSetupTab").then((mod) => mod.EventSetupTab) @@ -669,45 +664,14 @@ const EventTypePage = (props: EventTypeSetupProps) => { ); }; -const EventTypePageWrapper = (props: inferSSRProps) => { +const EventTypePageWrapper = (props: PageProps) => { const { data } = trpc.viewer.eventTypes.get.useQuery({ id: props.type }); if (!data) return null; return ; }; -export const getServerSideProps = async (context: GetServerSidePropsContext) => { - const { req, res, query } = context; - - const session = await getServerSession({ req, res }); - - const typeParam = parseInt(asStringOrThrow(query.type)); - const ssr = await ssrInit(context); - - if (Number.isNaN(typeParam)) { - return { - notFound: true, - }; - } - - if (!session?.user?.id) { - return { - redirect: { - permanent: false, - destination: "/auth/login", - }, - }; - } - - await ssr.viewer.eventTypes.get.prefetch({ id: typeParam }); - return { - props: { - type: typeParam, - trpcState: ssr.dehydrate(), - }, - }; -}; - EventTypePageWrapper.PageWrapper = PageWrapper; +export { getServerSideProps }; export default EventTypePageWrapper; diff --git a/apps/web/pages/getting-started/[[...step]].tsx b/apps/web/pages/getting-started/[[...step]].tsx index 28d5086dcd..7cc0080fd8 100644 --- a/apps/web/pages/getting-started/[[...step]].tsx +++ b/apps/web/pages/getting-started/[[...step]].tsx @@ -1,19 +1,14 @@ "use client"; -import type { GetServerSidePropsContext } from "next"; -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import Head from "next/head"; import { usePathname, useRouter } from "next/navigation"; import { Suspense } from "react"; import { z } from "zod"; -import { getLocale } from "@calcom/features/auth/lib/getLocale"; -import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; import { classNames } from "@calcom/lib"; import { APP_NAME } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { useParamsWithFallback } from "@calcom/lib/hooks/useParamsWithFallback"; -import prisma from "@calcom/prisma"; import { trpc } from "@calcom/trpc"; import { Button, StepCard, Steps } from "@calcom/ui"; import { Loader } from "@calcom/ui/components/icon"; @@ -25,7 +20,7 @@ import { SetupAvailability } from "@components/getting-started/steps-views/Setup import UserProfile from "@components/getting-started/steps-views/UserProfile"; import { UserSettings } from "@components/getting-started/steps-views/UserSettings"; -import { ssrInit } from "@server/lib/ssr"; +export { getServerSideProps } from "@lib/getting-started/[[...step]]/getServerSideProps"; const INITIAL_STEP = "user-settings"; const steps = [ @@ -183,57 +178,6 @@ const OnboardingPage = () => { ); }; -export const getServerSideProps = async (context: GetServerSidePropsContext) => { - const { req, res } = context; - - const session = await getServerSession({ req, res }); - - if (!session?.user?.id) { - return { redirect: { permanent: false, destination: "/auth/login" } }; - } - - const ssr = await ssrInit(context); - - await ssr.viewer.me.prefetch(); - - const user = await prisma.user.findUnique({ - where: { - id: session.user.id, - }, - select: { - completedOnboarding: true, - teams: { - select: { - accepted: true, - team: { - select: { - id: true, - name: true, - logo: true, - }, - }, - }, - }, - }, - }); - - if (!user) { - throw new Error("User from session not found"); - } - - if (user.completedOnboarding) { - return { redirect: { permanent: false, destination: "/event-types" } }; - } - const locale = await getLocale(context.req); - return { - props: { - ...(await serverSideTranslations(locale, ["common"])), - trpcState: ssr.dehydrate(), - hasPendingInvites: user.teams.find((team) => team.accepted === false) ?? false, - }, - }; -}; - OnboardingPage.PageWrapper = PageWrapper; export default OnboardingPage; diff --git a/apps/web/pages/teams/index.tsx b/apps/web/pages/teams/index.tsx index 87a49c83ac..38c06ff35a 100644 --- a/apps/web/pages/teams/index.tsx +++ b/apps/web/pages/teams/index.tsx @@ -1,9 +1,6 @@ "use client"; -import type { GetServerSidePropsContext } from "next"; - import { getLayout } from "@calcom/features/MainLayout"; -import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; import { TeamsListing } from "@calcom/features/ee/teams/components"; import { ShellMain } from "@calcom/features/shell/Shell"; import { WEBAPP_URL } from "@calcom/lib/constants"; @@ -14,7 +11,7 @@ import { Plus } from "@calcom/ui/components/icon"; import PageWrapper from "@components/PageWrapper"; -import { ssrInit } from "@server/lib/ssr"; +export { getServerSideProps } from "@lib/teams/getServerSideProps"; function Teams() { const { t } = useLocale(); @@ -42,27 +39,6 @@ function Teams() { ); } -export const getServerSideProps = async (context: GetServerSidePropsContext) => { - const ssr = await ssrInit(context); - await ssr.viewer.me.prefetch(); - const session = await getServerSession({ req: context.req, res: context.res }); - const token = Array.isArray(context.query?.token) ? context.query.token[0] : context.query?.token; - - const callbackUrl = token ? `/teams?token=${encodeURIComponent(token)}` : null; - - if (!session) { - return { - redirect: { - destination: callbackUrl ? `/auth/login?callbackUrl=${callbackUrl}` : "/auth/login", - permanent: false, - }, - props: {}, - }; - } - - return { props: { trpcState: ssr.dehydrate() } }; -}; - Teams.requiresLicense = false; Teams.PageWrapper = PageWrapper; Teams.getLayout = getLayout; diff --git a/apps/web/pages/video/[uid].tsx b/apps/web/pages/video/[uid].tsx index 49fd7e26eb..c3da0f4333 100644 --- a/apps/web/pages/video/[uid].tsx +++ b/apps/web/pages/video/[uid].tsx @@ -1,28 +1,23 @@ "use client"; import DailyIframe from "@daily-co/daily-js"; -import MarkdownIt from "markdown-it"; -import type { GetServerSidePropsContext } from "next"; import Head from "next/head"; import { useState, useEffect, useRef } from "react"; import dayjs from "@calcom/dayjs"; -import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; import classNames from "@calcom/lib/classNames"; import { APP_NAME, SEO_IMG_OGIMG_VIDEO, WEBSITE_URL } from "@calcom/lib/constants"; import { formatToLocalizedDate, formatToLocalizedTime } from "@calcom/lib/date-fns"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML"; -import prisma, { bookingMinimalSelect } from "@calcom/prisma"; import type { inferSSRProps } from "@calcom/types/inferSSRProps"; import { ChevronRight } from "@calcom/ui/components/icon"; +import type { getServerSideProps } from "@lib/video/[uid]/getServerSideProps"; + import PageWrapper from "@components/PageWrapper"; -import { ssrInit } from "@server/lib/ssr"; - export type JoinCallPageProps = Omit, "trpcState">; -const md = new MarkdownIt("default", { html: true, breaks: true, linkify: true }); export default function JoinCall(props: JoinCallPageProps) { const { t } = useLocale(); @@ -253,100 +248,3 @@ export function VideoMeetingInfo(props: VideoMeetingInfo) { } JoinCall.PageWrapper = PageWrapper; - -export async function getServerSideProps(context: GetServerSidePropsContext) { - const { req, res } = context; - - const ssr = await ssrInit(context); - - const booking = await prisma.booking.findUnique({ - where: { - uid: context.query.uid as string, - }, - select: { - ...bookingMinimalSelect, - uid: true, - description: true, - isRecorded: true, - user: { - select: { - id: true, - timeZone: true, - name: true, - email: true, - organization: { - select: { - calVideoLogo: true, - }, - }, - }, - }, - references: { - select: { - uid: true, - type: true, - meetingUrl: true, - meetingPassword: true, - }, - where: { - type: "daily_video", - }, - }, - }, - }); - - if (!booking || booking.references.length === 0 || !booking.references[0].meetingUrl) { - return { - redirect: { - destination: "/video/no-meeting-found", - permanent: false, - }, - }; - } - - //daily.co calls have a 60 minute exit buffer when a user enters a call when it's not available it will trigger the modals - const now = new Date(); - const exitDate = new Date(now.getTime() - 60 * 60 * 1000); - - //find out if the meeting is in the past - const isPast = booking?.endTime <= exitDate; - if (isPast) { - return { - redirect: { - destination: `/video/meeting-ended/${booking?.uid}`, - permanent: false, - }, - }; - } - - const bookingObj = Object.assign({}, booking, { - startTime: booking.startTime.toString(), - endTime: booking.endTime.toString(), - }); - - const session = await getServerSession({ req, res }); - - // set meetingPassword to null for guests - if (session?.user.id !== bookingObj.user?.id) { - bookingObj.references.forEach((bookRef) => { - bookRef.meetingPassword = null; - }); - } - - const videoReferences = bookingObj.references.filter((reference) => reference.type.includes("_video")); - const latestVideoReference = videoReferences[videoReferences.length - 1]; - - return { - props: { - meetingUrl: latestVideoReference.meetingUrl ?? "", - ...(typeof latestVideoReference.meetingPassword === "string" && { - meetingPassword: latestVideoReference.meetingPassword, - }), - booking: { - ...bookingObj, - ...(bookingObj.description && { description: md.render(bookingObj.description) }), - }, - trpcState: ssr.dehydrate(), - }, - }; -} diff --git a/apps/web/pages/video/meeting-ended/[uid].tsx b/apps/web/pages/video/meeting-ended/[uid].tsx index ce13db6233..75d867e23a 100644 --- a/apps/web/pages/video/meeting-ended/[uid].tsx +++ b/apps/web/pages/video/meeting-ended/[uid].tsx @@ -1,15 +1,13 @@ "use client"; -import type { NextPageContext } from "next"; - import dayjs from "@calcom/dayjs"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { detectBrowserTimeFormat } from "@calcom/lib/timeFormat"; -import prisma, { bookingMinimalSelect } from "@calcom/prisma"; import { Button, HeadSeo } from "@calcom/ui"; import { ArrowRight, Calendar, X } from "@calcom/ui/components/icon"; import type { inferSSRProps } from "@lib/types/inferSSRProps"; +import { getServerSideProps } from "@lib/video/meeting-ended/[uid]/getServerSideProps"; import PageWrapper from "@components/PageWrapper"; @@ -66,48 +64,5 @@ export default function MeetingUnavailable(props: inferSSRProps) { @@ -41,33 +40,6 @@ export default function MeetingNotStarted(props: inferSSRProps { const session = await getServerSession({ req, res }); if (!session?.user?.id) { - return res.writeHead(401).end(); + const redirect = { redirect: { permanent: false, destination: "/auth/login" } } as const; + + return redirect; } const credentials = await prisma.credential.findFirst({ where: { type: "alby_payment", - userId: session.user.id, + userId: session?.user.id, }, });