Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1c95f711b | ||
|
|
7cb7006c54 | ||
|
|
e1403bfbeb | ||
|
|
c38dd2d072 | ||
|
|
f9d9e74d6b | ||
|
|
2ab597addc | ||
|
|
33e394d5ed | ||
|
|
4577de3b17 | ||
|
|
658b529840 | ||
|
|
4aed769da4 | ||
|
|
6c753290aa | ||
|
|
59c91607db | ||
|
|
b0530d59af | ||
|
|
b1ff829745 | ||
|
|
d202b536b5 | ||
|
|
2ac5ef10ba | ||
|
|
8a2ab68e9a | ||
|
|
877220caa0 | ||
|
|
0686c08de3 | ||
|
|
d3f1f8b906 | ||
|
|
33a69d3ef6 | ||
|
|
d91b451d7b | ||
|
|
9e17149e5e | ||
|
|
de61b032b7 | ||
|
|
bdbf9bd04d | ||
|
|
ccd589ef38 | ||
|
|
b4c3753566 | ||
|
|
2fdadb98ac | ||
|
|
a33847a878 | ||
|
|
88cf535c8e | ||
|
|
ea0b59d7c0 | ||
|
|
39b93cdb5b | ||
|
|
e27fc05d5f | ||
|
|
20c010fef1 | ||
|
|
1a7911e9e2 | ||
|
|
cb09b5bc5f | ||
|
|
a99031bdd2 | ||
|
|
ada8a98362 | ||
|
|
e176e81bae | ||
|
|
b64dd66c2c | ||
|
|
7fd162601b | ||
|
|
c1f346c935 | ||
|
|
36d47bd2d8 | ||
|
|
26cdb6521f | ||
|
|
014f1986de | ||
|
|
3ef328421f | ||
|
|
c4fe69d826 | ||
|
|
6fd64b2209 | ||
|
|
585e36793a | ||
|
|
09b9370e13 | ||
|
|
a76a4996b4 | ||
|
|
b28d60b6dc | ||
|
|
a716eda14c | ||
|
|
99f1524183 |
No files matched your search
@@ -79,6 +79,9 @@ CALENDSO_ENCRYPTION_KEY=
|
|||||||
# Intercom Config
|
# Intercom Config
|
||||||
NEXT_PUBLIC_INTERCOM_APP_ID=
|
NEXT_PUBLIC_INTERCOM_APP_ID=
|
||||||
|
|
||||||
|
# Secret to enable Intercom Identity Verification
|
||||||
|
INTERCOM_SECRET=
|
||||||
|
|
||||||
# Zendesk Config
|
# Zendesk Config
|
||||||
NEXT_PUBLIC_ZENDESK_KEY=
|
NEXT_PUBLIC_ZENDESK_KEY=
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
- name: Analyze bundle
|
- name: Analyze bundle
|
||||||
run: |
|
run: |
|
||||||
cd apps/web
|
cd apps/web
|
||||||
npx -p nextjs-bundle-analysis report
|
npx -p nextjs-bundle-analysis@0.5.0 report
|
||||||
|
|
||||||
- name: Upload bundle
|
- name: Upload bundle
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
@@ -76,7 +76,7 @@ jobs:
|
|||||||
id: fc
|
id: fc
|
||||||
with:
|
with:
|
||||||
issue-number: ${{ github.event.number }}
|
issue-number: ${{ github.event.number }}
|
||||||
body-includes: "<!-- __NEXTJS_BUNDLE -->"
|
body-includes: "<!-- __NEXTJS_BUNDLE_@calcom/web -->"
|
||||||
|
|
||||||
- name: Create Comment
|
- name: Create Comment
|
||||||
uses: peter-evans/create-or-update-comment@v1.4.4
|
uses: peter-evans/create-or-update-comment@v1.4.4
|
||||||
|
|||||||
@@ -1,167 +0,0 @@
|
|||||||
import type { FormEvent } from "react";
|
|
||||||
import { useCallback, useEffect, useState } from "react";
|
|
||||||
import Cropper from "react-easy-crop";
|
|
||||||
|
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|
||||||
import { Button, Dialog, DialogClose, DialogContent, DialogTrigger } from "@calcom/ui";
|
|
||||||
|
|
||||||
import type { Area } from "@lib/cropImage";
|
|
||||||
import { getCroppedImg } from "@lib/cropImage";
|
|
||||||
import { useFileReader } from "@lib/hooks/useFileReader";
|
|
||||||
|
|
||||||
import Slider from "@components/Slider";
|
|
||||||
|
|
||||||
type ImageUploaderProps = {
|
|
||||||
id: string;
|
|
||||||
buttonMsg: string;
|
|
||||||
handleAvatarChange: (imageSrc: string) => void;
|
|
||||||
imageSrc?: string;
|
|
||||||
target: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface FileEvent<T = Element> extends FormEvent<T> {
|
|
||||||
target: EventTarget & T;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is separate to prevent loading the component until file upload
|
|
||||||
function CropContainer({
|
|
||||||
onCropComplete,
|
|
||||||
imageSrc,
|
|
||||||
}: {
|
|
||||||
imageSrc: string;
|
|
||||||
onCropComplete: (croppedAreaPixels: Area) => void;
|
|
||||||
}) {
|
|
||||||
const { t } = useLocale();
|
|
||||||
const [crop, setCrop] = useState({ x: 0, y: 0 });
|
|
||||||
const [zoom, setZoom] = useState(1);
|
|
||||||
|
|
||||||
const handleZoomSliderChange = (value: number) => {
|
|
||||||
value < 1 ? setZoom(1) : setZoom(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="crop-container h-40 max-h-40 w-40 rounded-full">
|
|
||||||
<div className="relative h-40 w-40 rounded-full">
|
|
||||||
<Cropper
|
|
||||||
image={imageSrc}
|
|
||||||
crop={crop}
|
|
||||||
zoom={zoom}
|
|
||||||
aspect={1}
|
|
||||||
onCropChange={setCrop}
|
|
||||||
onCropComplete={(croppedArea, croppedAreaPixels) => onCropComplete(croppedAreaPixels)}
|
|
||||||
onZoomChange={setZoom}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Slider
|
|
||||||
value={zoom}
|
|
||||||
min={1}
|
|
||||||
max={3}
|
|
||||||
step={0.1}
|
|
||||||
label={t("slide_zoom_drag_instructions")}
|
|
||||||
changeHandler={handleZoomSliderChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated Use `packages/ui/v2/core/ImageUploader.tsx` */
|
|
||||||
export default function ImageUploader({
|
|
||||||
target,
|
|
||||||
id,
|
|
||||||
buttonMsg,
|
|
||||||
handleAvatarChange,
|
|
||||||
...props
|
|
||||||
}: ImageUploaderProps) {
|
|
||||||
const { t } = useLocale();
|
|
||||||
const [imageSrc, setImageSrc] = useState<string | null>(null);
|
|
||||||
const [croppedAreaPixels, setCroppedAreaPixels] = useState<Area | null>(null);
|
|
||||||
|
|
||||||
const [{ result }, setFile] = useFileReader({
|
|
||||||
method: "readAsDataURL",
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (props.imageSrc) setImageSrc(props.imageSrc);
|
|
||||||
}, [props.imageSrc]);
|
|
||||||
|
|
||||||
const onInputFile = (e: FileEvent<HTMLInputElement>) => {
|
|
||||||
if (!e.target.files?.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setFile(e.target.files[0]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const showCroppedImage = useCallback(
|
|
||||||
async (croppedAreaPixels: Area | null) => {
|
|
||||||
try {
|
|
||||||
if (!croppedAreaPixels) return;
|
|
||||||
const croppedImage = await getCroppedImg(
|
|
||||||
result as string /* result is always string when using readAsDataUrl */,
|
|
||||||
croppedAreaPixels
|
|
||||||
);
|
|
||||||
setImageSrc(croppedImage);
|
|
||||||
handleAvatarChange(croppedImage);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[result, handleAvatarChange]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dialog
|
|
||||||
onOpenChange={
|
|
||||||
(opened) => !opened && setFile(null) // unset file on close
|
|
||||||
}>
|
|
||||||
<DialogTrigger asChild>
|
|
||||||
<div className="flex items-center">
|
|
||||||
<Button color="secondary" type="button" className="py-1 text-xs">
|
|
||||||
{buttonMsg}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</DialogTrigger>
|
|
||||||
<DialogContent>
|
|
||||||
<div className="mb-4 sm:flex sm:items-start">
|
|
||||||
<div className="mt-3 text-center sm:mt-0 sm:text-left">
|
|
||||||
<h3 className="font-cal text-emphasis text-lg leading-6" id="modal-title">
|
|
||||||
{t("upload_target", { target })}
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mb-4">
|
|
||||||
<div className="cropper mt-6 flex flex-col items-center justify-center p-8">
|
|
||||||
{!result && (
|
|
||||||
<div className="bg-muted flex h-20 max-h-20 w-20 items-center justify-start rounded-full">
|
|
||||||
{!imageSrc && (
|
|
||||||
<p className="text-inverted w-full text-center text-sm sm:text-xs">
|
|
||||||
{t("no_target", { target })}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
{imageSrc && (
|
|
||||||
// eslint-disable-next-line @next/next/no-img-element
|
|
||||||
<img className="h-20 w-20 rounded-full" src={imageSrc} alt={target} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{result && <CropContainer imageSrc={result as string} onCropComplete={setCroppedAreaPixels} />}
|
|
||||||
<label className="border-default bg-default hover:bg-mutedover:text-emphasis dark:hover:bg-inverted text-default dark:text-inverted focus:ring-empthasis mt-8 rounded-sm border px-3 py-1 text-xs font-medium leading-4 focus:outline-none focus:ring-2 focus:ring-offset-1 dark:border-gray-800 dark:bg-transparent">
|
|
||||||
<input
|
|
||||||
onInput={onInputFile}
|
|
||||||
type="file"
|
|
||||||
name={id}
|
|
||||||
placeholder={t("upload_image")}
|
|
||||||
className="pointer-events-none absolute mt-4 opacity-0"
|
|
||||||
accept="image/*"
|
|
||||||
/>
|
|
||||||
{t("choose_a_file")}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mt-5 gap-x-2 sm:mt-4 sm:flex sm:flex-row-reverse">
|
|
||||||
<DialogClose onClick={() => showCroppedImage(croppedAreaPixels)}>{t("save")}</DialogClose>
|
|
||||||
<DialogClose color="secondary">{t("cancel")}</DialogClose>
|
|
||||||
</div>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import { AdminRequired } from "components/ui/AdminRequired";
|
|
||||||
import { noop } from "lodash";
|
import { noop } from "lodash";
|
||||||
import type { LinkProps } from "next/link";
|
import type { LinkProps } from "next/link";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
@@ -6,6 +5,7 @@ import { useRouter } from "next/router";
|
|||||||
import type { FC, MouseEventHandler } from "react";
|
import type { FC, MouseEventHandler } from "react";
|
||||||
import { Fragment } from "react";
|
import { Fragment } from "react";
|
||||||
|
|
||||||
|
import { PermissionContainer } from "@calcom/features/auth/PermissionContainer";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
|
|
||||||
import classNames from "@lib/classNames";
|
import classNames from "@lib/classNames";
|
||||||
@@ -60,7 +60,7 @@ const NavTabs: FC<NavTabProps> = ({ tabs, linkProps, ...props }) => {
|
|||||||
}
|
}
|
||||||
: noop;
|
: noop;
|
||||||
|
|
||||||
const Component = tab.adminRequired ? AdminRequired : Fragment;
|
const Component = tab.adminRequired ? PermissionContainer : Fragment;
|
||||||
const className = tab.className || "";
|
const className = tab.className || "";
|
||||||
return (
|
return (
|
||||||
<Component key={tab.name}>
|
<Component key={tab.name}>
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -46,7 +46,7 @@ export default function SettingsShell({
|
|||||||
...rest
|
...rest
|
||||||
}: { children: React.ReactNode } & ComponentProps<typeof Shell>) {
|
}: { children: React.ReactNode } & ComponentProps<typeof Shell>) {
|
||||||
return (
|
return (
|
||||||
<Shell {...rest}>
|
<Shell {...rest} hideHeadingOnMobile>
|
||||||
<div className="sm:mx-auto">
|
<div className="sm:mx-auto">
|
||||||
<NavTabs tabs={tabs} />
|
<NavTabs tabs={tabs} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
import * as SliderPrimitive from "@radix-ui/react-slider";
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
const Slider = ({
|
|
||||||
value,
|
|
||||||
label,
|
|
||||||
changeHandler,
|
|
||||||
...props
|
|
||||||
}: Omit<SliderPrimitive.SliderProps, "value"> & {
|
|
||||||
value: number;
|
|
||||||
label: string;
|
|
||||||
changeHandler: (value: number) => void;
|
|
||||||
}) => (
|
|
||||||
<SliderPrimitive.Root
|
|
||||||
className="slider mt-2"
|
|
||||||
value={[value]}
|
|
||||||
aria-label={label}
|
|
||||||
onValueChange={(value: number[]) => changeHandler(value[0] ?? value)}
|
|
||||||
{...props}>
|
|
||||||
<SliderPrimitive.Track className="slider-track">
|
|
||||||
<SliderPrimitive.Range className="slider-range" />
|
|
||||||
</SliderPrimitive.Track>
|
|
||||||
<SliderPrimitive.Thumb className="slider-thumb" />
|
|
||||||
</SliderPrimitive.Root>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default Slider;
|
|
||||||
@@ -6,7 +6,7 @@ import React, { useState } from "react";
|
|||||||
import useAddAppMutation from "@calcom/app-store/_utils/useAddAppMutation";
|
import useAddAppMutation from "@calcom/app-store/_utils/useAddAppMutation";
|
||||||
import { InstallAppButton, AppDependencyComponent } from "@calcom/app-store/components";
|
import { InstallAppButton, AppDependencyComponent } from "@calcom/app-store/components";
|
||||||
import DisconnectIntegration from "@calcom/features/apps/components/DisconnectIntegration";
|
import DisconnectIntegration from "@calcom/features/apps/components/DisconnectIntegration";
|
||||||
import LicenseRequired from "@calcom/features/ee/common/components/v2/LicenseRequired";
|
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
|
||||||
import Shell from "@calcom/features/shell/Shell";
|
import Shell from "@calcom/features/shell/Shell";
|
||||||
import classNames from "@calcom/lib/classNames";
|
import classNames from "@calcom/lib/classNames";
|
||||||
import { APP_NAME, COMPANY_NAME, SUPPORT_MAIL_ADDRESS } from "@calcom/lib/constants";
|
import { APP_NAME, COMPANY_NAME, SUPPORT_MAIL_ADDRESS } from "@calcom/lib/constants";
|
||||||
@@ -41,7 +41,7 @@ const Component = ({
|
|||||||
isTemplate,
|
isTemplate,
|
||||||
dependencies,
|
dependencies,
|
||||||
}: Parameters<typeof App>[0]) => {
|
}: Parameters<typeof App>[0]) => {
|
||||||
const { t } = useLocale();
|
const { t, i18n } = useLocale();
|
||||||
const hasDescriptionItems = descriptionItems && descriptionItems.length > 0;
|
const hasDescriptionItems = descriptionItems && descriptionItems.length > 0;
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@@ -247,7 +247,7 @@ const Component = ({
|
|||||||
t("free_to_use_apps")
|
t("free_to_use_apps")
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{Intl.NumberFormat("en-US", {
|
{Intl.NumberFormat(i18n.language, {
|
||||||
style: "currency",
|
style: "currency",
|
||||||
currency: "USD",
|
currency: "USD",
|
||||||
useGrouping: false,
|
useGrouping: false,
|
||||||
@@ -366,7 +366,7 @@ export default function App(props: {
|
|||||||
dependencies?: string[];
|
dependencies?: string[];
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Shell smallHeading isPublic heading={<ShellHeading />} backPath="/apps" withoutSeo>
|
<Shell smallHeading isPublic hideHeadingOnMobile heading={<ShellHeading />} backPath="/apps" withoutSeo>
|
||||||
<HeadSeo
|
<HeadSeo
|
||||||
title={props.name}
|
title={props.name}
|
||||||
description={props.description}
|
description={props.description}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default function AppsLayout({ children, actions, emptyStore, ...rest }: A
|
|||||||
if (session.status === "loading") return <></>;
|
if (session.status === "loading") return <></>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Shell {...rest} actions={actions?.("block")}>
|
<Shell {...rest} actions={actions?.("block")} hideHeadingOnMobile>
|
||||||
<div className="flex flex-col xl:flex-row">
|
<div className="flex flex-col xl:flex-row">
|
||||||
<main className="w-full">
|
<main className="w-full">
|
||||||
{emptyStore ? (
|
{emptyStore ? (
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export default function InstalledAppsLayout({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Shell {...rest}>
|
<Shell {...rest} hideHeadingOnMobile>
|
||||||
<AppCategoryNavigation baseURL="/apps/installed" containerClassname="min-w-0 w-full">
|
<AppCategoryNavigation baseURL="/apps/installed" containerClassname="min-w-0 w-full">
|
||||||
{children}
|
{children}
|
||||||
</AppCategoryNavigation>
|
</AppCategoryNavigation>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export function AvailableEventLocations({ locations }: { locations: Props["event
|
|||||||
return (
|
return (
|
||||||
<div key={`${location.type}-${index}`} className="flex flex-row items-center text-sm font-medium">
|
<div key={`${location.type}-${index}`} className="flex flex-row items-center text-sm font-medium">
|
||||||
{eventLocationType.iconUrl === "/link.svg" ? (
|
{eventLocationType.iconUrl === "/link.svg" ? (
|
||||||
<Link className="text-default min-h-4 min-w-4 ml-[2px] opacity-70 ltr:mr-[10px] rtl:ml-[10px] " />
|
<Link className="text-default ml-[2px] h-4 w-4 ltr:mr-[10px] rtl:ml-[10px] " />
|
||||||
) : (
|
) : (
|
||||||
<img
|
<img
|
||||||
src={eventLocationType.iconUrl}
|
src={eventLocationType.iconUrl}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
import { i18n } from "next-i18next";
|
||||||
import type { TFunction } from "next-i18next";
|
import type { TFunction } from "next-i18next";
|
||||||
import { FormattedNumber, IntlProvider } from "react-intl";
|
|
||||||
|
|
||||||
import getPaymentAppData from "@calcom/lib/getPaymentAppData";
|
import getPaymentAppData from "@calcom/lib/getPaymentAppData";
|
||||||
import { CreditCard } from "@calcom/ui/components/icon";
|
import { CreditCard } from "@calcom/ui/components/icon";
|
||||||
@@ -7,28 +7,29 @@ import { CreditCard } from "@calcom/ui/components/icon";
|
|||||||
const BookingDescriptionPayment = (props: {
|
const BookingDescriptionPayment = (props: {
|
||||||
eventType: Parameters<typeof getPaymentAppData>[0];
|
eventType: Parameters<typeof getPaymentAppData>[0];
|
||||||
t: TFunction;
|
t: TFunction;
|
||||||
|
i18n: typeof i18n;
|
||||||
}) => {
|
}) => {
|
||||||
const paymentAppData = getPaymentAppData(props.eventType);
|
const paymentAppData = getPaymentAppData(props.eventType);
|
||||||
if (!paymentAppData || paymentAppData.price <= 0) return null;
|
if (!paymentAppData || paymentAppData.price <= 0) return null;
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
amount: paymentAppData.price / 100.0,
|
||||||
|
formatParams: { amount: { currency: paymentAppData.currency } },
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<p className="text-bookinglight -ml-2 px-2 text-sm ">
|
<p className="text-bookinglight -ml-2 px-2 text-sm ">
|
||||||
<CreditCard className="ml-[2px] -mt-1 inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
|
<CreditCard className="ml-[2px] -mt-1 inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
|
||||||
{paymentAppData.paymentOption === "HOLD" ? (
|
{paymentAppData.paymentOption === "HOLD" ? (
|
||||||
<>
|
<>{props.t("no_show_fee_amount", params)}</>
|
||||||
{props.t("no_show_fee_amount", {
|
|
||||||
amount: paymentAppData.price / 100.0,
|
|
||||||
formatParams: { amount: { currency: paymentAppData.currency } },
|
|
||||||
})}
|
|
||||||
</>
|
|
||||||
) : (
|
) : (
|
||||||
<IntlProvider locale="en">
|
<>
|
||||||
<FormattedNumber
|
{/* If undefined this will default to the browser locale */}
|
||||||
value={paymentAppData.price / 100.0}
|
{new Intl.NumberFormat(i18n?.language, {
|
||||||
style="currency"
|
style: "currency",
|
||||||
currency={paymentAppData.currency?.toUpperCase()}
|
currency: paymentAppData.currency,
|
||||||
/>
|
}).format(paymentAppData.price / 100)}
|
||||||
</IntlProvider>
|
</>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useEffect, useMemo, useReducer, useState } from "react";
|
import { useEffect, useMemo, useReducer, useState } from "react";
|
||||||
import { FormattedNumber, IntlProvider } from "react-intl";
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import BookingPageTagManager from "@calcom/app-store/BookingPageTagManager";
|
import BookingPageTagManager from "@calcom/app-store/BookingPageTagManager";
|
||||||
@@ -75,7 +74,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
|||||||
brandColor: profile.brandColor,
|
brandColor: profile.brandColor,
|
||||||
darkBrandColor: profile.darkBrandColor,
|
darkBrandColor: profile.darkBrandColor,
|
||||||
});
|
});
|
||||||
const { t } = useLocale();
|
const { t, i18n } = useLocale();
|
||||||
const availabilityDatePickerEmbedStyles = useEmbedStyles("availabilityDatePicker");
|
const availabilityDatePickerEmbedStyles = useEmbedStyles("availabilityDatePicker");
|
||||||
//TODO: Plan to remove shouldAlignCentrallyInEmbed config
|
//TODO: Plan to remove shouldAlignCentrallyInEmbed config
|
||||||
const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left";
|
const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left";
|
||||||
@@ -124,16 +123,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
|||||||
[timeZone]
|
[timeZone]
|
||||||
);
|
);
|
||||||
const paymentAppData = getPaymentAppData(eventType);
|
const paymentAppData = getPaymentAppData(eventType);
|
||||||
const paymentAmount = () => {
|
|
||||||
return;
|
|
||||||
<IntlProvider locale="en">
|
|
||||||
<FormattedNumber
|
|
||||||
value={paymentAppData.price / 100.0}
|
|
||||||
style="currency"
|
|
||||||
currency={paymentAppData.currency?.toUpperCase()}
|
|
||||||
/>
|
|
||||||
</IntlProvider>;
|
|
||||||
};
|
|
||||||
const rainbowAppData = getEventTypeAppData(eventType, "rainbow") || {};
|
const rainbowAppData = getEventTypeAppData(eventType, "rainbow") || {};
|
||||||
const rawSlug = profile.slug ? profile.slug.split("/") : [];
|
const rawSlug = profile.slug ? profile.slug.split("/") : [];
|
||||||
if (rawSlug.length > 1) rawSlug.pop(); //team events have team name as slug, but user events have [user]/[type] as slug.
|
if (rawSlug.length > 1) rawSlug.pop(); //team events have team name as slug, but user events have [user]/[type] as slug.
|
||||||
@@ -257,13 +247,12 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
|||||||
})}
|
})}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<IntlProvider locale="en">
|
<>
|
||||||
<FormattedNumber
|
{new Intl.NumberFormat(i18n.language, {
|
||||||
value={paymentAppData.price / 100.0}
|
style: "currency",
|
||||||
style="currency"
|
currency: paymentAppData.currency,
|
||||||
currency={paymentAppData.currency?.toUpperCase()}
|
}).format(paymentAppData.price / 100)}
|
||||||
/>
|
</>
|
||||||
</IntlProvider>
|
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -554,7 +554,7 @@ const BookingPage = ({
|
|||||||
{showEventTypeDetails && (
|
{showEventTypeDetails && (
|
||||||
<div className="sm:border-subtle text-default flex flex-col px-6 pt-6 pb-0 sm:w-1/2 sm:border-r sm:pb-6">
|
<div className="sm:border-subtle text-default flex flex-col px-6 pt-6 pb-0 sm:w-1/2 sm:border-r sm:pb-6">
|
||||||
<BookingDescription isBookingPage profile={profile} eventType={eventType}>
|
<BookingDescription isBookingPage profile={profile} eventType={eventType}>
|
||||||
<BookingDescriptionPayment eventType={eventType} t={t} />
|
<BookingDescriptionPayment eventType={eventType} t={t} i18n={i18n} />
|
||||||
{!rescheduleUid && eventType.recurringEvent?.freq && recurringEventCount && (
|
{!rescheduleUid && eventType.recurringEvent?.freq && recurringEventCount && (
|
||||||
<div className="dark:text-inverted text-default items-start text-sm font-medium">
|
<div className="dark:text-inverted text-default items-start text-sm font-medium">
|
||||||
<RefreshCw className="ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
|
<RefreshCw className="ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { Trans } from "next-i18next";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import type { Dispatch, SetStateAction } from "react";
|
import type { Dispatch, SetStateAction } from "react";
|
||||||
import { IntlProvider, FormattedNumber } from "react-intl";
|
|
||||||
|
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
@@ -40,6 +38,11 @@ export const ChargeCardDialog = (props: IRescheduleDialog) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const currencyStringParams = {
|
||||||
|
amount: props.paymentAmount / 100.0,
|
||||||
|
formatParams: { amount: { currency: props.paymentCurrency } },
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={isOpenDialog} onOpenChange={setIsOpenDialog}>
|
<Dialog open={isOpenDialog} onOpenChange={setIsOpenDialog}>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
@@ -49,19 +52,7 @@ export const ChargeCardDialog = (props: IRescheduleDialog) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="pt-1">
|
<div className="pt-1">
|
||||||
<DialogHeader title={t("charge_card")} />
|
<DialogHeader title={t("charge_card")} />
|
||||||
<Trans i18nKey="charge_card_dialog_body">
|
<p>{t("charge_card_dialog_body", currencyStringParams)}</p>
|
||||||
<p className="text-sm text-gray-500">
|
|
||||||
You are about to charge the attendee{" "}
|
|
||||||
<IntlProvider locale="en">
|
|
||||||
<FormattedNumber
|
|
||||||
value={props.paymentAmount / 100.0}
|
|
||||||
style="currency"
|
|
||||||
currency={props.paymentCurrency?.toUpperCase()}
|
|
||||||
/>
|
|
||||||
</IntlProvider>
|
|
||||||
. Are you sure you want to continue?
|
|
||||||
</p>
|
|
||||||
</Trans>
|
|
||||||
|
|
||||||
{chargeError && (
|
{chargeError && (
|
||||||
<div className="mt-4 flex text-red-500">
|
<div className="mt-4 flex text-red-500">
|
||||||
@@ -80,16 +71,7 @@ export const ChargeCardDialog = (props: IRescheduleDialog) => {
|
|||||||
bookingId,
|
bookingId,
|
||||||
})
|
})
|
||||||
}>
|
}>
|
||||||
<Trans i18nKey="charge_card_confirm">
|
{t("charge_attendee", currencyStringParams)}
|
||||||
Charge attendee{" "}
|
|
||||||
<IntlProvider locale="en">
|
|
||||||
<FormattedNumber
|
|
||||||
value={props.paymentAmount / 100.0}
|
|
||||||
style="currency"
|
|
||||||
currency={props.paymentCurrency?.toUpperCase()}
|
|
||||||
/>
|
|
||||||
</IntlProvider>
|
|
||||||
</Trans>
|
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -174,7 +174,6 @@ export const EditLocationDialog = (props: ISetLocationDialog) => {
|
|||||||
id="locationInput"
|
id="locationInput"
|
||||||
placeholder={t(eventLocationType.organizerInputPlaceholder || "")}
|
placeholder={t(eventLocationType.organizerInputPlaceholder || "")}
|
||||||
required
|
required
|
||||||
className="border-default block w-full rounded-sm text-sm"
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
defaultValue={
|
defaultValue={
|
||||||
defaultLocation ? defaultLocation[eventLocationType.defaultValueVariable] : undefined
|
defaultLocation ? defaultLocation[eventLocationType.defaultValueVariable] : undefined
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
import { SchedulingType } from "@prisma/client";
|
import { SchedulingType } from "@prisma/client";
|
||||||
import type { FormValues, EventTypeSetup } from "pages/event-types/[type]";
|
import type { EventTypeSetup, FormValues } from "pages/event-types/[type]";
|
||||||
|
import { useState } from "react";
|
||||||
import { Controller, useFormContext } from "react-hook-form";
|
import { Controller, useFormContext } from "react-hook-form";
|
||||||
import type { OptionProps, SingleValueProps } from "react-select";
|
import type { OptionProps, SingleValueProps } from "react-select";
|
||||||
import { components } from "react-select";
|
import { components } from "react-select";
|
||||||
|
|
||||||
import dayjs from "@calcom/dayjs";
|
import dayjs from "@calcom/dayjs";
|
||||||
import useLockedFieldsManager from "@calcom/features/ee/managed-event-types/hooks/useLockedFieldsManager";
|
import useLockedFieldsManager from "@calcom/features/ee/managed-event-types/hooks/useLockedFieldsManager";
|
||||||
import { NewScheduleButton } from "@calcom/features/schedules";
|
|
||||||
import classNames from "@calcom/lib/classNames";
|
import classNames from "@calcom/lib/classNames";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { weekdayNames } from "@calcom/lib/weekday";
|
import { weekdayNames } from "@calcom/lib/weekday";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
|
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
|
||||||
import { Badge, Button, Select, SettingsToggle, SkeletonText, EmptyScreen } from "@calcom/ui";
|
import { Badge, Button, Select, SettingsToggle, SkeletonText } from "@calcom/ui";
|
||||||
import { ExternalLink, Globe, Clock } from "@calcom/ui/components/icon";
|
import { ExternalLink, Globe } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
type AvailabilityOption = {
|
import { SelectSkeletonLoader } from "@components/availability/SkeletonLoader";
|
||||||
|
|
||||||
|
export type AvailabilityOption = {
|
||||||
label: string;
|
label: string;
|
||||||
value: number;
|
value: number;
|
||||||
isDefault: boolean;
|
isDefault: boolean;
|
||||||
@@ -62,40 +64,12 @@ const SingleValue = ({ ...props }: SingleValueProps<AvailabilityOption>) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const AvailabilitySelect = ({
|
|
||||||
className = "",
|
|
||||||
options,
|
|
||||||
value,
|
|
||||||
...props
|
|
||||||
}: {
|
|
||||||
className?: string;
|
|
||||||
name: string;
|
|
||||||
value: AvailabilityOption | undefined;
|
|
||||||
options: AvailabilityOption[];
|
|
||||||
isDisabled?: boolean;
|
|
||||||
onBlur: () => void;
|
|
||||||
onChange: (value: AvailabilityOption | null) => void;
|
|
||||||
}) => {
|
|
||||||
const { t } = useLocale();
|
|
||||||
return (
|
|
||||||
<Select
|
|
||||||
placeholder={t("select")}
|
|
||||||
options={options}
|
|
||||||
isDisabled={props.isDisabled}
|
|
||||||
isSearchable={false}
|
|
||||||
onChange={props.onChange}
|
|
||||||
className={classNames("block w-full min-w-0 flex-1 rounded-sm text-sm", className)}
|
|
||||||
defaultValue={value}
|
|
||||||
components={{ Option, SingleValue }}
|
|
||||||
isMulti={false}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const format = (date: Date, hour12: boolean) =>
|
const format = (date: Date, hour12: boolean) =>
|
||||||
Intl.DateTimeFormat(undefined, { hour: "numeric", minute: "numeric", hour12 }).format(
|
Intl.DateTimeFormat(undefined, {
|
||||||
new Date(dayjs.utc(date).format("YYYY-MM-DDTHH:mm:ss"))
|
hour: "numeric",
|
||||||
);
|
minute: "numeric",
|
||||||
|
hourCycle: hour12 ? "h12" : "h24",
|
||||||
|
}).format(new Date(dayjs.utc(date).format("YYYY-MM-DDTHH:mm:ss")));
|
||||||
|
|
||||||
const EventTypeScheduleDetails = ({
|
const EventTypeScheduleDetails = ({
|
||||||
isManagedEventType,
|
isManagedEventType,
|
||||||
@@ -188,61 +162,57 @@ const EventTypeSchedule = ({ eventType }: { eventType: EventTypeSetup }) => {
|
|||||||
);
|
);
|
||||||
const { watch } = useFormContext<FormValues>();
|
const { watch } = useFormContext<FormValues>();
|
||||||
const watchSchedule = watch("schedule");
|
const watchSchedule = watch("schedule");
|
||||||
|
const formMethods = useFormContext<FormValues>();
|
||||||
|
const [options, setOptions] = useState<AvailabilityOption[]>([]);
|
||||||
|
|
||||||
const { data, isLoading } = trpc.viewer.availability.list.useQuery();
|
const { isLoading } = trpc.viewer.availability.list.useQuery(undefined, {
|
||||||
|
onSuccess: ({ schedules }) => {
|
||||||
|
const options = schedules.map((schedule) => ({
|
||||||
|
value: schedule.id,
|
||||||
|
label: schedule.name,
|
||||||
|
isDefault: schedule.isDefault,
|
||||||
|
isManaged: false,
|
||||||
|
}));
|
||||||
|
|
||||||
if (!data?.schedules.length && !isLoading)
|
// We are showing a managed event for a team admin, so adding the option to let members choose their schedule
|
||||||
return (
|
if (isManagedEventType) {
|
||||||
<EmptyScreen
|
options.push({
|
||||||
Icon={Clock}
|
value: 0,
|
||||||
headline={t("new_schedule_heading")}
|
label: t("members_default_schedule"),
|
||||||
description={t("new_schedule_description")}
|
isDefault: false,
|
||||||
buttonRaw={<NewScheduleButton fromEventType />}
|
isManaged: false,
|
||||||
border={false}
|
});
|
||||||
/>
|
}
|
||||||
);
|
|
||||||
|
|
||||||
const schedules = data?.schedules || [];
|
// We are showing a managed event for a member and team owner selected their own schedule, so adding
|
||||||
|
// the managed schedule option
|
||||||
|
if (
|
||||||
|
isChildrenManagedEventType &&
|
||||||
|
watchSchedule &&
|
||||||
|
!schedules.find((schedule) => schedule.id === watchSchedule)
|
||||||
|
) {
|
||||||
|
options.push({
|
||||||
|
value: watchSchedule,
|
||||||
|
label: eventType.scheduleName ?? t("default_schedule_name"),
|
||||||
|
isDefault: false,
|
||||||
|
isManaged: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const options = schedules.map((schedule) => ({
|
setOptions(options);
|
||||||
value: schedule.id,
|
|
||||||
label: schedule.name,
|
|
||||||
isDefault: schedule.isDefault,
|
|
||||||
isManaged: false,
|
|
||||||
}));
|
|
||||||
|
|
||||||
// We are showing a managed event for a team admin, so adding the option to let members choose their schedule
|
const scheduleId = formMethods.getValues("schedule");
|
||||||
if (isManagedEventType) {
|
const value = options.find((option) =>
|
||||||
options.push({
|
scheduleId
|
||||||
value: 0,
|
? option.value === scheduleId
|
||||||
label: t("members_default_schedule"),
|
: option.value === schedules.find((schedule) => schedule.isDefault)?.id
|
||||||
isDefault: false,
|
);
|
||||||
isManaged: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are showing a managed event for a member and team owner selected their own schedule, so adding
|
formMethods.setValue("availability", value);
|
||||||
// the managed schedule option
|
},
|
||||||
if (
|
});
|
||||||
isChildrenManagedEventType &&
|
|
||||||
watchSchedule &&
|
|
||||||
!schedules.find((schedule) => schedule.id === watchSchedule)
|
|
||||||
) {
|
|
||||||
options.push({
|
|
||||||
value: watchSchedule,
|
|
||||||
label: eventType.scheduleName ?? t("default_schedule_name"),
|
|
||||||
isDefault: false,
|
|
||||||
isManaged: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const value = options.find((option) =>
|
const availabilityValue = formMethods.watch("availability");
|
||||||
watchSchedule
|
|
||||||
? option.value === watchSchedule
|
|
||||||
: isManagedEventType
|
|
||||||
? option.value === 0
|
|
||||||
: option.value === schedules.find((schedule) => schedule.isDefault)?.id
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
@@ -251,27 +221,33 @@ const EventTypeSchedule = ({ eventType }: { eventType: EventTypeSetup }) => {
|
|||||||
{t("availability")}
|
{t("availability")}
|
||||||
{shouldLockIndicator("availability")}
|
{shouldLockIndicator("availability")}
|
||||||
</label>
|
</label>
|
||||||
<Controller
|
{isLoading && <SelectSkeletonLoader />}
|
||||||
name="schedule"
|
{!isLoading && (
|
||||||
render={({ field }) => (
|
<Controller
|
||||||
<>
|
name="schedule"
|
||||||
<AvailabilitySelect
|
render={({ field }) => {
|
||||||
value={value}
|
return (
|
||||||
options={options}
|
<Select
|
||||||
onBlur={field.onBlur}
|
placeholder={t("select")}
|
||||||
isDisabled={shouldLockDisableProps("schedule").disabled}
|
options={options}
|
||||||
name={field.name}
|
isSearchable={false}
|
||||||
onChange={(selected) => {
|
onChange={(selected) => {
|
||||||
field.onChange(selected?.value || null);
|
field.onChange(selected?.value || null);
|
||||||
}}
|
if (selected?.value) formMethods.setValue("availability", selected);
|
||||||
/>
|
}}
|
||||||
</>
|
className="block w-full min-w-0 flex-1 rounded-sm text-sm"
|
||||||
)}
|
value={availabilityValue}
|
||||||
/>
|
components={{ Option, SingleValue }}
|
||||||
|
isMulti={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{value?.value !== 0 ? (
|
{availabilityValue?.value !== 0 ? (
|
||||||
<EventTypeScheduleDetails
|
<EventTypeScheduleDetails
|
||||||
selectedScheduleValue={value}
|
selectedScheduleValue={availabilityValue}
|
||||||
isManagedEventType={isManagedEventType || isChildrenManagedEventType}
|
isManagedEventType={isManagedEventType || isChildrenManagedEventType}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { z } from "zod";
|
|||||||
import type { EventLocationType } from "@calcom/app-store/locations";
|
import type { EventLocationType } from "@calcom/app-store/locations";
|
||||||
import { getEventLocationType, MeetLocationType, LocationType } from "@calcom/app-store/locations";
|
import { getEventLocationType, MeetLocationType, LocationType } from "@calcom/app-store/locations";
|
||||||
import useLockedFieldsManager from "@calcom/features/ee/managed-event-types/hooks/useLockedFieldsManager";
|
import useLockedFieldsManager from "@calcom/features/ee/managed-event-types/hooks/useLockedFieldsManager";
|
||||||
|
import cx from "@calcom/lib/classNames";
|
||||||
import { CAL_URL } from "@calcom/lib/constants";
|
import { CAL_URL } from "@calcom/lib/constants";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { md } from "@calcom/lib/markdownIt";
|
import { md } from "@calcom/lib/markdownIt";
|
||||||
@@ -80,6 +81,7 @@ const DescriptionEditor = (props: DescriptionEditorProps) => {
|
|||||||
const [mounted, setIsMounted] = useState(false);
|
const [mounted, setIsMounted] = useState(false);
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const { description } = props;
|
const { description } = props;
|
||||||
|
const [firstRender, setFirstRender] = useState(true);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsMounted(true);
|
setIsMounted(true);
|
||||||
}, []);
|
}, []);
|
||||||
@@ -91,6 +93,8 @@ const DescriptionEditor = (props: DescriptionEditorProps) => {
|
|||||||
excludedToolbarItems={["blockType"]}
|
excludedToolbarItems={["blockType"]}
|
||||||
placeholder={t("quick_video_meeting")}
|
placeholder={t("quick_video_meeting")}
|
||||||
editable={props.editable}
|
editable={props.editable}
|
||||||
|
firstRender={firstRender}
|
||||||
|
setFirstRender={setFirstRender}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<SkeletonContainer>
|
<SkeletonContainer>
|
||||||
@@ -277,7 +281,13 @@ export const EventSetupTab = (
|
|||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<img
|
<img
|
||||||
src={eventLocationType.iconUrl}
|
src={eventLocationType.iconUrl}
|
||||||
className="h-4 w-4"
|
className={cx(
|
||||||
|
"h-4 w-4",
|
||||||
|
// invert all the icons except app icons
|
||||||
|
eventLocationType.iconUrl &&
|
||||||
|
!eventLocationType.iconUrl.startsWith("/api") &&
|
||||||
|
"dark:invert"
|
||||||
|
)}
|
||||||
alt={`${eventLocationType.label} logo`}
|
alt={`${eventLocationType.label} logo`}
|
||||||
/>
|
/>
|
||||||
<span className="line-clamp-1 ms-1 text-sm">{eventLabel}</span>
|
<span className="line-clamp-1 ms-1 text-sm">{eventLabel}</span>
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import {
|
|||||||
} from "@calcom/ui/components/icon";
|
} from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
import { EmbedButton, EmbedDialog } from "@components/Embed";
|
import { EmbedButton, EmbedDialog } from "@components/Embed";
|
||||||
|
import type { AvailabilityOption } from "@components/eventtype/EventAvailabilityTab";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
@@ -63,6 +64,7 @@ type Props = {
|
|||||||
enabledWorkflowsNumber: number;
|
enabledWorkflowsNumber: number;
|
||||||
formMethods: UseFormReturn<FormValues>;
|
formMethods: UseFormReturn<FormValues>;
|
||||||
isUpdateMutationLoading?: boolean;
|
isUpdateMutationLoading?: boolean;
|
||||||
|
availability?: AvailabilityOption;
|
||||||
};
|
};
|
||||||
|
|
||||||
function getNavigation(props: {
|
function getNavigation(props: {
|
||||||
@@ -71,8 +73,10 @@ function getNavigation(props: {
|
|||||||
enabledAppsNumber: number;
|
enabledAppsNumber: number;
|
||||||
enabledWorkflowsNumber: number;
|
enabledWorkflowsNumber: number;
|
||||||
installedAppsNumber: number;
|
installedAppsNumber: number;
|
||||||
|
availability: AvailabilityOption | undefined;
|
||||||
}) {
|
}) {
|
||||||
const { eventType, t, enabledAppsNumber, installedAppsNumber, enabledWorkflowsNumber } = props;
|
const { eventType, t, enabledAppsNumber, installedAppsNumber, enabledWorkflowsNumber, availability } =
|
||||||
|
props;
|
||||||
const duration =
|
const duration =
|
||||||
eventType.metadata?.multipleDuration?.map((duration) => ` ${duration}`) || eventType.length;
|
eventType.metadata?.multipleDuration?.map((duration) => ` ${duration}`) || eventType.length;
|
||||||
|
|
||||||
@@ -128,6 +132,7 @@ function EventTypeSingleLayout({
|
|||||||
enabledWorkflowsNumber,
|
enabledWorkflowsNumber,
|
||||||
isUpdateMutationLoading,
|
isUpdateMutationLoading,
|
||||||
formMethods,
|
formMethods,
|
||||||
|
availability,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const utils = trpc.useContext();
|
const utils = trpc.useContext();
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
@@ -171,6 +176,7 @@ function EventTypeSingleLayout({
|
|||||||
enabledAppsNumber,
|
enabledAppsNumber,
|
||||||
installedAppsNumber,
|
installedAppsNumber,
|
||||||
enabledWorkflowsNumber,
|
enabledWorkflowsNumber,
|
||||||
|
availability,
|
||||||
});
|
});
|
||||||
navigation.splice(1, 0, {
|
navigation.splice(1, 0, {
|
||||||
name: "availability",
|
name: "availability",
|
||||||
@@ -214,7 +220,7 @@ function EventTypeSingleLayout({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return navigation;
|
return navigation;
|
||||||
}, [t, eventType, installedAppsNumber, enabledAppsNumber, enabledWorkflowsNumber, team]);
|
}, [t, eventType, installedAppsNumber, enabledAppsNumber, enabledWorkflowsNumber, team, availability]);
|
||||||
|
|
||||||
const permalink = `${CAL_URL}/${team ? `team/${team.slug}` : eventType.users[0].username}/${
|
const permalink = `${CAL_URL}/${team ? `team/${team.slug}` : eventType.users[0].username}/${
|
||||||
eventType.slug
|
eventType.slug
|
||||||
@@ -374,6 +380,8 @@ function EventTypeSingleLayout({
|
|||||||
tabs={EventTypeTabs}
|
tabs={EventTypeTabs}
|
||||||
sticky
|
sticky
|
||||||
linkProps={{ shallow: true }}
|
linkProps={{ shallow: true }}
|
||||||
|
itemClassname="items-start"
|
||||||
|
iconClassName="md:mt-px"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-2 md:mx-0 md:p-0 xl:hidden">
|
<div className="p-2 md:mx-0 md:p-0 xl:hidden">
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ const UserProfile = (props: IUserProfileProps) => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const createEventType = trpc.viewer.eventTypes.create.useMutation();
|
const createEventType = trpc.viewer.eventTypes.create.useMutation();
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
|
const [firstRender, setFirstRender] = useState(true);
|
||||||
|
|
||||||
const mutation = trpc.viewer.updateProfile.useMutation({
|
const mutation = trpc.viewer.updateProfile.useMutation({
|
||||||
onSuccess: async (_data, context) => {
|
onSuccess: async (_data, context) => {
|
||||||
@@ -147,6 +148,8 @@ const UserProfile = (props: IUserProfileProps) => {
|
|||||||
getText={() => md.render(getValues("bio") || user?.bio || "")}
|
getText={() => md.render(getValues("bio") || user?.bio || "")}
|
||||||
setText={(value: string) => setValue("bio", turndown(value))}
|
setText={(value: string) => setValue("bio", turndown(value))}
|
||||||
excludedToolbarItems={["blockType"]}
|
excludedToolbarItems={["blockType"]}
|
||||||
|
firstRender={firstRender}
|
||||||
|
setFirstRender={setFirstRender}
|
||||||
/>
|
/>
|
||||||
<p className="dark:text-inverted text-default mt-2 font-sans text-sm font-normal">
|
<p className="dark:text-inverted text-default mt-2 font-sans text-sm font-normal">
|
||||||
{t("few_sentences_about_yourself")}
|
{t("few_sentences_about_yourself")}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import { useSession } from "next-auth/react";
|
|
||||||
import type { FC } from "react";
|
|
||||||
import { Fragment } from "react";
|
|
||||||
|
|
||||||
type AdminRequiredProps = {
|
|
||||||
as?: keyof JSX.IntrinsicElements;
|
|
||||||
children?: React.ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @deprecated use PermssionContainer instead. Will delete once V2 goes live */
|
|
||||||
export const AdminRequired: FC<AdminRequiredProps> = ({ children, as, ...rest }) => {
|
|
||||||
const session = useSession();
|
|
||||||
|
|
||||||
if (session.data?.user.role !== "ADMIN") return null;
|
|
||||||
const Component = as ?? Fragment;
|
|
||||||
return <Component {...rest}>{children}</Component>;
|
|
||||||
};
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
import { APP_NAME, LOGO } from "@calcom/lib/constants";
|
import { HeadSeo, Logo } from "@calcom/ui";
|
||||||
import { HeadSeo } from "@calcom/ui";
|
|
||||||
|
|
||||||
import Loader from "@components/Loader";
|
import Loader from "@components/Loader";
|
||||||
|
|
||||||
@@ -18,10 +17,7 @@ export default function AuthContainer(props: React.PropsWithChildren<Props>) {
|
|||||||
return (
|
return (
|
||||||
<div className="flex min-h-screen flex-col justify-center bg-[#f3f4f6] py-12 sm:px-6 lg:px-8">
|
<div className="flex min-h-screen flex-col justify-center bg-[#f3f4f6] py-12 sm:px-6 lg:px-8">
|
||||||
<HeadSeo title={props.title} description={props.description} />
|
<HeadSeo title={props.title} description={props.description} />
|
||||||
{props.showLogo && (
|
{props.showLogo && <Logo small inline={false} className="mx-auto mb-auto" />}
|
||||||
// eslint-disable-next-line @next/next/no-img-element
|
|
||||||
<img className="mb-auto h-4" src={LOGO} alt={`${APP_NAME} Logo`} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className={classNames(props.showLogo ? "text-center" : "", "sm:mx-auto sm:w-full sm:max-w-md")}>
|
<div className={classNames(props.showLogo ? "text-center" : "", "sm:mx-auto sm:w-full sm:max-w-md")}>
|
||||||
{props.heading && <h2 className="font-cal text-emphasis text-center text-3xl">{props.heading}</h2>}
|
{props.heading && <h2 className="font-cal text-emphasis text-center text-3xl">{props.heading}</h2>}
|
||||||
|
|||||||
@@ -16,8 +16,10 @@ const EditableHeading = function EditableHeading({
|
|||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
const enableEditing = () => setIsEditing(true);
|
const enableEditing = () => setIsEditing(true);
|
||||||
return (
|
return (
|
||||||
<div className="group relative cursor-pointer" onClick={enableEditing}>
|
<div
|
||||||
<div className="flex items-center">
|
className="group pointer-events-none relative truncate sm:pointer-events-auto"
|
||||||
|
onClick={enableEditing}>
|
||||||
|
<div className="flex cursor-pointer items-center">
|
||||||
<label className="min-w-8 relative inline-block">
|
<label className="min-w-8 relative inline-block">
|
||||||
<span className="whitespace-pre text-xl tracking-normal text-transparent">{value} </span>
|
<span className="whitespace-pre text-xl tracking-normal text-transparent">{value} </span>
|
||||||
{!isEditing && isReady && (
|
{!isEditing && isReady && (
|
||||||
@@ -29,7 +31,7 @@ const EditableHeading = function EditableHeading({
|
|||||||
value={value}
|
value={value}
|
||||||
required
|
required
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"text-emphasis hover:text-default focus:text-emphasis absolute top-0 left-0 w-full cursor-pointer border-none bg-transparent p-0 align-top text-xl focus:outline-none focus:ring-0"
|
"text-emphasis hover:text-default focus:text-emphasis absolute top-0 left-0 w-full cursor-pointer truncate border-none bg-transparent p-0 align-top text-xl focus:outline-none focus:ring-0"
|
||||||
)}
|
)}
|
||||||
onFocus={(e) => {
|
onFocus={(e) => {
|
||||||
setIsEditing(true);
|
setIsEditing(true);
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ const CheckboxField = forwardRef<HTMLInputElement, Props>(
|
|||||||
{...rest}
|
{...rest}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="text-primary-600 focus:ring-primary-500 border-default h-4 w-4 rounded"
|
className="text-primary-600 focus:ring-primary-500 border-default bg-default h-4 w-4 rounded"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span className="ms-3 text-sm">{description}</span>
|
<span className="ms-3 text-sm">{description}</span>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { components } from "react-select";
|
|||||||
|
|
||||||
import type { EventLocationType } from "@calcom/app-store/locations";
|
import type { EventLocationType } from "@calcom/app-store/locations";
|
||||||
import { classNames } from "@calcom/lib";
|
import { classNames } from "@calcom/lib";
|
||||||
|
import cx from "@calcom/lib/classNames";
|
||||||
import { Select } from "@calcom/ui";
|
import { Select } from "@calcom/ui";
|
||||||
|
|
||||||
export type LocationOption = {
|
export type LocationOption = {
|
||||||
@@ -19,10 +20,14 @@ export type GroupOptionType = GroupBase<LocationOption>;
|
|||||||
const OptionWithIcon = ({ icon, label }: { icon?: string; label: string }) => {
|
const OptionWithIcon = ({ icon, label }: { icon?: string; label: string }) => {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
{/* TODO: figure out a way to invert icons when in dark mode. We can't just
|
{icon && (
|
||||||
dark:invert due to google meet cal etc all breaking when we do this
|
<img
|
||||||
*/}
|
src={icon}
|
||||||
{icon && <img src={icon} alt="cover" className="h-3.5 w-3.5 dark:hidden" />}
|
alt="cover"
|
||||||
|
// invert all the icons except app icons
|
||||||
|
className={cx("h-3.5 w-3.5", icon && !icon.startsWith("/api") && "dark:invert")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<span className={classNames("text-sm font-medium")}>{label}</span>
|
<span className={classNames("text-sm font-medium")}>{label}</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export type AppProps = Omit<NextAppProps<WithNonceProps & Record<string, unknown
|
|||||||
isThemeSupported?: boolean;
|
isThemeSupported?: boolean;
|
||||||
isBookingPage?: boolean | ((arg: { router: NextRouter }) => boolean);
|
isBookingPage?: boolean | ((arg: { router: NextRouter }) => boolean);
|
||||||
getLayout?: (page: React.ReactElement, router: NextRouter) => ReactNode;
|
getLayout?: (page: React.ReactElement, router: NextRouter) => ReactNode;
|
||||||
|
PageWrapper?: (props: AppProps) => JSX.Element;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Will be defined only is there was an error */
|
/** Will be defined only is there was an error */
|
||||||
@@ -154,6 +155,7 @@ const AppProviders = (props: AppPropsWithChildren) => {
|
|||||||
<SessionProvider session={session || undefined}>
|
<SessionProvider session={session || undefined}>
|
||||||
<CustomI18nextProvider {...props}>
|
<CustomI18nextProvider {...props}>
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
|
{/* color-scheme makes background:transparent not work which is required by embed. We need to ensure next-theme adds color-scheme to `body` instead of `html`(https://github.com/pacocoursey/next-themes/blob/main/src/index.tsx#L74). Once that's done we can enable color-scheme support */}
|
||||||
<CalcomThemeProvider
|
<CalcomThemeProvider
|
||||||
nonce={props.pageProps.nonce}
|
nonce={props.pageProps.nonce}
|
||||||
isThemeSupported={props.Component.isThemeSupported}
|
isThemeSupported={props.Component.isThemeSupported}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@calcom/web",
|
"name": "@calcom/web",
|
||||||
"version": "2.8.2",
|
"version": "2.8.6",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"analyze": "ANALYZE=true next build",
|
"analyze": "ANALYZE=true next build",
|
||||||
@@ -115,8 +115,6 @@
|
|||||||
"react-select": "^5.7.0",
|
"react-select": "^5.7.0",
|
||||||
"react-timezone-select": "^1.4.0",
|
"react-timezone-select": "^1.4.0",
|
||||||
"react-use-intercom": "1.5.1",
|
"react-use-intercom": "1.5.1",
|
||||||
"react-virtualized-auto-sizer": "^1.0.6",
|
|
||||||
"react-window": "^1.8.7",
|
|
||||||
"remark": "^14.0.2",
|
"remark": "^14.0.2",
|
||||||
"rrule": "^2.7.1",
|
"rrule": "^2.7.1",
|
||||||
"sanitize-html": "^2.10.0",
|
"sanitize-html": "^2.10.0",
|
||||||
@@ -155,8 +153,6 @@
|
|||||||
"@types/qrcode": "^1.4.3",
|
"@types/qrcode": "^1.4.3",
|
||||||
"@types/react": "18.0.26",
|
"@types/react": "18.0.26",
|
||||||
"@types/react-phone-number-input": "^3.0.14",
|
"@types/react-phone-number-input": "^3.0.14",
|
||||||
"@types/react-virtualized-auto-sizer": "^1.0.1",
|
|
||||||
"@types/react-window": "^1.8.5",
|
|
||||||
"@types/sanitize-html": "^2.9.0",
|
"@types/sanitize-html": "^2.9.0",
|
||||||
"@types/stripe": "^8.0.417",
|
"@types/stripe": "^8.0.417",
|
||||||
"@types/uuid": "8.3.1",
|
"@types/uuid": "8.3.1",
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|||||||
import { HeadSeo } from "@calcom/ui";
|
import { HeadSeo } from "@calcom/ui";
|
||||||
import { BookOpen, Check, ChevronRight, FileText } from "@calcom/ui/components/icon";
|
import { BookOpen, Check, ChevronRight, FileText } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
import { ssgInit } from "@server/lib/ssg";
|
import { ssgInit } from "@server/lib/ssg";
|
||||||
|
|
||||||
export default function Custom404() {
|
export default function Custom404() {
|
||||||
@@ -366,6 +368,8 @@ export default function Custom404() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Custom404.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export const getStaticProps = async (context: GetStaticPropsContext) => {
|
export const getStaticProps = async (context: GetStaticPropsContext) => {
|
||||||
const ssr = await ssgInit(context);
|
const ssr = await ssgInit(context);
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|||||||
import { Button, showToast } from "@calcom/ui";
|
import { Button, showToast } from "@calcom/ui";
|
||||||
import { Copy } from "@calcom/ui/components/icon";
|
import { Copy } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
export default function Error500() {
|
export default function Error500() {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -52,3 +54,5 @@ export default function Error500() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Error500.PageWrapper = PageWrapper;
|
||||||
@@ -32,6 +32,8 @@ import { ArrowRight } from "@calcom/ui/components/icon";
|
|||||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
import type { EmbedProps } from "@lib/withEmbedSsr";
|
import type { EmbedProps } from "@lib/withEmbedSsr";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
import { ssrInit } from "@server/lib/ssr";
|
||||||
|
|
||||||
export default function User(props: inferSSRProps<typeof getServerSideProps> & EmbedProps) {
|
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.isBookingPage = true;
|
||||||
|
User.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
const getEventTypesWithHiddenFromDB = async (userId: number) => {
|
const getEventTypesWithHiddenFromDB = async (userId: number) => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { isBrandingHidden } from "@lib/isBrandingHidden";
|
|||||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
import type { EmbedProps } from "@lib/withEmbedSsr";
|
import type { EmbedProps } from "@lib/withEmbedSsr";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import AvailabilityPage from "@components/booking/pages/AvailabilityPage";
|
import AvailabilityPage from "@components/booking/pages/AvailabilityPage";
|
||||||
|
|
||||||
export type AvailabilityPageProps = inferSSRProps<typeof getStaticProps> & EmbedProps;
|
export type AvailabilityPageProps = inferSSRProps<typeof getStaticProps> & EmbedProps;
|
||||||
@@ -55,6 +56,7 @@ export default function Type(props: AvailabilityPageProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Type.isBookingPage = true;
|
Type.isBookingPage = true;
|
||||||
|
Type.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
const paramsSchema = z.object({ type: z.string(), user: z.string() });
|
const paramsSchema = z.object({ type: z.string(), user: z.string() });
|
||||||
async function getUserPageProps(context: GetStaticPropsContext) {
|
async function getUserPageProps(context: GetStaticPropsContext) {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
|
|
||||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import BookingPage from "@components/booking/pages/BookingPage";
|
import BookingPage from "@components/booking/pages/BookingPage";
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
import { ssrInit } from "@server/lib/ssr";
|
||||||
@@ -70,6 +71,7 @@ export default function Book(props: BookPageProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Book.isBookingPage = true;
|
Book.isBookingPage = true;
|
||||||
|
Book.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
const querySchema = z.object({
|
const querySchema = z.object({
|
||||||
bookingUid: z.string().optional(),
|
bookingUid: z.string().optional(),
|
||||||
|
|||||||
+3
-91
@@ -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 { trpc } from "@calcom/trpc/react";
|
||||||
|
|
||||||
import type { AppProps } from "@lib/app-providers";
|
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";
|
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) {
|
function MyApp(props: AppProps) {
|
||||||
const { Component, pageProps, err, router } = props;
|
const { Component, pageProps } = props;
|
||||||
let pageStatus = "200";
|
if (Component.PageWrapper !== undefined) return Component.PageWrapper(props);
|
||||||
const { cssVarsPerTheme } = useEmbedUiConfig();
|
return <Component {...pageProps} />;
|
||||||
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>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default trpc.withTRPC(MyApp);
|
export default trpc.withTRPC(MyApp);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import type { NextPageContext } from "next";
|
||||||
import type { DocumentContext, DocumentProps } from "next/document";
|
import type { DocumentContext, DocumentProps } from "next/document";
|
||||||
import Document, { Head, Html, Main, NextScript } from "next/document";
|
import Document, { Head, Html, Main, NextScript } from "next/document";
|
||||||
import Script from "next/script";
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { getDirFromLang } from "@calcom/lib/i18n";
|
import { getDirFromLang } from "@calcom/lib/i18n";
|
||||||
@@ -8,15 +8,22 @@ import { getDirFromLang } from "@calcom/lib/i18n";
|
|||||||
import { csp } from "@lib/csp";
|
import { csp } from "@lib/csp";
|
||||||
|
|
||||||
type Props = Record<string, unknown> & DocumentProps;
|
type Props = Record<string, unknown> & DocumentProps;
|
||||||
|
function setHeader(ctx: NextPageContext, name: string, value: string) {
|
||||||
|
try {
|
||||||
|
ctx.res?.setHeader(name, value);
|
||||||
|
} catch (e) {
|
||||||
|
// Getting "Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client" when revalidate calendar chache
|
||||||
|
console.log(`Error setting header ${name}=${value} for ${ctx.asPath || "unknown asPath"}`, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
class MyDocument extends Document<Props> {
|
class MyDocument extends Document<Props> {
|
||||||
static async getInitialProps(ctx: DocumentContext) {
|
static async getInitialProps(ctx: DocumentContext) {
|
||||||
const { nonce } = csp(ctx.req || null, ctx.res || null);
|
const { nonce } = csp(ctx.req || null, ctx.res || null);
|
||||||
if (!process.env.CSP_POLICY) {
|
if (!process.env.CSP_POLICY) {
|
||||||
ctx.res?.setHeader("x-csp", "not-opted-in");
|
setHeader(ctx, "x-csp", "not-opted-in");
|
||||||
} else if (!ctx.res?.getHeader("x-csp")) {
|
} else if (!ctx.res?.getHeader("x-csp")) {
|
||||||
// If x-csp not set by gSSP, then it's initialPropsOnly
|
// If x-csp not set by gSSP, then it's initialPropsOnly
|
||||||
ctx.res?.setHeader("x-csp", "initialPropsOnly");
|
setHeader(ctx, "x-csp", "initialPropsOnly");
|
||||||
}
|
}
|
||||||
const asPath = ctx.asPath || "";
|
const asPath = ctx.asPath || "";
|
||||||
// Use a dummy URL as default so that URL parsing works for relative URLs as well. We care about searchParams and pathname only
|
// Use a dummy URL as default so that URL parsing works for relative URLs as well. We care about searchParams and pathname only
|
||||||
@@ -42,7 +49,6 @@ class MyDocument extends Document<Props> {
|
|||||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#000000" />
|
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#000000" />
|
||||||
<meta name="msapplication-TileColor" content="#ff0000" />
|
<meta name="msapplication-TileColor" content="#ff0000" />
|
||||||
<meta name="theme-color" content="var(--cal-bg)" />
|
<meta name="theme-color" content="var(--cal-bg)" />
|
||||||
<Script src="/embed-init-iframe.js" strategy="beforeInteractive" />
|
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<body
|
<body
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
import crypto from "node:crypto";
|
||||||
|
|
||||||
|
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||||
|
import { defaultHandler } from "@calcom/lib/server";
|
||||||
|
|
||||||
|
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
|
const session = await getServerSession({ req, res });
|
||||||
|
const secret = process.env.INTERCOM_SECRET;
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
return res.status(401).json({ message: "user not authenticated" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!secret) {
|
||||||
|
return res.status(400).json({ message: "Intercom Identity Verification secret not set" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const hmac = crypto.createHmac("sha256", secret);
|
||||||
|
hmac.update(String(session.user.id));
|
||||||
|
const hash = hmac.digest("hex");
|
||||||
|
|
||||||
|
return res.status(200).json({ hash });
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defaultHandler({
|
||||||
|
GET: Promise.resolve({ default: handler }),
|
||||||
|
});
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { IS_SELF_HOSTED, LOGO, LOGO_ICON, WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
|
|
||||||
|
function removePort(url: string) {
|
||||||
|
return url.replace(/:\d+$/, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractSubdomainAndDomain(hostname: string) {
|
||||||
|
const hostParts = removePort(hostname).split(".");
|
||||||
|
|
||||||
|
const subdomainParts = hostParts.slice(0, hostParts.length - 2);
|
||||||
|
const domain = hostParts.slice(hostParts.length - 2).join(".");
|
||||||
|
|
||||||
|
return [subdomainParts[0], domain];
|
||||||
|
}
|
||||||
|
|
||||||
|
const logoApiSchema = z.object({
|
||||||
|
icon: z.coerce.boolean().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const SYSTEM_SUBDOMAINS = ["console", "app", "www"];
|
||||||
|
|
||||||
|
async function getTeamLogos(subdomain: string) {
|
||||||
|
if (
|
||||||
|
// if not cal.com
|
||||||
|
IS_SELF_HOSTED ||
|
||||||
|
// missing subdomain (empty string)
|
||||||
|
!subdomain ||
|
||||||
|
// in SYSTEM_SUBDOMAINS list
|
||||||
|
SYSTEM_SUBDOMAINS.includes(subdomain)
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
appLogo: `${WEBAPP_URL}${LOGO}`,
|
||||||
|
appIconLogo: `${WEBAPP_URL}${LOGO_ICON}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// load from DB
|
||||||
|
const { default: prisma } = await import("@calcom/prisma");
|
||||||
|
const team = await prisma.team.findUniqueOrThrow({
|
||||||
|
where: {
|
||||||
|
slug: subdomain,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
appLogo: true,
|
||||||
|
appIconLogo: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// try to use team logos, otherwise default to LOGO/LOGO_ICON regardless
|
||||||
|
return {
|
||||||
|
appLogo: team.appLogo || `${WEBAPP_URL}${LOGO}`,
|
||||||
|
appIconLogo: team.appIconLogo || `${WEBAPP_URL}${LOGO_ICON}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This API endpoint is used to serve the logo associated with a team if no logo is found we serve our default logo
|
||||||
|
*/
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
|
const { query } = req;
|
||||||
|
const parsedQuery = logoApiSchema.parse(query);
|
||||||
|
|
||||||
|
const hostname = req?.headers["host"];
|
||||||
|
if (!hostname) throw new Error("No hostname");
|
||||||
|
const domains = extractSubdomainAndDomain(hostname);
|
||||||
|
if (!domains) throw new Error("No domains");
|
||||||
|
|
||||||
|
const [subdomain] = domains;
|
||||||
|
const { appLogo, appIconLogo } = await getTeamLogos(subdomain);
|
||||||
|
|
||||||
|
const filteredLogo = parsedQuery?.icon ? appIconLogo : appLogo;
|
||||||
|
|
||||||
|
const response = await fetch(filteredLogo);
|
||||||
|
const arrayBuffer = await response.arrayBuffer();
|
||||||
|
const buffer = Buffer.from(arrayBuffer);
|
||||||
|
res.setHeader("Content-Type", response.headers.get("content-type") as string);
|
||||||
|
res.setHeader("Cache-Control", "s-maxage=86400");
|
||||||
|
res.send(buffer);
|
||||||
|
}
|
||||||
@@ -9,13 +9,16 @@ import type { AppGetServerSideProps } from "@calcom/types/AppGetServerSideProps"
|
|||||||
|
|
||||||
import type { AppProps } from "@lib/app-providers";
|
import type { AppProps } from "@lib/app-providers";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
import { ssrInit } from "@server/lib/ssr";
|
||||||
|
|
||||||
type AppPageType = {
|
type AppPageType = {
|
||||||
getServerSideProps: AppGetServerSideProps;
|
getServerSideProps: AppGetServerSideProps;
|
||||||
// A component than can accept any properties
|
// A component than can accept any properties
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// 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 = {
|
type Found = {
|
||||||
@@ -94,6 +97,8 @@ AppPage.getLayout = (page, router) => {
|
|||||||
return route.Component.getLayout(page, router);
|
return route.Component.getLayout(page, router);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AppPage.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default AppPage;
|
export default AppPage;
|
||||||
|
|
||||||
export async function getServerSideProps(
|
export async function getServerSideProps(
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import prisma from "@calcom/prisma";
|
|||||||
|
|
||||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import App from "@components/apps/App";
|
import App from "@components/apps/App";
|
||||||
|
|
||||||
const md = new MarkdownIt("default", { html: true, breaks: true });
|
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;
|
export default SingleAppPage;
|
||||||
@@ -5,6 +5,8 @@ import { useRouter } from "next/router";
|
|||||||
import { AppSetupPage } from "@calcom/app-store/_pages/setup";
|
import { AppSetupPage } from "@calcom/app-store/_pages/setup";
|
||||||
import { getStaticProps } from "@calcom/app-store/_pages/setup/_getStaticProps";
|
import { getStaticProps } from "@calcom/app-store/_pages/setup/_getStaticProps";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
export default function SetupInformation(props: InferGetStaticPropsType<typeof getStaticProps>) {
|
export default function SetupInformation(props: InferGetStaticPropsType<typeof getStaticProps>) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const slug = router.query.slug as string;
|
const slug = router.query.slug as string;
|
||||||
@@ -26,6 +28,8 @@ export default function SetupInformation(props: InferGetStaticPropsType<typeof g
|
|||||||
return <AppSetupPage slug={slug} {...props} />;
|
return <AppSetupPage slug={slug} {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetupInformation.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export const getStaticPaths: GetStaticPaths = async () => {
|
export const getStaticPaths: GetStaticPaths = async () => {
|
||||||
return {
|
return {
|
||||||
paths: [],
|
paths: [],
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
import { AppCard, SkeletonText } from "@calcom/ui";
|
import { AppCard, SkeletonText } from "@calcom/ui";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
export default function Apps({ apps }: InferGetStaticPropsType<typeof getStaticProps>) {
|
export default function Apps({ apps }: InferGetStaticPropsType<typeof getStaticProps>) {
|
||||||
const { t, isLocaleReady } = useLocale();
|
const { t, isLocaleReady } = useLocale();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -47,6 +49,8 @@ export default function Apps({ apps }: InferGetStaticPropsType<typeof getStaticP
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Apps.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export const getStaticPaths = async () => {
|
export const getStaticPaths = async () => {
|
||||||
const paths = Object.keys(AppCategories);
|
const paths = Object.keys(AppCategories);
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,13 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|||||||
import { SkeletonText } from "@calcom/ui";
|
import { SkeletonText } from "@calcom/ui";
|
||||||
import { ArrowLeft, ArrowRight } from "@calcom/ui/components/icon";
|
import { ArrowLeft, ArrowRight } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
export default function Apps({ categories }: InferGetStaticPropsType<typeof getStaticProps>) {
|
export default function Apps({ categories }: InferGetStaticPropsType<typeof getStaticProps>) {
|
||||||
const { t, isLocaleReady } = useLocale();
|
const { t, isLocaleReady } = useLocale();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Shell isPublic large>
|
<Shell isPublic large hideHeadingOnMobile>
|
||||||
<div className="text-md flex items-center gap-1 px-4 pb-3 pt-3 font-normal md:px-8 lg:px-0 lg:pt-0">
|
<div className="text-md flex items-center gap-1 px-4 pb-3 pt-3 font-normal md:px-8 lg:px-0 lg:pt-0">
|
||||||
<Link
|
<Link
|
||||||
href="/apps"
|
href="/apps"
|
||||||
@@ -43,6 +45,8 @@ export default function Apps({ categories }: InferGetStaticPropsType<typeof getS
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Apps.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export const getStaticProps = async () => {
|
export const getStaticProps = async () => {
|
||||||
const appStore = await getAppRegistry();
|
const appStore = await getAppRegistry();
|
||||||
const categories = appStore.reduce((c, app) => {
|
const categories = appStore.reduce((c, app) => {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import type { HorizontalTabItemProps } from "@calcom/ui";
|
|||||||
import { AllApps, AppStoreCategories, HorizontalTabs, TextField, PopularAppsSlider } from "@calcom/ui";
|
import { AllApps, AppStoreCategories, HorizontalTabs, TextField, PopularAppsSlider } from "@calcom/ui";
|
||||||
import { Search } from "@calcom/ui/components/icon";
|
import { Search } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import AppsLayout from "@components/apps/layouts/AppsLayout";
|
import AppsLayout from "@components/apps/layouts/AppsLayout";
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
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) => {
|
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||||
const { req, res } = context;
|
const { req, res } = context;
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import {
|
|||||||
import { QueryCell } from "@lib/QueryCell";
|
import { QueryCell } from "@lib/QueryCell";
|
||||||
|
|
||||||
import AppListCard from "@components/AppListCard";
|
import AppListCard from "@components/AppListCard";
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import { CalendarListContainer } from "@components/apps/CalendarListContainer";
|
import { CalendarListContainer } from "@components/apps/CalendarListContainer";
|
||||||
import InstalledAppsLayout from "@components/apps/layouts/InstalledAppsLayout";
|
import InstalledAppsLayout from "@components/apps/layouts/InstalledAppsLayout";
|
||||||
|
|
||||||
@@ -372,3 +373,5 @@ export async function getServerSideProps(ctx: AppGetServerSidePropsContext) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InstalledApps.PageWrapper = PageWrapper;
|
||||||
@@ -7,6 +7,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|||||||
import { Button, SkeletonText } from "@calcom/ui";
|
import { Button, SkeletonText } from "@calcom/ui";
|
||||||
import { X } from "@calcom/ui/components/icon";
|
import { X } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import AuthContainer from "@components/ui/AuthContainer";
|
import AuthContainer from "@components/ui/AuthContainer";
|
||||||
|
|
||||||
import { ssgInit } from "@server/lib/ssg";
|
import { ssgInit } from "@server/lib/ssg";
|
||||||
@@ -49,6 +50,8 @@ export default function Error() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Error.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export const getStaticProps = async (context: GetStaticPropsContext) => {
|
export const getStaticProps = async (context: GetStaticPropsContext) => {
|
||||||
const ssr = await ssgInit(context);
|
const ssr = await ssgInit(context);
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
import { Button, TextField } from "@calcom/ui";
|
import { Button, TextField } from "@calcom/ui";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import AuthContainer from "@components/ui/AuthContainer";
|
import AuthContainer from "@components/ui/AuthContainer";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -174,7 +175,7 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Page.isThemeSupported = false;
|
Page.isThemeSupported = false;
|
||||||
|
Page.PageWrapper = PageWrapper;
|
||||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||||
const id = context.params?.id as string;
|
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 { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { Button, EmailField } from "@calcom/ui";
|
import { Button, EmailField } from "@calcom/ui";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import AuthContainer from "@components/ui/AuthContainer";
|
import AuthContainer from "@components/ui/AuthContainer";
|
||||||
|
|
||||||
export default function ForgotPassword({ csrfToken }: { csrfToken: string }) {
|
export default function ForgotPassword({ csrfToken }: { csrfToken: string }) {
|
||||||
@@ -144,6 +145,7 @@ export default function ForgotPassword({ csrfToken }: { csrfToken: string }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ForgotPassword.isThemeSupported = false;
|
ForgotPassword.isThemeSupported = false;
|
||||||
|
ForgotPassword.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||||
const { req, res } = context;
|
const { req, res } = context;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import type { WithNonceProps } from "@lib/withNonce";
|
|||||||
import withNonce from "@lib/withNonce";
|
import withNonce from "@lib/withNonce";
|
||||||
|
|
||||||
import AddToHomescreen from "@components/AddToHomescreen";
|
import AddToHomescreen from "@components/AddToHomescreen";
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import TwoFactor from "@components/auth/TwoFactor";
|
import TwoFactor from "@components/auth/TwoFactor";
|
||||||
import AuthContainer from "@components/ui/AuthContainer";
|
import AuthContainer from "@components/ui/AuthContainer";
|
||||||
|
|
||||||
@@ -164,7 +165,7 @@ export default function Login({
|
|||||||
{...register("email")}
|
{...register("email")}
|
||||||
/>
|
/>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div className="absolute -top-[6px] z-10 ltr:right-0 rtl:left-0">
|
<div className="z-5 absolute -top-1.5 ltr:right-0 rtl:left-0">
|
||||||
<Link
|
<Link
|
||||||
href="/auth/forgot-password"
|
href="/auth/forgot-password"
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
@@ -302,5 +303,6 @@ const _getServerSideProps = async function getServerSideProps(context: GetServer
|
|||||||
};
|
};
|
||||||
|
|
||||||
Login.isThemeSupported = false;
|
Login.isThemeSupported = false;
|
||||||
|
Login.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export const getServerSideProps = withNonce(_getServerSideProps);
|
export const getServerSideProps = withNonce(_getServerSideProps);
|
||||||
@@ -10,6 +10,7 @@ import { Check } from "@calcom/ui/components/icon";
|
|||||||
|
|
||||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import AuthContainer from "@components/ui/AuthContainer";
|
import AuthContainer from "@components/ui/AuthContainer";
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
import { ssrInit } from "@server/lib/ssr";
|
||||||
@@ -51,7 +52,7 @@ export function Logout(props: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Logout.isThemeSupported = false;
|
Logout.isThemeSupported = false;
|
||||||
|
Logout.PageWrapper = PageWrapper;
|
||||||
export default Logout;
|
export default Logout;
|
||||||
|
|
||||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { signIn } from "next-auth/react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
// To handle the IdP initiated login flow callback
|
// To handle the IdP initiated login flow callback
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -21,3 +23,4 @@ export default function Page() {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
Page.PageWrapper = PageWrapper;
|
||||||
@@ -11,6 +11,7 @@ import prisma from "@calcom/prisma";
|
|||||||
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
|
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||||
import { Meta, WizardForm } from "@calcom/ui";
|
import { Meta, WizardForm } from "@calcom/ui";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import { AdminUserContainer as AdminUser } from "@components/setup/AdminUser";
|
import { AdminUserContainer as AdminUser } from "@components/setup/AdminUser";
|
||||||
import ChooseLicense from "@components/setup/ChooseLicense";
|
import ChooseLicense from "@components/setup/ChooseLicense";
|
||||||
import EnterpriseLicense from "@components/setup/EnterpriseLicense";
|
import EnterpriseLicense from "@components/setup/EnterpriseLicense";
|
||||||
@@ -136,7 +137,7 @@ export function Setup(props: inferSSRProps<typeof getServerSideProps>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Setup.isThemeSupported = false;
|
Setup.isThemeSupported = false;
|
||||||
|
Setup.PageWrapper = PageWrapper;
|
||||||
export default Setup;
|
export default Setup;
|
||||||
|
|
||||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { getProviders, signIn, getCsrfToken } from "next-auth/react";
|
|||||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||||
import { Button } from "@calcom/ui";
|
import { Button } from "@calcom/ui";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
type Provider = {
|
type Provider = {
|
||||||
name: string;
|
name: string;
|
||||||
id: string;
|
id: string;
|
||||||
@@ -23,6 +25,8 @@ function signin({ providers }: { providers: Provider[] }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signin.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default signin;
|
export default signin;
|
||||||
|
|
||||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ import prisma from "@calcom/prisma";
|
|||||||
import { asStringOrNull } from "@lib/asStringOrNull";
|
import { asStringOrNull } from "@lib/asStringOrNull";
|
||||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
import { ssrInit } from "@server/lib/ssr";
|
||||||
|
|
||||||
export type SSOProviderPageProps = inferSSRProps<typeof getServerSideProps>;
|
export type SSOProviderPageProps = inferSSRProps<typeof getServerSideProps>;
|
||||||
@@ -49,6 +51,8 @@ export default function Provider(props: SSOProviderPageProps) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Provider.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||||
// get query params and typecast them to string
|
// get query params and typecast them to string
|
||||||
// (would be even better to assert them instead of typecasting)
|
// (would be even better to assert them instead of typecasting)
|
||||||
|
|||||||
@@ -1,33 +1,41 @@
|
|||||||
import { signIn } from "next-auth/react";
|
import { signIn } from "next-auth/react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
import { samlProductID, samlTenantID } from "@calcom/features/ee/sso/lib/saml";
|
import { samlProductID, samlTenantID } from "@calcom/features/ee/sso/lib/saml";
|
||||||
import { HOSTED_CAL_FEATURES } from "@calcom/lib/constants";
|
import { HOSTED_CAL_FEATURES } from "@calcom/lib/constants";
|
||||||
|
|
||||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
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.
|
// This page is used to initiate the SAML authentication flow by redirecting to the SAML provider.
|
||||||
// Accessible only on self-hosted Cal.com instances.
|
// Accessible only on self-hosted Cal.com instances.
|
||||||
export default function Page({ samlTenantID, samlProductID }: inferSSRProps<typeof getServerSideProps>) {
|
export default function Page({ samlTenantID, samlProductID }: inferSSRProps<typeof getServerSideProps>) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
if (HOSTED_CAL_FEATURES) {
|
useEffect(() => {
|
||||||
router.push("/auth/login");
|
if (HOSTED_CAL_FEATURES) {
|
||||||
return;
|
router.push("/auth/login");
|
||||||
}
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Initiate SAML authentication flow
|
useEffect(() => {
|
||||||
signIn(
|
// Initiate SAML authentication flow
|
||||||
"saml",
|
signIn(
|
||||||
{
|
"saml",
|
||||||
callbackUrl: "/",
|
{
|
||||||
},
|
callbackUrl: "/",
|
||||||
{ tenant: samlTenantID, product: samlProductID }
|
},
|
||||||
);
|
{ tenant: samlTenantID, product: samlProductID }
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Page.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export async function getServerSideProps() {
|
export async function getServerSideProps() {
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { trpc } from "@calcom/trpc/react";
|
|||||||
import { Button, showToast } from "@calcom/ui";
|
import { Button, showToast } from "@calcom/ui";
|
||||||
|
|
||||||
import Loader from "@components/Loader";
|
import Loader from "@components/Loader";
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
async function sendVerificationLogin(email: string, username: string) {
|
async function sendVerificationLogin(email: string, username: string) {
|
||||||
await signIn("email", {
|
await signIn("email", {
|
||||||
@@ -177,3 +178,5 @@ export default function Verify() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Verify.PageWrapper = PageWrapper;
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
import { useState } from "react";
|
||||||
import { Controller, useFieldArray, useForm } from "react-hook-form";
|
import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
@@ -24,13 +25,19 @@ import {
|
|||||||
Tooltip,
|
Tooltip,
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
|
DropdownMenuSeparator,
|
||||||
|
Dropdown,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownItem,
|
||||||
|
DropdownMenuTrigger,
|
||||||
ConfirmationDialogContent,
|
ConfirmationDialogContent,
|
||||||
VerticalDivider,
|
VerticalDivider,
|
||||||
} from "@calcom/ui";
|
} from "@calcom/ui";
|
||||||
import { Info, Plus, Trash } from "@calcom/ui/components/icon";
|
import { Info, Plus, Trash, MoreHorizontal } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
import { HttpError } from "@lib/core/http/error";
|
import { HttpError } from "@lib/core/http/error";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import { SelectSkeletonLoader } from "@components/availability/SkeletonLoader";
|
import { SelectSkeletonLoader } from "@components/availability/SkeletonLoader";
|
||||||
import EditableHeading from "@components/ui/EditableHeading";
|
import EditableHeading from "@components/ui/EditableHeading";
|
||||||
|
|
||||||
@@ -96,6 +103,7 @@ export default function Availability() {
|
|||||||
|
|
||||||
const { fromEventType } = router.query;
|
const { fromEventType } = router.query;
|
||||||
const { timeFormat } = me.data || { timeFormat: null };
|
const { timeFormat } = me.data || { timeFormat: null };
|
||||||
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||||
const { data: schedule, isLoading } = trpc.viewer.availability.schedule.get.useQuery(
|
const { data: schedule, isLoading } = trpc.viewer.availability.schedule.get.useQuery(
|
||||||
{ scheduleId },
|
{ scheduleId },
|
||||||
{
|
{
|
||||||
@@ -181,11 +189,8 @@ export default function Availability() {
|
|||||||
}
|
}
|
||||||
CTA={
|
CTA={
|
||||||
<div className="flex items-center justify-end">
|
<div className="flex items-center justify-end">
|
||||||
<div className="sm:hover:bg-subtle flex items-center rounded-md px-2">
|
<div className="hidden items-center rounded-md px-2 sm:flex sm:hover:bg-gray-100">
|
||||||
<Skeleton
|
<Skeleton as={Label} htmlFor="hiddenSwitch" className="mt-2 cursor-pointer self-center pr-2 ">
|
||||||
as={Label}
|
|
||||||
htmlFor="hiddenSwitch"
|
|
||||||
className="mt-2 hidden cursor-pointer self-center pr-2 sm:inline">
|
|
||||||
{t("set_to_default")}
|
{t("set_to_default")}
|
||||||
</Skeleton>
|
</Skeleton>
|
||||||
<Switch
|
<Switch
|
||||||
@@ -198,7 +203,7 @@ export default function Availability() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<VerticalDivider />
|
<VerticalDivider className="hidden sm:inline" />
|
||||||
<Dialog>
|
<Dialog>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
@@ -206,6 +211,7 @@ export default function Availability() {
|
|||||||
variant="icon"
|
variant="icon"
|
||||||
color="destructive"
|
color="destructive"
|
||||||
aria-label={t("delete")}
|
aria-label={t("delete")}
|
||||||
|
className="hidden sm:inline"
|
||||||
disabled={schedule?.isLastSchedule}
|
disabled={schedule?.isLastSchedule}
|
||||||
tooltip={t("requires_at_least_one_schedule")}
|
tooltip={t("requires_at_least_one_schedule")}
|
||||||
/>
|
/>
|
||||||
@@ -222,8 +228,51 @@ export default function Availability() {
|
|||||||
{t("delete_schedule_description")}
|
{t("delete_schedule_description")}
|
||||||
</ConfirmationDialogContent>
|
</ConfirmationDialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
<VerticalDivider className="hidden sm:inline" />
|
||||||
<VerticalDivider />
|
<Dropdown>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button className="sm:hidden" StartIcon={MoreHorizontal} variant="icon" color="secondary" />
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent style={{ minWidth: "200px" }}>
|
||||||
|
<DropdownItem
|
||||||
|
type="button"
|
||||||
|
color="destructive"
|
||||||
|
StartIcon={Trash}
|
||||||
|
onClick={() => setDeleteDialogOpen(true)}>
|
||||||
|
{t("delete")}
|
||||||
|
</DropdownItem>
|
||||||
|
<Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
|
||||||
|
<ConfirmationDialogContent
|
||||||
|
isLoading={deleteMutation.isLoading}
|
||||||
|
variety="danger"
|
||||||
|
title={t("delete_schedule")}
|
||||||
|
confirmBtnText={t("delete")}
|
||||||
|
loadingText={t("delete")}
|
||||||
|
onConfirm={() => {
|
||||||
|
schedule !== undefined && deleteMutation.mutate({ scheduleId: schedule.id });
|
||||||
|
}}>
|
||||||
|
{t("delete_schedule_description")}
|
||||||
|
</ConfirmationDialogContent>
|
||||||
|
</Dialog>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<div className="flex h-9 flex-row items-center justify-between py-2 px-4 hover:bg-gray-100">
|
||||||
|
<Skeleton
|
||||||
|
as={Label}
|
||||||
|
htmlFor="hiddenSwitch"
|
||||||
|
className="mt-2 cursor-pointer self-center pr-2 sm:inline">
|
||||||
|
{t("set_to_default")}
|
||||||
|
</Skeleton>
|
||||||
|
<Switch
|
||||||
|
id="hiddenSwitch"
|
||||||
|
disabled={isLoading || schedule?.isDefault}
|
||||||
|
checked={form.watch("isDefault")}
|
||||||
|
onCheckedChange={(e) => {
|
||||||
|
form.setValue("isDefault", e);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</Dropdown>
|
||||||
|
|
||||||
<div className="border-default border-l-2" />
|
<div className="border-default border-l-2" />
|
||||||
<Button className="ml-4 lg:ml-0" type="submit" form="availability-form">
|
<Button className="ml-4 lg:ml-0" type="submit" form="availability-form">
|
||||||
@@ -301,3 +350,5 @@ export default function Availability() {
|
|||||||
</Shell>
|
</Shell>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Availability.PageWrapper = PageWrapper;
|
||||||
@@ -11,6 +11,7 @@ import { Clock } from "@calcom/ui/components/icon";
|
|||||||
import { withQuery } from "@lib/QueryCell";
|
import { withQuery } from "@lib/QueryCell";
|
||||||
import { HttpError } from "@lib/core/http/error";
|
import { HttpError } from "@lib/core/http/error";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import SkeletonLoader from "@components/availability/SkeletonLoader";
|
import SkeletonLoader from "@components/availability/SkeletonLoader";
|
||||||
|
|
||||||
export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availability"]["list"]) {
|
export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availability"]["list"]) {
|
||||||
@@ -110,9 +111,15 @@ export default function AvailabilityPage() {
|
|||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Shell heading={t("availability")} subtitle={t("configure_availability")} CTA={<NewScheduleButton />}>
|
<Shell
|
||||||
|
heading={t("availability")}
|
||||||
|
hideHeadingOnMobile
|
||||||
|
subtitle={t("configure_availability")}
|
||||||
|
CTA={<NewScheduleButton />}>
|
||||||
<WithQuery success={({ data }) => <AvailabilityList {...data} />} customLoader={<SkeletonLoader />} />
|
<WithQuery success={({ data }) => <AvailabilityList {...data} />} customLoader={<SkeletonLoader />} />
|
||||||
</Shell>
|
</Shell>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AvailabilityPage.PageWrapper = PageWrapper;
|
||||||
@@ -7,6 +7,8 @@ import { SkeletonText } from "@calcom/ui";
|
|||||||
|
|
||||||
import useRouterQuery from "@lib/hooks/useRouterQuery";
|
import useRouterQuery from "@lib/hooks/useRouterQuery";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
type User = RouterOutputs["viewer"]["me"];
|
type User = RouterOutputs["viewer"]["me"];
|
||||||
|
|
||||||
export interface IBusySlot {
|
export interface IBusySlot {
|
||||||
@@ -120,12 +122,13 @@ export default function Troubleshoot() {
|
|||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Shell heading={t("troubleshoot")} subtitle={t("troubleshoot_description")}>
|
<Shell heading={t("troubleshoot")} hideHeadingOnMobile subtitle={t("troubleshoot_description")}>
|
||||||
{!isLoading && data && <AvailabilityView user={data} />}
|
{!isLoading && data && <AvailabilityView user={data} />}
|
||||||
</Shell>
|
</Shell>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Troubleshoot.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
function convertMinsToHrsMins(mins: number) {
|
function convertMinsToHrsMins(mins: number) {
|
||||||
const h = Math.floor(mins / 60);
|
const h = Math.floor(mins / 60);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
useIsBackgroundTransparent,
|
useIsBackgroundTransparent,
|
||||||
useIsEmbed,
|
useIsEmbed,
|
||||||
} from "@calcom/embed-core/embed-iframe";
|
} from "@calcom/embed-core/embed-iframe";
|
||||||
|
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||||
import {
|
import {
|
||||||
SystemField,
|
SystemField,
|
||||||
getBookingFieldsWithSystemFields,
|
getBookingFieldsWithSystemFields,
|
||||||
@@ -53,6 +54,7 @@ import { X, ExternalLink, ChevronLeft, Check, Calendar } from "@calcom/ui/compon
|
|||||||
import { timeZone } from "@lib/clock";
|
import { timeZone } from "@lib/clock";
|
||||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import CancelBooking from "@components/booking/CancelBooking";
|
import CancelBooking from "@components/booking/CancelBooking";
|
||||||
import EventReservationSchema from "@components/schemas/EventReservationSchema";
|
import EventReservationSchema from "@components/schemas/EventReservationSchema";
|
||||||
|
|
||||||
@@ -105,10 +107,10 @@ export default function Success(props: SuccessProps) {
|
|||||||
seatReferenceUid,
|
seatReferenceUid,
|
||||||
} = querySchema.parse(router.query);
|
} = querySchema.parse(router.query);
|
||||||
|
|
||||||
const tz =
|
const attendeeTimeZone = props?.bookingInfo?.attendees.find(
|
||||||
(isSuccessBookingPage
|
(attendee) => attendee.email === email
|
||||||
? props.bookingInfo.attendees.find((attendee) => attendee.email === email)?.timeZone
|
)?.timeZone;
|
||||||
: props.bookingInfo.eventType?.timeZone || props.bookingInfo.user?.timeZone) || timeZone();
|
const tz = isSuccessBookingPage && attendeeTimeZone ? attendeeTimeZone : props.tz ? props.tz : timeZone();
|
||||||
|
|
||||||
const location = props.bookingInfo.location as ReturnType<typeof getEventLocationValue>;
|
const location = props.bookingInfo.location as ReturnType<typeof getEventLocationValue>;
|
||||||
|
|
||||||
@@ -708,6 +710,7 @@ export default function Success(props: SuccessProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Success.isBookingPage = true;
|
Success.isBookingPage = true;
|
||||||
|
Success.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
type RecurringBookingsProps = {
|
type RecurringBookingsProps = {
|
||||||
eventType: SuccessProps["eventType"];
|
eventType: SuccessProps["eventType"];
|
||||||
@@ -917,7 +920,16 @@ const handleSeatsEventTypeOnBooking = (
|
|||||||
|
|
||||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||||
const ssr = await ssrInit(context);
|
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);
|
const parsedQuery = querySchema.safeParse(context.query);
|
||||||
|
|
||||||
if (!parsedQuery.success) return { notFound: true };
|
if (!parsedQuery.success) return { notFound: true };
|
||||||
const { uid, email, eventTypeSlug, cancel, isSuccessBookingPage } = parsedQuery.data;
|
const { uid, email, eventTypeSlug, cancel, isSuccessBookingPage } = parsedQuery.data;
|
||||||
|
|
||||||
@@ -1049,6 +1061,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
|||||||
dynamicEventName: bookingInfo?.eventType?.eventName || "",
|
dynamicEventName: bookingInfo?.eventType?.eventName || "",
|
||||||
bookingInfo,
|
bookingInfo,
|
||||||
paymentStatus: payment,
|
paymentStatus: payment,
|
||||||
|
...(tz && { tz }),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { Calendar } from "@calcom/ui/components/icon";
|
|||||||
|
|
||||||
import { useInViewObserver } from "@lib/hooks/useInViewObserver";
|
import { useInViewObserver } from "@lib/hooks/useInViewObserver";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import BookingListItem from "@components/booking/BookingListItem";
|
import BookingListItem from "@components/booking/BookingListItem";
|
||||||
import SkeletonLoader from "@components/booking/SkeletonLoader";
|
import SkeletonLoader from "@components/booking/SkeletonLoader";
|
||||||
|
|
||||||
@@ -194,6 +195,8 @@ export default function Bookings() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bookings.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export const getStaticProps: GetStaticProps = async (ctx) => {
|
export const getStaticProps: GetStaticProps = async (ctx) => {
|
||||||
const params = querySchema.safeParse(ctx.params);
|
const params = querySchema.safeParse(ctx.params);
|
||||||
const ssg = await ssgInit(ctx);
|
const ssg = await ssgInit(ctx);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
|||||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
import type { EmbedProps } from "@lib/withEmbedSsr";
|
import type { EmbedProps } from "@lib/withEmbedSsr";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import AvailabilityPage from "@components/booking/pages/AvailabilityPage";
|
import AvailabilityPage from "@components/booking/pages/AvailabilityPage";
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
import { ssrInit } from "@server/lib/ssr";
|
||||||
@@ -25,6 +26,7 @@ export default function Type(props: DynamicAvailabilityPageProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Type.isBookingPage = true;
|
Type.isBookingPage = true;
|
||||||
|
Type.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
const querySchema = z.object({
|
const querySchema = z.object({
|
||||||
link: z.string().optional().default(""),
|
link: z.string().optional().default(""),
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { customInputSchema, eventTypeBookingFields, EventTypeMetaDataSchema } fr
|
|||||||
import { asStringOrNull, asStringOrThrow } from "@lib/asStringOrNull";
|
import { asStringOrNull, asStringOrThrow } from "@lib/asStringOrNull";
|
||||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import BookingPage from "@components/booking/pages/BookingPage";
|
import BookingPage from "@components/booking/pages/BookingPage";
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
import { ssrInit } from "@server/lib/ssr";
|
||||||
@@ -20,6 +21,7 @@ export default function Book(props: HashLinkPageProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Book.isBookingPage = true;
|
Book.isBookingPage = true;
|
||||||
|
Book.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||||
const ssr = await ssrInit(context);
|
const ssr = await ssrInit(context);
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import type { PeriodType } from "@prisma/client";
|
import type { PeriodType, SchedulingType } from "@prisma/client";
|
||||||
import type { SchedulingType } from "@prisma/client";
|
|
||||||
import type { GetServerSidePropsContext } from "next";
|
import type { GetServerSidePropsContext } from "next";
|
||||||
import { Trans } from "next-i18next";
|
import { Trans } from "next-i18next";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
@@ -18,10 +17,10 @@ import { CAL_URL } from "@calcom/lib/constants";
|
|||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery";
|
import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery";
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { useTelemetry, telemetryEventTypes } from "@calcom/lib/telemetry";
|
import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||||
import type { Prisma } from "@calcom/prisma/client";
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
import { eventTypeBookingFields } from "@calcom/prisma/zod-utils";
|
|
||||||
import type { customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
import type { customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||||
|
import { eventTypeBookingFields } from "@calcom/prisma/zod-utils";
|
||||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import type { IntervalLimit, RecurringEvent } from "@calcom/types/Calendar";
|
import type { IntervalLimit, RecurringEvent } from "@calcom/types/Calendar";
|
||||||
@@ -30,9 +29,11 @@ import { ConfirmationDialogContent, Dialog, Form, showToast } from "@calcom/ui";
|
|||||||
import { asStringOrThrow } from "@lib/asStringOrNull";
|
import { asStringOrThrow } from "@lib/asStringOrNull";
|
||||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
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
|
// 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 { EventAdvancedTab } from "@components/eventtype/EventAdvancedTab";
|
||||||
import { EventAppsTab } from "@components/eventtype/EventAppsTab";
|
import { EventAppsTab } from "@components/eventtype/EventAppsTab";
|
||||||
|
import type { AvailabilityOption } from "@components/eventtype/EventAvailabilityTab";
|
||||||
import { EventAvailabilityTab } from "@components/eventtype/EventAvailabilityTab";
|
import { EventAvailabilityTab } from "@components/eventtype/EventAvailabilityTab";
|
||||||
import { EventLimitsTab } from "@components/eventtype/EventLimitsTab";
|
import { EventLimitsTab } from "@components/eventtype/EventLimitsTab";
|
||||||
import { EventRecurringTab } from "@components/eventtype/EventRecurringTab";
|
import { EventRecurringTab } from "@components/eventtype/EventRecurringTab";
|
||||||
@@ -93,6 +94,7 @@ export type FormValues = {
|
|||||||
children: ChildrenEventType[];
|
children: ChildrenEventType[];
|
||||||
hosts: { userId: number; isFixed: boolean }[];
|
hosts: { userId: number; isFixed: boolean }[];
|
||||||
bookingFields: z.infer<typeof eventTypeBookingFields>;
|
bookingFields: z.infer<typeof eventTypeBookingFields>;
|
||||||
|
availability?: AvailabilityOption;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CustomInputParsed = typeof customInputSchema._output;
|
export type CustomInputParsed = typeof customInputSchema._output;
|
||||||
@@ -261,6 +263,7 @@ const EventTypePage = (props: EventTypeSetupProps) => {
|
|||||||
}, [defaultValues]);
|
}, [defaultValues]);
|
||||||
|
|
||||||
const appsMetadata = formMethods.getValues("metadata")?.apps;
|
const appsMetadata = formMethods.getValues("metadata")?.apps;
|
||||||
|
const availability = formMethods.watch("availability");
|
||||||
const numberOfInstalledApps = eventTypeApps?.filter((app) => app.isInstalled).length || 0;
|
const numberOfInstalledApps = eventTypeApps?.filter((app) => app.isInstalled).length || 0;
|
||||||
let numberOfActiveApps = 0;
|
let numberOfActiveApps = 0;
|
||||||
|
|
||||||
@@ -377,6 +380,7 @@ const EventTypePage = (props: EventTypeSetupProps) => {
|
|||||||
enabledWorkflowsNumber={eventType.workflows.length}
|
enabledWorkflowsNumber={eventType.workflows.length}
|
||||||
eventType={eventType}
|
eventType={eventType}
|
||||||
team={team}
|
team={team}
|
||||||
|
availability={availability}
|
||||||
isUpdateMutationLoading={updateMutation.isLoading}
|
isUpdateMutationLoading={updateMutation.isLoading}
|
||||||
formMethods={formMethods}
|
formMethods={formMethods}
|
||||||
disableBorder={tabName === "apps" || tabName === "workflows" || tabName === "webhooks"}
|
disableBorder={tabName === "apps" || tabName === "workflows" || tabName === "webhooks"}
|
||||||
@@ -384,13 +388,66 @@ const EventTypePage = (props: EventTypeSetupProps) => {
|
|||||||
<Form
|
<Form
|
||||||
form={formMethods}
|
form={formMethods}
|
||||||
id="event-type-form"
|
id="event-type-form"
|
||||||
handleSubmit={async (values: FormValues) => {
|
handleSubmit={async (values) => {
|
||||||
if (!values.children.length) return handleSubmit(values);
|
const {
|
||||||
const existingSlugEventTypes = values.children.filter((ch) =>
|
periodDates,
|
||||||
ch.owner.eventTypeSlugs.includes(slug)
|
periodCountCalendarDays,
|
||||||
);
|
beforeBufferTime,
|
||||||
if (!existingSlugEventTypes.length) return handleSubmit(values);
|
afterBufferTime,
|
||||||
setSlugExistsChildrenDialogOpen(existingSlugEventTypes);
|
seatsPerTimeSlot,
|
||||||
|
seatsShowAttendees,
|
||||||
|
bookingLimits,
|
||||||
|
durationLimits,
|
||||||
|
recurringEvent,
|
||||||
|
locations,
|
||||||
|
metadata,
|
||||||
|
customInputs,
|
||||||
|
// We don't need to send send these values to the backend
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
seatsPerTimeSlotEnabled,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
minimumBookingNoticeInDurationType,
|
||||||
|
availability,
|
||||||
|
...input
|
||||||
|
} = values;
|
||||||
|
|
||||||
|
if (bookingLimits) {
|
||||||
|
const isValid = validateIntervalLimitOrder(bookingLimits);
|
||||||
|
if (!isValid) throw new Error(t("event_setup_booking_limits_error"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (durationLimits) {
|
||||||
|
const isValid = validateIntervalLimitOrder(durationLimits);
|
||||||
|
if (!isValid) throw new Error(t("event_setup_duration_limits_error"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata?.multipleDuration !== undefined) {
|
||||||
|
if (metadata?.multipleDuration.length < 1) {
|
||||||
|
throw new Error(t("event_setup_multiple_duration_error"));
|
||||||
|
} else {
|
||||||
|
if (!input.length && !metadata?.multipleDuration?.includes(input.length)) {
|
||||||
|
throw new Error(t("event_setup_multiple_duration_default_error"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMutation.mutate({
|
||||||
|
...input,
|
||||||
|
locations,
|
||||||
|
recurringEvent,
|
||||||
|
periodStartDate: periodDates.startDate,
|
||||||
|
periodEndDate: periodDates.endDate,
|
||||||
|
periodCountCalendarDays: periodCountCalendarDays === "1",
|
||||||
|
id: eventType.id,
|
||||||
|
beforeEventBuffer: beforeBufferTime,
|
||||||
|
afterEventBuffer: afterBufferTime,
|
||||||
|
bookingLimits,
|
||||||
|
durationLimits,
|
||||||
|
seatsPerTimeSlot,
|
||||||
|
seatsShowAttendees,
|
||||||
|
metadata,
|
||||||
|
customInputs,
|
||||||
|
});
|
||||||
}}>
|
}}>
|
||||||
<div ref={animationParentRef}>{tabMap[tabName]}</div>
|
<div ref={animationParentRef}>{tabMap[tabName]}</div>
|
||||||
</Form>
|
</Form>
|
||||||
@@ -477,4 +534,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
EventTypePageWrapper.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default EventTypePageWrapper;
|
export default EventTypePageWrapper;
|
||||||
@@ -61,6 +61,7 @@ import { withQuery } from "@lib/QueryCell";
|
|||||||
import { HttpError } from "@lib/core/http/error";
|
import { HttpError } from "@lib/core/http/error";
|
||||||
|
|
||||||
import { EmbedButton, EmbedDialog } from "@components/Embed";
|
import { EmbedButton, EmbedDialog } from "@components/Embed";
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import SkeletonLoader from "@components/eventtype/SkeletonLoader";
|
import SkeletonLoader from "@components/eventtype/SkeletonLoader";
|
||||||
|
|
||||||
type EventTypeGroups = RouterOutputs["viewer"]["eventTypes"]["getByViewer"]["eventTypeGroups"];
|
type EventTypeGroups = RouterOutputs["viewer"]["eventTypes"]["getByViewer"]["eventTypeGroups"];
|
||||||
@@ -767,6 +768,7 @@ const EventTypesPage = () => {
|
|||||||
<Shell
|
<Shell
|
||||||
withoutSeo
|
withoutSeo
|
||||||
heading={t("event_types_page_title")}
|
heading={t("event_types_page_title")}
|
||||||
|
hideHeadingOnMobile
|
||||||
subtitle={t("event_types_page_subtitle")}
|
subtitle={t("event_types_page_subtitle")}
|
||||||
CTA={<CTA />}>
|
CTA={<CTA />}>
|
||||||
<WithQuery
|
<WithQuery
|
||||||
@@ -817,4 +819,6 @@ const EventTypesPage = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
EventTypesPage.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default EventTypesPage;
|
export default EventTypesPage;
|
||||||
@@ -13,6 +13,7 @@ import { Button, StepCard, Steps } from "@calcom/ui";
|
|||||||
|
|
||||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import { ConnectedCalendars } from "@components/getting-started/steps-views/ConnectCalendars";
|
import { ConnectedCalendars } from "@components/getting-started/steps-views/ConnectCalendars";
|
||||||
import { SetupAvailability } from "@components/getting-started/steps-views/SetupAvailability";
|
import { SetupAvailability } from "@components/getting-started/steps-views/SetupAvailability";
|
||||||
import UserProfile from "@components/getting-started/steps-views/UserProfile";
|
import UserProfile from "@components/getting-started/steps-views/UserProfile";
|
||||||
@@ -203,5 +204,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
OnboardingPage.isThemeSupported = false;
|
OnboardingPage.isThemeSupported = false;
|
||||||
|
OnboardingPage.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default OnboardingPage;
|
export default OnboardingPage;
|
||||||
@@ -17,6 +17,8 @@ import { trpc } from "@calcom/trpc";
|
|||||||
import { Button, ButtonGroup } from "@calcom/ui";
|
import { Button, ButtonGroup } from "@calcom/ui";
|
||||||
import { RefreshCcw, UserPlus, Users } from "@calcom/ui/components/icon";
|
import { RefreshCcw, UserPlus, Users } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
const Heading = () => {
|
const Heading = () => {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
|
|
||||||
@@ -53,7 +55,7 @@ export default function InsightsPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Shell>
|
<Shell hideHeadingOnMobile>
|
||||||
<UpgradeTip
|
<UpgradeTip
|
||||||
title={t("make_informed_decisions")}
|
title={t("make_informed_decisions")}
|
||||||
description={t("make_informed_decisions_description")}
|
description={t("make_informed_decisions_description")}
|
||||||
@@ -111,6 +113,8 @@ export default function InsightsPage() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InsightsPage.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
// If feature flag is disabled, return not found on getServerSideProps
|
// If feature flag is disabled, return not found on getServerSideProps
|
||||||
export const getServerSideProps = async () => {
|
export const getServerSideProps = async () => {
|
||||||
const prisma = await import("@calcom/prisma").then((mod) => mod.default);
|
const prisma = await import("@calcom/prisma").then((mod) => mod.default);
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { APP_NAME, WEBSITE_URL } from "@calcom/lib/constants";
|
|||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { Button } from "@calcom/ui";
|
import { Button } from "@calcom/ui";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
export default function MaintenancePage() {
|
export default function MaintenancePage() {
|
||||||
const { t, isLocaleReady } = useLocale();
|
const { t, isLocaleReady } = useLocale();
|
||||||
if (!isLocaleReady) return null;
|
if (!isLocaleReady) return null;
|
||||||
@@ -25,3 +27,5 @@ export default function MaintenancePage() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaintenancePage.PageWrapper = PageWrapper;
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
import Shell, { MobileNavigationMoreItems } from "@calcom/features/shell/Shell";
|
import Shell, { MobileNavigationMoreItems } from "@calcom/features/shell/Shell";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
export default function MorePage() {
|
export default function MorePage() {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
return (
|
return (
|
||||||
<Shell>
|
<Shell hideHeadingOnMobile>
|
||||||
<div className="max-w-screen-lg">
|
<div className="max-w-screen-lg">
|
||||||
<MobileNavigationMoreItems />
|
<MobileNavigationMoreItems />
|
||||||
<p className="text-subtle mt-6 text-xs leading-tight md:hidden">{t("more_page_footer")}</p>
|
<p className="text-subtle mt-6 text-xs leading-tight md:hidden">{t("more_page_footer")}</p>
|
||||||
@@ -12,3 +14,4 @@ export default function MorePage() {
|
|||||||
</Shell>
|
</Shell>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
MorePage.PageWrapper = PageWrapper;
|
||||||
@@ -2,8 +2,10 @@ import PaymentPage from "@calcom/features/ee/payments/components/PaymentPage";
|
|||||||
import { getServerSideProps } from "@calcom/features/ee/payments/pages/payment";
|
import { getServerSideProps } from "@calcom/features/ee/payments/pages/payment";
|
||||||
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
|
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
export default function Payment(props: inferSSRProps<typeof getServerSideProps>) {
|
export default function Payment(props: inferSSRProps<typeof getServerSideProps>) {
|
||||||
return <PaymentPage {...props} />;
|
return <PaymentPage {...props} />;
|
||||||
}
|
}
|
||||||
|
Payment.PageWrapper = PageWrapper;
|
||||||
export { getServerSideProps };
|
export { getServerSideProps };
|
||||||
@@ -2,6 +2,7 @@ import AdminAppsList from "@calcom/features/apps/AdminAppsList";
|
|||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { Meta } from "@calcom/ui";
|
import { Meta } from "@calcom/ui";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import { getLayout } from "@components/auth/layouts/AdminLayout";
|
import { getLayout } from "@components/auth/layouts/AdminLayout";
|
||||||
|
|
||||||
function AdminAppsView() {
|
function AdminAppsView() {
|
||||||
@@ -15,5 +16,6 @@ function AdminAppsView() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AdminAppsView.getLayout = getLayout;
|
AdminAppsView.getLayout = getLayout;
|
||||||
|
AdminAppsView.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default AdminAppsView;
|
export default AdminAppsView;
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
import { FlagListingView } from "@calcom/features/flags/pages/flag-listing-view";
|
import { FlagListingView } from "@calcom/features/flags/pages/flag-listing-view";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import { getLayout } from "@components/auth/layouts/AdminLayout";
|
import { getLayout } from "@components/auth/layouts/AdminLayout";
|
||||||
|
|
||||||
const FlagsPage = () => <FlagListingView />;
|
const FlagsPage = () => <FlagListingView />;
|
||||||
|
|
||||||
FlagsPage.getLayout = getLayout;
|
FlagsPage.getLayout = getLayout;
|
||||||
|
FlagsPage.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default FlagsPage;
|
export default FlagsPage;
|
||||||
@@ -4,6 +4,7 @@ import { useRef } from "react";
|
|||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { Button, Meta, TextField } from "@calcom/ui";
|
import { Button, Meta, TextField } from "@calcom/ui";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import { getLayout } from "@components/auth/layouts/AdminLayout";
|
import { getLayout } from "@components/auth/layouts/AdminLayout";
|
||||||
|
|
||||||
function AdminView() {
|
function AdminView() {
|
||||||
@@ -37,5 +38,6 @@ function AdminView() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AdminView.getLayout = getLayout;
|
AdminView.getLayout = getLayout;
|
||||||
|
AdminView.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default AdminView;
|
export default AdminView;
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Meta } from "@calcom/ui";
|
import { Meta } from "@calcom/ui";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import { getLayout } from "@components/auth/layouts/AdminLayout";
|
import { getLayout } from "@components/auth/layouts/AdminLayout";
|
||||||
|
|
||||||
function AdminAppsView() {
|
function AdminAppsView() {
|
||||||
@@ -12,5 +13,6 @@ function AdminAppsView() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AdminAppsView.getLayout = getLayout;
|
AdminAppsView.getLayout = getLayout;
|
||||||
|
AdminAppsView.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default AdminAppsView;
|
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;
|
||||||
@@ -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 { Button, Meta } from "@calcom/ui";
|
||||||
import { ExternalLink } from "@calcom/ui/components/icon";
|
import { ExternalLink } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
interface CtaRowProps {
|
interface CtaRowProps {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
@@ -37,8 +39,8 @@ const BillingView = () => {
|
|||||||
const returnTo = router.asPath;
|
const returnTo = router.asPath;
|
||||||
const billingHref = `/api/integrations/stripepayment/portal?returnTo=${WEBAPP_URL}${returnTo}`;
|
const billingHref = `/api/integrations/stripepayment/portal?returnTo=${WEBAPP_URL}${returnTo}`;
|
||||||
|
|
||||||
const onContactSupportClick = () => {
|
const onContactSupportClick = async () => {
|
||||||
open();
|
await open();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -64,5 +66,6 @@ const BillingView = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
BillingView.getLayout = getLayout;
|
BillingView.getLayout = getLayout;
|
||||||
|
BillingView.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default BillingView;
|
export default BillingView;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import type { TApiKeys } from "@calcom/ee/api-keys/components/ApiKeyListItem";
|
import type { TApiKeys } from "@calcom/ee/api-keys/components/ApiKeyListItem";
|
||||||
import LicenseRequired from "@calcom/ee/common/components/v2/LicenseRequired";
|
import LicenseRequired from "@calcom/ee/common/components/LicenseRequired";
|
||||||
import ApiKeyDialogForm from "@calcom/features/ee/api-keys/components/ApiKeyDialogForm";
|
import ApiKeyDialogForm from "@calcom/features/ee/api-keys/components/ApiKeyDialogForm";
|
||||||
import ApiKeyListItem from "@calcom/features/ee/api-keys/components/ApiKeyListItem";
|
import ApiKeyListItem from "@calcom/features/ee/api-keys/components/ApiKeyListItem";
|
||||||
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
|
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
|
||||||
@@ -18,6 +18,8 @@ import {
|
|||||||
} from "@calcom/ui";
|
} from "@calcom/ui";
|
||||||
import { Link as LinkIcon, Plus } from "@calcom/ui/components/icon";
|
import { Link as LinkIcon, Plus } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
const ApiKeysView = () => {
|
const ApiKeysView = () => {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
|
|
||||||
@@ -92,5 +94,6 @@ const ApiKeysView = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ApiKeysView.getLayout = getLayout;
|
ApiKeysView.getLayout = getLayout;
|
||||||
|
ApiKeysView.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default ApiKeysView;
|
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,
|
UpgradeTeamsBadge,
|
||||||
} from "@calcom/ui";
|
} from "@calcom/ui";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
const SkeletonLoader = ({ title, description }: { title: string; description: string }) => {
|
const SkeletonLoader = ({ title, description }: { title: string; description: string }) => {
|
||||||
return (
|
return (
|
||||||
<SkeletonContainer>
|
<SkeletonContainer>
|
||||||
@@ -50,6 +52,7 @@ const AppearanceView = () => {
|
|||||||
const utils = trpc.useContext();
|
const utils = trpc.useContext();
|
||||||
const { data: user, isLoading } = trpc.viewer.me.useQuery();
|
const { data: user, isLoading } = trpc.viewer.me.useQuery();
|
||||||
const [darkModeError, setDarkModeError] = useState(false);
|
const [darkModeError, setDarkModeError] = useState(false);
|
||||||
|
const [lightModeError, setLightModeError] = useState(false);
|
||||||
|
|
||||||
const { isLoading: isTeamPlanStatusLoading, hasPaidPlan } = useHasPaidPlan();
|
const { isLoading: isTeamPlanStatusLoading, hasPaidPlan } = useHasPaidPlan();
|
||||||
|
|
||||||
@@ -143,7 +146,14 @@ const AppearanceView = () => {
|
|||||||
<p className="text-default mb-2 block text-sm font-medium">{t("light_brand_color")}</p>
|
<p className="text-default mb-2 block text-sm font-medium">{t("light_brand_color")}</p>
|
||||||
<ColorPicker
|
<ColorPicker
|
||||||
defaultValue={user.brandColor}
|
defaultValue={user.brandColor}
|
||||||
onChange={(value) => formMethods.setValue("brandColor", value, { shouldDirty: true })}
|
onChange={(value) => {
|
||||||
|
if (!checkWCAGContrastColor("#ffffff", value)) {
|
||||||
|
setLightModeError(true);
|
||||||
|
} else {
|
||||||
|
setLightModeError(false);
|
||||||
|
}
|
||||||
|
formMethods.setValue("brandColor", value, { shouldDirty: true });
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -178,6 +188,14 @@ const AppearanceView = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
{lightModeError ? (
|
||||||
|
<div className="mt-4">
|
||||||
|
<Alert
|
||||||
|
severity="warning"
|
||||||
|
message="Light Theme color doesn't pass contrast check. We recommend you change this colour so your buttons will be more visible."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
{/* TODO future PR to preview brandColors */}
|
{/* TODO future PR to preview brandColors */}
|
||||||
{/* <Button
|
{/* <Button
|
||||||
color="secondary"
|
color="secondary"
|
||||||
@@ -230,5 +248,6 @@ const AppearanceView = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
AppearanceView.getLayout = getLayout;
|
AppearanceView.getLayout = getLayout;
|
||||||
|
AppearanceView.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default AppearanceView;
|
export default AppearanceView;
|
||||||
@@ -28,6 +28,7 @@ import { Plus, Calendar } from "@calcom/ui/components/icon";
|
|||||||
|
|
||||||
import { QueryCell } from "@lib/QueryCell";
|
import { QueryCell } from "@lib/QueryCell";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import { CalendarSwitch } from "@components/settings/CalendarSwitch";
|
import { CalendarSwitch } from "@components/settings/CalendarSwitch";
|
||||||
|
|
||||||
const SkeletonLoader = () => {
|
const SkeletonLoader = () => {
|
||||||
@@ -228,5 +229,6 @@ const CalendarsView = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
CalendarsView.getLayout = getLayout;
|
CalendarsView.getLayout = getLayout;
|
||||||
|
CalendarsView.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default CalendarsView;
|
export default CalendarsView;
|
||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
import { AlertCircle, MoreHorizontal, Trash, Video } from "@calcom/ui/components/icon";
|
import { AlertCircle, MoreHorizontal, Trash, Video } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
import AppListCard from "@components/AppListCard";
|
import AppListCard from "@components/AppListCard";
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
const SkeletonLoader = ({ title, description }: { title: string; description: string }) => {
|
const SkeletonLoader = ({ title, description }: { title: string; description: string }) => {
|
||||||
return (
|
return (
|
||||||
@@ -188,5 +189,6 @@ const ConferencingLayout = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ConferencingLayout.getLayout = getLayout;
|
ConferencingLayout.getLayout = getLayout;
|
||||||
|
ConferencingLayout.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default ConferencingLayout;
|
export default ConferencingLayout;
|
||||||
@@ -22,6 +22,8 @@ import {
|
|||||||
|
|
||||||
import { withQuery } from "@lib/QueryCell";
|
import { withQuery } from "@lib/QueryCell";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
const SkeletonLoader = ({ title, description }: { title: string; description: string }) => {
|
const SkeletonLoader = ({ title, description }: { title: string; description: string }) => {
|
||||||
return (
|
return (
|
||||||
<SkeletonContainer>
|
<SkeletonContainer>
|
||||||
@@ -219,5 +221,6 @@ const GeneralView = ({ localeProp, user }: GeneralViewProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
GeneralQueryView.getLayout = getLayout;
|
GeneralQueryView.getLayout = getLayout;
|
||||||
|
GeneralQueryView.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default GeneralQueryView;
|
export default GeneralQueryView;
|
||||||
@@ -40,6 +40,7 @@ import {
|
|||||||
} from "@calcom/ui";
|
} from "@calcom/ui";
|
||||||
import { AlertTriangle, Trash2 } from "@calcom/ui/components/icon";
|
import { AlertTriangle, Trash2 } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import TwoFactor from "@components/auth/TwoFactor";
|
import TwoFactor from "@components/auth/TwoFactor";
|
||||||
import { UsernameAvailabilityField } from "@components/ui/UsernameAvailability";
|
import { UsernameAvailabilityField } from "@components/ui/UsernameAvailability";
|
||||||
|
|
||||||
@@ -319,6 +320,7 @@ const ProfileForm = ({
|
|||||||
extraField?: React.ReactNode;
|
extraField?: React.ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
|
const [firstRender, setFirstRender] = useState(true);
|
||||||
|
|
||||||
const profileFormSchema = z.object({
|
const profileFormSchema = z.object({
|
||||||
username: z.string(),
|
username: z.string(),
|
||||||
@@ -384,6 +386,8 @@ const ProfileForm = ({
|
|||||||
}}
|
}}
|
||||||
excludedToolbarItems={["blockType"]}
|
excludedToolbarItems={["blockType"]}
|
||||||
disableLists
|
disableLists
|
||||||
|
firstRender={firstRender}
|
||||||
|
setFirstRender={setFirstRender}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button disabled={isDisabled} color="primary" className="mt-8" type="submit">
|
<Button disabled={isDisabled} color="primary" className="mt-8" type="submit">
|
||||||
@@ -394,5 +398,6 @@ const ProfileForm = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
ProfileView.getLayout = getLayout;
|
ProfileView.getLayout = getLayout;
|
||||||
|
ProfileView.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default ProfileView;
|
export default ProfileView;
|
||||||
@@ -6,6 +6,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import { Button, Form, Label, Meta, showToast, Skeleton, Switch } from "@calcom/ui";
|
import { Button, Form, Label, Meta, showToast, Skeleton, Switch } from "@calcom/ui";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
import { ssrInit } from "@server/lib/ssr";
|
||||||
|
|
||||||
const ProfileImpersonationView = () => {
|
const ProfileImpersonationView = () => {
|
||||||
@@ -85,6 +87,7 @@ const ProfileImpersonationView = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ProfileImpersonationView.getLayout = getLayout;
|
ProfileImpersonationView.getLayout = getLayout;
|
||||||
|
ProfileImpersonationView.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||||
const ssr = await ssrInit(context);
|
const ssr = await ssrInit(context);
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import { userMetadata } from "@calcom/prisma/zod-utils";
|
|||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import { Alert, Button, Form, Meta, PasswordField, Select, SettingsToggle, showToast } from "@calcom/ui";
|
import { Alert, Button, Form, Meta, PasswordField, Select, SettingsToggle, showToast } from "@calcom/ui";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
type ChangePasswordSessionFormValues = {
|
type ChangePasswordSessionFormValues = {
|
||||||
oldPassword: string;
|
oldPassword: string;
|
||||||
newPassword: string;
|
newPassword: string;
|
||||||
@@ -207,5 +209,6 @@ const PasswordView = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
PasswordView.getLayout = getLayout;
|
PasswordView.getLayout = getLayout;
|
||||||
|
PasswordView.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default PasswordView;
|
export default PasswordView;
|
||||||
@@ -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 { trpc } from "@calcom/trpc/react";
|
||||||
import { Badge, Meta, Switch, SkeletonButton, SkeletonContainer, SkeletonText, Alert } from "@calcom/ui";
|
import { Badge, Meta, Switch, SkeletonButton, SkeletonContainer, SkeletonText, Alert } from "@calcom/ui";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import DisableTwoFactorModal from "@components/settings/DisableTwoFactorModal";
|
import DisableTwoFactorModal from "@components/settings/DisableTwoFactorModal";
|
||||||
import EnableTwoFactorModal from "@components/settings/EnableTwoFactorModal";
|
import EnableTwoFactorModal from "@components/settings/EnableTwoFactorModal";
|
||||||
|
|
||||||
@@ -84,5 +85,6 @@ const TwoFactorAuthView = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TwoFactorAuthView.getLayout = getLayout;
|
TwoFactorAuthView.getLayout = getLayout;
|
||||||
|
TwoFactorAuthView.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default TwoFactorAuthView;
|
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 AddNewTeamMembers from "@calcom/features/ee/teams/components/AddNewTeamMembers";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import WizardLayout from "@components/layouts/WizardLayout";
|
import WizardLayout from "@components/layouts/WizardLayout";
|
||||||
|
|
||||||
const OnboardTeamMembersPage = () => {
|
const OnboardTeamMembersPage = () => {
|
||||||
@@ -24,4 +25,6 @@ OnboardTeamMembersPage.getLayout = (page: React.ReactElement) => (
|
|||||||
</WizardLayout>
|
</WizardLayout>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
OnboardTeamMembersPage.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default OnboardTeamMembersPage;
|
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;
|
||||||
@@ -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;
|
||||||
@@ -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 { CreateANewTeamForm } from "@calcom/features/ee/teams/components";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import WizardLayout from "@components/layouts/WizardLayout";
|
import WizardLayout from "@components/layouts/WizardLayout";
|
||||||
|
|
||||||
const CreateNewTeamPage = () => {
|
const CreateNewTeamPage = () => {
|
||||||
@@ -26,5 +27,6 @@ const LayoutWrapper = (page: React.ReactElement) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
CreateNewTeamPage.getLayout = LayoutWrapper;
|
CreateNewTeamPage.getLayout = LayoutWrapper;
|
||||||
|
CreateNewTeamPage.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default CreateNewTeamPage;
|
export default CreateNewTeamPage;
|
||||||
@@ -5,7 +5,7 @@ import type { CSSProperties } from "react";
|
|||||||
import type { SubmitHandler } from "react-hook-form";
|
import type { SubmitHandler } from "react-hook-form";
|
||||||
import { FormProvider, useForm } from "react-hook-form";
|
import { FormProvider, useForm } from "react-hook-form";
|
||||||
|
|
||||||
import LicenseRequired from "@calcom/features/ee/common/components/v2/LicenseRequired";
|
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
|
||||||
import { isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml";
|
import { isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml";
|
||||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
@@ -14,6 +14,8 @@ import prisma from "@calcom/prisma";
|
|||||||
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
|
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||||
import { Alert, Button, EmailField, HeadSeo, PasswordField, TextField } from "@calcom/ui";
|
import { Alert, Button, EmailField, HeadSeo, PasswordField, TextField } from "@calcom/ui";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
import { asStringOrNull } from "../lib/asStringOrNull";
|
import { asStringOrNull } from "../lib/asStringOrNull";
|
||||||
import { IS_GOOGLE_LOGIN_ENABLED } from "../server/lib/constants";
|
import { IS_GOOGLE_LOGIN_ENABLED } from "../server/lib/constants";
|
||||||
import { ssrInit } from "../server/lib/ssr";
|
import { ssrInit } from "../server/lib/ssr";
|
||||||
@@ -230,3 +232,4 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Signup.isThemeSupported = false;
|
Signup.isThemeSupported = false;
|
||||||
|
Signup.PageWrapper = PageWrapper;
|
||||||
@@ -20,6 +20,7 @@ import { ArrowRight } from "@calcom/ui/components/icon";
|
|||||||
import { useToggleQuery } from "@lib/hooks/useToggleQuery";
|
import { useToggleQuery } from "@lib/hooks/useToggleQuery";
|
||||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import Team from "@components/team/screens/Team";
|
import Team from "@components/team/screens/Team";
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
import { ssrInit } from "@server/lib/ssr";
|
||||||
@@ -204,5 +205,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
TeamPage.isBookingPage = true;
|
TeamPage.isBookingPage = true;
|
||||||
|
TeamPage.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export default TeamPage;
|
export default TeamPage;
|
||||||
@@ -14,6 +14,7 @@ import { asStringOrNull } from "@lib/asStringOrNull";
|
|||||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
import type { EmbedProps } from "@lib/withEmbedSsr";
|
import type { EmbedProps } from "@lib/withEmbedSsr";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import AvailabilityPage from "@components/booking/pages/AvailabilityPage";
|
import AvailabilityPage from "@components/booking/pages/AvailabilityPage";
|
||||||
|
|
||||||
import { ssgInit } from "@server/lib/ssg";
|
import { ssgInit } from "@server/lib/ssg";
|
||||||
@@ -25,6 +26,7 @@ export default function TeamType(props: AvailabilityTeamPageProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TeamType.isBookingPage = true;
|
TeamType.isBookingPage = true;
|
||||||
|
TeamType.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||||
const slugParam = asStringOrNull(context.query.slug);
|
const slugParam = asStringOrNull(context.query.slug);
|
||||||
|
|||||||
Loaded 100 of 209 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user