Compare commits

...
12 Commits
Author SHA1 Message Date
Keith Williams 36d47bd2d8 v2.8.3
release.yml / release (push) Canceled after 0s
2023-04-18 18:22:24 -03:00
26cdb6521f perf: Adds PageWrapper to pages (#8344)
* Adds PageWrapper to pages

* Add missing PageWrapper

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-04-18 15:45:32 -03:00
Leo Giovanetti 014f1986de Adding missing mutation (#8357)
* Adding missing mutation

* Returning to prop for disabled
2023-04-18 16:48:19 +00:00
Carina WollendorferandCarinaWolli 3ef328421f Date override fixes (#8330)
* fix date override for fixed round robin + time zone in date override

* check if slot is within working hours of fixed hosts

* add test for date override in different time zone

* fix date overrides for not fixed hosts (round robin)

* code clean up

* fix added test

* use the correct timezone of user for date overrides

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-04-18 17:21:27 +02:00
Ben HybertandHariom Balhara c4fe69d826 Add Plausible (Custom) App (#8189)
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-04-18 19:24:51 +05:30
Hariom Balhara 6fd64b2209 Fix: cssVars API not working correctly on Booker Timeslot selection page (#8296)
* Use a method out of react scope to set CSS vars as that doesnt need react

* Refactor
2023-04-18 12:53:46 +00:00
Crowdin Bot 585e36793a New Crowdin translations by Github Action 2023-04-18 12:53:33 +00:00
Crowdin Bot 09b9370e13 New Crowdin translations by Github Action 2023-04-18 12:52:43 +00:00
Udit Takkar a76a4996b4 fix: address input (#8349)
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-04-18 18:21:46 +05:30
Hariom Balhara b28d60b6dc API Support: Manage Booking Questions and responses (#8115) 2023-04-18 18:05:06 +05:30
Nafees Nazik a716eda14c fix: use the correct timezone of the user in booking detail page (#7915)
* fix: send timezone in query

* fiz: timezone

* fix: remove tz from createPayment

* fix: send timezone in query

* fiz: timezone

* fix: remove tz

* fix: remove tz

* fix: remove timezone query

* fix: timezone
2023-04-18 14:29:26 +02:00
Crowdin Bot 99f1524183 New Crowdin translations by Github Action 2023-04-18 12:10:14 +00:00
102 changed files with 771 additions and 206 deletions
+99
View File
@@ -0,0 +1,99 @@
import { DefaultSeo } from "next-seo";
import { Inter } from "next/font/google";
import localFont from "next/font/local";
import Script from "next/script";
import "@calcom/embed-core/src/embed-iframe";
import { useEmbedUiConfig } from "@calcom/embed-core/src/embed-iframe";
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
import type { AppProps } from "@lib/app-providers";
import AppProviders from "@lib/app-providers";
import { seoConfig } from "@lib/config/next-seo.config";
import I18nLanguageHandler from "@components/I18nLanguageHandler";
export interface CalPageWrapper {
(props?: any): JSX.Element;
PageWrapper?: AppProps["Component"]["PageWrapper"];
}
const interFont = Inter({ subsets: ["latin"], variable: "--font-inter", preload: true, display: "swap" });
const calFont = localFont({
src: "../fonts/CalSans-SemiBold.woff2",
variable: "--font-cal",
preload: true,
display: "swap",
});
function PageWrapper(props: AppProps) {
const { Component, pageProps, err, router } = props;
let pageStatus = "200";
const { cssVarsPerTheme } = useEmbedUiConfig();
const cssVarsStyle = [];
if (cssVarsPerTheme) {
for (const [themeName, cssVars] of Object.entries(cssVarsPerTheme)) {
cssVarsStyle.push(`.${themeName} {`);
for (const [cssVarName, value] of Object.entries(cssVars)) {
cssVarsStyle.push(`--${cssVarName}: ${value};`);
}
cssVarsStyle.push(`}`);
}
}
if (router.pathname === "/404") {
pageStatus = "404";
} else if (router.pathname === "/500") {
pageStatus = "500";
}
// On client side don't let nonce creep into DOM
// It also avoids hydration warning that says that Client has the nonce value but server has "" because browser removes nonce attributes before DOM is built
// See https://github.com/kentcdodds/nonce-hydration-issues
// Set "" only if server had it set otherwise keep it undefined because server has to match with client to avoid hydration error
const nonce = typeof window !== "undefined" ? (pageProps.nonce ? "" : undefined) : pageProps.nonce;
const providerProps = {
...props,
pageProps: {
...props.pageProps,
nonce,
},
};
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout ?? ((page) => page);
return (
<AppProviders {...providerProps}>
<DefaultSeo {...seoConfig.defaultNextSeo} />
<I18nLanguageHandler />
<Script
nonce={nonce}
id="page-status"
dangerouslySetInnerHTML={{ __html: `window.CalComPageStatus = '${pageStatus}'` }}
/>
<style jsx global>{`
:root {
--font-inter: ${interFont.style.fontFamily};
--font-cal: ${calFont.style.fontFamily};
}
`}</style>
<style jsx global>
{`
${cssVarsStyle.join("")}
`}
</style>
{getLayout(
Component.requiresLicense ? (
<LicenseRequired>
<Component {...pageProps} err={err} />
</LicenseRequired>
) : (
<Component {...pageProps} err={err} />
),
router
)}
</AppProviders>
);
}
export default PageWrapper;
+1
View File
@@ -30,6 +30,7 @@ export type AppProps = Omit<NextAppProps<WithNonceProps & Record<string, unknown
isThemeSupported?: boolean;
isBookingPage?: boolean | ((arg: { router: NextRouter }) => boolean);
getLayout?: (page: React.ReactElement, router: NextRouter) => ReactNode;
PageWrapper?: (props: AppProps) => JSX.Element;
};
/** Will be defined only is there was an error */
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@calcom/web",
"version": "2.8.2",
"version": "2.8.3",
"private": true,
"scripts": {
"analyze": "ANALYZE=true next build",
+4
View File
@@ -8,6 +8,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { HeadSeo } from "@calcom/ui";
import { BookOpen, Check, ChevronRight, FileText } from "@calcom/ui/components/icon";
import PageWrapper from "@components/PageWrapper";
import { ssgInit } from "@server/lib/ssg";
export default function Custom404() {
@@ -366,6 +368,8 @@ export default function Custom404() {
);
}
Custom404.PageWrapper = PageWrapper;
export const getStaticProps = async (context: GetStaticPropsContext) => {
const ssr = await ssgInit(context);
+4
View File
@@ -6,6 +6,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button, showToast } from "@calcom/ui";
import { Copy } from "@calcom/ui/components/icon";
import PageWrapper from "@components/PageWrapper";
export default function Error500() {
const { t } = useLocale();
const router = useRouter();
@@ -52,3 +54,5 @@ export default function Error500() {
</div>
);
}
Error500.PageWrapper = PageWrapper;
+3
View File
@@ -32,6 +32,8 @@ import { ArrowRight } from "@calcom/ui/components/icon";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import type { EmbedProps } from "@lib/withEmbedSsr";
import PageWrapper from "@components/PageWrapper";
import { ssrInit } from "@server/lib/ssr";
export default function User(props: inferSSRProps<typeof getServerSideProps> & EmbedProps) {
@@ -196,6 +198,7 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
}
User.isBookingPage = true;
User.PageWrapper = PageWrapper;
const getEventTypesWithHiddenFromDB = async (userId: number) => {
return (
+2
View File
@@ -12,6 +12,7 @@ import { isBrandingHidden } from "@lib/isBrandingHidden";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import type { EmbedProps } from "@lib/withEmbedSsr";
import PageWrapper from "@components/PageWrapper";
import AvailabilityPage from "@components/booking/pages/AvailabilityPage";
export type AvailabilityPageProps = inferSSRProps<typeof getStaticProps> & EmbedProps;
@@ -55,6 +56,7 @@ export default function Type(props: AvailabilityPageProps) {
}
Type.isBookingPage = true;
Type.PageWrapper = PageWrapper;
const paramsSchema = z.object({ type: z.string(), user: z.string() });
async function getUserPageProps(context: GetStaticPropsContext) {
+2
View File
@@ -26,6 +26,7 @@ import {
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import PageWrapper from "@components/PageWrapper";
import BookingPage from "@components/booking/pages/BookingPage";
import { ssrInit } from "@server/lib/ssr";
@@ -70,6 +71,7 @@ export default function Book(props: BookPageProps) {
}
Book.isBookingPage = true;
Book.PageWrapper = PageWrapper;
const querySchema = z.object({
bookingUid: z.string().optional(),
+3 -91
View File
@@ -1,101 +1,13 @@
import { DefaultSeo } from "next-seo";
import { Inter } from "next/font/google";
import localFont from "next/font/local";
import Head from "next/head";
import Script from "next/script";
import "@calcom/embed-core/src/embed-iframe";
import { useEmbedUiConfig } from "@calcom/embed-core/src/embed-iframe";
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
import { trpc } from "@calcom/trpc/react";
import type { AppProps } from "@lib/app-providers";
import AppProviders from "@lib/app-providers";
import { seoConfig } from "@lib/config/next-seo.config";
import I18nLanguageHandler from "@components/I18nLanguageHandler";
import "../styles/globals.css";
const interFont = Inter({ subsets: ["latin"], variable: "--font-inter", preload: true, display: "swap" });
const calFont = localFont({
src: "../fonts/CalSans-SemiBold.woff2",
variable: "--font-cal",
preload: true,
display: "swap",
});
function MyApp(props: AppProps) {
const { Component, pageProps, err, router } = props;
let pageStatus = "200";
const { cssVarsPerTheme } = useEmbedUiConfig();
const cssVarsStyle = [];
if (cssVarsPerTheme) {
for (const [themeName, cssVars] of Object.entries(cssVarsPerTheme)) {
cssVarsStyle.push(`.${themeName} {`);
for (const [cssVarName, value] of Object.entries(cssVars)) {
cssVarsStyle.push(`--${cssVarName}: ${value};`);
}
cssVarsStyle.push(`}`);
}
}
if (router.pathname === "/404") {
pageStatus = "404";
} else if (router.pathname === "/500") {
pageStatus = "500";
}
// On client side don't let nonce creep into DOM
// It also avoids hydration warning that says that Client has the nonce value but server has "" because browser removes nonce attributes before DOM is built
// See https://github.com/kentcdodds/nonce-hydration-issues
// Set "" only if server had it set otherwise keep it undefined because server has to match with client to avoid hydration error
const nonce = typeof window !== "undefined" ? (pageProps.nonce ? "" : undefined) : pageProps.nonce;
const providerProps = {
...props,
pageProps: {
...props.pageProps,
nonce,
},
};
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout ?? ((page) => page);
return (
<AppProviders {...providerProps}>
<DefaultSeo {...seoConfig.defaultNextSeo} />
<I18nLanguageHandler />
<Script
nonce={nonce}
id="page-status"
dangerouslySetInnerHTML={{ __html: `window.CalComPageStatus = '${pageStatus}'` }}
/>
<style jsx global>{`
:root {
--font-inter: ${interFont.style.fontFamily};
--font-cal: ${calFont.style.fontFamily};
}
`}</style>
<style jsx global>
{`
${cssVarsStyle.join("")}
`}
</style>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
</Head>
{getLayout(
Component.requiresLicense ? (
<LicenseRequired>
<Component {...pageProps} err={err} />
</LicenseRequired>
) : (
<Component {...pageProps} err={err} />
),
router
)}
</AppProviders>
);
const { Component, pageProps } = props;
if (Component.PageWrapper !== undefined) return Component.PageWrapper(props);
return <Component {...pageProps} />;
}
export default trpc.withTRPC(MyApp);
-2
View File
@@ -1,6 +1,5 @@
import type { DocumentContext, DocumentProps } from "next/document";
import Document, { Head, Html, Main, NextScript } from "next/document";
import Script from "next/script";
import { z } from "zod";
import { getDirFromLang } from "@calcom/lib/i18n";
@@ -42,7 +41,6 @@ class MyDocument extends Document<Props> {
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#000000" />
<meta name="msapplication-TileColor" content="#ff0000" />
<meta name="theme-color" content="var(--cal-bg)" />
<Script src="/embed-init-iframe.js" strategy="beforeInteractive" />
</Head>
<body
+6 -1
View File
@@ -9,13 +9,16 @@ import type { AppGetServerSideProps } from "@calcom/types/AppGetServerSideProps"
import type { AppProps } from "@lib/app-providers";
import PageWrapper from "@components/PageWrapper";
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">;
default: ((props: any) => JSX.Element) &
Pick<AppProps["Component"], "isBookingPage" | "getLayout" | "PageWrapper">;
};
type Found = {
@@ -94,6 +97,8 @@ AppPage.getLayout = (page, router) => {
return route.Component.getLayout(page, router);
};
AppPage.PageWrapper = PageWrapper;
export default AppPage;
export async function getServerSideProps(
+3
View File
@@ -10,6 +10,7 @@ import prisma from "@calcom/prisma";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import PageWrapper from "@components/PageWrapper";
import App from "@components/apps/App";
const md = new MarkdownIt("default", { html: true, breaks: true });
@@ -122,4 +123,6 @@ export const getStaticProps = async (ctx: GetStaticPropsContext) => {
};
};
SingleAppPage.PageWrapper = PageWrapper;
export default SingleAppPage;
+4
View File
@@ -5,6 +5,8 @@ import { useRouter } from "next/router";
import { AppSetupPage } from "@calcom/app-store/_pages/setup";
import { getStaticProps } from "@calcom/app-store/_pages/setup/_getStaticProps";
import PageWrapper from "@components/PageWrapper";
export default function SetupInformation(props: InferGetStaticPropsType<typeof getStaticProps>) {
const router = useRouter();
const slug = router.query.slug as string;
@@ -26,6 +28,8 @@ export default function SetupInformation(props: InferGetStaticPropsType<typeof g
return <AppSetupPage slug={slug} {...props} />;
}
SetupInformation.PageWrapper = PageWrapper;
export const getStaticPaths: GetStaticPaths = async () => {
return {
paths: [],
@@ -9,6 +9,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import prisma from "@calcom/prisma";
import { AppCard, SkeletonText } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
export default function Apps({ apps }: InferGetStaticPropsType<typeof getStaticProps>) {
const { t, isLocaleReady } = useLocale();
const router = useRouter();
@@ -47,6 +49,8 @@ export default function Apps({ apps }: InferGetStaticPropsType<typeof getStaticP
);
}
Apps.PageWrapper = PageWrapper;
export const getStaticPaths = async () => {
const paths = Object.keys(AppCategories);
+4
View File
@@ -7,6 +7,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { SkeletonText } from "@calcom/ui";
import { ArrowLeft, ArrowRight } from "@calcom/ui/components/icon";
import PageWrapper from "@components/PageWrapper";
export default function Apps({ categories }: InferGetStaticPropsType<typeof getStaticProps>) {
const { t, isLocaleReady } = useLocale();
@@ -43,6 +45,8 @@ export default function Apps({ categories }: InferGetStaticPropsType<typeof getS
);
}
Apps.PageWrapper = PageWrapper;
export const getStaticProps = async () => {
const appStore = await getAppRegistry();
const categories = appStore.reduce((c, app) => {
+3
View File
@@ -12,6 +12,7 @@ import type { HorizontalTabItemProps } from "@calcom/ui";
import { AllApps, AppStoreCategories, HorizontalTabs, TextField, PopularAppsSlider } from "@calcom/ui";
import { Search } from "@calcom/ui/components/icon";
import PageWrapper from "@components/PageWrapper";
import AppsLayout from "@components/apps/layouts/AppsLayout";
import { ssrInit } from "@server/lib/ssr";
@@ -85,6 +86,8 @@ export default function Apps({ categories, appStore }: inferSSRProps<typeof getS
);
}
Apps.PageWrapper = PageWrapper;
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
const { req, res } = context;
@@ -44,6 +44,7 @@ import {
import { QueryCell } from "@lib/QueryCell";
import AppListCard from "@components/AppListCard";
import PageWrapper from "@components/PageWrapper";
import { CalendarListContainer } from "@components/apps/CalendarListContainer";
import InstalledAppsLayout from "@components/apps/layouts/InstalledAppsLayout";
@@ -372,3 +373,5 @@ export async function getServerSideProps(ctx: AppGetServerSidePropsContext) {
},
};
}
InstalledApps.PageWrapper = PageWrapper;
+3
View File
@@ -7,6 +7,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button, SkeletonText } from "@calcom/ui";
import { X } from "@calcom/ui/components/icon";
import PageWrapper from "@components/PageWrapper";
import AuthContainer from "@components/ui/AuthContainer";
import { ssgInit } from "@server/lib/ssg";
@@ -49,6 +50,8 @@ export default function Error() {
);
}
Error.PageWrapper = PageWrapper;
export const getStaticProps = async (context: GetStaticPropsContext) => {
const ssr = await ssgInit(context);
+2 -1
View File
@@ -12,6 +12,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import prisma from "@calcom/prisma";
import { Button, TextField } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
import AuthContainer from "@components/ui/AuthContainer";
type Props = {
@@ -174,7 +175,7 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
}
Page.isThemeSupported = false;
Page.PageWrapper = PageWrapper;
export async function getServerSideProps(context: GetServerSidePropsContext) {
const id = context.params?.id as string;
@@ -11,6 +11,7 @@ import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button, EmailField } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
import AuthContainer from "@components/ui/AuthContainer";
export default function ForgotPassword({ csrfToken }: { csrfToken: string }) {
@@ -144,6 +145,7 @@ export default function ForgotPassword({ csrfToken }: { csrfToken: string }) {
}
ForgotPassword.isThemeSupported = false;
ForgotPassword.PageWrapper = PageWrapper;
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
const { req, res } = context;
+2
View File
@@ -26,6 +26,7 @@ import type { WithNonceProps } from "@lib/withNonce";
import withNonce from "@lib/withNonce";
import AddToHomescreen from "@components/AddToHomescreen";
import PageWrapper from "@components/PageWrapper";
import TwoFactor from "@components/auth/TwoFactor";
import AuthContainer from "@components/ui/AuthContainer";
@@ -302,5 +303,6 @@ const _getServerSideProps = async function getServerSideProps(context: GetServer
};
Login.isThemeSupported = false;
Login.PageWrapper = PageWrapper;
export const getServerSideProps = withNonce(_getServerSideProps);
+2 -1
View File
@@ -10,6 +10,7 @@ import { Check } from "@calcom/ui/components/icon";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import PageWrapper from "@components/PageWrapper";
import AuthContainer from "@components/ui/AuthContainer";
import { ssrInit } from "@server/lib/ssr";
@@ -51,7 +52,7 @@ export function Logout(props: Props) {
}
Logout.isThemeSupported = false;
Logout.PageWrapper = PageWrapper;
export default Logout;
export async function getServerSideProps(context: GetServerSidePropsContext) {
+3
View File
@@ -2,6 +2,8 @@ import { signIn } from "next-auth/react";
import { useRouter } from "next/router";
import { useEffect } from "react";
import PageWrapper from "@components/PageWrapper";
// To handle the IdP initiated login flow callback
export default function Page() {
const router = useRouter();
@@ -21,3 +23,4 @@ export default function Page() {
return null;
}
Page.PageWrapper = PageWrapper;
+2 -1
View File
@@ -11,6 +11,7 @@ import prisma from "@calcom/prisma";
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
import { Meta, WizardForm } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
import { AdminUserContainer as AdminUser } from "@components/setup/AdminUser";
import ChooseLicense from "@components/setup/ChooseLicense";
import EnterpriseLicense from "@components/setup/EnterpriseLicense";
@@ -136,7 +137,7 @@ export function Setup(props: inferSSRProps<typeof getServerSideProps>) {
}
Setup.isThemeSupported = false;
Setup.PageWrapper = PageWrapper;
export default Setup;
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
+4
View File
@@ -4,6 +4,8 @@ import { getProviders, signIn, getCsrfToken } from "next-auth/react";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { Button } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
type Provider = {
name: string;
id: string;
@@ -23,6 +25,8 @@ function signin({ providers }: { providers: Provider[] }) {
);
}
signin.PageWrapper = PageWrapper;
export default signin;
export async function getServerSideProps(context: GetServerSidePropsContext) {
+4
View File
@@ -19,6 +19,8 @@ import prisma from "@calcom/prisma";
import { asStringOrNull } from "@lib/asStringOrNull";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import PageWrapper from "@components/PageWrapper";
import { ssrInit } from "@server/lib/ssr";
export type SSOProviderPageProps = inferSSRProps<typeof getServerSideProps>;
@@ -49,6 +51,8 @@ export default function Provider(props: SSOProviderPageProps) {
return null;
}
Provider.PageWrapper = PageWrapper;
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
// get query params and typecast them to string
// (would be even better to assert them instead of typecasting)
+4
View File
@@ -6,6 +6,8 @@ import { HOSTED_CAL_FEATURES } from "@calcom/lib/constants";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import PageWrapper from "@components/PageWrapper";
// This page is used to initiate the SAML authentication flow by redirecting to the SAML provider.
// Accessible only on self-hosted Cal.com instances.
export default function Page({ samlTenantID, samlProductID }: inferSSRProps<typeof getServerSideProps>) {
@@ -28,6 +30,8 @@ export default function Page({ samlTenantID, samlProductID }: inferSSRProps<type
return null;
}
Page.PageWrapper = PageWrapper;
export async function getServerSideProps() {
return {
props: {
+3
View File
@@ -11,6 +11,7 @@ import { trpc } from "@calcom/trpc/react";
import { Button, showToast } from "@calcom/ui";
import Loader from "@components/Loader";
import PageWrapper from "@components/PageWrapper";
async function sendVerificationLogin(email: string, username: string) {
await signIn("email", {
@@ -177,3 +178,5 @@ export default function Verify() {
</div>
);
}
Verify.PageWrapper = PageWrapper;
@@ -31,6 +31,7 @@ import { Info, Plus, Trash } from "@calcom/ui/components/icon";
import { HttpError } from "@lib/core/http/error";
import PageWrapper from "@components/PageWrapper";
import { SelectSkeletonLoader } from "@components/availability/SkeletonLoader";
import EditableHeading from "@components/ui/EditableHeading";
@@ -301,3 +302,5 @@ export default function Availability() {
</Shell>
);
}
Availability.PageWrapper = PageWrapper;
+3
View File
@@ -11,6 +11,7 @@ import { Clock } from "@calcom/ui/components/icon";
import { withQuery } from "@lib/QueryCell";
import { HttpError } from "@lib/core/http/error";
import PageWrapper from "@components/PageWrapper";
import SkeletonLoader from "@components/availability/SkeletonLoader";
export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availability"]["list"]) {
@@ -116,3 +117,5 @@ export default function AvailabilityPage() {
</div>
);
}
AvailabilityPage.PageWrapper = PageWrapper;
@@ -7,6 +7,8 @@ import { SkeletonText } from "@calcom/ui";
import useRouterQuery from "@lib/hooks/useRouterQuery";
import PageWrapper from "@components/PageWrapper";
type User = RouterOutputs["viewer"]["me"];
export interface IBusySlot {
@@ -126,6 +128,7 @@ export default function Troubleshoot() {
</div>
);
}
Troubleshoot.PageWrapper = PageWrapper;
function convertMinsToHrsMins(mins: number) {
const h = Math.floor(mins / 60);
+17 -4
View File
@@ -23,6 +23,7 @@ import {
useIsBackgroundTransparent,
useIsEmbed,
} from "@calcom/embed-core/embed-iframe";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import {
SystemField,
getBookingFieldsWithSystemFields,
@@ -53,6 +54,7 @@ import { X, ExternalLink, ChevronLeft, Check, Calendar } from "@calcom/ui/compon
import { timeZone } from "@lib/clock";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import PageWrapper from "@components/PageWrapper";
import CancelBooking from "@components/booking/CancelBooking";
import EventReservationSchema from "@components/schemas/EventReservationSchema";
@@ -105,10 +107,10 @@ export default function Success(props: SuccessProps) {
seatReferenceUid,
} = querySchema.parse(router.query);
const tz =
(isSuccessBookingPage
? props.bookingInfo.attendees.find((attendee) => attendee.email === email)?.timeZone
: props.bookingInfo.eventType?.timeZone || props.bookingInfo.user?.timeZone) || timeZone();
const attendeeTimeZone = props?.bookingInfo?.attendees.find(
(attendee) => attendee.email === email
)?.timeZone;
const tz = isSuccessBookingPage && attendeeTimeZone ? attendeeTimeZone : props.tz ? props.tz : timeZone();
const location = props.bookingInfo.location as ReturnType<typeof getEventLocationValue>;
@@ -708,6 +710,7 @@ export default function Success(props: SuccessProps) {
}
Success.isBookingPage = true;
Success.PageWrapper = PageWrapper;
type RecurringBookingsProps = {
eventType: SuccessProps["eventType"];
@@ -917,7 +920,16 @@ const handleSeatsEventTypeOnBooking = (
export async function getServerSideProps(context: GetServerSidePropsContext) {
const ssr = await ssrInit(context);
const session = await getServerSession(context);
let tz: string | null = null;
if (session) {
const user = await ssr.viewer.me.fetch();
tz = user.timeZone;
}
const parsedQuery = querySchema.safeParse(context.query);
if (!parsedQuery.success) return { notFound: true };
const { uid, email, eventTypeSlug, cancel, isSuccessBookingPage } = parsedQuery.data;
@@ -1049,6 +1061,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
dynamicEventName: bookingInfo?.eventType?.eventName || "",
bookingInfo,
paymentStatus: payment,
...(tz && { tz }),
},
};
}
+3
View File
@@ -16,6 +16,7 @@ import { Calendar } from "@calcom/ui/components/icon";
import { useInViewObserver } from "@lib/hooks/useInViewObserver";
import PageWrapper from "@components/PageWrapper";
import BookingListItem from "@components/booking/BookingListItem";
import SkeletonLoader from "@components/booking/SkeletonLoader";
@@ -194,6 +195,8 @@ export default function Bookings() {
);
}
Bookings.PageWrapper = PageWrapper;
export const getStaticProps: GetStaticProps = async (ctx) => {
const params = querySchema.safeParse(ctx.params);
const ssg = await ssgInit(ctx);
+2
View File
@@ -14,6 +14,7 @@ import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import type { EmbedProps } from "@lib/withEmbedSsr";
import PageWrapper from "@components/PageWrapper";
import AvailabilityPage from "@components/booking/pages/AvailabilityPage";
import { ssrInit } from "@server/lib/ssr";
@@ -25,6 +26,7 @@ export default function Type(props: DynamicAvailabilityPageProps) {
}
Type.isBookingPage = true;
Type.PageWrapper = PageWrapper;
const querySchema = z.object({
link: z.string().optional().default(""),
+2
View File
@@ -9,6 +9,7 @@ import { customInputSchema, eventTypeBookingFields, EventTypeMetaDataSchema } fr
import { asStringOrNull, asStringOrThrow } from "@lib/asStringOrNull";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import PageWrapper from "@components/PageWrapper";
import BookingPage from "@components/booking/pages/BookingPage";
import { ssrInit } from "@server/lib/ssr";
@@ -20,6 +21,7 @@ export default function Book(props: HashLinkPageProps) {
}
Book.isBookingPage = true;
Book.PageWrapper = PageWrapper;
export async function getServerSideProps(context: GetServerSidePropsContext) {
const ssr = await ssrInit(context);
@@ -30,6 +30,7 @@ import { ConfirmationDialogContent, Dialog, Form, showToast } from "@calcom/ui";
import { asStringOrThrow } from "@lib/asStringOrNull";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import PageWrapper from "@components/PageWrapper";
// These can't really be moved into calcom/ui due to the fact they use infered getserverside props typings
import { EventAdvancedTab } from "@components/eventtype/EventAdvancedTab";
import { EventAppsTab } from "@components/eventtype/EventAppsTab";
@@ -477,4 +478,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
};
};
EventTypePageWrapper.PageWrapper = PageWrapper;
export default EventTypePageWrapper;
+3
View File
@@ -61,6 +61,7 @@ import { withQuery } from "@lib/QueryCell";
import { HttpError } from "@lib/core/http/error";
import { EmbedButton, EmbedDialog } from "@components/Embed";
import PageWrapper from "@components/PageWrapper";
import SkeletonLoader from "@components/eventtype/SkeletonLoader";
type EventTypeGroups = RouterOutputs["viewer"]["eventTypes"]["getByViewer"]["eventTypeGroups"];
@@ -817,4 +818,6 @@ const EventTypesPage = () => {
);
};
EventTypesPage.PageWrapper = PageWrapper;
export default EventTypesPage;
@@ -13,6 +13,7 @@ import { Button, StepCard, Steps } from "@calcom/ui";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import PageWrapper from "@components/PageWrapper";
import { ConnectedCalendars } from "@components/getting-started/steps-views/ConnectCalendars";
import { SetupAvailability } from "@components/getting-started/steps-views/SetupAvailability";
import UserProfile from "@components/getting-started/steps-views/UserProfile";
@@ -203,5 +204,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
};
OnboardingPage.isThemeSupported = false;
OnboardingPage.PageWrapper = PageWrapper;
export default OnboardingPage;
+4
View File
@@ -17,6 +17,8 @@ import { trpc } from "@calcom/trpc";
import { Button, ButtonGroup } from "@calcom/ui";
import { RefreshCcw, UserPlus, Users } from "@calcom/ui/components/icon";
import PageWrapper from "@components/PageWrapper";
const Heading = () => {
const { t } = useLocale();
@@ -111,6 +113,8 @@ export default function InsightsPage() {
);
}
InsightsPage.PageWrapper = PageWrapper;
// If feature flag is disabled, return not found on getServerSideProps
export const getServerSideProps = async () => {
const prisma = await import("@calcom/prisma").then((mod) => mod.default);
+4
View File
@@ -4,6 +4,8 @@ import { APP_NAME, WEBSITE_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
export default function MaintenancePage() {
const { t, isLocaleReady } = useLocale();
if (!isLocaleReady) return null;
@@ -25,3 +27,5 @@ export default function MaintenancePage() {
</div>
);
}
MaintenancePage.PageWrapper = PageWrapper;
+3
View File
@@ -1,6 +1,8 @@
import Shell, { MobileNavigationMoreItems } from "@calcom/features/shell/Shell";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import PageWrapper from "@components/PageWrapper";
export default function MorePage() {
const { t } = useLocale();
return (
@@ -12,3 +14,4 @@ export default function MorePage() {
</Shell>
);
}
MorePage.PageWrapper = PageWrapper;
+3 -1
View File
@@ -2,8 +2,10 @@ import PaymentPage from "@calcom/features/ee/payments/components/PaymentPage";
import { getServerSideProps } from "@calcom/features/ee/payments/pages/payment";
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
import PageWrapper from "@components/PageWrapper";
export default function Payment(props: inferSSRProps<typeof getServerSideProps>) {
return <PaymentPage {...props} />;
}
Payment.PageWrapper = PageWrapper;
export { getServerSideProps };
@@ -2,6 +2,7 @@ import AdminAppsList from "@calcom/features/apps/AdminAppsList";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Meta } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
import { getLayout } from "@components/auth/layouts/AdminLayout";
function AdminAppsView() {
@@ -15,5 +16,6 @@ function AdminAppsView() {
}
AdminAppsView.getLayout = getLayout;
AdminAppsView.PageWrapper = PageWrapper;
export default AdminAppsView;
+2
View File
@@ -1,9 +1,11 @@
import { FlagListingView } from "@calcom/features/flags/pages/flag-listing-view";
import PageWrapper from "@components/PageWrapper";
import { getLayout } from "@components/auth/layouts/AdminLayout";
const FlagsPage = () => <FlagListingView />;
FlagsPage.getLayout = getLayout;
FlagsPage.PageWrapper = PageWrapper;
export default FlagsPage;
@@ -4,6 +4,7 @@ import { useRef } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button, Meta, TextField } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
import { getLayout } from "@components/auth/layouts/AdminLayout";
function AdminView() {
@@ -37,5 +38,6 @@ function AdminView() {
}
AdminView.getLayout = getLayout;
AdminView.PageWrapper = PageWrapper;
export default AdminView;
+2
View File
@@ -1,5 +1,6 @@
import { Meta } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
import { getLayout } from "@components/auth/layouts/AdminLayout";
function AdminAppsView() {
@@ -12,5 +13,6 @@ function AdminAppsView() {
}
AdminAppsView.getLayout = getLayout;
AdminAppsView.PageWrapper = PageWrapper;
export default AdminAppsView;
@@ -1 +1,9 @@
export { default } from "@calcom/features/ee/users/pages/users-edit-view";
import UsersEditView from "@calcom/features/ee/users/pages/users-edit-view";
import type { CalPageWrapper } from "@components/PageWrapper";
import PageWrapper from "@components/PageWrapper";
const Page = UsersEditView as CalPageWrapper;
Page.PageWrapper = PageWrapper;
export default Page;
+9 -1
View File
@@ -1 +1,9 @@
export { default } from "@calcom/features/ee/users/pages/users-add-view";
import UsersAddView from "@calcom/features/ee/users/pages/users-add-view";
import type { CalPageWrapper } from "@components/PageWrapper";
import PageWrapper from "@components/PageWrapper";
const Page = UsersAddView as CalPageWrapper;
Page.PageWrapper = PageWrapper;
export default Page;
@@ -1 +1,9 @@
export { default } from "@calcom/features/ee/users/pages/users-listing-view";
import UsersListingView from "@calcom/features/ee/users/pages/users-listing-view";
import type { CalPageWrapper } from "@components/PageWrapper";
import PageWrapper from "@components/PageWrapper";
const Page = UsersListingView as CalPageWrapper;
Page.PageWrapper = PageWrapper;
export default Page;
@@ -8,6 +8,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button, Meta } from "@calcom/ui";
import { ExternalLink } from "@calcom/ui/components/icon";
import PageWrapper from "@components/PageWrapper";
interface CtaRowProps {
title: string;
description: string;
@@ -64,5 +66,6 @@ const BillingView = () => {
};
BillingView.getLayout = getLayout;
BillingView.PageWrapper = PageWrapper;
export default BillingView;
@@ -18,6 +18,8 @@ import {
} from "@calcom/ui";
import { Link as LinkIcon, Plus } from "@calcom/ui/components/icon";
import PageWrapper from "@components/PageWrapper";
const ApiKeysView = () => {
const { t } = useLocale();
@@ -92,5 +94,6 @@ const ApiKeysView = () => {
};
ApiKeysView.getLayout = getLayout;
ApiKeysView.PageWrapper = PageWrapper;
export default ApiKeysView;
@@ -1 +1,9 @@
export { default } from "@calcom/features/webhooks/pages/webhook-edit-view";
import WebhookEditView from "@calcom/features/webhooks/pages/webhook-edit-view";
import type { CalPageWrapper } from "@components/PageWrapper";
import PageWrapper from "@components/PageWrapper";
const Page = WebhookEditView as CalPageWrapper;
Page.PageWrapper = PageWrapper;
export default Page;
@@ -1 +1,9 @@
export { default } from "@calcom/features/webhooks/pages/webhooks-view";
import WeebhooksView from "@calcom/features/webhooks/pages/webhooks-view";
import type { CalPageWrapper } from "@components/PageWrapper";
import PageWrapper from "@components/PageWrapper";
const Page = WeebhooksView as CalPageWrapper;
Page.PageWrapper = PageWrapper;
export default Page;
@@ -1 +1,9 @@
export { default } from "@calcom/features/webhooks/pages/webhook-new-view";
import WeebhookNewView from "@calcom/features/webhooks/pages/webhook-new-view";
import type { CalPageWrapper } from "@components/PageWrapper";
import PageWrapper from "@components/PageWrapper";
const Page = WeebhookNewView as CalPageWrapper;
Page.PageWrapper = PageWrapper;
export default Page;
@@ -22,6 +22,8 @@ import {
UpgradeTeamsBadge,
} from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
const SkeletonLoader = ({ title, description }: { title: string; description: string }) => {
return (
<SkeletonContainer>
@@ -230,5 +232,6 @@ const AppearanceView = () => {
};
AppearanceView.getLayout = getLayout;
AppearanceView.PageWrapper = PageWrapper;
export default AppearanceView;
@@ -28,6 +28,7 @@ import { Plus, Calendar } from "@calcom/ui/components/icon";
import { QueryCell } from "@lib/QueryCell";
import PageWrapper from "@components/PageWrapper";
import { CalendarSwitch } from "@components/settings/CalendarSwitch";
const SkeletonLoader = () => {
@@ -228,5 +229,6 @@ const CalendarsView = () => {
};
CalendarsView.getLayout = getLayout;
CalendarsView.PageWrapper = PageWrapper;
export default CalendarsView;
@@ -27,6 +27,7 @@ import {
import { AlertCircle, MoreHorizontal, Trash, Video } from "@calcom/ui/components/icon";
import AppListCard from "@components/AppListCard";
import PageWrapper from "@components/PageWrapper";
const SkeletonLoader = ({ title, description }: { title: string; description: string }) => {
return (
@@ -188,5 +189,6 @@ const ConferencingLayout = () => {
};
ConferencingLayout.getLayout = getLayout;
ConferencingLayout.PageWrapper = PageWrapper;
export default ConferencingLayout;
@@ -22,6 +22,8 @@ import {
import { withQuery } from "@lib/QueryCell";
import PageWrapper from "@components/PageWrapper";
const SkeletonLoader = ({ title, description }: { title: string; description: string }) => {
return (
<SkeletonContainer>
@@ -219,5 +221,6 @@ const GeneralView = ({ localeProp, user }: GeneralViewProps) => {
};
GeneralQueryView.getLayout = getLayout;
GeneralQueryView.PageWrapper = PageWrapper;
export default GeneralQueryView;
@@ -40,6 +40,7 @@ import {
} from "@calcom/ui";
import { AlertTriangle, Trash2 } from "@calcom/ui/components/icon";
import PageWrapper from "@components/PageWrapper";
import TwoFactor from "@components/auth/TwoFactor";
import { UsernameAvailabilityField } from "@components/ui/UsernameAvailability";
@@ -394,5 +395,6 @@ const ProfileForm = ({
};
ProfileView.getLayout = getLayout;
ProfileView.PageWrapper = PageWrapper;
export default ProfileView;
@@ -6,6 +6,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Button, Form, Label, Meta, showToast, Skeleton, Switch } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
import { ssrInit } from "@server/lib/ssr";
const ProfileImpersonationView = () => {
@@ -85,6 +87,7 @@ const ProfileImpersonationView = () => {
};
ProfileImpersonationView.getLayout = getLayout;
ProfileImpersonationView.PageWrapper = PageWrapper;
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
const ssr = await ssrInit(context);
@@ -9,6 +9,8 @@ import { userMetadata } from "@calcom/prisma/zod-utils";
import { trpc } from "@calcom/trpc/react";
import { Alert, Button, Form, Meta, PasswordField, Select, SettingsToggle, showToast } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
type ChangePasswordSessionFormValues = {
oldPassword: string;
newPassword: string;
@@ -207,5 +209,6 @@ const PasswordView = () => {
};
PasswordView.getLayout = getLayout;
PasswordView.PageWrapper = PageWrapper;
export default PasswordView;
+9 -1
View File
@@ -1 +1,9 @@
export { default } from "@calcom/features/ee/sso/page/user-sso-view";
import UserSSOView from "@calcom/features/ee/sso/page/user-sso-view";
import type { CalPageWrapper } from "@components/PageWrapper";
import PageWrapper from "@components/PageWrapper";
const Page = UserSSOView as CalPageWrapper;
Page.PageWrapper = PageWrapper;
export default Page;
@@ -5,6 +5,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Badge, Meta, Switch, SkeletonButton, SkeletonContainer, SkeletonText, Alert } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
import DisableTwoFactorModal from "@components/settings/DisableTwoFactorModal";
import EnableTwoFactorModal from "@components/settings/EnableTwoFactorModal";
@@ -84,5 +85,6 @@ const TwoFactorAuthView = () => {
};
TwoFactorAuthView.getLayout = getLayout;
TwoFactorAuthView.PageWrapper = PageWrapper;
export default TwoFactorAuthView;
@@ -1 +1,9 @@
export { default } from "@calcom/features/ee/teams/pages/team-appearance-view";
import TeamAppearenceView from "@calcom/features/ee/teams/pages/team-appearance-view";
import type { CalPageWrapper } from "@components/PageWrapper";
import PageWrapper from "@components/PageWrapper";
const Page = TeamAppearenceView as CalPageWrapper;
Page.PageWrapper = PageWrapper;
export default Page;
@@ -1 +1,9 @@
export { default } from "@calcom/features/ee/teams/pages/team-billing-view";
import TeamBillingView from "@calcom/features/ee/teams/pages/team-billing-view";
import type { CalPageWrapper } from "@components/PageWrapper";
import PageWrapper from "@components/PageWrapper";
const Page = TeamBillingView as CalPageWrapper;
Page.PageWrapper = PageWrapper;
export default Page;
@@ -1 +1,9 @@
export { default } from "@calcom/features/ee/teams/pages/team-members-view";
import TeamMembersView from "@calcom/features/ee/teams/pages/team-members-view";
import type { CalPageWrapper } from "@components/PageWrapper";
import PageWrapper from "@components/PageWrapper";
const Page = TeamMembersView as CalPageWrapper;
Page.PageWrapper = PageWrapper;
export default Page;
@@ -3,6 +3,7 @@ import Head from "next/head";
import AddNewTeamMembers from "@calcom/features/ee/teams/components/AddNewTeamMembers";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import PageWrapper from "@components/PageWrapper";
import WizardLayout from "@components/layouts/WizardLayout";
const OnboardTeamMembersPage = () => {
@@ -24,4 +25,6 @@ OnboardTeamMembersPage.getLayout = (page: React.ReactElement) => (
</WizardLayout>
);
OnboardTeamMembersPage.PageWrapper = PageWrapper;
export default OnboardTeamMembersPage;
@@ -1 +1,9 @@
export { default } from "@calcom/features/ee/teams/pages/team-profile-view";
import TeamProfileView from "@calcom/features/ee/teams/pages/team-profile-view";
import type { CalPageWrapper } from "@components/PageWrapper";
import PageWrapper from "@components/PageWrapper";
const Page = TeamProfileView as CalPageWrapper;
Page.PageWrapper = PageWrapper;
export default Page;
+9 -1
View File
@@ -1 +1,9 @@
export { default } from "@calcom/features/ee/sso/page/teams-sso-view";
import TeamSSOView from "@calcom/features/ee/sso/page/teams-sso-view";
import type { CalPageWrapper } from "@components/PageWrapper";
import PageWrapper from "@components/PageWrapper";
const Page = TeamSSOView as CalPageWrapper;
Page.PageWrapper = PageWrapper;
export default Page;
+9 -1
View File
@@ -1 +1,9 @@
export { default } from "@calcom/features/ee/teams/pages/team-listing-view";
import TeamListView from "@calcom/features/ee/teams/pages/team-listing-view";
import PageWrapper from "@components/PageWrapper";
import type { CalPageWrapper } from "@components/PageWrapper";
const Page = TeamListView as CalPageWrapper;
Page.PageWrapper = PageWrapper;
export default Page;
@@ -3,6 +3,7 @@ import Head from "next/head";
import { CreateANewTeamForm } from "@calcom/features/ee/teams/components";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import PageWrapper from "@components/PageWrapper";
import WizardLayout from "@components/layouts/WizardLayout";
const CreateNewTeamPage = () => {
@@ -26,5 +27,6 @@ const LayoutWrapper = (page: React.ReactElement) => {
};
CreateNewTeamPage.getLayout = LayoutWrapper;
CreateNewTeamPage.PageWrapper = PageWrapper;
export default CreateNewTeamPage;
+3
View File
@@ -14,6 +14,8 @@ import prisma from "@calcom/prisma";
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
import { Alert, Button, EmailField, HeadSeo, PasswordField, TextField } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
import { asStringOrNull } from "../lib/asStringOrNull";
import { IS_GOOGLE_LOGIN_ENABLED } from "../server/lib/constants";
import { ssrInit } from "../server/lib/ssr";
@@ -230,3 +232,4 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
};
Signup.isThemeSupported = false;
Signup.PageWrapper = PageWrapper;
+2
View File
@@ -20,6 +20,7 @@ import { ArrowRight } from "@calcom/ui/components/icon";
import { useToggleQuery } from "@lib/hooks/useToggleQuery";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import PageWrapper from "@components/PageWrapper";
import Team from "@components/team/screens/Team";
import { ssrInit } from "@server/lib/ssr";
@@ -204,5 +205,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
};
TeamPage.isBookingPage = true;
TeamPage.PageWrapper = PageWrapper;
export default TeamPage;
+2
View File
@@ -14,6 +14,7 @@ import { asStringOrNull } from "@lib/asStringOrNull";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import type { EmbedProps } from "@lib/withEmbedSsr";
import PageWrapper from "@components/PageWrapper";
import AvailabilityPage from "@components/booking/pages/AvailabilityPage";
import { ssgInit } from "@server/lib/ssg";
@@ -25,6 +26,7 @@ export default function TeamType(props: AvailabilityTeamPageProps) {
}
TeamType.isBookingPage = true;
TeamType.PageWrapper = PageWrapper;
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
const slugParam = asStringOrNull(context.query.slug);
+2
View File
@@ -14,6 +14,7 @@ import { customInputSchema, eventTypeBookingFields, EventTypeMetaDataSchema } fr
import { asStringOrNull, asStringOrThrow } from "@lib/asStringOrNull";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import PageWrapper from "@components/PageWrapper";
import BookingPage from "@components/booking/pages/BookingPage";
import { ssrInit } from "@server/lib/ssr";
@@ -24,6 +25,7 @@ export default function TeamBookingPage(props: TeamBookingPageProps) {
return <BookingPage {...props} />;
}
TeamBookingPage.isBookingPage = true;
TeamBookingPage.PageWrapper = PageWrapper;
const querySchema = z.object({
rescheduleUid: z.string().optional(),
+3
View File
@@ -7,6 +7,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button } from "@calcom/ui";
import { Plus } from "@calcom/ui/components/icon";
import PageWrapper from "@components/PageWrapper";
function Teams() {
const { t } = useLocale();
return (
@@ -36,5 +38,6 @@ export const getStaticProps = async () => {
};
Teams.requiresLicense = false;
Teams.PageWrapper = PageWrapper;
export default Teams;
+4
View File
@@ -16,6 +16,8 @@ import prisma, { bookingMinimalSelect } from "@calcom/prisma";
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
import { ChevronRight } from "@calcom/ui/components/icon";
import PageWrapper from "@components/PageWrapper";
import { ssrInit } from "@server/lib/ssr";
const recordingStartedEventResponse = z
@@ -261,6 +263,8 @@ export function VideoMeetingInfo(props: VideoMeetingInfo) {
);
}
VideoMeetingInfo.PageWrapper = PageWrapper;
export async function getServerSideProps(context: GetServerSidePropsContext) {
const { req, res } = context;
@@ -9,6 +9,8 @@ import { ArrowRight, Calendar, X } from "@calcom/ui/components/icon";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import PageWrapper from "@components/PageWrapper";
export default function MeetingUnavailable(props: inferSSRProps<typeof getServerSideProps>) {
const { t } = useLocale();
@@ -62,6 +64,8 @@ export default function MeetingUnavailable(props: inferSSRProps<typeof getServer
);
}
MeetingUnavailable.PageWrapper = PageWrapper;
export async function getServerSideProps(context: NextPageContext) {
const booking = await prisma.booking.findUnique({
where: {
@@ -8,6 +8,8 @@ import type { inferSSRProps } from "@calcom/types/inferSSRProps";
import { Button, HeadSeo, EmptyScreen } from "@calcom/ui";
import { ArrowRight, Calendar, Clock } from "@calcom/ui/components/icon";
import PageWrapper from "@components/PageWrapper";
export default function MeetingNotStarted(props: inferSSRProps<typeof getServerSideProps>) {
const { t } = useLocale();
return (
@@ -37,6 +39,8 @@ export default function MeetingNotStarted(props: inferSSRProps<typeof getServerS
);
}
MeetingNotStarted.PageWrapper = PageWrapper;
export async function getServerSideProps(context: NextPageContext) {
const booking = await prisma.booking.findUnique({
where: {
@@ -2,6 +2,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button, EmptyScreen, HeadSeo } from "@calcom/ui";
import { X, ArrowRight } from "@calcom/ui/components/icon";
import PageWrapper from "@components/PageWrapper";
export default function NoMeetingFound() {
const { t } = useLocale();
@@ -23,3 +25,5 @@ export default function NoMeetingFound() {
</>
);
}
NoMeetingFound.PageWrapper = PageWrapper;
+9 -1
View File
@@ -1,7 +1,10 @@
import type { GetStaticPaths, GetStaticProps } from "next";
import { z } from "zod";
export { default } from "@calcom/features/ee/workflows/pages/workflow";
import Workflow from "@calcom/features/ee/workflows/pages/workflow";
import PageWrapper from "@components/PageWrapper";
import type { CalPageWrapper } from "@components/PageWrapper";
const querySchema = z.object({
workflow: z.string(),
@@ -26,3 +29,8 @@ export const getStaticPaths: GetStaticPaths = () => {
fallback: "blocking",
};
};
const WorkflowsPage = Workflow as CalPageWrapper;
WorkflowsPage.PageWrapper = PageWrapper;
export default WorkflowsPage;
+9 -1
View File
@@ -1 +1,9 @@
export { default } from "@calcom/features/ee/workflows/pages/index";
import Workflows from "@calcom/features/ee/workflows/pages/index";
import PageWrapper from "@components/PageWrapper";
import type { CalPageWrapper } from "@components/PageWrapper";
const WorkflowsPage = Workflows as CalPageWrapper;
WorkflowsPage.PageWrapper = PageWrapper;
export default WorkflowsPage;
-26
View File
@@ -1,26 +0,0 @@
const calEmbedMode = typeof new URL(document.URL).searchParams.get("embed") === "string";
/* Iframe Name */
window.name.includes("cal-embed");
window.isEmbed = () => {
// Once an embed mode always an embed mode
return calEmbedMode;
};
window.resetEmbedStatus = () => {
try {
// eslint-disable-next-line @calcom/eslint/avoid-web-storage
window.sessionStorage.removeItem("calEmbedMode");
} catch (e) {}
};
window.getEmbedTheme = () => {
const url = new URL(document.URL);
return url.searchParams.get("theme");
};
window.getEmbedNamespace = () => {
const url = new URL(document.URL);
const namespace = url.searchParams.get("embed");
return namespace;
};
@@ -1594,7 +1594,7 @@
"attendee_no_longer_attending_subject": "Uczestnik nie bierze już udziału w wydarzeniu {{title}} odbywającym się {{date}}.",
"attendee_no_longer_attending": "Uczestnik nie bierze już udziału w Twoim wydarzeniu.",
"attendee_no_longer_attending_subtitle": "Użytkownik {{name}} anulował rezerwację. To oznacza, że zwolniło się miejsce w tym terminie.",
"create_event_on": "Utwórz wydarzenie w terminie",
"create_event_on": "Utwórz wydarzenie w kalendarzu",
"default_app_link_title": "Ustaw domyślny link do aplikacji",
"default_app_link_description": "Ustawienie domyślnego linku do aplikacji pozwala wszystkim nowo utworzonym typom wydarzeń na używanie ustawionego przez Ciebie linku do aplikacji.",
"change_default_conferencing_app": "Ustaw jako domyślne",
@@ -1640,7 +1640,7 @@
"this_meeting_has_not_started_yet": "To spotkanie jeszcze się nie rozpoczęło.",
"this_app_requires_connected_account": "Aplikacja {{appName}} wymaga połączonego konta {{dependencyName}}.",
"connect_app": "Połącz {{dependencyName}}",
"app_is_connected": "{{dependencyName}} jest połączone.",
"app_is_connected": "Aplikacja {{dependencyName}} jest połączona.",
"requires_app": "Wymaga {{dependencyName}}",
"verification_code": "Kod weryfikacyjny",
"can_you_try_again": "Możesz spróbować ponownie w innym terminie?",
@@ -111,7 +111,7 @@
"hidden_team_owner_message": "É preciso ter uma conta Pro para usar equipes, você permanecerá oculto até a atualização.",
"link_expires": "P.S.: Expira em {{expiresIn}} horas.",
"upgrade_to_per_seat": "Atualize para \"Por assento\"",
"seat_options_doesnt_support_confirmation": "A opção de assentos não é compatível com requisito de confirmação",
"seat_options_doesnt_support_confirmation": "Não é possível usar reservas com assento quando a reserva exigir confirmação",
"team_upgrade_seats_details": "Dos {{memberCount}} membros da sua equipe, há {{unpaidCount}} assento(s) não pago(s). A ${{seatPrice}}/mês por assento, o custo total estimado da sua assinatura é de ${{totalCost}}/mês.",
"team_upgrade_banner_description": "Agradecemos por testar nosso novo plano de equipe. Notamos que a sua equipe \"{{teamName}}\" precisa ser atualizada.",
"team_upgrade_banner_action": "Atualizar aqui",
@@ -1589,9 +1589,9 @@
"create_a_one_one_template": "Crie um modelo um a um para um tipo de evento e distribua para vários membros.",
"collective_or_roundrobin": "Coletivo ou round-robin",
"book_your_team_members": "Reúna os membros da sua equipe com eventos coletivos, ou selecione a pessoa certa com o round-robin.",
"event_no_longer_attending_subject": "Não está mais participando de {{title}} em {{date}}",
"event_no_longer_attending_subject": "Não está mais participando de {{title}} à(s) {{date}}",
"no_longer_attending": "Você não está mais participando deste evento",
"attendee_no_longer_attending_subject": "Um partipante não está mais participando de {{title}} em {{date}}",
"attendee_no_longer_attending_subject": "Um partipante não está mais participando de {{title}} à(s) {{date}}",
"attendee_no_longer_attending": "Um partipante não está mais participando do seu evento",
"attendee_no_longer_attending_subtitle": "{{name}} cancelou. Quer dizer que um assento foi liberado para este espaço de tempo",
"create_event_on": "Criar evento em",
+18
View File
@@ -784,6 +784,24 @@ describe("getSchedule", () => {
dateString: plus2DateString,
}
);
const scheduleForEventOnADayWithDateOverrideDifferentTimezone = await getSchedule(
{
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+6:00"],
},
ctx
);
// it should return the same as this is the utc time
expect(scheduleForEventOnADayWithDateOverrideDifferentTimezone).toHaveTimeSlots(
["08:30:00.000Z", "09:30:00.000Z", "10:30:00.000Z", "11:30:00.000Z"],
{
dateString: plus2DateString,
}
);
});
test("that a user is considered busy when there's a booking they host", async () => {
+25 -5
View File
@@ -17,13 +17,33 @@ export default function BookingPageTagManager({
if (!tag) {
return null;
}
const trackingId = getEventTypeAppData(eventType, appId as keyof typeof appDataSchemas)?.trackingId;
if (!trackingId) {
const appData = getEventTypeAppData(eventType, appId as keyof typeof appDataSchemas);
if (!appData) {
return null;
}
const parseValue = <T extends string | undefined>(val: T): T =>
//TODO: Support more template variables.
val ? (val.replace(/\{TRACKING_ID\}/g, trackingId) as T) : val;
const parseValue = <T extends string | undefined>(val: T): T => {
if (!val) {
return val;
}
// Only support UpperCase,_and numbers in template variables. This prevents accidental replacement of other strings.
const regex = /\{([A-Z_\d]+)\}/g;
let matches;
while ((matches = regex.exec(val))) {
const variableName = matches[1];
if (appData[variableName]) {
// Replace if value is available. It can possible not be a template variable that just matches the regex.
val = val.replace(
new RegExp(`{${variableName}}`, "g"),
appData[variableName]
) as NonNullable<T>;
}
}
return val;
};
return tag.scripts.map((script, index) => {
const parsedAttributes: NonNullable<(typeof tag.scripts)[number]["attrs"]> = {};
@@ -15,7 +15,13 @@ export const getEventTypeAppData = <T extends EventTypeAppsList>(
const appMetadata = metadata?.apps && metadata.apps[appId];
if (appMetadata) {
const allowDataGet = forcedGet ? true : appMetadata.enabled;
return allowDataGet ? appMetadata : null;
return allowDataGet
? {
...appMetadata,
// trackingId is legacy way to store value for TRACKING_ID. So, we need to support both.
TRACKING_ID: appMetadata.TRACKING_ID || appMetadata.trackingId,
}
: null;
}
// Backward compatibility for existing event types.
+13 -1
View File
@@ -2,6 +2,7 @@ import Link from "next/link";
import { useRouter } from "next/router";
import { useEffect, useRef } from "react";
import useAddAppMutation from "@calcom/app-store/_utils/useAddAppMutation";
import classNames from "@calcom/lib/classNames";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { CAL_URL } from "@calcom/lib/constants";
@@ -20,10 +21,21 @@ export const InstallAppButtonWithoutPlanCheck = (
type: App["type"];
} & InstallAppButtonProps
) => {
const mutation = useAddAppMutation(null);
const key = deriveAppDictKeyFromType(props.type, InstallAppButtonMap);
const InstallAppButtonComponent = InstallAppButtonMap[key as keyof typeof InstallAppButtonMap];
if (!InstallAppButtonComponent)
return <>{props.render({ useDefaultComponent: true, disabled: props.disableInstall })}</>;
return (
<>
{props.render({
useDefaultComponent: true,
disabled: props.disableInstall,
onClick: () => {
mutation.mutate({ type: props.type });
},
})}
</>
);
return (
<InstallAppButtonComponent
@@ -9,6 +9,7 @@ import type { appDataSchema } from "../zod";
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app }) {
const [getAppData, setAppData] = useAppContextWithSchema<typeof appDataSchema>();
const plausibleUrl = getAppData("PLAUSIBLE_URL");
const trackingId = getAppData("trackingId");
const [enabled, setEnabled] = useState(getAppData("enabled"));
@@ -24,8 +25,18 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
}
}}
switchChecked={enabled}>
<TextField
name="Plausible URL"
defaultValue="https://plausible.io/js/script.js"
placeholder="https://plausible.io/js/script.js"
value={plausibleUrl}
onChange={(e) => {
setAppData("PLAUSIBLE_URL", e.target.value);
}}
/>
<TextField
name="Tracked Domain"
placeholder="yourdomain.com"
value={trackingId}
onChange={(e) => {
setAppData("trackingId", e.target.value);
+1 -1
View File
@@ -15,7 +15,7 @@
"tag": {
"scripts": [
{
"src": "https://plausible.io/js/script.js",
"src": "{PLAUSIBLE_URL}",
"attrs": {
"data-domain": "{TRACKING_ID}"
}
+1
View File
@@ -4,6 +4,7 @@ import { eventTypeAppCardZod } from "../eventTypeAppCardZod";
export const appDataSchema = eventTypeAppCardZod.merge(
z.object({
PLAUSIBLE_URL: z.string().optional().default("https://plausible.io/js/script.js").or(z.undefined()),
trackingId: z.string().default("").optional(),
})
);
@@ -0,0 +1,55 @@
export default function EmbedInitIframe() {
if (typeof window === "undefined" || window.isEmbed) {
return;
}
const calEmbedMode = typeof new URL(document.URL).searchParams.get("embed") === "string";
/* Iframe Name */
window.name.includes("cal-embed");
window.isEmbed = () => {
// Once an embed mode always an embed mode
return calEmbedMode;
};
window.resetEmbedStatus = () => {
try {
// eslint-disable-next-line @calcom/eslint/avoid-web-storage
window.sessionStorage.removeItem("calEmbedMode");
} catch (e) {}
};
window.getEmbedTheme = () => {
const url = new URL(document.URL);
return url.searchParams.get("theme") as "light" | "dark" | null;
};
window.getEmbedNamespace = () => {
const url = new URL(document.URL);
const namespace = url.searchParams.get("embed");
return namespace;
};
window.CalEmbed = window.CalEmbed || {};
window.CalEmbed.applyCssVars = (cssVarsPerTheme) => {
const cssVarsStyle = [];
if (cssVarsPerTheme) {
for (const [themeName, cssVars] of Object.entries(cssVarsPerTheme)) {
cssVarsStyle.push(`.${themeName} {`);
for (const [cssVarName, value] of Object.entries(cssVars)) {
cssVarsStyle.push(`--${cssVarName}: ${value};`);
}
cssVarsStyle.push(`}`);
}
}
const style = document.createElement("style");
style.id = "embed-css-vars";
style.innerText = cssVarsStyle.join("\n");
if (document.head.querySelector("#embed-css-vars")) {
return;
}
document.head.appendChild(style);
};
}
+10 -10
View File
@@ -174,20 +174,20 @@
If you render booking embed in me, I won't restrict you. The entire page is yours. Content is by
default aligned center
</div>
<button
onclick="(function () {Cal.ns.second('ui', {styles:{eventTypeListItem:{backgroundColor:'blue'}}})})()">
Change <code>eventTypeListItem</code> bg color
</button>
<button onclick="(function () {Cal.ns.second('ui', {styles:{body:{background:'red'}}})})()">
Change <code>body</code> bg color
</button>
<button
onclick="(function () {Cal.ns.second('ui', {cssVarsPerTheme:{light:{'cal-border-booker':'green', 'cal-border-booker-width':'20px'},dark:{'cal-border-booker':'red', 'cal-border-booker-width':'5px'}}})})()">
Change booker border for dark and light themes
</button>
<button onclick="(function () {Cal.ns.second('ui', {styles:{align:'left'}})})()">Align left</button>
<button
onclick="(function () {Cal.ns.second('ui', {styles:{eventTypeListItem:{backgroundColor:'blue'}}})})()">
Change <code>eventTypeListItem</code> bg color[Deprecated]
</button>
<button onclick="(function () {Cal.ns.second('ui', {styles:{body:{background:'red'}}})})()">
Change <code>body</code> bg color[Deprecated]
</button>
<button onclick="(function () {Cal.ns.second('ui', {styles:{align:'left'}})})()">Align left[Deprecated]</button>
<button onclick="(function () {Cal.ns.second('ui', {styles:{align:'center'}})})()">
Align Center
Align Center[Deprecated]
</button>
<button
onclick="(function () {Cal.ns.second('ui', {styles:{enabledDateButton: {
@@ -196,7 +196,7 @@
disabledDateButton: {
backgroundColor: generateRandomHexColor(),
},}})})()">
Change 'enabledDateButton` and `disabledDateButton` background Color
Change 'enabledDateButton` and `disabledDateButton` background Color[Deprecated]
</button>
</div>
</div>
+11 -1
View File
@@ -2,6 +2,8 @@ import { useRouter } from "next/router";
import type { CSSProperties } from "react";
import { useState, useEffect } from "react";
import embedInit from "@calcom/embed-core/embed-iframe-init";
import type { Message } from "./embed";
import { sdkActionManager } from "./sdk-event";
@@ -40,9 +42,10 @@ declare global {
CalEmbed: {
__logQueue?: unknown[];
embedStore: typeof embedStore;
applyCssVars: (cssVarsPerTheme: UiConfig["cssVarsPerTheme"]) => void;
};
CalComPageStatus: string;
isEmbed: () => boolean;
isEmbed?: () => boolean;
resetEmbedStatus: () => void;
getEmbedNamespace: () => string | null;
getEmbedTheme: () => "dark" | "light" | null;
@@ -303,6 +306,11 @@ const methods = {
// Set the value here so that if setUiConfig state isn't available and later it's defined,it uses this value
embedStore.uiConfig = uiConfig;
if (uiConfig.cssVarsPerTheme) {
window.CalEmbed.applyCssVars(uiConfig.cssVarsPerTheme);
}
if (embedStore.setUiConfig) {
embedStore.setUiConfig(uiConfig);
}
@@ -423,6 +431,8 @@ function keepParentInformedAboutDimensionChanges() {
if (isBrowser) {
log("Embed SDK loaded", { isEmbed: window?.isEmbed?.() || false });
// Exposes certain global variables/fns that are used by the app to get interface with the embed.
embedInit();
const url = new URL(document.URL);
embedStore.theme = (window?.getEmbedTheme?.() || "auto") as UiConfig["theme"];
if (url.searchParams.get("prerender") !== "true" && window?.isEmbed?.()) {
+13
View File
@@ -20,6 +20,19 @@ function App() {
action: "*",
callback,
});
api("ui", {
cssVarsPerTheme: {
light: {
"cal-border-booker": "red",
"cal-border-booker-width": "20px",
},
dark: {
"cal-border-booker": "red",
"cal-border-booker-width": "5px",
},
},
});
});
return () => {
api.then((api) => {
@@ -53,7 +53,7 @@ import { updateWebUser as syncServicesUpdateWebUser } from "@calcom/lib/sync/Syn
import { TimeFormat } from "@calcom/lib/timeFormat";
import prisma, { userSelect } from "@calcom/prisma";
import type { BookingReference } from "@calcom/prisma/client";
import type { bookingCreateSchemaLegacyPropsForApi } from "@calcom/prisma/zod-utils";
import { bookingCreateSchemaLegacyPropsForApi } from "@calcom/prisma/zod-utils";
import {
bookingCreateBodySchemaForApi,
customInputSchema,
@@ -394,21 +394,81 @@ function getBookingData({
isNotAnApiCall: boolean;
eventType: Awaited<ReturnType<typeof getEventTypesFromDB>>;
}) {
const responsesSchema = getBookingResponsesSchema({
eventType: {
bookingFields: eventType.bookingFields,
},
view: req.body.rescheduleUid ? "reschedule" : "booking",
});
const bookingDataSchema = isNotAnApiCall
? extendedBookingCreateBody.merge(
z.object({
responses: getBookingResponsesSchema({
eventType: {
bookingFields: eventType.bookingFields,
},
view: req.body.rescheduleUid ? "reschedule" : "booking",
}),
responses: responsesSchema,
})
)
: bookingCreateBodySchemaForApi;
: bookingCreateBodySchemaForApi
.merge(
z.object({
responses: responsesSchema.optional(),
})
)
.superRefine((val, ctx) => {
if (val.responses && val.customInputs) {
ctx.addIssue({
code: "custom",
message:
"Don't use both customInputs and responses. `customInputs` is only there for legacy support.",
});
return;
}
const legacyProps = Object.keys(bookingCreateSchemaLegacyPropsForApi.shape);
if (val.responses) {
const unwantedProps: string[] = [];
legacyProps.forEach((legacyProp) => {
if (val[legacyProp as keyof typeof val]) {
unwantedProps.push(legacyProp);
}
});
if (unwantedProps.length) {
ctx.addIssue({
code: "custom",
message: `Legacy Props: ${unwantedProps.join(",")}. They can't be used with \`responses\``,
});
return;
}
} else if (val.customInputs) {
const { success } = bookingCreateSchemaLegacyPropsForApi.safeParse(val);
if (!success) {
ctx.addIssue({
code: "custom",
message: `With \`customInputs\` you must specify legacy props ${legacyProps.join(",")}`,
});
}
}
});
const reqBody = bookingDataSchema.parse(req.body);
if ("responses" in reqBody) {
if ("customInputs" in reqBody) {
if (reqBody.customInputs) {
// Check if required custom inputs exist
handleCustomInputs(eventType.customInputs as EventTypeCustomInput[], reqBody.customInputs);
}
const reqBodyWithLegacyProps = bookingCreateSchemaLegacyPropsForApi.parse(reqBody);
return {
...reqBody,
name: reqBodyWithLegacyProps.name,
email: reqBodyWithLegacyProps.email,
guests: reqBodyWithLegacyProps.guests,
location: reqBodyWithLegacyProps.location || "",
smsReminderNumber: reqBodyWithLegacyProps.smsReminderNumber,
notes: reqBodyWithLegacyProps.notes,
rescheduleReason: reqBodyWithLegacyProps.rescheduleReason,
};
} else {
if (!reqBody.responses) {
throw new Error("`responses` must not be nullish");
}
const responses = reqBody.responses;
const { userFieldsResponses: calEventUserFieldsResponses, responses: calEventResponses } =
getCalEventResponses({
@@ -427,20 +487,6 @@ function getBookingData({
rescheduleReason: responses.rescheduleReason,
calEventResponses,
};
} else {
// Check if required custom inputs exist
handleCustomInputs(eventType.customInputs as EventTypeCustomInput[], reqBody.customInputs);
return {
...reqBody,
name: reqBody.name,
email: reqBody.email,
guests: reqBody.guests,
location: reqBody.location || "",
smsReminderNumber: reqBody.smsReminderNumber,
notes: reqBody.notes,
rescheduleReason: reqBody.rescheduleReason,
};
}
}
+16 -5
View File
@@ -208,11 +208,22 @@ const getSlots = ({
});
if (!!activeOverrides.length) {
const overrides = activeOverrides.flatMap((override) => ({
userIds: override.userId ? [override.userId] : [],
startTime: override.start.getUTCHours() * 60 + override.start.getUTCMinutes(),
endTime: override.end.getUTCHours() * 60 + override.end.getUTCMinutes(),
}));
const overrides = activeOverrides.flatMap((override) => {
const organizerUtcOffset = dayjs(override.start.toString()).tz(override.timeZone).utcOffset();
const inviteeUtcOffset = dayjs(override.start.toString()).tz(timeZone).utcOffset();
const offset = inviteeUtcOffset - organizerUtcOffset;
return {
userIds: override.userId ? [override.userId] : [],
startTime:
dayjs(override.start).utc().add(offset, "minute").hour() * 60 +
dayjs(override.start).utc().add(offset, "minute").minute(),
endTime:
dayjs(override.end).utc().add(offset, "minute").hour() * 60 +
dayjs(override.end).utc().add(offset, "minute").minute(),
};
});
// unset all working hours that relate to this user availability override
overrides.forEach((override) => {
let i = -1;
+1 -1
View File
@@ -220,7 +220,7 @@ export const bookingCreateSchemaLegacyPropsForApi = z.object({
// This is the schema that is used for the API. It has all the legacy props that are part of `responses` now.
export const bookingCreateBodySchemaForApi = extendedBookingCreateBody.merge(
bookingCreateSchemaLegacyPropsForApi
bookingCreateSchemaLegacyPropsForApi.partial()
);
export const schemaBookingCancelParams = z.object({
+76 -5
View File
@@ -19,6 +19,7 @@ import type prisma from "@calcom/prisma";
import { availabilityUserSelect } from "@calcom/prisma";
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
import type { EventBusyDate } from "@calcom/types/Calendar";
import type { WorkingHours } from "@calcom/types/schedule";
import { TRPCError } from "@trpc/server";
@@ -75,12 +76,21 @@ const checkIfIsAvailable = ({
time,
busy,
eventLength,
dateOverrides = [],
workingHours = [],
currentSeats,
organizerTimeZone,
}: {
time: Dayjs;
busy: EventBusyDate[];
eventLength: number;
dateOverrides?: {
start: Date;
end: Date;
}[];
workingHours?: WorkingHours[];
currentSeats?: CurrentSeats;
organizerTimeZone?: string;
}): boolean => {
if (currentSeats?.some((booking) => booking.startTime.toISOString() === time.toISOString())) {
return true;
@@ -89,6 +99,57 @@ const checkIfIsAvailable = ({
const slotEndTime = time.add(eventLength, "minutes").utc();
const slotStartTime = time.utc();
//check if date override for slot exists
let dateOverrideExist = false;
if (
dateOverrides.find((date) => {
const utcOffset = organizerTimeZone ? dayjs.tz(date.start, organizerTimeZone).utcOffset() * -1 : 0;
if (
dayjs(date.start).add(utcOffset, "minutes").format("YYYY MM DD") ===
slotStartTime.format("YYYY MM DD")
) {
dateOverrideExist = true;
if (dayjs(date.start).add(utcOffset, "minutes") === dayjs(date.end).add(utcOffset, "minutes")) {
return true;
}
if (
slotEndTime.isBefore(dayjs(date.start).add(utcOffset, "minutes")) ||
slotEndTime.isSame(dayjs(date.start).add(utcOffset, "minutes"))
) {
return true;
}
if (slotStartTime.isAfter(dayjs(date.end).add(utcOffset, "minutes"))) {
return true;
}
}
})
) {
// slot is not within the date override
return false;
}
if (dateOverrideExist) {
return true;
}
//if no date override for slot exists check if it is within normal work hours
if (
workingHours.find((workingHour) => {
if (workingHour.days.includes(slotStartTime.day())) {
const start = slotStartTime.hour() * 60 + slotStartTime.minute();
const end = slotStartTime.hour() * 60 + slotStartTime.minute();
if (start < workingHour.startTime || end > workingHour.endTime) {
return true;
}
}
})
) {
// slot is outside of working hours
return false;
}
return busy.every((busyTime) => {
const startTime = dayjs.utc(busyTime.start).utc();
const endTime = dayjs.utc(busyTime.end);
@@ -115,7 +176,6 @@ const checkIfIsAvailable = ({
else if (startTime.isBetween(time, slotEndTime)) {
return false;
}
return true;
});
};
@@ -348,7 +408,11 @@ export async function getSchedule(input: z.infer<typeof getScheduleSchema>, ctx:
);
// flattens availability of multiple users
const dateOverrides = userAvailability.flatMap((availability) =>
availability.dateOverrides.map((override) => ({ userId: availability.user.id, ...override }))
availability.dateOverrides.map((override) => ({
userId: availability.user.id,
timeZone: availability.timeZone,
...override,
}))
);
const workingHours = getAggregateWorkingHours(userAvailability, eventType.schedulingType);
const availabilityCheckProps = {
@@ -372,6 +436,9 @@ export async function getSchedule(input: z.infer<typeof getScheduleSchema>, ctx:
const timeSlots: ReturnType<typeof getTimeSlots> = [];
const organizerTimeZone =
eventType.timeZone || eventType?.schedule?.timeZone || userAvailability?.[0]?.timeZone;
for (
let currentCheckedTime = startTime;
currentCheckedTime.isBefore(endTime);
@@ -386,8 +453,7 @@ export async function getSchedule(input: z.infer<typeof getScheduleSchema>, ctx:
dateOverrides,
minimumBookingNotice: eventType.minimumBookingNotice,
frequency: eventType.slotInterval || input.duration || eventType.length,
organizerTimeZone:
eventType.timeZone || eventType?.schedule?.timeZone || userAvailability?.[0]?.timeZone,
organizerTimeZone,
})
);
}
@@ -423,6 +489,7 @@ export async function getSchedule(input: z.infer<typeof getScheduleSchema>, ctx:
time: slot.time,
...schedule,
...availabilityCheckProps,
organizerTimeZone: schedule.timeZone,
});
const endCheckForAvailability = performance.now();
checkForAvailabilityCount++;
@@ -430,6 +497,7 @@ export async function getSchedule(input: z.infer<typeof getScheduleSchema>, ctx:
return isAvailable;
});
});
// what else are you going to call it?
const looseHostAvailability = userAvailability.filter(({ user: { isFixed } }) => !isFixed);
if (looseHostAvailability.length > 0) {
@@ -446,6 +514,7 @@ export async function getSchedule(input: z.infer<typeof getScheduleSchema>, ctx:
time: slot.time,
...userSchedule,
...availabilityCheckProps,
organizerTimeZone: userSchedule.timeZone,
});
});
return slot;
@@ -507,17 +576,19 @@ export async function getSchedule(input: z.infer<typeof getScheduleSchema>, ctx:
return false;
}
const userSchedule = userAvailability.find(({ user: { id: userId } }) => userId === slotUserId);
return checkIfIsAvailable({
time: slot.time,
busy,
...availabilityCheckProps,
organizerTimeZone: userSchedule?.timeZone,
});
});
return slot;
})
.filter((slot) => !!slot.userIds?.length);
}
availableTimeSlots = availableTimeSlots.filter((slot) => isTimeWithinBounds(slot.time));
const computedAvailableSlots = availableTimeSlots.reduce(

Some files were not shown because too many files have changed in this diff Show More