Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe5eca8eb3 | ||
|
|
7c6468953a | ||
|
|
28a0553d18 | ||
|
|
ffcb04fa99 | ||
|
|
5ca216b922 | ||
|
|
0abff9f562 | ||
|
|
942dc38b58 | ||
|
|
827d8995a1 | ||
|
|
850e222f0e | ||
|
|
ede2357203 | ||
|
|
559ab4192f | ||
|
|
3c8c6d0574 | ||
|
|
2ae2c15083 | ||
|
|
313bb89789 | ||
|
|
95e037c664 | ||
|
|
da026d909d | ||
|
|
c6b50bfd14 | ||
|
|
30b433397a | ||
|
|
ff1aefe539 | ||
|
|
5685d343b1 | ||
|
|
ae3f30fabf | ||
|
|
c11e76bac9 | ||
|
|
eed34559b5 | ||
|
|
bf958c82da | ||
|
|
728a386bf0 | ||
|
|
41efb5ea04 | ||
|
|
b268540d35 | ||
|
|
bdd1d3a99d | ||
|
|
dd7673b1f9 | ||
|
|
29f37a7e98 | ||
|
|
3983351dac | ||
|
|
01322431fc | ||
|
|
dcd06b0663 | ||
|
|
26e50d24b0 | ||
|
|
74803dc122 | ||
|
|
de65b85862 | ||
|
|
0ee56be1d8 | ||
|
|
de6f7dcfc0 | ||
|
|
956f2c7a2b | ||
|
|
14de0a1d62 | ||
|
|
51cca7481f | ||
|
|
3fe0280dee | ||
|
|
876fc188d4 | ||
|
|
d1810d9f14 | ||
|
|
a25cd43ddf | ||
|
|
833a91375e | ||
|
|
8124627cc5 | ||
|
|
749747ad7e | ||
|
|
967f70a5ec | ||
|
|
51c9b94fb5 | ||
|
|
1976dd15c3 | ||
|
|
03671e2a58 | ||
|
|
5e5f223908 | ||
|
|
9076a7eb42 | ||
|
|
a9e50d76ca | ||
|
|
bd4722554d | ||
|
|
105d373b8e |
No files matched your search
@@ -138,6 +138,11 @@ FORMBRICKS_HOST_URL=https://app.formbricks.com
|
|||||||
FORMBRICKS_ENVIRONMENT_ID=
|
FORMBRICKS_ENVIRONMENT_ID=
|
||||||
FORMBRICKS_FEEDBACK_SURVEY_ID=
|
FORMBRICKS_FEEDBACK_SURVEY_ID=
|
||||||
|
|
||||||
|
# AvatarAPI
|
||||||
|
# Used to pre-fill avatar during signup
|
||||||
|
AVATARAPI_USERNAME=
|
||||||
|
AVATARAPI_PASSWORD=
|
||||||
|
|
||||||
# Twilio
|
# Twilio
|
||||||
# Used to send SMS reminders in workflows
|
# Used to send SMS reminders in workflows
|
||||||
TWILIO_SID=
|
TWILIO_SID=
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ jobs:
|
|||||||
shard: [1, 2]
|
shard: [1, 2]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/dangerous-git-checkout
|
- uses: ./.github/actions/dangerous-git-checkout
|
||||||
- uses: ./.github/actions/yarn-install
|
- uses: ./.github/actions/yarn-install
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ jobs:
|
|||||||
shard: [1, 2]
|
shard: [1, 2]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/dangerous-git-checkout
|
- uses: ./.github/actions/dangerous-git-checkout
|
||||||
- uses: ./.github/actions/yarn-install
|
- uses: ./.github/actions/yarn-install
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ jobs:
|
|||||||
shard: [1, 2]
|
shard: [1, 2]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/dangerous-git-checkout
|
- uses: ./.github/actions/dangerous-git-checkout
|
||||||
- uses: ./.github/actions/yarn-install
|
- uses: ./.github/actions/yarn-install
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
shard: [1, 2, 3, 4, 5]
|
shard: [1, 2, 3, 4, 5]
|
||||||
steps:
|
steps:
|
||||||
|
- uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/dangerous-git-checkout
|
- uses: ./.github/actions/dangerous-git-checkout
|
||||||
- uses: ./.github/actions/yarn-install
|
- uses: ./.github/actions/yarn-install
|
||||||
|
|||||||
@@ -12,14 +12,6 @@ concurrency:
|
|||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
login:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
changes:
|
changes:
|
||||||
name: Detect changes
|
name: Detect changes
|
||||||
runs-on: buildjet-4vcpu-ubuntu-2204
|
runs-on: buildjet-4vcpu-ubuntu-2204
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export const membershipEditBodySchema = Membership.omit({
|
|||||||
/** To avoid complication, let's avoid updating these, instead you can delete and create a new invite */
|
/** To avoid complication, let's avoid updating these, instead you can delete and create a new invite */
|
||||||
teamId: true,
|
teamId: true,
|
||||||
userId: true,
|
userId: true,
|
||||||
|
id: true,
|
||||||
})
|
})
|
||||||
.partial({
|
.partial({
|
||||||
accepted: true,
|
accepted: true,
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
"@sentry/nextjs": "^7.73.0",
|
"@sentry/nextjs": "^7.73.0",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"memory-cache": "^0.2.0",
|
"memory-cache": "^0.2.0",
|
||||||
"next": "^13.4.6",
|
"next": "^13.5.4",
|
||||||
"next-api-middleware": "^1.0.1",
|
"next-api-middleware": "^1.0.1",
|
||||||
"next-axiom": "^0.17.0",
|
"next-axiom": "^0.17.0",
|
||||||
"next-swagger-doc": "^0.3.6",
|
"next-swagger-doc": "^0.3.6",
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
const { usernameList, ...rest } = req.query;
|
const { usernameList, ...rest } = req.query;
|
||||||
let slugs = usernameList;
|
let slugs = usernameList;
|
||||||
if (!Array.isArray(usernameList)) {
|
if (!Array.isArray(usernameList)) {
|
||||||
slugs = usernameList ? [usernameList] : [];
|
slugs = usernameList ? [usernameList] : undefined;
|
||||||
}
|
}
|
||||||
const input = getScheduleSchema.parse({ usernameList: slugs, ...rest });
|
const input = getScheduleSchema.parse({ usernameList: slugs, ...rest });
|
||||||
const timeZoneSupported = input.timeZone ? isSupportedTimeZone(input.timeZone) : false;
|
const timeZoneSupported = input.timeZone ? isSupportedTimeZone(input.timeZone) : false;
|
||||||
@@ -40,7 +40,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
)
|
)
|
||||||
: availableSlots;
|
: availableSlots;
|
||||||
|
|
||||||
return slotsInProvidedTimeZone;
|
return { slots: slotsInProvidedTimeZone };
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
} catch (cause) {
|
} catch (cause) {
|
||||||
if (cause instanceof TRPCError) {
|
if (cause instanceof TRPCError) {
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export async function patchHandler(req: NextApiRequest) {
|
|||||||
args.data.userId = bodyUserId;
|
args.data.userId = bodyUserId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.data.eventTriggers) {
|
if (eventTriggers) {
|
||||||
const eventTriggersSet = new Set(eventTriggers);
|
const eventTriggersSet = new Set(eventTriggers);
|
||||||
args.data.eventTriggers = Array.from(eventTriggersSet);
|
args.data.eventTriggers = Array.from(eventTriggersSet);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ async function postHandler(req: NextApiRequest) {
|
|||||||
args.data.userId = bodyUserId;
|
args.data.userId = bodyUserId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.data.eventTriggers) {
|
if (eventTriggers) {
|
||||||
const eventTriggersSet = new Set(eventTriggers);
|
const eventTriggersSet = new Set(eventTriggers);
|
||||||
args.data.eventTriggers = Array.from(eventTriggersSet);
|
args.data.eventTriggers = Array.from(eventTriggersSet);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"@storybook/blocks": "^7.6.3",
|
"@storybook/blocks": "^7.6.3",
|
||||||
"@storybook/nextjs": "^7.6.3",
|
"@storybook/nextjs": "^7.6.3",
|
||||||
"@storybook/preview-api": "^7.6.3",
|
"@storybook/preview-api": "^7.6.3",
|
||||||
"next": "^13.4.6",
|
"next": "^13.5.4",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"storybook-addon-rtl-direction": "^0.0.19"
|
"storybook-addon-rtl-direction": "^0.0.19"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"highlight.js": "^11.6.0",
|
"highlight.js": "^11.6.0",
|
||||||
"isarray": "2.0.5",
|
"isarray": "2.0.5",
|
||||||
"next": "^13.4.6",
|
"next": "^13.5.4",
|
||||||
"openapi-snippet": "^0.13.0",
|
"openapi-snippet": "^0.13.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import type { GetStaticProps, GetStaticPropsContext } from "next";
|
||||||
|
import { notFound, redirect } from "next/navigation";
|
||||||
|
|
||||||
|
export const withAppDirSsg =
|
||||||
|
<T extends Record<string, any>>(getStaticProps: GetStaticProps<T>) =>
|
||||||
|
async (context: GetStaticPropsContext) => {
|
||||||
|
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 }),
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { GetServerSideProps, GetServerSidePropsContext } from "next";
|
import type { GetServerSideProps, GetServerSidePropsContext } from "next";
|
||||||
import { notFound, redirect } from "next/navigation";
|
import { notFound, redirect } from "next/navigation";
|
||||||
|
|
||||||
export const withAppDir =
|
export const withAppDirSsr =
|
||||||
<T extends Record<string, any>>(getServerSideProps: GetServerSideProps<T>) =>
|
<T extends Record<string, any>>(getServerSideProps: GetServerSideProps<T>) =>
|
||||||
async (context: GetServerSidePropsContext): Promise<T> => {
|
async (context: GetServerSidePropsContext) => {
|
||||||
const ssrResponse = await getServerSideProps(context);
|
const ssrResponse = await getServerSideProps(context);
|
||||||
|
|
||||||
if ("redirect" in ssrResponse) {
|
if ("redirect" in ssrResponse) {
|
||||||
@@ -13,9 +13,11 @@ export const withAppDir =
|
|||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const props = await Promise.resolve(ssrResponse.props);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...ssrResponse.props,
|
...props,
|
||||||
// includes dehydratedState required for future page trpcPropvider
|
// includes dehydratedState required for future page trpcPropvider
|
||||||
...("trpcState" in ssrResponse.props && { dehydratedState: ssrResponse.props.trpcState }),
|
...("trpcState" in props && { dehydratedState: props.trpcState }),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,197 @@
|
|||||||
|
import LegacyPage, { getLayout } from "@pages/apps/[slug]/[...pages]";
|
||||||
|
import type { PageProps, SearchParams } from "app/_types";
|
||||||
|
import { _generateMetadata } from "app/_utils";
|
||||||
|
import type { GetServerSidePropsContext } from "next";
|
||||||
|
import type { Params } from "next/dist/shared/lib/router/utils/route-matcher";
|
||||||
|
import { cookies, headers } from "next/headers";
|
||||||
|
import { notFound, redirect } from "next/navigation";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
import { getAppWithMetadata } from "@calcom/app-store/_appRegistry";
|
||||||
|
import RoutingFormsRoutingConfig, {
|
||||||
|
serverSidePropsConfig,
|
||||||
|
} from "@calcom/app-store/routing-forms/pages/app-routing.config";
|
||||||
|
import TypeformRoutingConfig from "@calcom/app-store/typeform/pages/app-routing.config";
|
||||||
|
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||||
|
import { APP_NAME } from "@calcom/lib/constants";
|
||||||
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { AppGetServerSideProps } from "@calcom/types/AppGetServerSideProps";
|
||||||
|
|
||||||
|
import type { AppProps } from "@lib/app-providers";
|
||||||
|
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapperAppDir";
|
||||||
|
|
||||||
|
import { ssrInit } from "@server/lib/ssr";
|
||||||
|
|
||||||
|
type AppPageType = {
|
||||||
|
getServerSideProps: AppGetServerSideProps;
|
||||||
|
// A component than can accept any properties
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
default: ((props: any) => JSX.Element) &
|
||||||
|
Pick<AppProps["Component"], "isBookingPage" | "getLayout" | "PageWrapper">;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Found = {
|
||||||
|
notFound: false;
|
||||||
|
Component: AppPageType["default"];
|
||||||
|
getServerSideProps: AppPageType["getServerSideProps"];
|
||||||
|
};
|
||||||
|
|
||||||
|
const AppsRouting = {
|
||||||
|
"routing-forms": RoutingFormsRoutingConfig,
|
||||||
|
typeform: TypeformRoutingConfig,
|
||||||
|
};
|
||||||
|
|
||||||
|
const paramsSchema = z.object({
|
||||||
|
slug: z.string(),
|
||||||
|
pages: z.array(z.string()),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const generateMetadata = async ({
|
||||||
|
params,
|
||||||
|
searchParams,
|
||||||
|
}: {
|
||||||
|
params: Params;
|
||||||
|
searchParams: SearchParams;
|
||||||
|
}) => {
|
||||||
|
const p = paramsSchema.safeParse(params);
|
||||||
|
|
||||||
|
if (!p.success) {
|
||||||
|
return notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
const mainPage = p.data.pages[0];
|
||||||
|
|
||||||
|
if (mainPage === "forms") {
|
||||||
|
return await _generateMetadata(
|
||||||
|
() => `Forms | ${APP_NAME}`,
|
||||||
|
() => ""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const legacyContext = buildLegacyCtx(
|
||||||
|
headers(),
|
||||||
|
cookies(),
|
||||||
|
params,
|
||||||
|
searchParams
|
||||||
|
) as unknown as GetServerSidePropsContext;
|
||||||
|
const { form } = await getPageProps(legacyContext);
|
||||||
|
|
||||||
|
return await _generateMetadata(
|
||||||
|
() => `${form.name} | ${APP_NAME}`,
|
||||||
|
() => form.description
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
function getRoute(appName: string, pages: string[]) {
|
||||||
|
const routingConfig = AppsRouting[appName as keyof typeof AppsRouting] as Record<string, AppPageType>;
|
||||||
|
|
||||||
|
if (!routingConfig) {
|
||||||
|
notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
const mainPage = pages[0];
|
||||||
|
const appPage = routingConfig.layoutHandler || (routingConfig[mainPage] as AppPageType);
|
||||||
|
|
||||||
|
const getServerSidePropsHandler = serverSidePropsConfig[mainPage];
|
||||||
|
|
||||||
|
if (!appPage) {
|
||||||
|
notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
notFound: false,
|
||||||
|
Component: appPage.default,
|
||||||
|
...appPage,
|
||||||
|
getServerSideProps: getServerSidePropsHandler,
|
||||||
|
} as Found;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPageProps = async ({ params, query, req }: GetServerSidePropsContext) => {
|
||||||
|
const p = paramsSchema.safeParse(params);
|
||||||
|
|
||||||
|
if (!p.success) {
|
||||||
|
return notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { slug: appName, pages } = p.data;
|
||||||
|
|
||||||
|
const route = getRoute(appName, pages);
|
||||||
|
|
||||||
|
if (route.notFound) {
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (route.getServerSideProps) {
|
||||||
|
// TODO: Document somewhere that right now it is just a convention that filename should have appPages in it's name.
|
||||||
|
// appPages is actually hardcoded here and no matter the fileName the same variable would be used.
|
||||||
|
// We can write some validation logic later on that ensures that [...appPages].tsx file exists
|
||||||
|
params!.appPages = pages.slice(1);
|
||||||
|
|
||||||
|
const ctx = { req, params, query };
|
||||||
|
|
||||||
|
const session = await getServerSession({ req });
|
||||||
|
const user = session?.user;
|
||||||
|
const app = await getAppWithMetadata({ slug: appName });
|
||||||
|
|
||||||
|
if (!app) {
|
||||||
|
notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await route.getServerSideProps(
|
||||||
|
{
|
||||||
|
...ctx,
|
||||||
|
params: {
|
||||||
|
...ctx.params,
|
||||||
|
appPages: pages.slice(1),
|
||||||
|
},
|
||||||
|
} as GetServerSidePropsContext<{
|
||||||
|
slug: string;
|
||||||
|
pages: string[];
|
||||||
|
appPages: string[];
|
||||||
|
}>,
|
||||||
|
prisma,
|
||||||
|
user,
|
||||||
|
ssrInit
|
||||||
|
);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
//@ts-ignore
|
||||||
|
|
||||||
|
if (result.notFound) {
|
||||||
|
notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.redirect) {
|
||||||
|
redirect(result.redirect.destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
appName,
|
||||||
|
appUrl: app.simplePath || `/apps/${appName}`,
|
||||||
|
...result.props,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
appName,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function Page({ params, searchParams }: PageProps) {
|
||||||
|
const h = headers();
|
||||||
|
const nonce = h.get("x-nonce") ?? undefined;
|
||||||
|
|
||||||
|
const legacyContext = buildLegacyCtx(
|
||||||
|
h,
|
||||||
|
cookies(),
|
||||||
|
params,
|
||||||
|
searchParams
|
||||||
|
) as unknown as GetServerSidePropsContext;
|
||||||
|
const props = await getPageProps(legacyContext);
|
||||||
|
return (
|
||||||
|
<PageWrapper getLayout={getLayout} requiresLicense={false} nonce={nonce} themeBasis={null} {...props}>
|
||||||
|
<LegacyPage {...props} />
|
||||||
|
</PageWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import { WithLayout } from "app/layoutHOC";
|
|
||||||
|
|
||||||
export default WithLayout({ getLayout: null })<"L">;
|
|
||||||
@@ -1,40 +1,33 @@
|
|||||||
import AppPage from "@pages/apps/[slug]/index";
|
import Page from "@pages/apps/[slug]/index";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
|
import { withAppDirSsg } from "app/WithAppDirSsg";
|
||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
import fs from "fs";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
import matter from "gray-matter";
|
import type { InferGetStaticPropsType } from "next";
|
||||||
import { notFound } from "next/navigation";
|
import { cookies, headers } from "next/headers";
|
||||||
import path from "path";
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
import { getAppWithMetadata } from "@calcom/app-store/_appRegistry";
|
import { APP_NAME } from "@calcom/lib/constants";
|
||||||
import { getAppAssetFullPath } from "@calcom/app-store/getAppAssetFullPath";
|
|
||||||
import { APP_NAME, IS_PRODUCTION } from "@calcom/lib/constants";
|
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
|
||||||
const sourceSchema = z.object({
|
import { getStaticProps } from "@lib/apps/[slug]/getStaticProps";
|
||||||
content: z.string(),
|
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||||
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 generateMetadata = async ({ params }: { params: Record<string, string | string[]> }) => {
|
type Y = InferGetStaticPropsType<typeof getStaticProps>;
|
||||||
const { data } = await getPageProps({ params });
|
const getData = withAppDirSsg<Y>(getStaticProps);
|
||||||
|
|
||||||
|
export const generateMetadata = async ({
|
||||||
|
params,
|
||||||
|
searchParams,
|
||||||
|
}: {
|
||||||
|
params: Record<string, string | string[]>;
|
||||||
|
searchParams: { [key: string]: string | string[] | undefined };
|
||||||
|
}) => {
|
||||||
|
const legacyContext = buildLegacyCtx(headers(), cookies(), params, searchParams);
|
||||||
|
const res = await getData(legacyContext);
|
||||||
|
|
||||||
return await _generateMetadata(
|
return await _generateMetadata(
|
||||||
() => `${data.name} | ${APP_NAME}`,
|
() => `${res?.data.name} | ${APP_NAME}`,
|
||||||
() => data.description
|
() => res?.data.description ?? ""
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,74 +46,6 @@ export const generateStaticParams = async () => {
|
|||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPageProps = async ({ params }: { params: Record<string, string | string[]> }) => {
|
export default WithLayout({ getLayout: null, Page, getData });
|
||||||
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<string, string | string[]> }) {
|
|
||||||
const pageProps = await getPageProps({ params });
|
|
||||||
|
|
||||||
return <AppPage {...pageProps} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const dynamic = "force-static";
|
export const dynamic = "force-static";
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
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 { _generateMetadata } from "app/_utils";
|
||||||
import type { GetServerSidePropsContext } from "next";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
import { cookies, headers } from "next/headers";
|
import type { InferGetServerSidePropsType } from "next";
|
||||||
import { notFound, redirect } from "next/navigation";
|
|
||||||
|
|
||||||
import { getServerSideProps } from "@calcom/app-store/_pages/setup/_getServerSideProps";
|
import { getServerSideProps } from "@calcom/app-store/_pages/setup/_getServerSideProps";
|
||||||
import { APP_NAME } from "@calcom/lib/constants";
|
import { APP_NAME } from "@calcom/lib/constants";
|
||||||
@@ -14,23 +14,8 @@ export const generateMetadata = async ({ params }: { params: Record<string, stri
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPageProps = async ({ params }: { params: Record<string, string | string[]> }) => {
|
type T = InferGetServerSidePropsType<typeof getServerSideProps>;
|
||||||
const req = { headers: headers(), cookies: cookies() };
|
|
||||||
|
|
||||||
const result = await getServerSideProps({ params, req } as unknown as GetServerSidePropsContext);
|
const getData = withAppDirSsr<T>(getServerSideProps);
|
||||||
|
|
||||||
if (!result || "notFound" in result) {
|
export default WithLayout({ getLayout: null, Page, getData });
|
||||||
notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("redirect" in result) {
|
|
||||||
redirect(result.redirect.destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.props;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default async function Page({ params }: { params: Record<string, string | string[]> }) {
|
|
||||||
const pageProps = await getPageProps({ params });
|
|
||||||
return <SetupPage {...pageProps} />;
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import CategoryPage from "@pages/apps/categories/[category]";
|
import CategoryPage, { type PageProps } from "@pages/apps/categories/[category]";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
|
import { withAppDirSsg } from "app/WithAppDirSsg";
|
||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
import { notFound } from "next/navigation";
|
|
||||||
import z from "zod";
|
|
||||||
|
|
||||||
import { getAppRegistry } from "@calcom/app-store/_appRegistry";
|
|
||||||
import { APP_NAME } from "@calcom/lib/constants";
|
import { APP_NAME } from "@calcom/lib/constants";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
import { AppCategories } from "@calcom/prisma/enums";
|
import { AppCategories } from "@calcom/prisma/enums";
|
||||||
|
|
||||||
|
import { getStaticProps } from "@lib/apps/categories/[category]/getStaticProps";
|
||||||
|
|
||||||
export const generateMetadata = async () => {
|
export const generateMetadata = async () => {
|
||||||
return await _generateMetadata(
|
return await _generateMetadata(
|
||||||
() => `${APP_NAME} | ${APP_NAME}`,
|
() => `${APP_NAME} | ${APP_NAME}`,
|
||||||
@@ -34,38 +34,7 @@ export const generateStaticParams = async () => {
|
|||||||
return paths.map((category) => ({ category }));
|
return paths.map((category) => ({ category }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const querySchema = z.object({
|
const getData = withAppDirSsg<PageProps>(getStaticProps);
|
||||||
category: z.nativeEnum(AppCategories),
|
|
||||||
});
|
|
||||||
|
|
||||||
const getPageProps = async ({ params }: { params: Record<string, string | string[]> }) => {
|
export default WithLayout({ getData, Page: CategoryPage, getLayout: null })<"P">;
|
||||||
const p = querySchema.safeParse(params);
|
|
||||||
|
|
||||||
if (!p.success) {
|
|
||||||
return notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
const appQuery = await prisma.app.findMany({
|
|
||||||
where: {
|
|
||||||
categories: {
|
|
||||||
has: p.data.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 {
|
|
||||||
apps,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// @ts-expect-error getData arg
|
|
||||||
export default WithLayout({ getData: getPageProps, Page: CategoryPage })<"P">;
|
|
||||||
export const dynamic = "force-static";
|
export const dynamic = "force-static";
|
||||||
@@ -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 { _generateMetadata } from "app/_utils";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
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 { APP_NAME } from "@calcom/lib/constants";
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
import { getServerSideProps } from "@lib/apps/categories/getServerSideProps";
|
||||||
|
|
||||||
export const generateMetadata = async () => {
|
export const generateMetadata = async () => {
|
||||||
return await _generateMetadata(
|
return await _generateMetadata(
|
||||||
@@ -16,29 +14,4 @@ export const generateMetadata = async () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getData = async (ctx: GetServerSidePropsContext) => {
|
export default WithLayout({ getData: withAppDirSsr(getServerSideProps), Page, getLayout: null })<"P">;
|
||||||
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<string, number>);
|
|
||||||
|
|
||||||
return {
|
|
||||||
categories: Object.entries(categories).map(([name, count]) => ({ name, count })),
|
|
||||||
dehydratedState: ssr.dehydrate(),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default WithLayout({ getData, Page: LegacyPage, getLayout: null })<"P">;
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import { WithLayout } from "app/layoutHOC";
|
|
||||||
|
|
||||||
export default WithLayout({ getLayout: null })<"L">;
|
|
||||||
@@ -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 { _generateMetadata } from "app/_utils";
|
||||||
import { notFound } from "next/navigation";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
import { APP_NAME } from "@calcom/lib/constants";
|
import { APP_NAME } from "@calcom/lib/constants";
|
||||||
import { AppCategories } from "@calcom/prisma/enums";
|
|
||||||
|
|
||||||
const querySchema = z.object({
|
import { getServerSideProps } from "@lib/apps/installed/[category]/getServerSideProps";
|
||||||
category: z.nativeEnum(AppCategories),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const generateMetadata = async () => {
|
export const generateMetadata = async () => {
|
||||||
return await _generateMetadata(
|
return await _generateMetadata(
|
||||||
@@ -17,20 +14,6 @@ export const generateMetadata = async () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPageProps = async ({ params }: { params: Record<string, string | string[]> }) => {
|
const getData = withAppDirSsr(getServerSideProps);
|
||||||
const p = querySchema.safeParse(params);
|
|
||||||
|
|
||||||
if (!p.success) {
|
export default WithLayout({ getLayout: null, getData, Page });
|
||||||
return notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
category: p.data.category,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default async function Page({ params }: { params: Record<string, string | string[]> }) {
|
|
||||||
await getPageProps({ params });
|
|
||||||
|
|
||||||
return <LegacyPage />;
|
|
||||||
}
|
|
||||||
@@ -1,17 +1,12 @@
|
|||||||
import AppsPage from "@pages/apps";
|
import AppsPage from "@pages/apps";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
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 { 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 { 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 () => {
|
export const generateMetadata = async () => {
|
||||||
return await _generateMetadata(
|
return await _generateMetadata(
|
||||||
@@ -20,44 +15,4 @@ export const generateMetadata = async () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getData = async (ctx: GetServerSidePropsContext) => {
|
export default WithLayout({ getLayout, getData: withAppDirSsr(getServerSideProps), Page: AppsPage });
|
||||||
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<string, number>);
|
|
||||||
|
|
||||||
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 });
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import SetNewUserPassword from "@pages/auth/forgot-password/[id]";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
import { _generateMetadata } from "app/_utils";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
|
import { getServerSideProps } from "@server/lib/forgot-password/[id]/getServerSideProps";
|
||||||
|
|
||||||
|
export const generateMetadata = async () => {
|
||||||
|
return await _generateMetadata(
|
||||||
|
(t) => t("reset_password"),
|
||||||
|
(t) => t("change_your_password")
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WithLayout({
|
||||||
|
getLayout: null,
|
||||||
|
Page: SetNewUserPassword,
|
||||||
|
getData: withAppDirSsr(getServerSideProps),
|
||||||
|
})<"P">;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import ForgotPassword from "@pages/auth/forgot-password";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
import { _generateMetadata } from "app/_utils";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
|
import { getServerSideProps } from "@server/lib/forgot-password/getServerSideProps";
|
||||||
|
|
||||||
|
export const generateMetadata = async () => {
|
||||||
|
return await _generateMetadata(
|
||||||
|
(t) => t("reset_password"),
|
||||||
|
(t) => t("change_your_password")
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WithLayout({
|
||||||
|
getLayout: null,
|
||||||
|
Page: ForgotPassword,
|
||||||
|
getData: withAppDirSsr(getServerSideProps),
|
||||||
|
})<"P">;
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import Login from "@pages/auth/login";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
import { _generateMetadata } from "app/_utils";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
import type { InferGetServerSidePropsType } from "next";
|
||||||
|
|
||||||
|
import { APP_NAME } from "@calcom/lib/constants";
|
||||||
|
|
||||||
|
import { getServerSideProps } from "@server/lib/auth/login/getServerSideProps";
|
||||||
|
|
||||||
|
export const generateMetadata = async () => {
|
||||||
|
return await _generateMetadata(
|
||||||
|
(t) => `${t("login")} | ${APP_NAME}`,
|
||||||
|
(t) => t("login")
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WithLayout({
|
||||||
|
getLayout: null,
|
||||||
|
Page: Login,
|
||||||
|
getData: withAppDirSsr<InferGetServerSidePropsType<typeof getServerSideProps>>(getServerSideProps),
|
||||||
|
})<"P">;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import Logout from "@pages/auth/logout";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
|
import { getServerSideProps } from "@server/lib/auth/logout/getServerSideProps";
|
||||||
|
|
||||||
|
export default WithLayout({ getLayout: null, Page: Logout, getData: withAppDirSsr(getServerSideProps) })<"P">;
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import signin from "@pages/auth/signin";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
import type { InferGetServerSidePropsType } from "next";
|
||||||
|
|
||||||
|
import { getServerSideProps } from "@server/lib/auth/signin/getServerSideProps";
|
||||||
|
|
||||||
|
export default WithLayout({
|
||||||
|
getLayout: null,
|
||||||
|
Page: signin,
|
||||||
|
// @ts-expect-error TODO: fix this
|
||||||
|
getData: withAppDirSsr<InferGetServerSidePropsType<typeof getServerSideProps>>(getServerSideProps),
|
||||||
|
})<"P">;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import Provider from "@pages/auth/sso/[provider]";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
import type { InferGetServerSidePropsType } from "next";
|
||||||
|
|
||||||
|
import { getServerSideProps } from "@server/lib/auth/sso/[provider]/getServerSideProps";
|
||||||
|
|
||||||
|
export default WithLayout({
|
||||||
|
getLayout: null,
|
||||||
|
Page: Provider,
|
||||||
|
getData: withAppDirSsr<InferGetServerSidePropsType<typeof getServerSideProps>>(getServerSideProps),
|
||||||
|
})<"P">;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import DirectSSOLogin from "@pages/auth/sso/direct";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
|
import { getServerSideProps } from "@server/lib/auth/sso/direct/getServerSideProps";
|
||||||
|
|
||||||
|
export default WithLayout({
|
||||||
|
getLayout: null,
|
||||||
|
Page: DirectSSOLogin,
|
||||||
|
getData: withAppDirSsr(getServerSideProps),
|
||||||
|
})<"P">;
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import VerifyEmailPage from "@pages/auth/verify-email";
|
||||||
|
import { _generateMetadata } from "app/_utils";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
|
export const generateMetadata = async () => {
|
||||||
|
return await _generateMetadata(
|
||||||
|
(t) => t("check_your_email"),
|
||||||
|
(t) => t("check_your_email")
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WithLayout({
|
||||||
|
getLayout: null,
|
||||||
|
Page: VerifyEmailPage,
|
||||||
|
})<"P">;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import VerifyPage from "@pages/auth/verify";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
|
import { getServerSideProps } from "@server/lib/auth/verify/getServerSideProps";
|
||||||
|
|
||||||
|
export default WithLayout({
|
||||||
|
getLayout: null,
|
||||||
|
Page: VerifyPage,
|
||||||
|
getData: withAppDirSsr(getServerSideProps),
|
||||||
|
})<"P">;
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import OldPage from "@pages/booking/[uid]";
|
import { type PageProps, getServerSideProps } from "@pages/booking/[uid]";
|
||||||
|
import OldPage from "@pages/booking/[uid]/embed";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
import withEmbedSsrAppDir from "app/WithEmbedSSR";
|
import withEmbedSsrAppDir from "app/WithEmbedSSR";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
import { getData } from "../page";
|
const getData = withAppDirSsr<PageProps>(getServerSideProps);
|
||||||
|
|
||||||
const getEmbedData = withEmbedSsrAppDir(getData);
|
const getEmbedData = withEmbedSsrAppDir(getData);
|
||||||
|
|
||||||
// @ts-expect-error Type '(context: GetServerSidePropsContext) => Promise<any>' is not assignable to type '(arg: {
|
|
||||||
export default WithLayout({ getLayout: null, getData: getEmbedData, Page: OldPage });
|
export default WithLayout({ getLayout: null, getData: getEmbedData, Page: OldPage });
|
||||||
@@ -1,204 +1,36 @@
|
|||||||
import OldPage from "@pages/booking/[uid]";
|
import OldPage, { type PageProps } from "@pages/booking/[uid]";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
import type { Params, SearchParams } from "app/_types";
|
||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
import type { GetServerSidePropsContext } from "next";
|
import { type GetServerSidePropsContext } from "next";
|
||||||
import { notFound } from "next/navigation";
|
import { cookies, headers } from "next/headers";
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
import { BookingStatus } from "@calcom/prisma/enums";
|
||||||
import { getBookingWithResponses } from "@calcom/features/bookings/lib/get-booking";
|
|
||||||
import { parseRecurringEvent } from "@calcom/lib";
|
|
||||||
import { getDefaultEvent } from "@calcom/lib/defaultEvents";
|
|
||||||
import { maybeGetBookingUidFromSeat } from "@calcom/lib/server/maybeGetBookingUidFromSeat";
|
|
||||||
import prisma from "@calcom/prisma";
|
|
||||||
import { customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
|
||||||
|
|
||||||
import { getRecurringBookings, handleSeatsEventTypeOnBooking, getEventTypesFromDB } from "@lib/booking";
|
import { getServerSideProps } from "@lib/booking/[uid]/getServerSideProps";
|
||||||
|
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
export const generateMetadata = async ({
|
||||||
|
params,
|
||||||
const stringToBoolean = z
|
searchParams,
|
||||||
.string()
|
}: {
|
||||||
.optional()
|
params: Params;
|
||||||
.transform((val) => val === "true");
|
searchParams: SearchParams;
|
||||||
|
}) => {
|
||||||
const querySchema = z.object({
|
const { bookingInfo, eventType, recurringBookings } = await getData(
|
||||||
uid: z.string(),
|
buildLegacyCtx(headers(), cookies(), params, searchParams) as unknown as GetServerSidePropsContext
|
||||||
email: z.string().optional(),
|
|
||||||
eventTypeSlug: z.string().optional(),
|
|
||||||
cancel: stringToBoolean,
|
|
||||||
allRemainingBookings: stringToBoolean,
|
|
||||||
changes: stringToBoolean,
|
|
||||||
reschedule: stringToBoolean,
|
|
||||||
isSuccessBookingPage: stringToBoolean,
|
|
||||||
formerTime: z.string().optional(),
|
|
||||||
seatReferenceUid: z.string().optional(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const generateMetadata = async () =>
|
|
||||||
await _generateMetadata(
|
|
||||||
() => "",
|
|
||||||
() => ""
|
|
||||||
);
|
);
|
||||||
|
const needsConfirmation = bookingInfo.status === BookingStatus.PENDING && eventType.requiresConfirmation;
|
||||||
|
|
||||||
export const getData = async (context: GetServerSidePropsContext) => {
|
return await _generateMetadata(
|
||||||
const ssr = await ssrInit(context);
|
(t) =>
|
||||||
const session = await getServerSession(context);
|
t(`booking_${needsConfirmation ? "submitted" : "confirmed"}${recurringBookings ? "_recurring" : ""}`),
|
||||||
let tz: string | null = null;
|
(t) =>
|
||||||
let userTimeFormat: number | null = null;
|
t(`booking_${needsConfirmation ? "submitted" : "confirmed"}${recurringBookings ? "_recurring" : ""}`)
|
||||||
let requiresLoginToUpdate = false;
|
);
|
||||||
if (session) {
|
|
||||||
const user = await ssr.viewer.me.fetch();
|
|
||||||
tz = user.timeZone;
|
|
||||||
userTimeFormat = user.timeFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
const parsedQuery = querySchema.safeParse(context.query);
|
|
||||||
|
|
||||||
if (!parsedQuery.success) {
|
|
||||||
notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
const { uid, eventTypeSlug, seatReferenceUid } = parsedQuery.data;
|
|
||||||
|
|
||||||
const { uid: maybeUid } = await maybeGetBookingUidFromSeat(prisma, uid);
|
|
||||||
const bookingInfoRaw = await prisma.booking.findFirst({
|
|
||||||
where: {
|
|
||||||
uid: maybeUid,
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
title: true,
|
|
||||||
id: true,
|
|
||||||
uid: true,
|
|
||||||
description: true,
|
|
||||||
customInputs: true,
|
|
||||||
smsReminderNumber: true,
|
|
||||||
recurringEventId: true,
|
|
||||||
startTime: true,
|
|
||||||
endTime: true,
|
|
||||||
location: true,
|
|
||||||
status: true,
|
|
||||||
metadata: true,
|
|
||||||
cancellationReason: true,
|
|
||||||
responses: true,
|
|
||||||
rejectionReason: true,
|
|
||||||
user: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
name: true,
|
|
||||||
email: true,
|
|
||||||
username: true,
|
|
||||||
timeZone: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
attendees: {
|
|
||||||
select: {
|
|
||||||
name: true,
|
|
||||||
email: true,
|
|
||||||
timeZone: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
eventTypeId: true,
|
|
||||||
eventType: {
|
|
||||||
select: {
|
|
||||||
eventName: true,
|
|
||||||
slug: true,
|
|
||||||
timeZone: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
seatsReferences: {
|
|
||||||
select: {
|
|
||||||
referenceUid: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!bookingInfoRaw) {
|
|
||||||
notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
const eventTypeRaw = !bookingInfoRaw.eventTypeId
|
|
||||||
? getDefaultEvent(eventTypeSlug || "")
|
|
||||||
: await getEventTypesFromDB(bookingInfoRaw.eventTypeId);
|
|
||||||
if (!eventTypeRaw) {
|
|
||||||
notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventTypeRaw.seatsPerTimeSlot && !seatReferenceUid && !session) {
|
|
||||||
requiresLoginToUpdate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bookingInfo = getBookingWithResponses(bookingInfoRaw);
|
|
||||||
// @NOTE: had to do this because Server side cant return [Object objects]
|
|
||||||
// probably fixable with json.stringify -> json.parse
|
|
||||||
bookingInfo["startTime"] = (bookingInfo?.startTime as Date)?.toISOString() as unknown as Date;
|
|
||||||
bookingInfo["endTime"] = (bookingInfo?.endTime as Date)?.toISOString() as unknown as Date;
|
|
||||||
|
|
||||||
eventTypeRaw.users = !!eventTypeRaw.hosts?.length
|
|
||||||
? eventTypeRaw.hosts.map((host) => host.user)
|
|
||||||
: eventTypeRaw.users;
|
|
||||||
|
|
||||||
if (!eventTypeRaw.users.length) {
|
|
||||||
if (!eventTypeRaw.owner) {
|
|
||||||
notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
eventTypeRaw.users.push({
|
|
||||||
...eventTypeRaw.owner,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const eventType = {
|
|
||||||
...eventTypeRaw,
|
|
||||||
periodStartDate: eventTypeRaw.periodStartDate?.toString() ?? null,
|
|
||||||
periodEndDate: eventTypeRaw.periodEndDate?.toString() ?? null,
|
|
||||||
metadata: EventTypeMetaDataSchema.parse(eventTypeRaw.metadata),
|
|
||||||
recurringEvent: parseRecurringEvent(eventTypeRaw.recurringEvent),
|
|
||||||
customInputs: customInputSchema.array().parse(eventTypeRaw.customInputs),
|
|
||||||
};
|
|
||||||
|
|
||||||
const profile = {
|
|
||||||
name: eventType.team?.name || eventType.users[0]?.name || null,
|
|
||||||
email: eventType.team ? null : eventType.users[0].email || null,
|
|
||||||
theme: (!eventType.team?.name && eventType.users[0]?.theme) || null,
|
|
||||||
brandColor: eventType.team ? null : eventType.users[0].brandColor || null,
|
|
||||||
darkBrandColor: eventType.team ? null : eventType.users[0].darkBrandColor || null,
|
|
||||||
slug: eventType.team?.slug || eventType.users[0]?.username || null,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (bookingInfo !== null && eventType.seatsPerTimeSlot) {
|
|
||||||
await handleSeatsEventTypeOnBooking(eventType, bookingInfo, seatReferenceUid, session?.user.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
const payment = await prisma.payment.findFirst({
|
|
||||||
where: {
|
|
||||||
bookingId: bookingInfo.id,
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
success: true,
|
|
||||||
refunded: true,
|
|
||||||
currency: true,
|
|
||||||
amount: true,
|
|
||||||
paymentOption: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
themeBasis: eventType.team ? eventType.team.slug : eventType.users[0]?.username,
|
|
||||||
hideBranding: eventType.team ? eventType.team.hideBranding : eventType.users[0].hideBranding,
|
|
||||||
profile,
|
|
||||||
eventType,
|
|
||||||
recurringBookings: await getRecurringBookings(bookingInfo.recurringEventId),
|
|
||||||
dehydratedState: ssr.dehydrate(),
|
|
||||||
dynamicEventName: bookingInfo?.eventType?.eventName || "",
|
|
||||||
bookingInfo,
|
|
||||||
paymentStatus: payment,
|
|
||||||
...(tz && { tz }),
|
|
||||||
userTimeFormat,
|
|
||||||
requiresLoginToUpdate,
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// @ts-expect-error Argument of type '{ req: { headers: ReadonlyHeaders; cookies: ReadonlyRequestCookies; }; }' is not assignable to parameter of type 'GetServerSidePropsContext'.
|
const getData = withAppDirSsr<PageProps>(getServerSideProps);
|
||||||
|
|
||||||
export default WithLayout({ getLayout: null, getData, Page: OldPage });
|
export default WithLayout({ getLayout: null, getData, Page: OldPage });
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
import { _generateMetadata } from "app/_utils";
|
|
||||||
import { WithLayout } from "app/layoutHOC";
|
|
||||||
import type { GetServerSidePropsContext } from "next";
|
|
||||||
import { notFound } from "next/navigation";
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
import { getLayout } from "@calcom/features/MainLayoutAppDir";
|
|
||||||
import { APP_NAME } from "@calcom/lib/constants";
|
|
||||||
|
|
||||||
import { ssgInit } from "@server/lib/ssg";
|
|
||||||
|
|
||||||
const validStatuses = ["upcoming", "recurring", "past", "cancelled", "unconfirmed"] as const;
|
|
||||||
|
|
||||||
const querySchema = z.object({
|
|
||||||
status: z.enum(validStatuses),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const generateMetadata = async () =>
|
|
||||||
await _generateMetadata(
|
|
||||||
(t) => `${APP_NAME} | ${t("bookings")}`,
|
|
||||||
() => ""
|
|
||||||
);
|
|
||||||
|
|
||||||
export const generateStaticParams = async () => {
|
|
||||||
return validStatuses.map((status) => ({ status }));
|
|
||||||
};
|
|
||||||
|
|
||||||
const getData = async (ctx: GetServerSidePropsContext) => {
|
|
||||||
const parsedParams = querySchema.safeParse(ctx.params);
|
|
||||||
|
|
||||||
if (!parsedParams.success) {
|
|
||||||
notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
const ssg = await ssgInit(ctx);
|
|
||||||
|
|
||||||
return {
|
|
||||||
status: parsedParams.data.status,
|
|
||||||
dehydratedState: ssg.dehydrate(),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default WithLayout({ getLayout, getData })<"L">;
|
|
||||||
|
|
||||||
export const dynamic = "force-static";
|
|
||||||
@@ -1 +1,29 @@
|
|||||||
export { default } from "@pages/bookings/[status]";
|
import Page from "@pages/bookings/[status]";
|
||||||
|
import { withAppDirSsg } from "app/WithAppDirSsg";
|
||||||
|
import { _generateMetadata } from "app/_utils";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
import type { InferGetStaticPropsType } from "next";
|
||||||
|
|
||||||
|
import { getLayout } from "@calcom/features/MainLayoutAppDir";
|
||||||
|
import { APP_NAME } from "@calcom/lib/constants";
|
||||||
|
|
||||||
|
import { getStaticProps } from "@lib/bookings/[status]/getStaticProps";
|
||||||
|
|
||||||
|
const validStatuses = ["upcoming", "recurring", "past", "cancelled", "unconfirmed"] as const;
|
||||||
|
|
||||||
|
type Y = InferGetStaticPropsType<typeof getStaticProps>;
|
||||||
|
const getData = withAppDirSsg<Y>(getStaticProps);
|
||||||
|
|
||||||
|
export const generateMetadata = async () =>
|
||||||
|
await _generateMetadata(
|
||||||
|
(t) => `${APP_NAME} | ${t("bookings")}`,
|
||||||
|
() => ""
|
||||||
|
);
|
||||||
|
|
||||||
|
export const generateStaticParams = async () => {
|
||||||
|
return validStatuses.map((status) => ({ status }));
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WithLayout({ getLayout, getData, Page })<"P">;
|
||||||
|
|
||||||
|
export const dynamic = "force-static";
|
||||||
@@ -1,27 +1,21 @@
|
|||||||
import LegacyPage, { type PageProps } from "@pages/d/[link]/[slug]";
|
import LegacyPage from "@pages/d/[link]/[slug]";
|
||||||
import { withAppDir } from "app/AppDirSSRHOC";
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
import type { Params, SearchParams } from "app/_types";
|
||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
import type { GetServerSidePropsContext } from "next";
|
|
||||||
import { cookies, headers } from "next/headers";
|
import { cookies, headers } from "next/headers";
|
||||||
import { notFound } from "next/navigation";
|
|
||||||
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 { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||||
|
import { getServerSideProps } from "@lib/d/[link]/[slug]/getServerSideProps";
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
export const generateMetadata = async ({
|
||||||
|
params,
|
||||||
export const generateMetadata = async ({ params }: { params: Record<string, string | string[]> }) => {
|
searchParams,
|
||||||
const pageProps = await getPageProps(
|
}: {
|
||||||
buildLegacyCtx(headers(), cookies(), params) as unknown as GetServerSidePropsContext
|
params: Params;
|
||||||
);
|
searchParams: SearchParams;
|
||||||
|
}) => {
|
||||||
|
const pageProps = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
|
||||||
|
|
||||||
const { entity, booking, user, slug, isTeamEvent } = pageProps;
|
const { entity, booking, user, slug, isTeamEvent } = pageProps;
|
||||||
const rescheduleUid = booking?.uid;
|
const rescheduleUid = booking?.uid;
|
||||||
@@ -38,95 +32,5 @@ export const generateMetadata = async ({ params }: { params: Record<string, stri
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
async function getPageProps(context: GetServerSidePropsContext) {
|
const getData = withAppDirSsr(getServerSideProps);
|
||||||
const session = await getServerSession({ req: context.req });
|
|
||||||
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 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = await prisma.user.findFirst({
|
|
||||||
where: {
|
|
||||||
username,
|
|
||||||
organization: isValidOrgDomain
|
|
||||||
? {
|
|
||||||
slug: currentOrgDomain,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
away: true,
|
|
||||||
hideBranding: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
return notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
let booking: GetBookingType | null = null;
|
|
||||||
if (rescheduleUid) {
|
|
||||||
booking = await getBookingForReschedule(`${rescheduleUid}`, session?.user?.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
const isTeamEvent = !!hashedLink.eventType?.team?.id;
|
|
||||||
const ssr = await ssrInit(context);
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
entity: eventData.entity,
|
|
||||||
duration: getMultipleDurationValue(eventData.metadata?.multipleDuration, queryDuration, eventData.length),
|
|
||||||
booking,
|
|
||||||
away: user?.away,
|
|
||||||
user: username,
|
|
||||||
slug,
|
|
||||||
dehydratedState: 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)) });
|
|
||||||
|
|
||||||
// @ts-expect-error arg
|
|
||||||
const getData = withAppDir<PageProps>(getPageProps);
|
|
||||||
export default WithLayout({ getLayout: null, Page: LegacyPage, getData })<"P">;
|
export default WithLayout({ getLayout: null, Page: LegacyPage, getData })<"P">;
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import { WithLayout } from "app/layoutHOC";
|
|
||||||
|
|
||||||
import { getLayout } from "@calcom/features/MainLayoutAppDir";
|
|
||||||
|
|
||||||
export default WithLayout({ getLayout })<"L">;
|
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
|
import { getLayout } from "@calcom/features/MainLayoutAppDir";
|
||||||
|
|
||||||
import EnterprisePage from "@components/EnterprisePage";
|
import EnterprisePage from "@components/EnterprisePage";
|
||||||
|
|
||||||
@@ -8,4 +11,4 @@ export const generateMetadata = async () =>
|
|||||||
(t) => t("create_your_org_description")
|
(t) => t("create_your_org_description")
|
||||||
);
|
);
|
||||||
|
|
||||||
export default EnterprisePage;
|
export default WithLayout({ getLayout, Page: EnterprisePage })<"P">;
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import { WithLayout } from "app/layoutHOC";
|
|
||||||
|
|
||||||
import { getLayout } from "@calcom/features/MainLayoutAppDir";
|
|
||||||
|
|
||||||
export default WithLayout({ getLayout })<"L">;
|
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
import EventTypes from "@pages/event-types";
|
import EventTypes from "@pages/event-types";
|
||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
|
import { getLayout } from "@calcom/features/MainLayoutAppDir";
|
||||||
|
|
||||||
export const generateMetadata = async () =>
|
export const generateMetadata = async () =>
|
||||||
await _generateMetadata(
|
await _generateMetadata(
|
||||||
@@ -7,4 +10,4 @@ export const generateMetadata = async () =>
|
|||||||
(t) => t("event_types_page_subtitle")
|
(t) => t("event_types_page_subtitle")
|
||||||
);
|
);
|
||||||
|
|
||||||
export default EventTypes;
|
export default WithLayout({ getLayout, Page: EventTypes })<"P">;
|
||||||
@@ -1,57 +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 { WithLayout } from "app/layoutHOC";
|
||||||
import { type GetServerSidePropsContext } from "next";
|
|
||||||
import { redirect } from "next/navigation";
|
|
||||||
|
|
||||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
import { getServerSideProps } from "@lib/getting-started/[[...step]]/getServerSideProps";
|
||||||
import prisma from "@calcom/prisma";
|
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
export default WithLayout({ getLayout: null, getData: withAppDirSsr(getServerSideProps), Page });
|
||||||
|
|
||||||
const getData = async (ctx: GetServerSidePropsContext) => {
|
|
||||||
const session = await getServerSession({ req: ctx.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 });
|
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import LegacyPage from "@pages/insights/index";
|
import LegacyPage, { getServerSideProps } from "@pages/insights/index";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
import { notFound } from "next/navigation";
|
|
||||||
|
|
||||||
import { getLayout } from "@calcom/features/MainLayoutAppDir";
|
import { getLayout } from "@calcom/features/MainLayoutAppDir";
|
||||||
import { getFeatureFlagMap } from "@calcom/features/flags/server/utils";
|
|
||||||
|
import { type inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
|
|
||||||
export const generateMetadata = async () =>
|
export const generateMetadata = async () =>
|
||||||
await _generateMetadata(
|
await _generateMetadata(
|
||||||
@@ -12,15 +13,6 @@ export const generateMetadata = async () =>
|
|||||||
(t) => t("insights_subtitle")
|
(t) => t("insights_subtitle")
|
||||||
);
|
);
|
||||||
|
|
||||||
async function getData() {
|
const getData = withAppDirSsr<inferSSRProps<typeof getServerSideProps>>(getServerSideProps);
|
||||||
const prisma = await import("@calcom/prisma").then((mod) => mod.default);
|
|
||||||
const flags = await getFeatureFlagMap(prisma);
|
|
||||||
|
|
||||||
if (flags.insights === false) {
|
|
||||||
return notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default WithLayout({ getLayout, getData, Page: LegacyPage });
|
export default WithLayout({ getLayout, getData, Page: LegacyPage });
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
import { type PageProps } from "@pages/org/[orgSlug]/[user]/[type]";
|
import { type PageProps } from "@pages/org/[orgSlug]/[user]/[type]";
|
||||||
import Page from "@pages/org/[orgSlug]/[user]/[type]/embed";
|
import Page from "@pages/org/[orgSlug]/[user]/[type]/embed";
|
||||||
import { withAppDir } from "app/AppDirSSRHOC";
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
import withEmbedSsrAppDir from "app/WithEmbedSSR";
|
import withEmbedSsrAppDir from "app/WithEmbedSSR";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
import { getServerSideProps } from "@lib/org/[orgSlug]/[user]/[type]/getServerSideProps";
|
import { getServerSideProps } from "@lib/org/[orgSlug]/[user]/[type]/getServerSideProps";
|
||||||
|
|
||||||
const getData = withAppDir<PageProps>(getServerSideProps);
|
const getData = withAppDirSsr<PageProps>(getServerSideProps);
|
||||||
|
|
||||||
const getEmbedData = withEmbedSsrAppDir(getData);
|
const getEmbedData = withEmbedSsrAppDir(getData);
|
||||||
|
|
||||||
export default WithLayout({ getLayout: null, getData: getEmbedData, isBookingPage: true, Page });
|
export default WithLayout({ getLayout: null, getData: getEmbedData, isBookingPage: true, Page });
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import Page, { type PageProps } from "@pages/org/[orgSlug]/[user]/[type]";
|
import Page, { type PageProps } from "@pages/org/[orgSlug]/[user]/[type]";
|
||||||
import { withAppDir } from "app/AppDirSSRHOC";
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
import { getServerSideProps } from "@lib/org/[orgSlug]/[user]/[type]/getServerSideProps";
|
import { getServerSideProps } from "@lib/org/[orgSlug]/[user]/[type]/getServerSideProps";
|
||||||
|
|
||||||
const getData = withAppDir<PageProps>(getServerSideProps);
|
const getData = withAppDirSsr<PageProps>(getServerSideProps);
|
||||||
|
|
||||||
export default WithLayout({ getLayout: null, getData, isBookingPage: true, Page });
|
export default WithLayout({ getLayout: null, getData, isBookingPage: true, Page });
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import { getServerSideProps, type PageProps } from "@pages/org/[orgSlug]/[user]";
|
import { getServerSideProps, type PageProps } from "@pages/org/[orgSlug]/[user]";
|
||||||
import Page from "@pages/org/[orgSlug]/[user]/embed";
|
import Page from "@pages/org/[orgSlug]/[user]/embed";
|
||||||
import { withAppDir } from "app/AppDirSSRHOC";
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
import withEmbedSsrAppDir from "app/WithEmbedSSR";
|
import withEmbedSsrAppDir from "app/WithEmbedSSR";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
const getData = withAppDir<PageProps>(getServerSideProps);
|
const getData = withAppDirSsr<PageProps>(getServerSideProps);
|
||||||
|
|
||||||
const getEmbedData = withEmbedSsrAppDir(getData);
|
const getEmbedData = withEmbedSsrAppDir(getData);
|
||||||
|
|
||||||
export default WithLayout({ getLayout: null, getData: getEmbedData, isBookingPage: true, Page });
|
export default WithLayout({ getLayout: null, getData: getEmbedData, isBookingPage: true, Page });
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import Page, { getServerSideProps, type PageProps } from "@pages/org/[orgSlug]/[user]";
|
import Page, { getServerSideProps, type PageProps } from "@pages/org/[orgSlug]/[user]";
|
||||||
import { withAppDir } from "app/AppDirSSRHOC";
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
const getData = withAppDir<PageProps>(getServerSideProps);
|
const getData = withAppDirSsr<PageProps>(getServerSideProps);
|
||||||
|
|
||||||
export default WithLayout({ getLayout: null, getData, isBookingPage: true, Page });
|
export default WithLayout({ getLayout: null, getData, isBookingPage: true, Page });
|
||||||
@@ -1,18 +1,10 @@
|
|||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
import { type GetServerSidePropsContext } from "next";
|
|
||||||
import { redirect, notFound } from "next/navigation";
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
|
||||||
import PaymentPage from "@calcom/features/ee/payments/components/PaymentPage";
|
import PaymentPage from "@calcom/features/ee/payments/components/PaymentPage";
|
||||||
import { getClientSecretFromPayment } from "@calcom/features/ee/payments/pages/getClientSecretFromPayment";
|
import { getServerSideProps, type PaymentPageProps } from "@calcom/features/ee/payments/pages/payment";
|
||||||
import { APP_NAME } from "@calcom/lib/constants";
|
import { APP_NAME } from "@calcom/lib/constants";
|
||||||
import prisma from "@calcom/prisma";
|
|
||||||
import { BookingStatus } from "@calcom/prisma/enums";
|
|
||||||
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
|
||||||
|
|
||||||
export const generateMetadata = async () =>
|
export const generateMetadata = async () =>
|
||||||
await _generateMetadata(
|
await _generateMetadata(
|
||||||
@@ -21,147 +13,6 @@ export const generateMetadata = async () =>
|
|||||||
() => ""
|
() => ""
|
||||||
);
|
);
|
||||||
|
|
||||||
const querySchema = z.object({
|
const getData = withAppDirSsr<PaymentPageProps>(getServerSideProps);
|
||||||
uid: z.string(),
|
|
||||||
});
|
|
||||||
|
|
||||||
async function getData(context: GetServerSidePropsContext) {
|
|
||||||
const session = await getServerSession({ req: context.req });
|
|
||||||
|
|
||||||
if (!session?.user?.id) {
|
|
||||||
return redirect("/auth/login");
|
|
||||||
}
|
|
||||||
|
|
||||||
const ssr = await ssrInit(context);
|
|
||||||
await ssr.viewer.me.prefetch();
|
|
||||||
|
|
||||||
const { uid } = querySchema.parse(context.params);
|
|
||||||
const rawPayment = await prisma.payment.findFirst({
|
|
||||||
where: {
|
|
||||||
uid,
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
data: true,
|
|
||||||
success: true,
|
|
||||||
uid: true,
|
|
||||||
refunded: true,
|
|
||||||
bookingId: true,
|
|
||||||
appId: true,
|
|
||||||
amount: true,
|
|
||||||
currency: true,
|
|
||||||
paymentOption: true,
|
|
||||||
booking: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
uid: true,
|
|
||||||
description: true,
|
|
||||||
title: true,
|
|
||||||
startTime: true,
|
|
||||||
endTime: true,
|
|
||||||
attendees: {
|
|
||||||
select: {
|
|
||||||
email: true,
|
|
||||||
name: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
eventTypeId: true,
|
|
||||||
location: true,
|
|
||||||
status: true,
|
|
||||||
rejectionReason: true,
|
|
||||||
cancellationReason: true,
|
|
||||||
eventType: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
title: true,
|
|
||||||
description: true,
|
|
||||||
length: true,
|
|
||||||
eventName: true,
|
|
||||||
requiresConfirmation: true,
|
|
||||||
userId: true,
|
|
||||||
metadata: true,
|
|
||||||
users: {
|
|
||||||
select: {
|
|
||||||
name: true,
|
|
||||||
username: true,
|
|
||||||
hideBranding: true,
|
|
||||||
theme: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
team: {
|
|
||||||
select: {
|
|
||||||
name: true,
|
|
||||||
hideBranding: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
price: true,
|
|
||||||
currency: true,
|
|
||||||
successRedirectUrl: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!rawPayment) {
|
|
||||||
return notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
const { data, booking: _booking, ...restPayment } = rawPayment;
|
|
||||||
|
|
||||||
const payment = {
|
|
||||||
...restPayment,
|
|
||||||
data: data as Record<string, unknown>,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!_booking) {
|
|
||||||
return notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
const { startTime, endTime, eventType, ...restBooking } = _booking;
|
|
||||||
const booking = {
|
|
||||||
...restBooking,
|
|
||||||
startTime: startTime.toString(),
|
|
||||||
endTime: endTime.toString(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!eventType) {
|
|
||||||
return notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventType.users.length === 0 && !!!eventType.team) {
|
|
||||||
return notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
const [user] = eventType?.users.length
|
|
||||||
? eventType.users
|
|
||||||
: [{ name: null, theme: null, hideBranding: null, username: null }];
|
|
||||||
const profile = {
|
|
||||||
name: eventType.team?.name || user?.name || null,
|
|
||||||
theme: (!eventType.team?.name && user?.theme) || null,
|
|
||||||
hideBranding: eventType.team?.hideBranding || user?.hideBranding || null,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (
|
|
||||||
([BookingStatus.CANCELLED, BookingStatus.REJECTED] as BookingStatus[]).includes(
|
|
||||||
booking.status as BookingStatus
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return redirect(`/booking/${booking.uid}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
user,
|
|
||||||
eventType: {
|
|
||||||
...eventType,
|
|
||||||
metadata: EventTypeMetaDataSchema.parse(eventType.metadata),
|
|
||||||
},
|
|
||||||
booking,
|
|
||||||
dehydratedState: ssr.dehydrate(),
|
|
||||||
payment,
|
|
||||||
clientSecret: getClientSecretFromPayment(payment),
|
|
||||||
profile,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default WithLayout({ getLayout: null, getData, Page: PaymentPage });
|
export default WithLayout({ getLayout: null, getData, Page: PaymentPage });
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { getServerSideProps } from "@pages/reschedule/[uid]";
|
import { getServerSideProps } from "@pages/reschedule/[uid]";
|
||||||
import { withAppDir } from "app/AppDirSSRHOC";
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
import type { SearchParams } from "app/_types";
|
||||||
import type { Params } from "next/dist/shared/lib/router/utils/route-matcher";
|
import type { Params } from "next/dist/shared/lib/router/utils/route-matcher";
|
||||||
import { cookies, headers } from "next/headers";
|
import { cookies, headers } from "next/headers";
|
||||||
|
|
||||||
@@ -8,12 +9,12 @@ import withEmbedSsr from "@lib/withEmbedSsr";
|
|||||||
|
|
||||||
type PageProps = Readonly<{
|
type PageProps = Readonly<{
|
||||||
params: Params;
|
params: Params;
|
||||||
|
searchParams: SearchParams;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
const Page = async ({ params }: PageProps) => {
|
const Page = async ({ params, searchParams }: PageProps) => {
|
||||||
const legacyCtx = buildLegacyCtx(headers(), cookies(), params);
|
const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams);
|
||||||
// @ts-expect-error Argument of type '{ query: Params; params: Params; req: { headers: ReadonlyHeaders; cookies: ReadonlyRequestCookies; }; }'
|
await withAppDirSsr(withEmbedSsr(getServerSideProps))(legacyCtx);
|
||||||
await withAppDir(withEmbedSsr(getServerSideProps))(legacyCtx);
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import OldPage, { getServerSideProps as _getServerSideProps } from "@pages/reschedule/[uid]";
|
import { getServerSideProps } from "@pages/reschedule/[uid]";
|
||||||
import { withAppDir } from "app/AppDirSSRHOC";
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
import type { SearchParams } from "app/_types";
|
||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
import type { Params } from "next/dist/shared/lib/router/utils/route-matcher";
|
import type { Params } from "next/dist/shared/lib/router/utils/route-matcher";
|
||||||
import { headers, cookies } from "next/headers";
|
import { headers, cookies } from "next/headers";
|
||||||
@@ -14,17 +15,17 @@ export const generateMetadata = async () =>
|
|||||||
|
|
||||||
type PageProps = Readonly<{
|
type PageProps = Readonly<{
|
||||||
params: Params;
|
params: Params;
|
||||||
|
searchParams: SearchParams;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
const getData = withAppDir(_getServerSideProps);
|
const getData = withAppDirSsr(getServerSideProps);
|
||||||
|
|
||||||
const Page = async ({ params }: PageProps) => {
|
const Page = async ({ params, searchParams }: PageProps) => {
|
||||||
const legacyCtx = buildLegacyCtx(headers(), cookies(), params);
|
const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams);
|
||||||
|
|
||||||
// @ts-expect-error Argument of type '{ query: Params; params: Params; req: { headers: ReadonlyHeaders; cookies: ReadonlyRequestCookies; }; }'
|
|
||||||
await getData(legacyCtx);
|
await getData(legacyCtx);
|
||||||
|
|
||||||
return <OldPage />;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Page;
|
export default Page;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
|
const getPageProps = () => {
|
||||||
|
return redirect(`/apps/routing-forms/forms`);
|
||||||
|
};
|
||||||
|
const Page = () => {
|
||||||
|
getPageProps();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { type SearchParams } from "app/_types";
|
||||||
|
import { type GetServerSidePropsContext } from "next";
|
||||||
|
import type { Params } from "next/dist/shared/lib/router/utils/route-matcher";
|
||||||
|
import { cookies, headers } from "next/headers";
|
||||||
|
import { redirect } from "next/navigation";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||||
|
|
||||||
|
const paramsSchema = z
|
||||||
|
.object({
|
||||||
|
pages: z.array(z.string()),
|
||||||
|
})
|
||||||
|
.catch({
|
||||||
|
pages: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const getPageProps = async (context: GetServerSidePropsContext) => {
|
||||||
|
const { pages } = paramsSchema.parse(context.params);
|
||||||
|
|
||||||
|
return redirect(`/apps/routing-forms/${pages.length ? pages.join("/") : ""}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
type PageProps = Readonly<{
|
||||||
|
params: Params;
|
||||||
|
searchParams: SearchParams;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
const Page = async ({ params, searchParams }: PageProps) => {
|
||||||
|
const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams);
|
||||||
|
await getPageProps(legacyCtx as unknown as GetServerSidePropsContext);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -1,36 +1,32 @@
|
|||||||
import { getServerCaller } from "app/_trpc/serverClient";
|
|
||||||
import { type Params } from "app/_types";
|
import { type Params } from "app/_types";
|
||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
import { cookies, headers } from "next/headers";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import Page from "@calcom/features/ee/users/pages/users-edit-view";
|
import Page from "@calcom/features/ee/users/pages/users-edit-view";
|
||||||
import prisma from "@calcom/prisma";
|
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayoutAppDir";
|
||||||
|
|
||||||
const userIdSchema = z.object({ id: z.coerce.number() });
|
const userIdSchema = z.object({ id: z.coerce.number() });
|
||||||
|
|
||||||
export const generateMetadata = async ({ params }: { params: Params }) => {
|
export const generateMetadata = async ({ params }: { params: Params }) => {
|
||||||
const input = userIdSchema.safeParse(params);
|
const input = userIdSchema.safeParse(params);
|
||||||
|
|
||||||
let title = "";
|
|
||||||
if (!input.success) {
|
if (!input.success) {
|
||||||
title = "Editing user";
|
return await _generateMetadata(
|
||||||
} else {
|
() => "",
|
||||||
const req = {
|
() => "Here you can edit a current user."
|
||||||
headers: headers(),
|
);
|
||||||
cookies: cookies(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// @ts-expect-error Type '{ headers: ReadonlyHeaders; cookies: ReadonlyRequestCookies; }' is not assignable to type 'NextApiRequest'
|
|
||||||
const data = await getServerCaller({ req, prisma }).viewer.users.get({ userId: input.data.id });
|
|
||||||
const { user } = data;
|
|
||||||
title = `Editing user: ${user.username}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const userId = input.data.id;
|
||||||
|
const { trpc } = await import("@calcom/trpc");
|
||||||
|
const [data] = trpc.viewer.users.get.useSuspenseQuery({ userId });
|
||||||
|
const { user } = data;
|
||||||
|
const title = `Editing user: ${user.username}`;
|
||||||
|
|
||||||
return await _generateMetadata(
|
return await _generateMetadata(
|
||||||
() => title,
|
() => title,
|
||||||
() => "Here you can edit a current user."
|
() => "Here you can edit a current user."
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Page;
|
export default WithLayout({ getLayout, Page })<"P">;
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
import Page from "@calcom/features/ee/users/pages/users-add-view";
|
import Page from "@calcom/features/ee/users/pages/users-add-view";
|
||||||
|
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayoutAppDir";
|
||||||
|
|
||||||
export const generateMetadata = async () =>
|
export const generateMetadata = async () =>
|
||||||
await _generateMetadata(
|
await _generateMetadata(
|
||||||
@@ -8,4 +10,4 @@ export const generateMetadata = async () =>
|
|||||||
() => "Here you can add a new user."
|
() => "Here you can add a new user."
|
||||||
);
|
);
|
||||||
|
|
||||||
export default Page;
|
export default WithLayout({ getLayout, Page })<"P">;
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import { WithLayout } from "app/layoutHOC";
|
|
||||||
|
|
||||||
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayoutAppDir";
|
|
||||||
|
|
||||||
export default WithLayout({ getLayout })<"L">;
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
import Page from "@calcom/features/ee/users/pages/users-listing-view";
|
import Page from "@calcom/features/ee/users/pages/users-listing-view";
|
||||||
|
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayoutAppDir";
|
||||||
|
|
||||||
export const generateMetadata = async () =>
|
export const generateMetadata = async () =>
|
||||||
await _generateMetadata(
|
await _generateMetadata(
|
||||||
@@ -8,4 +10,4 @@ export const generateMetadata = async () =>
|
|||||||
() => "A list of all the users in your account including their name, title, email and role."
|
() => "A list of all the users in your account including their name, title, email and role."
|
||||||
);
|
);
|
||||||
|
|
||||||
export default Page;
|
export default WithLayout({ getLayout, Page })<"P">;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import LegacyPage, {
|
import LegacyPage, {
|
||||||
buildWrappedOnboardTeamMembersPage,
|
buildWrappedOnboardTeamMembersPage,
|
||||||
} from "@pages/settings/organizations/[id]/onboard-admins";
|
} from "@pages/settings/organizations/[id]/onboard-members";
|
||||||
import { type Params } from "app/_types";
|
import { type Params } from "app/_types";
|
||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
import { headers } from "next/headers";
|
import { headers } from "next/headers";
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import LegacyPage, { WrappedCreateNewOrganizationPage } from "@pages/settings/organizations/new/index";
|
import LegacyPage, { getServerSideProps, LayoutWrapperAppDir } from "@pages/settings/organizations/new/index";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
import { type GetServerSidePropsContext } from "next";
|
|
||||||
import { notFound } from "next/navigation";
|
|
||||||
|
|
||||||
import { getFeatureFlagMap } from "@calcom/features/flags/server/utils";
|
import { type inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
|
|
||||||
export const generateMetadata = async () =>
|
export const generateMetadata = async () =>
|
||||||
await _generateMetadata(
|
await _generateMetadata(
|
||||||
@@ -12,23 +11,8 @@ export const generateMetadata = async () =>
|
|||||||
(t) => t("organizations_description")
|
(t) => t("organizations_description")
|
||||||
);
|
);
|
||||||
|
|
||||||
const getPageProps = async (context: GetServerSidePropsContext) => {
|
|
||||||
const prisma = await import("@calcom/prisma").then((mod) => mod.default);
|
|
||||||
const flags = await getFeatureFlagMap(prisma);
|
|
||||||
// Check if organizations are enabled
|
|
||||||
if (flags["organizations"] !== true) {
|
|
||||||
return notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
const querySlug = context.query.slug as string;
|
|
||||||
|
|
||||||
return {
|
|
||||||
querySlug: querySlug ?? null,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default WithLayout({
|
export default WithLayout({
|
||||||
getLayout: WrappedCreateNewOrganizationPage,
|
getLayout: LayoutWrapperAppDir,
|
||||||
Page: LegacyPage,
|
Page: LegacyPage,
|
||||||
getData: getPageProps,
|
getData: withAppDirSsr<inferSSRProps<typeof getServerSideProps>>(getServerSideProps),
|
||||||
});
|
});
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import LegacyPage, { type SignupProps } from "@pages/signup";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
import { _generateMetadata } from "app/_utils";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
|
import { getServerSideProps } from "@lib/signup/getServerSideProps";
|
||||||
|
|
||||||
|
export const generateMetadata = async () =>
|
||||||
|
await _generateMetadata(
|
||||||
|
(t) => t("sign_up"),
|
||||||
|
(t) => t("sign_up")
|
||||||
|
);
|
||||||
|
|
||||||
|
const getData = withAppDirSsr<SignupProps>(getServerSideProps);
|
||||||
|
|
||||||
|
export default WithLayout({
|
||||||
|
Page: LegacyPage,
|
||||||
|
getLayout: null,
|
||||||
|
getData,
|
||||||
|
})<"P">;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import LegacyPage, { getServerSideProps } from "@pages/team/[slug]/[type]/embed";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
import withEmbedSsrAppDir from "app/WithEmbedSSR";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
|
const getData = withAppDirSsr(getServerSideProps);
|
||||||
|
const getEmbedData = withEmbedSsrAppDir(getData);
|
||||||
|
|
||||||
|
// @ts-expect-error Type is missing the following properties from type: entity, duration, booking, away, and 7 more.
|
||||||
|
export default WithLayout({ getLayout: null, getData: getEmbedData, Page: LegacyPage })<"P">;
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import LegacyPage, { type PageProps, getServerSideProps } from "@pages/team/[slug]/[type]";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
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,
|
||||||
|
searchParams,
|
||||||
|
}: {
|
||||||
|
params: Record<string, string | string[]>;
|
||||||
|
searchParams: { [key: string]: string | string[] | undefined };
|
||||||
|
}) => {
|
||||||
|
const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams);
|
||||||
|
const props = await getData(legacyCtx as unknown as GetServerSidePropsContext);
|
||||||
|
const { entity, user, slug, booking } = props;
|
||||||
|
const { trpc } = await import("@calcom/trpc");
|
||||||
|
const { data: event } = trpc.viewer.public.event.useQuery(
|
||||||
|
{ username: user, eventSlug: slug, isTeamEvent: false, org: entity.orgSlug ?? null },
|
||||||
|
{ refetchOnWindowFocus: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
const profileName = event?.profile?.name ?? "";
|
||||||
|
const title = event?.title ?? "";
|
||||||
|
|
||||||
|
return await _generateMetadata(
|
||||||
|
(t) => `${booking?.uid && !!booking ? t("reschedule") : ""} ${title} | ${profileName}`,
|
||||||
|
(t) => `${booking?.uid ? t("reschedule") : ""} ${title}`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const getData = withAppDirSsr<PageProps>(getServerSideProps);
|
||||||
|
|
||||||
|
export default WithLayout({
|
||||||
|
Page: LegacyPage,
|
||||||
|
getData,
|
||||||
|
getLayout: null,
|
||||||
|
isBookingPage: true,
|
||||||
|
})<"P">;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import LegacyPage, { type PageProps, getServerSideProps } from "@pages/team/[slug]";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
import withEmbedSsrAppDir from "app/WithEmbedSSR";
|
||||||
|
import { WithLayout } from "app/layoutHOC";
|
||||||
|
|
||||||
|
const getData = withAppDirSsr<PageProps>(getServerSideProps);
|
||||||
|
const getEmbedData = withEmbedSsrAppDir(getData);
|
||||||
|
|
||||||
|
export default WithLayout({ getLayout: null, getData: getEmbedData, Page: LegacyPage })<"P">;
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import LegacyPage, { getServerSideProps, type PageProps } from "@pages/team/[slug]";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
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,
|
||||||
|
searchParams,
|
||||||
|
}: {
|
||||||
|
params: Record<string, string | string[]>;
|
||||||
|
searchParams: { [key: string]: string | string[] | undefined };
|
||||||
|
}) => {
|
||||||
|
const props = await getData(
|
||||||
|
buildLegacyCtx(headers(), cookies(), params, searchParams) as unknown as GetServerSidePropsContext
|
||||||
|
);
|
||||||
|
const teamName = props.team.name || "Nameless Team";
|
||||||
|
|
||||||
|
return await _generateMetadata(
|
||||||
|
() => teamName,
|
||||||
|
() => teamName
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getData = withAppDirSsr<PageProps>(getServerSideProps);
|
||||||
|
|
||||||
|
export default WithLayout({
|
||||||
|
Page: LegacyPage,
|
||||||
|
getData,
|
||||||
|
getLayout: null,
|
||||||
|
isBookingPage: true,
|
||||||
|
})<"P">;
|
||||||
@@ -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 { _generateMetadata } from "app/_utils";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
import type { GetServerSidePropsContext } from "next";
|
|
||||||
import { redirect } from "next/navigation";
|
|
||||||
|
|
||||||
import { getLayout } from "@calcom/features/MainLayoutAppDir";
|
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 () =>
|
export const generateMetadata = async () =>
|
||||||
await _generateMetadata(
|
await _generateMetadata(
|
||||||
@@ -15,23 +13,4 @@ export const generateMetadata = async () =>
|
|||||||
(t) => t("create_manage_teams_collaborative")
|
(t) => t("create_manage_teams_collaborative")
|
||||||
);
|
);
|
||||||
|
|
||||||
async function getData(context: GetServerSidePropsContext) {
|
export default WithLayout({ getData: withAppDirSsr(getServerSideProps), getLayout, Page })<"P">;
|
||||||
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">;
|
|
||||||
@@ -1,15 +1,11 @@
|
|||||||
import OldPage from "@pages/video/[uid]";
|
import Page, { type JoinCallPageProps } from "@pages/video/[uid]";
|
||||||
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
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 { 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 () =>
|
export const generateMetadata = async () =>
|
||||||
await _generateMetadata(
|
await _generateMetadata(
|
||||||
@@ -17,86 +13,6 @@ export const generateMetadata = async () =>
|
|||||||
(t) => t("quick_video_meeting")
|
(t) => t("quick_video_meeting")
|
||||||
);
|
);
|
||||||
|
|
||||||
const md = new MarkdownIt("default", { html: true, breaks: true, linkify: true });
|
const getData = withAppDirSsr<JoinCallPageProps>(getServerSideProps);
|
||||||
|
|
||||||
async function getData(context: GetServerSidePropsContext) {
|
export default WithLayout({ getData, Page, getLayout: null })<"P">;
|
||||||
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">;
|
|
||||||
@@ -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 { _generateMetadata } from "app/_utils";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
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 () =>
|
export const generateMetadata = async () =>
|
||||||
await _generateMetadata(
|
await _generateMetadata(
|
||||||
@@ -12,41 +11,6 @@ export const generateMetadata = async () =>
|
|||||||
() => "Meeting Unavailable"
|
() => "Meeting Unavailable"
|
||||||
);
|
);
|
||||||
|
|
||||||
async function getData(context: Omit<GetServerSidePropsContext, "res" | "resolvedUrl">) {
|
const getData = withAppDirSsr(getServerSideProps);
|
||||||
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,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!booking) {
|
export default WithLayout({ getData, Page, getLayout: null })<"P">;
|
||||||
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">;
|
|
||||||
@@ -1,15 +1,12 @@
|
|||||||
import OldPage from "@pages/video/meeting-not-started/[uid]";
|
import Page from "@pages/video/meeting-not-started/[uid]";
|
||||||
import { type Params } from "app/_types";
|
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||||
|
import type { PageProps } from "app/_types";
|
||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
import { type GetServerSidePropsContext } from "next";
|
|
||||||
import { redirect } from "next/navigation";
|
|
||||||
|
|
||||||
import prisma, { bookingMinimalSelect } from "@calcom/prisma";
|
import prisma, { bookingMinimalSelect } from "@calcom/prisma";
|
||||||
|
|
||||||
type PageProps = Readonly<{
|
import { getServerSideProps } from "@lib/video/meeting-not-started/[uid]/getServerSideProps";
|
||||||
params: Params;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export const generateMetadata = async ({ params }: PageProps) => {
|
export const generateMetadata = async ({ params }: PageProps) => {
|
||||||
const booking = await prisma.booking.findUnique({
|
const booking = await prisma.booking.findUnique({
|
||||||
@@ -25,26 +22,6 @@ export const generateMetadata = async ({ params }: PageProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
async function getData(context: Omit<GetServerSidePropsContext, "res" | "resolvedUrl">) {
|
const getData = withAppDirSsr(getServerSideProps);
|
||||||
const booking = await prisma.booking.findUnique({
|
|
||||||
where: {
|
|
||||||
uid: typeof context?.params?.uid === "string" ? context.params.uid : "",
|
|
||||||
},
|
|
||||||
select: bookingMinimalSelect,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!booking) {
|
export default WithLayout({ getData, Page, getLayout: null })<"P">;
|
||||||
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">;
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import LegacyPage from "@pages/video/no-meeting-found";
|
import LegacyPage from "@pages/video/no-meeting-found";
|
||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
import { type GetServerSidePropsContext } from "next";
|
import type { GetServerSidePropsContext } from "next";
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
import { ssrInit } from "@server/lib/ssr";
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ export const generateMetadata = async () =>
|
|||||||
(t) => t("no_meeting_found")
|
(t) => t("no_meeting_found")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ssr was added by Intuita, legacy page does not have it
|
||||||
const getData = async (context: GetServerSidePropsContext) => {
|
const getData = async (context: GetServerSidePropsContext) => {
|
||||||
const ssr = await ssrInit(context);
|
const ssr = await ssrInit(context);
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
|
import LegacyPage, { getStaticProps } from "@pages/workflows/[workflow]";
|
||||||
|
import { withAppDirSsg } from "app/WithAppDirSsg";
|
||||||
import { _generateMetadata } from "app/_utils";
|
import { _generateMetadata } from "app/_utils";
|
||||||
import { WithLayout } from "app/layoutHOC";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
import { type GetServerSidePropsContext } from "next";
|
import { type GetServerSidePropsContext } from "next";
|
||||||
import { headers, cookies } from "next/headers";
|
import { headers, cookies } from "next/headers";
|
||||||
import { notFound } from "next/navigation";
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
import LegacyPage from "@calcom/features/ee/workflows/pages/workflow";
|
|
||||||
|
|
||||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||||
|
|
||||||
const querySchema = z.object({
|
export const generateMetadata = async ({
|
||||||
workflow: z.string(),
|
params,
|
||||||
});
|
searchParams,
|
||||||
|
}: {
|
||||||
export const generateMetadata = async ({ params }: { params: Record<string, string | string[]> }) => {
|
params: Record<string, string | string[]>;
|
||||||
const { workflow } = await getProps(
|
searchParams: { [key: string]: string | string[] | undefined };
|
||||||
buildLegacyCtx(headers(), cookies(), params) as unknown as GetServerSidePropsContext
|
}) => {
|
||||||
|
const { workflow } = await getData(
|
||||||
|
buildLegacyCtx(headers(), cookies(), params, searchParams) as unknown as GetServerSidePropsContext
|
||||||
);
|
);
|
||||||
return await _generateMetadata(
|
return await _generateMetadata(
|
||||||
() => workflow ?? "Untitled",
|
() => workflow ?? "Untitled",
|
||||||
@@ -23,19 +23,12 @@ export const generateMetadata = async ({ params }: { params: Record<string, stri
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
async function getProps(context: GetServerSidePropsContext) {
|
const getData = withAppDirSsg(getStaticProps);
|
||||||
const safeParams = querySchema.safeParse(context.params);
|
|
||||||
|
|
||||||
console.log("Built workflow page:", safeParams);
|
|
||||||
if (!safeParams.success) {
|
|
||||||
return notFound();
|
|
||||||
}
|
|
||||||
return { workflow: safeParams.data.workflow };
|
|
||||||
}
|
|
||||||
|
|
||||||
export const generateStaticParams = () => [];
|
export const generateStaticParams = () => [];
|
||||||
|
|
||||||
export default WithLayout({ getLayout: null, getData: getProps, Page: LegacyPage })<"P">;
|
// @ts-expect-error TODO: fix this
|
||||||
|
export default WithLayout({ getLayout: null, getData, Page: LegacyPage })<"P">;
|
||||||
export const dynamic = "force-static";
|
export const dynamic = "force-static";
|
||||||
// generate segments on demand
|
// generate segments on demand
|
||||||
export const dynamicParams = true;
|
export const dynamicParams = true;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import PageWrapper from "@components/PageWrapperAppDir";
|
|||||||
type WithLayoutParams<T extends Record<string, any>> = {
|
type WithLayoutParams<T extends Record<string, any>> = {
|
||||||
getLayout: ((page: React.ReactElement) => React.ReactNode) | null;
|
getLayout: ((page: React.ReactElement) => React.ReactNode) | null;
|
||||||
Page?: (props: T) => React.ReactElement | null;
|
Page?: (props: T) => React.ReactElement | null;
|
||||||
getData?: (arg: GetServerSidePropsContext) => Promise<T>;
|
getData?: (arg: GetServerSidePropsContext) => Promise<T | undefined>;
|
||||||
isBookingPage?: boolean;
|
isBookingPage?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -22,9 +22,11 @@ export function WithLayout<T extends Record<string, any>>({
|
|||||||
return async <P extends "P" | "L">(p: P extends "P" ? PageProps : LayoutProps) => {
|
return async <P extends "P" | "L">(p: P extends "P" ? PageProps : LayoutProps) => {
|
||||||
const h = headers();
|
const h = headers();
|
||||||
const nonce = h.get("x-nonce") ?? undefined;
|
const nonce = h.get("x-nonce") ?? undefined;
|
||||||
const props = getData
|
let props = {} as T;
|
||||||
? await getData(buildLegacyCtx(h, cookies(), p.params) as unknown as GetServerSidePropsContext)
|
|
||||||
: ({} as T);
|
if ("searchParams" in p && getData) {
|
||||||
|
props = (await getData(buildLegacyCtx(h, cookies(), p.params, p.searchParams))) ?? ({} as T);
|
||||||
|
}
|
||||||
|
|
||||||
const children = "children" in p ? p.children : null;
|
const children = "children" in p ? p.children : null;
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ import NotFoundPage from "@pages/404";
|
|||||||
import { WithLayout } from "app/layoutHOC";
|
import { WithLayout } from "app/layoutHOC";
|
||||||
import type { GetStaticPropsContext } from "next";
|
import type { GetStaticPropsContext } from "next";
|
||||||
|
|
||||||
import { ssgInit } from "@server/lib/ssg";
|
import { getTranslations } from "@server/lib/getTranslations";
|
||||||
|
|
||||||
const getData = async (context: GetStaticPropsContext) => {
|
const getData = async (context: GetStaticPropsContext) => {
|
||||||
const ssg = await ssgInit(context);
|
const i18n = await getTranslations(context);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dehydratedState: ssg.dehydrate(),
|
i18n,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -89,8 +89,7 @@ function PageWrapper(props: AppProps) {
|
|||||||
</LicenseRequired>
|
</LicenseRequired>
|
||||||
) : (
|
) : (
|
||||||
<Component {...pageProps} err={err} />
|
<Component {...pageProps} err={err} />
|
||||||
),
|
)
|
||||||
router
|
|
||||||
)}
|
)}
|
||||||
</AppProviders>
|
</AppProviders>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -528,7 +528,10 @@ const IntervalLimitItem = ({
|
|||||||
onIntervalSelect,
|
onIntervalSelect,
|
||||||
}: IntervalLimitItemProps) => {
|
}: IntervalLimitItemProps) => {
|
||||||
return (
|
return (
|
||||||
<div className="mb-4 flex max-h-9 items-center space-x-2 text-sm rtl:space-x-reverse" key={limitKey}>
|
<div
|
||||||
|
data-testid="add-limit"
|
||||||
|
className="mb-4 flex max-h-9 items-center space-x-2 text-sm rtl:space-x-reverse"
|
||||||
|
key={limitKey}>
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
type="number"
|
type="number"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { Webhook } from "@prisma/client";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import type { EventTypeSetup, FormValues } from "pages/event-types/[type]";
|
import type { EventTypeSetup, FormValues } from "pages/event-types/[type]";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
@@ -5,10 +6,16 @@ import { useFormContext } from "react-hook-form";
|
|||||||
|
|
||||||
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
|
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
|
||||||
import useLockedFieldsManager from "@calcom/features/ee/managed-event-types/hooks/useLockedFieldsManager";
|
import useLockedFieldsManager from "@calcom/features/ee/managed-event-types/hooks/useLockedFieldsManager";
|
||||||
|
import { WebhookForm } from "@calcom/features/webhooks/components";
|
||||||
|
import type { WebhookFormSubmitData } from "@calcom/features/webhooks/components/WebhookForm";
|
||||||
|
import WebhookListItem from "@calcom/features/webhooks/components/WebhookListItem";
|
||||||
|
import { subscriberUrlReserved } from "@calcom/features/webhooks/lib/subscriberUrlReserved";
|
||||||
import { classNames } from "@calcom/lib";
|
import { classNames } from "@calcom/lib";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { Alert, Button, EmptyScreen, SettingsToggle } from "@calcom/ui";
|
import { WebhookTriggerEvents } from "@calcom/prisma/enums";
|
||||||
import { PhoneCall } from "@calcom/ui/components/icon";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
|
import { Alert, Button, EmptyScreen, SettingsToggle, Dialog, DialogContent, showToast } from "@calcom/ui";
|
||||||
|
import { PhoneCall, Plus, Lock, Webhook as TbWebhook } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
type InstantEventControllerProps = {
|
type InstantEventControllerProps = {
|
||||||
eventType: EventTypeSetup;
|
eventType: EventTypeSetup;
|
||||||
@@ -82,11 +89,7 @@ export default function InstantEventController({
|
|||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<div className="border-subtle rounded-b-lg border border-t-0 p-6">
|
<div className="border-subtle rounded-b-lg border border-t-0 p-6">
|
||||||
{instantEventState && (
|
{instantEventState && <InstantMeetingWebhooks eventType={eventType} />}
|
||||||
<div data-testid="instant-event-collapsible" className="flex flex-col gap-2 text-sm">
|
|
||||||
<p>{t("warning_payment_instant_meeting_event")}</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</SettingsToggle>
|
</SettingsToggle>
|
||||||
</>
|
</>
|
||||||
@@ -97,3 +100,201 @@ export default function InstantEventController({
|
|||||||
</LicenseRequired>
|
</LicenseRequired>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const InstantMeetingWebhooks = ({ eventType }: { eventType: EventTypeSetup }) => {
|
||||||
|
const { t } = useLocale();
|
||||||
|
const utils = trpc.useContext();
|
||||||
|
const { data: webhooks } = trpc.viewer.webhook.list.useQuery({
|
||||||
|
eventTypeId: eventType.id,
|
||||||
|
eventTriggers: [WebhookTriggerEvents.INSTANT_MEETING],
|
||||||
|
});
|
||||||
|
const { data: installedApps, isLoading } = trpc.viewer.integrations.useQuery({
|
||||||
|
variant: "other",
|
||||||
|
onlyInstalled: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const [createModalOpen, setCreateModalOpen] = useState(false);
|
||||||
|
const [editModalOpen, setEditModalOpen] = useState(false);
|
||||||
|
const [webhookToEdit, setWebhookToEdit] = useState<Webhook>();
|
||||||
|
|
||||||
|
const editWebhookMutation = trpc.viewer.webhook.edit.useMutation({
|
||||||
|
async onSuccess() {
|
||||||
|
setEditModalOpen(false);
|
||||||
|
await utils.viewer.webhook.list.invalidate();
|
||||||
|
showToast(t("webhook_updated_successfully"), "success");
|
||||||
|
},
|
||||||
|
onError(error) {
|
||||||
|
showToast(`${error.message}`, "error");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const createWebhookMutation = trpc.viewer.webhook.create.useMutation({
|
||||||
|
async onSuccess() {
|
||||||
|
showToast(t("webhook_created_successfully"), "success");
|
||||||
|
await utils.viewer.webhook.list.invalidate();
|
||||||
|
setCreateModalOpen(false);
|
||||||
|
},
|
||||||
|
onError(error) {
|
||||||
|
showToast(`${error.message}`, "error");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const onCreateWebhook = async (values: WebhookFormSubmitData) => {
|
||||||
|
if (
|
||||||
|
subscriberUrlReserved({
|
||||||
|
subscriberUrl: values.subscriberUrl,
|
||||||
|
id: values.id,
|
||||||
|
webhooks,
|
||||||
|
eventTypeId: eventType.id,
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
showToast(t("webhook_subscriber_url_reserved"), "error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!values.payloadTemplate) {
|
||||||
|
values.payloadTemplate = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
createWebhookMutation.mutate({
|
||||||
|
subscriberUrl: values.subscriberUrl,
|
||||||
|
eventTriggers: values.eventTriggers,
|
||||||
|
active: values.active,
|
||||||
|
payloadTemplate: values.payloadTemplate,
|
||||||
|
secret: values.secret,
|
||||||
|
eventTypeId: eventType.id,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const NewWebhookButton = () => {
|
||||||
|
const { t } = useLocale();
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
color="secondary"
|
||||||
|
data-testid="new_webhook"
|
||||||
|
StartIcon={Plus}
|
||||||
|
onClick={() => setCreateModalOpen(true)}>
|
||||||
|
{t("new_webhook")}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { shouldLockDisableProps, isChildrenManagedEventType, isManagedEventType } = useLockedFieldsManager(
|
||||||
|
eventType,
|
||||||
|
t("locked_fields_admin_description"),
|
||||||
|
t("locked_fields_member_description")
|
||||||
|
);
|
||||||
|
const webhookLockedStatus = shouldLockDisableProps("webhooks");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{webhooks && !isLoading && (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
{webhooks.length ? (
|
||||||
|
<>
|
||||||
|
<div className="border-subtle my-2 rounded-md border">
|
||||||
|
{webhooks.map((webhook, index) => {
|
||||||
|
return (
|
||||||
|
<WebhookListItem
|
||||||
|
key={webhook.id}
|
||||||
|
webhook={webhook}
|
||||||
|
lastItem={webhooks.length === index + 1}
|
||||||
|
canEditWebhook={!webhookLockedStatus.disabled}
|
||||||
|
onEditWebhook={() => {
|
||||||
|
setEditModalOpen(true);
|
||||||
|
setWebhookToEdit(webhook);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<p className="text-default text-sm font-normal">
|
||||||
|
{t("warning_payment_instant_meeting_event")}
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<p className="text-default mb-4 text-sm font-normal">
|
||||||
|
{t("warning_payment_instant_meeting_event")}
|
||||||
|
</p>
|
||||||
|
<EmptyScreen
|
||||||
|
Icon={TbWebhook}
|
||||||
|
headline={t("create_your_first_webhook")}
|
||||||
|
description={t("create_instant_meeting_webhook_description")}
|
||||||
|
buttonRaw={
|
||||||
|
isChildrenManagedEventType && !isManagedEventType ? (
|
||||||
|
<Button StartIcon={Lock} color="secondary" disabled>
|
||||||
|
{t("locked_by_admin")}
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<NewWebhookButton />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* New webhook dialog */}
|
||||||
|
<Dialog open={createModalOpen} onOpenChange={(isOpen) => !isOpen && setCreateModalOpen(false)}>
|
||||||
|
<DialogContent
|
||||||
|
enableOverflow
|
||||||
|
title={t("create_webhook")}
|
||||||
|
description={t("create_webhook_team_event_type")}>
|
||||||
|
<WebhookForm
|
||||||
|
noRoutingFormTriggers={true}
|
||||||
|
onSubmit={onCreateWebhook}
|
||||||
|
onCancel={() => setCreateModalOpen(false)}
|
||||||
|
apps={installedApps?.items.map((app) => app.slug)}
|
||||||
|
selectOnlyInstantMeetingOption={true}
|
||||||
|
/>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
{/* Edit webhook dialog */}
|
||||||
|
<Dialog open={editModalOpen} onOpenChange={(isOpen) => !isOpen && setEditModalOpen(false)}>
|
||||||
|
<DialogContent enableOverflow title={t("edit_webhook")}>
|
||||||
|
<WebhookForm
|
||||||
|
noRoutingFormTriggers={true}
|
||||||
|
webhook={webhookToEdit}
|
||||||
|
apps={installedApps?.items.map((app) => app.slug)}
|
||||||
|
onCancel={() => setEditModalOpen(false)}
|
||||||
|
onSubmit={(values: WebhookFormSubmitData) => {
|
||||||
|
if (
|
||||||
|
subscriberUrlReserved({
|
||||||
|
subscriberUrl: values.subscriberUrl,
|
||||||
|
id: webhookToEdit?.id,
|
||||||
|
webhooks,
|
||||||
|
eventTypeId: eventType.id,
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
showToast(t("webhook_subscriber_url_reserved"), "error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.changeSecret) {
|
||||||
|
values.secret = values.newSecret.length ? values.newSecret : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!values.payloadTemplate) {
|
||||||
|
values.payloadTemplate = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
editWebhookMutation.mutate({
|
||||||
|
id: webhookToEdit?.id || "",
|
||||||
|
subscriberUrl: values.subscriberUrl,
|
||||||
|
eventTriggers: values.eventTriggers,
|
||||||
|
active: values.active,
|
||||||
|
payloadTemplate: values.payloadTemplate,
|
||||||
|
secret: values.secret,
|
||||||
|
eventTypeId: webhookToEdit?.eventTypeId || undefined,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -37,6 +37,7 @@ export type AppProps = Omit<
|
|||||||
WithNonceProps<{
|
WithNonceProps<{
|
||||||
themeBasis?: string;
|
themeBasis?: string;
|
||||||
session: Session;
|
session: Session;
|
||||||
|
i18n?: SSRConfig;
|
||||||
}>
|
}>
|
||||||
>
|
>
|
||||||
>,
|
>,
|
||||||
@@ -46,7 +47,7 @@ export type AppProps = Omit<
|
|||||||
requiresLicense?: boolean;
|
requiresLicense?: boolean;
|
||||||
isThemeSupported?: boolean;
|
isThemeSupported?: boolean;
|
||||||
isBookingPage?: boolean | ((arg: { router: NextAppProps["router"] }) => boolean);
|
isBookingPage?: boolean | ((arg: { router: NextAppProps["router"] }) => boolean);
|
||||||
getLayout?: (page: React.ReactElement, router: NextAppProps["router"]) => ReactNode;
|
getLayout?: (page: React.ReactElement) => ReactNode;
|
||||||
PageWrapper?: (props: AppProps) => JSX.Element;
|
PageWrapper?: (props: AppProps) => JSX.Element;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -108,7 +109,7 @@ const CustomI18nextProvider = (props: AppPropsWithoutNonce) => {
|
|||||||
}, [locale]);
|
}, [locale]);
|
||||||
|
|
||||||
const clientViewerI18n = useViewerI18n(locale);
|
const clientViewerI18n = useViewerI18n(locale);
|
||||||
const i18n = clientViewerI18n.data?.i18n;
|
const i18n = clientViewerI18n.data?.i18n ?? props.pageProps.i18n;
|
||||||
|
|
||||||
const passedProps = {
|
const passedProps = {
|
||||||
...props,
|
...props,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -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,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -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 } = context;
|
||||||
|
|
||||||
|
const ssr = await ssrInit(context);
|
||||||
|
|
||||||
|
const session = await getServerSession({ 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<string, number>);
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
categories: Object.entries(categories).map(([name, count]) => ({ name, count })),
|
||||||
|
trpcState: ssr.dehydrate(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -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 } = context;
|
||||||
|
|
||||||
|
const ssr = await ssrInit(context);
|
||||||
|
|
||||||
|
const session = await getServerSession({ 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<string, number>);
|
||||||
|
|
||||||
|
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(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import type { GetServerSidePropsContext } from "next";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { AppCategories } from "@calcom/prisma/enums";
|
||||||
|
|
||||||
|
export type querySchemaType = z.infer<typeof querySchema>;
|
||||||
|
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export async function getServerSideProps() {
|
||||||
|
return { redirect: { permanent: false, destination: "/apps/installed/calendar" } };
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { type GetStaticProps } from "next";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { getTranslations } from "@server/lib/getTranslations";
|
||||||
|
|
||||||
|
const validStatuses = ["upcoming", "recurring", "past", "cancelled", "unconfirmed"] as const;
|
||||||
|
|
||||||
|
const querySchema = z.object({
|
||||||
|
status: z.enum(validStatuses),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getStaticProps: GetStaticProps = async (ctx) => {
|
||||||
|
const params = querySchema.safeParse(ctx.params);
|
||||||
|
const i18n = await getTranslations(ctx);
|
||||||
|
|
||||||
|
if (!params.success) return { notFound: true };
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
status: params.data.status,
|
||||||
|
i18n,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,23 +1,49 @@
|
|||||||
|
import type { SearchParams } from "app/_types";
|
||||||
import { type Params } from "app/_types";
|
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 ReadonlyHeaders } from "next/dist/server/web/spec-extension/adapters/headers";
|
||||||
import { type ReadonlyRequestCookies } from "next/dist/server/web/spec-extension/adapters/request-cookies";
|
import { type ReadonlyRequestCookies } from "next/dist/server/web/spec-extension/adapters/request-cookies";
|
||||||
|
|
||||||
// returns query object same as ctx.query but for app dir
|
const createProxifiedObject = (object: Record<string, string>) =>
|
||||||
export const getQuery = (url: string, params: Params) => {
|
new Proxy(object, {
|
||||||
if (!url.length) {
|
set: () => {
|
||||||
return params;
|
throw new Error("You are trying to modify 'headers' or 'cookies', which is not supported in app dir");
|
||||||
}
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const { searchParams } = new URL(url);
|
const buildLegacyHeaders = (headers: ReadonlyHeaders) => {
|
||||||
const searchParamsObj = Object.fromEntries(searchParams.entries());
|
const headersObject = Object.fromEntries(headers.entries());
|
||||||
|
|
||||||
return { ...searchParamsObj, ...params };
|
return createProxifiedObject(headersObject);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const buildLegacyCtx = (headers: ReadonlyHeaders, cookies: ReadonlyRequestCookies, params: Params) => {
|
const buildLegacyCookies = (cookies: ReadonlyRequestCookies) => {
|
||||||
|
const cookiesObject = cookies.getAll().reduce<Record<string, string>>((acc, { name, value }) => {
|
||||||
|
acc[name] = value;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
return createProxifiedObject(cookiesObject);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const buildLegacyCtx = (
|
||||||
|
headers: ReadonlyHeaders,
|
||||||
|
cookies: ReadonlyRequestCookies,
|
||||||
|
params: Params,
|
||||||
|
searchParams: SearchParams
|
||||||
|
) => {
|
||||||
return {
|
return {
|
||||||
query: getQuery(headers.get("x-url") ?? "", params),
|
query: { ...searchParams, ...params },
|
||||||
params,
|
params,
|
||||||
req: { headers, cookies },
|
req: { headers: buildLegacyHeaders(headers), cookies: buildLegacyCookies(cookies) },
|
||||||
};
|
res: new Proxy(Object.create(null), {
|
||||||
|
// const { req, res } = ctx - valid
|
||||||
|
// res.anything - throw
|
||||||
|
get() {
|
||||||
|
throw new Error(
|
||||||
|
"You are trying to access the 'res' property of the context, which is not supported in app dir"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
} as unknown as GetServerSidePropsContext;
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
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<typeof getServerSideProps> & 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;
|
||||||
|
|
||||||
|
const notFound = {
|
||||||
|
notFound: true,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
if (!hashedLink || !username) {
|
||||||
|
return notFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await prisma.user.findFirst({
|
||||||
|
where: {
|
||||||
|
username,
|
||||||
|
organization: isValidOrgDomain
|
||||||
|
? {
|
||||||
|
slug: currentOrgDomain,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
away: true,
|
||||||
|
hideBranding: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return notFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
@@ -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<typeof getServerSideProps>;
|
||||||
|
|
||||||
|
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(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// returns query object same as ctx.query but for app dir
|
||||||
|
export const getQuery = (url: string, params: Record<string, string | string[]>) => {
|
||||||
|
if (!url.length) {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { searchParams } = new URL(url);
|
||||||
|
const searchParamsObj = Object.fromEntries(searchParams.entries());
|
||||||
|
|
||||||
|
return { ...searchParamsObj, ...params };
|
||||||
|
};
|
||||||
@@ -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 } = context;
|
||||||
|
|
||||||
|
const session = await getServerSession({ req });
|
||||||
|
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { getFeatureFlagMap } from "@calcom/features/flags/server/utils";
|
||||||
|
|
||||||
|
// If feature flag is disabled, return not found on getServerSideProps
|
||||||
|
export const getServerSideProps = async () => {
|
||||||
|
const prisma = await import("@calcom/prisma").then((mod) => mod.default);
|
||||||
|
const flags = await getFeatureFlagMap(prisma);
|
||||||
|
|
||||||
|
if (flags.insights === false) {
|
||||||
|
return {
|
||||||
|
notFound: true,
|
||||||
|
} as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { props: {} };
|
||||||
|
};
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import type { GetServerSidePropsContext } from "next";
|
||||||
|
|
||||||
|
import { getFeatureFlagMap } from "@calcom/features/flags/server/utils";
|
||||||
|
|
||||||
|
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||||
|
const prisma = await import("@calcom/prisma").then((mod) => mod.default);
|
||||||
|
const flags = await getFeatureFlagMap(prisma);
|
||||||
|
// Check if organizations are enabled
|
||||||
|
if (flags["organizations"] !== true) {
|
||||||
|
return {
|
||||||
|
notFound: true,
|
||||||
|
} as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
const querySlug = context.query.slug as string;
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
querySlug: querySlug ?? null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
import type { GetServerSidePropsContext } from "next";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { getOrgUsernameFromEmail } from "@calcom/features/auth/signup/utils/getOrgUsernameFromEmail";
|
||||||
|
import { checkPremiumUsername } from "@calcom/features/ee/common/lib/checkPremiumUsername";
|
||||||
|
import { isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml";
|
||||||
|
import { getFeatureFlagMap } from "@calcom/features/flags/server/utils";
|
||||||
|
import { IS_SELF_HOSTED, WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
|
import slugify from "@calcom/lib/slugify";
|
||||||
|
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||||
|
|
||||||
|
import { IS_GOOGLE_LOGIN_ENABLED } from "@server/lib/constants";
|
||||||
|
import { ssrInit } from "@server/lib/ssr";
|
||||||
|
|
||||||
|
const checkValidEmail = (email: string) => z.string().email().safeParse(email).success;
|
||||||
|
|
||||||
|
const querySchema = z.object({
|
||||||
|
username: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.transform((val) => val || ""),
|
||||||
|
email: z.string().email().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
|
||||||
|
const prisma = await import("@calcom/prisma").then((mod) => mod.default);
|
||||||
|
const flags = await getFeatureFlagMap(prisma);
|
||||||
|
const ssr = await ssrInit(ctx);
|
||||||
|
const token = z.string().optional().parse(ctx.query.token);
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
isGoogleLoginEnabled: IS_GOOGLE_LOGIN_ENABLED,
|
||||||
|
isSAMLLoginEnabled,
|
||||||
|
trpcState: ssr.dehydrate(),
|
||||||
|
prepopulateFormValues: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
// username + email prepopulated from query params
|
||||||
|
const { username: preFillusername, email: prefilEmail } = querySchema.parse(ctx.query);
|
||||||
|
|
||||||
|
if ((process.env.NEXT_PUBLIC_DISABLE_SIGNUP === "true" && !token) || flags["disable-signup"]) {
|
||||||
|
return {
|
||||||
|
notFound: true,
|
||||||
|
} as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no token given, treat as a normal signup without verification token
|
||||||
|
if (!token) {
|
||||||
|
return {
|
||||||
|
props: JSON.parse(
|
||||||
|
JSON.stringify({
|
||||||
|
...props,
|
||||||
|
prepopulateFormValues: {
|
||||||
|
username: preFillusername || null,
|
||||||
|
email: prefilEmail || null,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const verificationToken = await prisma.verificationToken.findUnique({
|
||||||
|
where: {
|
||||||
|
token,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
team: {
|
||||||
|
select: {
|
||||||
|
metadata: true,
|
||||||
|
parentId: true,
|
||||||
|
parent: {
|
||||||
|
select: {
|
||||||
|
slug: true,
|
||||||
|
metadata: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
slug: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!verificationToken || verificationToken.expires < new Date()) {
|
||||||
|
return {
|
||||||
|
notFound: true,
|
||||||
|
} as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingUser = await prisma.user.findFirst({
|
||||||
|
where: {
|
||||||
|
AND: [
|
||||||
|
{
|
||||||
|
email: verificationToken?.identifier,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
emailVerified: {
|
||||||
|
not: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (existingUser) {
|
||||||
|
return {
|
||||||
|
redirect: {
|
||||||
|
permanent: false,
|
||||||
|
destination: `/auth/login?callbackUrl=${WEBAPP_URL}/${ctx.query.callbackUrl}`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const guessUsernameFromEmail = (email: string) => {
|
||||||
|
const [username] = email.split("@");
|
||||||
|
return username;
|
||||||
|
};
|
||||||
|
|
||||||
|
let username = guessUsernameFromEmail(verificationToken.identifier);
|
||||||
|
|
||||||
|
const tokenTeam = {
|
||||||
|
...verificationToken?.team,
|
||||||
|
metadata: teamMetadataSchema.parse(verificationToken?.team?.metadata),
|
||||||
|
};
|
||||||
|
|
||||||
|
const isATeamInOrganization = tokenTeam?.parentId !== null;
|
||||||
|
const isOrganization = tokenTeam.metadata?.isOrganization;
|
||||||
|
// Detect if the team is an org by either the metadata flag or if it has a parent team
|
||||||
|
const isOrganizationOrATeamInOrganization = isOrganization || isATeamInOrganization;
|
||||||
|
// If we are dealing with an org, the slug may come from the team itself or its parent
|
||||||
|
const orgSlug = isOrganizationOrATeamInOrganization
|
||||||
|
? tokenTeam.metadata?.requestedSlug || tokenTeam.parent?.slug || tokenTeam.slug
|
||||||
|
: null;
|
||||||
|
|
||||||
|
// Org context shouldn't check if a username is premium
|
||||||
|
if (!IS_SELF_HOSTED && !isOrganizationOrATeamInOrganization) {
|
||||||
|
// Im not sure we actually hit this because of next redirects signup to website repo - but just in case this is pretty cool :)
|
||||||
|
const { available, suggestion } = await checkPremiumUsername(username);
|
||||||
|
|
||||||
|
username = available ? username : suggestion || username;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isValidEmail = checkValidEmail(verificationToken.identifier);
|
||||||
|
const isOrgInviteByLink = isOrganizationOrATeamInOrganization && !isValidEmail;
|
||||||
|
const parentMetaDataForSubteam = tokenTeam?.parent?.metadata
|
||||||
|
? teamMetadataSchema.parse(tokenTeam.parent.metadata)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
...props,
|
||||||
|
token,
|
||||||
|
prepopulateFormValues: !isOrgInviteByLink
|
||||||
|
? {
|
||||||
|
email: verificationToken.identifier,
|
||||||
|
username: isOrganizationOrATeamInOrganization
|
||||||
|
? getOrgUsernameFromEmail(
|
||||||
|
verificationToken.identifier,
|
||||||
|
(isOrganization
|
||||||
|
? tokenTeam.metadata?.orgAutoAcceptEmail
|
||||||
|
: parentMetaDataForSubteam?.orgAutoAcceptEmail) || ""
|
||||||
|
)
|
||||||
|
: slugify(username),
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
orgSlug,
|
||||||
|
orgAutoAcceptEmail: isOrgInviteByLink
|
||||||
|
? tokenTeam?.metadata?.orgAutoAcceptEmail ?? parentMetaDataForSubteam?.orgAutoAcceptEmail ?? null
|
||||||
|
: 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({
|
||||||
|
slugs: slug,
|
||||||
|
redirectType: RedirectType.Team,
|
||||||
|
eventTypeSlug: null,
|
||||||
|
currentQuery: context.query,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (redirect) {
|
||||||
|
return redirect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ssr = await ssrInit(context);
|
||||||
|
const metadata = teamMetadataSchema.parse(team?.metadata ?? {});
|
||||||
|
|
||||||
|
// Taking care of sub-teams and orgs
|
||||||
|
if (
|
||||||
|
(!isValidOrgDomain && team?.parent) ||
|
||||||
|
(!isValidOrgDomain && !!metadata?.isOrganization) ||
|
||||||
|
!isOrganizationFeatureEnabled
|
||||||
|
) {
|
||||||
|
return { notFound: true } as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!team || (team.parent && !team.parent.slug)) {
|
||||||
|
const unpublishedTeam = await prisma.team.findFirst({
|
||||||
|
where: {
|
||||||
|
...(team?.parent
|
||||||
|
? { id: team.parent.id }
|
||||||
|
: {
|
||||||
|
metadata: {
|
||||||
|
path: ["requestedSlug"],
|
||||||
|
equals: slug,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!unpublishedTeam) return { notFound: true } as const;
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
isUnpublished: true,
|
||||||
|
team: { ...unpublishedTeam, createdAt: null },
|
||||||
|
trpcState: ssr.dehydrate(),
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
team.eventTypes =
|
||||||
|
team.eventTypes?.map((type) => ({
|
||||||
|
...type,
|
||||||
|
users: type.users.map((user) => ({
|
||||||
|
...user,
|
||||||
|
avatar: `/${user.username}/avatar.png`,
|
||||||
|
})),
|
||||||
|
descriptionAsSafeHTML: markdownToSafeHTML(type.description),
|
||||||
|
})) ?? null;
|
||||||
|
|
||||||
|
const safeBio = markdownToSafeHTML(team.bio) || "";
|
||||||
|
|
||||||
|
const members = !team.isPrivate
|
||||||
|
? team.members.map((member) => {
|
||||||
|
return {
|
||||||
|
name: member.name,
|
||||||
|
id: member.id,
|
||||||
|
bio: member.bio,
|
||||||
|
subteams: member.subteams,
|
||||||
|
username: member.username,
|
||||||
|
accepted: member.accepted,
|
||||||
|
organizationId: member.organizationId,
|
||||||
|
safeBio: markdownToSafeHTML(member.bio || ""),
|
||||||
|
bookerUrl: getBookerBaseUrlSync(member.organization?.slug || ""),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const markdownStrippedBio = stripMarkdown(team?.bio || "");
|
||||||
|
|
||||||
|
const { inviteToken: _inviteToken, ...serializableTeam } = team;
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
team: { ...serializableTeam, safeBio, members, metadata },
|
||||||
|
themeBasis: serializableTeam.slug,
|
||||||
|
trpcState: ssr.dehydrate(),
|
||||||
|
markdownStrippedBio,
|
||||||
|
isValidOrgDomain,
|
||||||
|
currentOrgDomain,
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
};
|
||||||
@@ -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() } };
|
||||||
|
};
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
import MarkdownIt from "markdown-it";
|
||||||
|
import type { GetServerSidePropsContext } from "next";
|
||||||
|
|
||||||
|
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||||
|
import { getCalVideoReference } from "@calcom/features/get-cal-video-reference";
|
||||||
|
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 } = 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 });
|
||||||
|
|
||||||
|
// set meetingPassword to null for guests
|
||||||
|
if (session?.user.id !== bookingObj.user?.id) {
|
||||||
|
bookingObj.references.forEach((bookRef) => {
|
||||||
|
bookRef.meetingPassword = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const videoReference = getCalVideoReference(bookingObj.references);
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
meetingUrl: videoReference.meetingUrl ?? "",
|
||||||
|
...(typeof videoReference.meetingPassword === "string" && {
|
||||||
|
meetingPassword: videoReference.meetingPassword,
|
||||||
|
}),
|
||||||
|
booking: {
|
||||||
|
...bookingObj,
|
||||||
|
...(bookingObj.description && { description: md.render(bookingObj.description) }),
|
||||||
|
},
|
||||||
|
trpcState: ssr.dehydrate(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import type { GetStaticProps } from "next";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
const querySchema = z.object({
|
||||||
|
workflow: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getStaticProps: GetStaticProps = (ctx) => {
|
||||||
|
const params = querySchema.safeParse(ctx.params);
|
||||||
|
console.log("Built workflow page:", params);
|
||||||
|
if (!params.success) return { notFound: true };
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
workflow: params.data.workflow,
|
||||||
|
},
|
||||||
|
revalidate: 10, // seconds
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { get } from "@vercel/edge-config";
|
import { get } from "@vercel/edge-config";
|
||||||
import { collectEvents } from "next-collect/server";
|
import { collectEvents } from "next-collect/server";
|
||||||
|
import { cookies } from "next/headers";
|
||||||
import type { NextRequest } from "next/server";
|
import type { NextRequest } from "next/server";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
@@ -81,6 +82,10 @@ const middleware = async (req: NextRequest): Promise<NextResponse<unknown>> => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (url.pathname.startsWith("/future/auth/logout")) {
|
||||||
|
cookies().delete("next-auth.session-token");
|
||||||
|
}
|
||||||
|
|
||||||
requestHeaders.set("x-pathname", url.pathname);
|
requestHeaders.set("x-pathname", url.pathname);
|
||||||
|
|
||||||
const locale = await getLocale(req);
|
const locale = await getLocale(req);
|
||||||
@@ -112,10 +117,12 @@ export const config = {
|
|||||||
"/api/trpc/:path*",
|
"/api/trpc/:path*",
|
||||||
"/login",
|
"/login",
|
||||||
"/auth/login",
|
"/auth/login",
|
||||||
|
"/future/auth/login",
|
||||||
/**
|
/**
|
||||||
* Paths required by routingForms.handle
|
* Paths required by routingForms.handle
|
||||||
*/
|
*/
|
||||||
"/apps/routing_forms/:path*",
|
"/apps/routing_forms/:path*",
|
||||||
|
|
||||||
"/event-types",
|
"/event-types",
|
||||||
"/future/event-types/",
|
"/future/event-types/",
|
||||||
"/settings/admin/:path*",
|
"/settings/admin/:path*",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@calcom/web",
|
"name": "@calcom/web",
|
||||||
"version": "3.7.2",
|
"version": "3.7.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"analyze": "ANALYZE=true next build",
|
"analyze": "ANALYZE=true next build",
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
"memory-cache": "^0.2.0",
|
"memory-cache": "^0.2.0",
|
||||||
"micro": "^10.0.1",
|
"micro": "^10.0.1",
|
||||||
"mime-types": "^2.1.35",
|
"mime-types": "^2.1.35",
|
||||||
"next": "^13.4.6",
|
"next": "^13.5.4",
|
||||||
"next-auth": "^4.22.1",
|
"next-auth": "^4.22.1",
|
||||||
"next-axiom": "^0.17.0",
|
"next-axiom": "^0.17.0",
|
||||||
"next-collect": "^0.2.1",
|
"next-collect": "^0.2.1",
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { Discord } from "@calcom/ui/components/icon/Discord";
|
|||||||
|
|
||||||
import PageWrapper from "@components/PageWrapper";
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
import { ssgInit } from "@server/lib/ssg";
|
import { getTranslations } from "@server/lib/getTranslations";
|
||||||
|
|
||||||
enum pageType {
|
enum pageType {
|
||||||
ORG = "org",
|
ORG = "org",
|
||||||
@@ -273,11 +273,11 @@ export default function Custom404() {
|
|||||||
Custom404.PageWrapper = PageWrapper;
|
Custom404.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export const getStaticProps = async (context: GetStaticPropsContext) => {
|
export const getStaticProps = async (context: GetStaticPropsContext) => {
|
||||||
const ssr = await ssgInit(context);
|
const i18n = await getTranslations(context);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
trpcState: ssr.dehydrate(),
|
i18n,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
Loaded 100 of 320 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user