Merge branch 'main' into testE2E-timezone

This commit is contained in:
GitStart-Cal.com 2023-11-23 09:01:59 +05:45 committed by GitHub
commit 457dfa645d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 767 additions and 394 deletions

View File

@ -283,3 +283,9 @@ E2E_TEST_OIDC_USER_EMAIL=
E2E_TEST_OIDC_USER_PASSWORD=
# ***********************************************************************************************************
# provide a value between 0 and 100 to ensure the percentage of traffic
# redirected from the legacy to the future pages
AB_TEST_BUCKET_PROBABILITY=50
# whether we redirect to the future/event-types from event-types or not
APP_ROUTER_EVENT_TYPES_ENABLED=1

View File

@ -10,7 +10,7 @@
"@calcom/config": "*",
"@calcom/dayjs": "*",
"@calcom/ui": "*",
"@radix-ui/react-avatar": "^1.0.0",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-collapsible": "^1.0.0",
"@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.5",
@ -49,7 +49,7 @@
"storybook-addon-designs": "^6.3.1",
"storybook-addon-next": "^1.6.9",
"storybook-react-i18next": "^1.1.2",
"tailwindcss": "^3.3.1",
"tailwindcss": "^3.3.3",
"typescript": "^4.9.4",
"vite": "^4.1.2"
}

View File

@ -1,16 +1,21 @@
import { getBucket } from "abTest/utils";
import type { NextMiddleware, NextRequest } from "next/server";
import { NextResponse } from "next/server";
import { NextResponse, URLPattern } from "next/server";
import z from "zod";
const ROUTES: [RegExp, boolean][] = [
[/^\/event-types$/, Boolean(process.env.APP_ROUTER_EVENT_TYPES_ENABLED)],
];
const ROUTES: [URLPattern, boolean][] = [
["/event-types", process.env.APP_ROUTER_EVENT_TYPES_ENABLED === "1"] as const,
].map(([pathname, enabled]) => [
new URLPattern({
pathname,
}),
enabled,
]);
const FUTURE_ROUTES_OVERRIDE_COOKIE_NAME = "x-calcom-future-routes-override";
const FUTURE_ROUTES_ENABLED_COOKIE_NAME = "x-calcom-future-routes-enabled";
const bucketSchema = z.union([z.literal("legacy"), z.literal("future")]).default("legacy");
const bucketSchema = z.union([z.literal("legacy"), z.literal("future")]);
export const abTestMiddlewareFactory =
(next: (req: NextRequest) => Promise<NextResponse<unknown>>): NextMiddleware =>
@ -21,7 +26,7 @@ export const abTestMiddlewareFactory =
const override = req.cookies.has(FUTURE_ROUTES_OVERRIDE_COOKIE_NAME);
const route = ROUTES.find(([regExp]) => regExp.test(pathname)) ?? null;
const route = ROUTES.find(([regExp]) => regExp.test(req.url)) ?? null;
const enabled = route !== null ? route[1] || override : false;
@ -35,16 +40,29 @@ export const abTestMiddlewareFactory =
if (!safeParsedBucket.success) {
// cookie does not exist or it has incorrect value
const bucket = getBucket();
const res = NextResponse.next(response);
res.cookies.set(FUTURE_ROUTES_ENABLED_COOKIE_NAME, getBucket(), { expires: 1000 * 60 * 30 }); // 30 min in ms
return res;
response.cookies.set(FUTURE_ROUTES_ENABLED_COOKIE_NAME, bucket, {
expires: Date.now() + 1000 * 60 * 30,
httpOnly: true,
}); // 30 min in ms
if (bucket === "legacy") {
return response;
}
const url = req.nextUrl.clone();
url.pathname = `future${pathname}/`;
return NextResponse.rewrite(url, response);
}
const bucketUrlPrefix = safeParsedBucket.data === "future" ? "future" : "";
if (safeParsedBucket.data === "legacy") {
return response;
}
const url = req.nextUrl.clone();
url.pathname = `${bucketUrlPrefix}${pathname}/`;
url.pathname = `future${pathname}/`;
return NextResponse.rewrite(url, response);
};

View File

@ -0,0 +1,8 @@
"use client";
import { createHydrateClient } from "app/_trpc/createHydrateClient";
import superjson from "superjson";
export const HydrateClient = createHydrateClient({
transformer: superjson,
});

View File

@ -0,0 +1,5 @@
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
import { createTRPCReact } from "@trpc/react-query";
export const trpc = createTRPCReact<AppRouter>({});

View File

@ -0,0 +1,21 @@
"use client";
import { type DehydratedState, Hydrate } from "@tanstack/react-query";
import { useMemo } from "react";
import type { DataTransformer } from "@trpc/server";
export function createHydrateClient(opts: { transformer?: DataTransformer }) {
return function HydrateClient(props: { children: React.ReactNode; state: DehydratedState }) {
const { state, children } = props;
const transformedState: DehydratedState = useMemo(() => {
if (opts.transformer) {
return opts.transformer.deserialize(state);
}
return state;
}, [state]);
return <Hydrate state={transformedState}>{children}</Hydrate>;
};
}

View File

@ -0,0 +1,128 @@
import { type DehydratedState, QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { HydrateClient } from "app/_trpc/HydrateClient";
import { trpc } from "app/_trpc/client";
import { useState } from "react";
import superjson from "superjson";
import { httpBatchLink } from "@calcom/trpc/client/links/httpBatchLink";
import { httpLink } from "@calcom/trpc/client/links/httpLink";
import { loggerLink } from "@calcom/trpc/client/links/loggerLink";
import { splitLink } from "@calcom/trpc/client/links/splitLink";
const ENDPOINTS = [
"admin",
"apiKeys",
"appRoutingForms",
"apps",
"auth",
"availability",
"appBasecamp3",
"bookings",
"deploymentSetup",
"eventTypes",
"features",
"insights",
"payments",
"public",
"saml",
"slots",
"teams",
"organizations",
"users",
"viewer",
"webhook",
"workflows",
"appsRouter",
"googleWorkspace",
] as const;
export type Endpoint = (typeof ENDPOINTS)[number];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const resolveEndpoint = (links: any) => {
// TODO: Update our trpc routes so they are more clear.
// This function parses paths like the following and maps them
// to the correct API endpoints.
// - viewer.me - 2 segment paths like this are for logged in requests
// - viewer.public.i18n - 3 segments paths can be public or authed
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (ctx: any) => {
const parts = ctx.op.path.split(".");
let endpoint;
let path = "";
if (parts.length == 2) {
endpoint = parts[0] as keyof typeof links;
path = parts[1];
} else {
endpoint = parts[1] as keyof typeof links;
path = parts.splice(2, parts.length - 2).join(".");
}
return links[endpoint]({ ...ctx, op: { ...ctx.op, path } });
};
};
export const TrpcProvider: React.FC<{ children: React.ReactNode; dehydratedState?: DehydratedState }> = ({
children,
dehydratedState,
}) => {
const [queryClient] = useState(
() =>
new QueryClient({
defaultOptions: { queries: { staleTime: 5000 } },
})
);
const url =
typeof window !== "undefined"
? "/api/trpc"
: process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}/api/trpc`
: `${process.env.NEXT_PUBLIC_WEBAPP_URL}/api/trpc`;
const [trpcClient] = useState(() =>
trpc.createClient({
links: [
// adds pretty logs to your console in development and logs errors in production
loggerLink({
enabled: (opts) =>
!!process.env.NEXT_PUBLIC_DEBUG || (opts.direction === "down" && opts.result instanceof Error),
}),
splitLink({
// check for context property `skipBatch`
condition: (op) => !!op.context.skipBatch,
// when condition is true, use normal request
true: (runtime) => {
const links = Object.fromEntries(
ENDPOINTS.map((endpoint) => [
endpoint,
httpLink({
url: `${url}/${endpoint}`,
})(runtime),
])
);
return resolveEndpoint(links);
},
// when condition is false, use batch request
false: (runtime) => {
const links = Object.fromEntries(
ENDPOINTS.map((endpoint) => [
endpoint,
httpBatchLink({
url: `${url}/${endpoint}`,
})(runtime),
])
);
return resolveEndpoint(links);
},
}),
],
transformer: superjson,
})
);
return (
<trpc.Provider client={trpcClient} queryClient={queryClient}>
<QueryClientProvider client={queryClient}>
{dehydratedState ? <HydrateClient state={dehydratedState}>{children}</HydrateClient> : children}
</QueryClientProvider>
</trpc.Provider>
);
};

40
apps/web/app/_utils.tsx Normal file
View File

@ -0,0 +1,40 @@
import { type TFunction } from "i18next";
import { headers } from "next/headers";
import { constructGenericImage } from "@calcom/lib/OgImages";
import { IS_CALCOM, WEBAPP_URL, APP_NAME, SEO_IMG_OGIMG } from "@calcom/lib/constants";
import { getFixedT } from "@calcom/lib/server/getFixedT";
import { preparePageMetadata } from "@lib/metadata";
export const _generateMetadata = async (
getTitle: (t: TFunction<string, undefined>) => string,
getDescription: (t: TFunction<string, undefined>) => string
) => {
const h = headers();
const canonical = h.get("x-pathname") ?? "";
const locale = h.get("x-locale") ?? "en";
const t = await getFixedT(locale, "common");
const title = getTitle(t);
const description = getDescription(t);
const metadataBase = new URL(IS_CALCOM ? "https://cal.com" : WEBAPP_URL);
const image =
SEO_IMG_OGIMG +
constructGenericImage({
title,
description,
});
return preparePageMetadata({
title,
canonical,
image,
description,
siteName: APP_NAME,
metadataBase,
});
};

64
apps/web/app/error.tsx Normal file
View File

@ -0,0 +1,64 @@
"use client";
/**
* Typescript class based component for custom-error
* @link https://nextjs.org/docs/advanced-features/custom-error-page
*/
import type { NextPage } from "next";
import type { ErrorProps } from "next/error";
import React from "react";
import { HttpError } from "@calcom/lib/http-error";
import logger from "@calcom/lib/logger";
import { redactError } from "@calcom/lib/redactError";
import { ErrorPage } from "@components/error/error-page";
type NextError = Error & { digest?: string };
// Ref: https://nextjs.org/docs/app/api-reference/file-conventions/error#props
export type DefaultErrorProps = {
error: NextError;
reset: () => void; // A function to reset the error boundary
};
type AugmentedError = NextError | HttpError | null;
type CustomErrorProps = {
err?: AugmentedError;
statusCode?: number;
message?: string;
} & Omit<ErrorProps, "err" | "statusCode">;
const log = logger.getSubLogger({ prefix: ["[error]"] });
const CustomError: NextPage<DefaultErrorProps> = (props) => {
const { error } = props;
let errorObject: CustomErrorProps = {
message: error.message,
err: error,
};
if (error instanceof HttpError) {
const redactedError = redactError(error);
errorObject = {
statusCode: error.statusCode,
title: redactedError.name,
message: redactedError.message,
err: {
...redactedError,
...error,
},
};
}
// `error.digest` property contains an automatically generated hash of the error that can be used to match the corresponding error in server-side logs
log.debug(`${error?.toString() ?? JSON.stringify(error)}`);
log.info("errorObject: ", errorObject);
return (
<ErrorPage statusCode={errorObject.statusCode} error={errorObject.err} message={errorObject.message} />
);
};
export default CustomError;

View File

@ -0,0 +1,10 @@
import EventTypes from "@pages/event-types";
import { _generateMetadata } from "app/_utils";
export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("event_types_page_title"),
(t) => t("event_types_page_subtitle")
);
export default EventTypes;

View File

@ -0,0 +1,22 @@
// pages without layout (e.g., /availability/index.tsx) are supposed to go under (layout) folder
import { headers } from "next/headers";
import { type ReactElement } from "react";
import { getLayout } from "@calcom/features/MainLayoutAppDir";
import PageWrapper from "@components/PageWrapperAppDir";
type WrapperWithLayoutProps = {
children: ReactElement;
};
export default async function WrapperWithLayout({ children }: WrapperWithLayoutProps) {
const h = headers();
const nonce = h.get("x-nonce") ?? undefined;
return (
<PageWrapper getLayout={getLayout} requiresLicense={false} nonce={nonce} themeBasis={null}>
{children}
</PageWrapper>
);
}

View File

@ -0,0 +1,17 @@
"use client";
import { type NextPage } from "next";
import CustomError, { type DefaultErrorProps } from "./error";
export const GlobalError: NextPage<DefaultErrorProps> = (props) => {
return (
<html>
<body>
<CustomError {...props} />
</body>
</html>
);
};
export default GlobalError;

View File

@ -1,84 +1,63 @@
import type { Metadata } from "next";
import { headers as nextHeaders, cookies as nextCookies } from "next/headers";
import { dir } from "i18next";
import { headers, cookies } from "next/headers";
import Script from "next/script";
import React from "react";
import { getLocale } from "@calcom/features/auth/lib/getLocale";
import { IS_PRODUCTION } from "@calcom/lib/constants";
import { prepareRootMetadata } from "@lib/metadata";
import "../styles/globals.css";
export const metadata: Metadata = {
icons: {
icon: [
{
sizes: "32x32",
url: "/api/logo?type=favicon-32",
},
{
sizes: "16x16",
url: "/api/logo?type=favicon-16",
},
],
apple: {
sizes: "180x180",
url: "/api/logo?type=apple-touch-icon",
export const generateMetadata = () =>
prepareRootMetadata({
twitterCreator: "@calcom",
twitterSite: "@calcom",
robots: {
index: false,
follow: false,
},
other: [
{
url: "/safari-pinned-tab.svg",
rel: "mask-icon",
},
],
},
manifest: "/site.webmanifest",
themeColor: [
{ media: "(prefers-color-scheme: light)", color: "#f9fafb" },
{ media: "(prefers-color-scheme: dark)", color: "#1C1C1C" },
],
other: {
"msapplication-TileColor": "#000000",
},
};
});
const getInitialProps = async (
url: string,
headers: ReturnType<typeof nextHeaders>,
cookies: ReturnType<typeof nextCookies>
) => {
const getInitialProps = async (url: string) => {
const { pathname, searchParams } = new URL(url);
const isEmbed = pathname.endsWith("/embed") || (searchParams?.get("embedType") ?? null) !== null;
const embedColorScheme = searchParams?.get("ui.color-scheme");
// @ts-expect-error we cannot access ctx.req in app dir, however headers and cookies are only properties needed to extract the locale
const newLocale = await getLocale({ headers, cookies });
let direction = "ltr";
try {
const intlLocale = new Intl.Locale(newLocale);
// @ts-expect-error INFO: Typescript does not know about the Intl.Locale textInfo attribute
direction = intlLocale.textInfo?.direction;
} catch (e) {
console.error(e);
}
const req = { headers: headers(), cookies: cookies() };
const newLocale = await getLocale(req);
const direction = dir(newLocale);
return { isEmbed, embedColorScheme, locale: newLocale, direction };
};
const getFallbackProps = () => ({
locale: "en",
direction: "ltr",
isEmbed: false,
embedColorScheme: false,
});
export default async function RootLayout({ children }: { children: React.ReactNode }) {
const headers = nextHeaders();
const cookies = nextCookies();
const h = headers();
const fullUrl = headers.get("x-url") ?? "";
const nonce = headers.get("x-csp") ?? "";
const fullUrl = h.get("x-url") ?? "";
const nonce = h.get("x-csp") ?? "";
const isSSG = !fullUrl;
const { locale, direction, isEmbed, embedColorScheme } = isSSG
? getFallbackProps()
: await getInitialProps(fullUrl);
const { locale, direction, isEmbed, embedColorScheme } = await getInitialProps(fullUrl, headers, cookies);
return (
<html
lang={locale}
dir={direction}
style={embedColorScheme ? { colorScheme: embedColorScheme as string } : undefined}>
style={embedColorScheme ? { colorScheme: embedColorScheme as string } : undefined}
data-nextjs-router="app">
<head nonce={nonce}>
{!IS_PRODUCTION && process.env.VERCEL_ENV === "preview" && (
// eslint-disable-next-line @next/next/no-sync-scripts

View File

@ -1,5 +1,6 @@
"use client";
import { type DehydratedState } from "@tanstack/react-query";
import type { SSRConfig } from "next-i18next";
import { Inter } from "next/font/google";
import localFont from "next/font/local";
@ -10,7 +11,6 @@ import type { ReactNode } from "react";
import "@calcom/embed-core/src/embed-iframe";
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
import { trpc } from "@calcom/trpc/react";
import type { AppProps } from "@lib/app-providers-app-dir";
import AppProviders from "@lib/app-providers-app-dir";
@ -29,13 +29,14 @@ const calFont = localFont({
});
export type PageWrapperProps = Readonly<{
getLayout: (page: React.ReactElement) => ReactNode;
getLayout: ((page: React.ReactElement) => ReactNode) | null;
children: React.ReactElement;
requiresLicense: boolean;
isThemeSupported: boolean;
isBookingPage: boolean;
nonce: string | undefined;
themeBasis: string | null;
dehydratedState?: DehydratedState;
isThemeSupported?: boolean;
isBookingPage?: boolean;
i18n?: SSRConfig;
}>;
@ -85,4 +86,4 @@ function PageWrapper(props: PageWrapperProps) {
);
}
export default trpc.withTRPC(PageWrapper);
export default PageWrapper;

View File

@ -1,4 +1,5 @@
import { TooltipProvider } from "@radix-ui/react-tooltip";
import { TrpcProvider } from "app/_trpc/trpc-provider";
import { dir } from "i18next";
import type { Session } from "next-auth";
import { SessionProvider, useSession } from "next-auth/react";
@ -255,26 +256,28 @@ const AppProviders = (props: PageWrapperProps) => {
const isBookingPage = useIsBookingPage();
const RemainingProviders = (
<EventCollectionProvider options={{ apiPath: "/api/collect-events" }}>
<SessionProvider>
<CustomI18nextProvider i18n={props.i18n}>
<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
themeBasis={props.themeBasis}
nonce={props.nonce}
isThemeSupported={props.isThemeSupported}
isBookingPage={props.isBookingPage || isBookingPage}>
<FeatureFlagsProvider>
<OrgBrandProvider>
<MetaProvider>{props.children}</MetaProvider>
</OrgBrandProvider>
</FeatureFlagsProvider>
</CalcomThemeProvider>
</TooltipProvider>
</CustomI18nextProvider>
</SessionProvider>
</EventCollectionProvider>
<TrpcProvider dehydratedState={props.dehydratedState}>
<EventCollectionProvider options={{ apiPath: "/api/collect-events" }}>
<SessionProvider>
<CustomI18nextProvider i18n={props.i18n}>
<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
themeBasis={props.themeBasis}
nonce={props.nonce}
isThemeSupported={/* undefined gets treated as true */ props.isThemeSupported ?? true}
isBookingPage={props.isBookingPage || isBookingPage}>
<FeatureFlagsProvider>
<OrgBrandProvider>
<MetaProvider>{props.children}</MetaProvider>
</OrgBrandProvider>
</FeatureFlagsProvider>
</CalcomThemeProvider>
</TooltipProvider>
</CustomI18nextProvider>
</SessionProvider>
</EventCollectionProvider>
</TrpcProvider>
);
if (isBookingPage) {

83
apps/web/lib/metadata.ts Normal file
View File

@ -0,0 +1,83 @@
import type { Metadata } from "next";
import { truncateOnWord } from "@calcom/lib/text";
type RootMetadataRecipe = Readonly<{
twitterCreator: string;
twitterSite: string;
robots: {
index: boolean;
follow: boolean;
};
}>;
export type PageMetadataRecipe = Readonly<{
title: string;
canonical: string;
image: string;
description: string;
siteName: string;
metadataBase: URL;
}>;
export const prepareRootMetadata = (recipe: RootMetadataRecipe): Metadata => ({
icons: {
icon: "/favicon.icon",
apple: "/api/logo?type=apple-touch-icon",
other: [
{
rel: "icon-mask",
url: "/safari-pinned-tab.svg",
// @ts-expect-error TODO available in the never Next.js version
color: "#000000",
},
{
url: "/api/logo?type=favicon-16",
sizes: "16x16",
type: "image/png",
},
{
url: "/api/logo?type=favicon-32",
sizes: "32x32",
type: "image/png",
},
],
},
manifest: "/site.webmanifest",
viewport: "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0",
robots: recipe.robots,
other: {
"application-TileColor": "#ff0000",
},
themeColor: [
{
media: "(prefers-color-scheme: light)",
color: "#f9fafb",
},
{
media: "(prefers-color-scheme: dark)",
color: "#1C1C1C",
},
],
twitter: {
site: recipe.twitterSite,
creator: recipe.twitterCreator,
card: "summary_large_image",
},
});
export const preparePageMetadata = (recipe: PageMetadataRecipe): Metadata => ({
title: recipe.title,
alternates: {
canonical: recipe.canonical,
},
openGraph: {
description: truncateOnWord(recipe.description, 158),
url: recipe.canonical,
type: "website",
siteName: recipe.siteName,
title: recipe.title,
images: [recipe.image],
},
metadataBase: recipe.metadataBase,
});

View File

@ -1,13 +1,16 @@
import { get } from "@vercel/edge-config";
import { collectEvents } from "next-collect/server";
import type { NextMiddleware } from "next/server";
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
import { getLocale } from "@calcom/features/auth/lib/getLocale";
import { extendEventData, nextCollectBasicSettings } from "@calcom/lib/telemetry";
import { csp } from "@lib/csp";
const middleware: NextMiddleware = async (req) => {
import { abTestMiddlewareFactory } from "./abTest/middlewareFactory";
const middleware = async (req: NextRequest): Promise<NextResponse<unknown>> => {
const url = req.nextUrl;
const requestHeaders = new Headers(req.headers);
@ -61,6 +64,12 @@ const middleware: NextMiddleware = async (req) => {
requestHeaders.set("x-csp-enforce", "true");
}
requestHeaders.set("x-pathname", url.pathname);
const locale = await getLocale(req);
requestHeaders.set("x-locale", locale);
return NextResponse.next({
request: {
headers: requestHeaders,
@ -90,11 +99,13 @@ export const config = {
* Paths required by routingForms.handle
*/
"/apps/routing_forms/:path*",
"/event-types",
"/future/event-types/",
],
};
export default collectEvents({
middleware,
middleware: abTestMiddlewareFactory(middleware),
...nextCollectBasicSettings,
cookieName: "__clnds",
extend: extendEventData,

View File

@ -1,6 +1,6 @@
{
"name": "@calcom/web",
"version": "3.5.0",
"version": "3.5.1",
"private": true,
"scripts": {
"analyze": "ANALYZE=true next build",
@ -45,7 +45,7 @@
"@hookform/resolvers": "^2.9.7",
"@next-auth/prisma-adapter": "^1.0.4",
"@next/bundle-analyzer": "^13.1.6",
"@radix-ui/react-avatar": "^1.0.0",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-collapsible": "^1.0.0",
"@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.5",
@ -170,7 +170,7 @@
"node-html-parser": "^6.1.10",
"node-mocks-http": "^1.11.0",
"postcss": "^8.4.18",
"tailwindcss": "^3.3.1",
"tailwindcss": "^3.3.3",
"tailwindcss-animate": "^1.0.6",
"ts-node": "^10.9.1",
"typescript": "^4.9.4"

View File

@ -1,3 +1,5 @@
"use client";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import type { User } from "@prisma/client";
import { Trans } from "next-i18next";

View File

@ -5,16 +5,47 @@ import { WEBAPP_URL } from "@calcom/lib/constants";
import { randomString } from "@calcom/lib/random";
import { test } from "./lib/fixtures";
import { testBothFutureAndLegacyRoutes } from "./lib/future-legacy-routes";
import { bookTimeSlot, createNewEventType, selectFirstAvailableTimeSlotNextMonth } from "./lib/testUtils";
test.describe.configure({ mode: "parallel" });
test.describe("Event Types A/B tests", () => {
test("should point to the /future/event-types page", async ({ page, users, context }) => {
await context.addCookies([
{
name: "x-calcom-future-routes-override",
value: "1",
url: "http://localhost:3000",
},
]);
const user = await users.create();
await user.apiLogin();
await page.goto("/event-types");
await page.waitForLoadState();
const dataNextJsRouter = await page.evaluate(() =>
window.document.documentElement.getAttribute("data-nextjs-router")
);
expect(dataNextJsRouter).toEqual("app");
const locator = page.getByRole("heading", { name: "Event Types" });
await expect(locator).toBeVisible();
});
});
test.describe("Event Types tests", () => {
test.describe("user", () => {
testBothFutureAndLegacyRoutes.describe("user", () => {
test.beforeEach(async ({ page, users }) => {
const user = await users.create();
await user.apiLogin();
await page.goto("/event-types");
// We wait until loading is finished
await page.waitForSelector('[data-testid="event-types"]');
});

View File

@ -0,0 +1,33 @@
import { test } from "./fixtures";
export type RouteVariant = "future" | "legacy";
const routeVariants = ["future", "legacy"];
/**
* Small wrapper around test.describe().
* When using testbothFutureLegacyRoutes.describe() instead of test.describe(), this will run the specified
* tests twice. One with the pages route, and one with the new app dir "future" route. It will also add the route variant
* name to the test name for easier debugging.
* Finally it also adds a parameter routeVariant to your testBothFutureAndLegacyRoutes.describe() callback, which
* can be used to do any conditional rendering in the test for a specific route variant (should be as little
* as possible).
*
* See apps/web/playwright/event-types.e2e.ts for an example.
*/
export const testBothFutureAndLegacyRoutes = {
describe: (testName: string, testFn: (routeVariant: RouteVariant) => void) => {
routeVariants.forEach((routeVariant) => {
test.describe(`${testName} -- ${routeVariant}`, () => {
if (routeVariant === "future") {
test.beforeEach(({ context }) => {
context.addCookies([
{ name: "x-calcom-future-routes-override", value: "1", url: "http://localhost:3000" },
]);
});
}
testFn(routeVariant as RouteVariant);
});
});
},
};

View File

@ -5,6 +5,7 @@
"paths": {
"~/*": ["modules/*"],
"@components/*": ["components/*"],
"@pages/*": ["pages/*"],
"@lib/*": ["lib/*"],
"@server/*": ["server/*"],
"@prisma/client/*": ["@calcom/prisma/client/*"]

View File

@ -26,7 +26,7 @@
"lodash": "^4.17.21",
"qs-stringify": "^1.2.1",
"react-i18next": "^12.2.0",
"stripe": "^14.3.0"
"stripe": "^9.16.0"
},
"devDependencies": {
"@calcom/types": "*"

View File

@ -31,7 +31,7 @@
"prettier": "^2.8.6",
"prettier-plugin-tailwindcss": "^0.2.5",
"tailwind-scrollbar": "^2.0.1",
"tailwindcss": "^3.3.1",
"tailwindcss": "^3.3.3",
"typescript": "^4.9.4"
}
}

View File

@ -17,7 +17,7 @@ class CalendarEventClass implements CalendarEvent {
organizer!: Person;
attendees!: Person[];
description?: string | null;
team?: { name: string; members: Person[] };
team?: { name: string; members: Person[]; id: number };
location?: string | null;
conferenceData?: ConferenceData;
additionalInformation?: AdditionalInformation;

View File

@ -48,7 +48,7 @@
"autoprefixer": "^10.4.12",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.18",
"tailwindcss": "^3.3.1",
"tailwindcss": "^3.3.3",
"typescript": "^4.9.4",
"vite": "^4.1.2"
}

View File

@ -0,0 +1,19 @@
"use client";
import type { ComponentProps } from "react";
import React from "react";
import Shell from "@calcom/features/shell/Shell";
export default function MainLayout({
children,
...rest
}: { children: React.ReactNode } & ComponentProps<typeof Shell>) {
return (
<Shell withoutMain={true} {...rest}>
{children}
</Shell>
);
}
export const getLayout = (page: React.ReactElement) => <MainLayout>{page}</MainLayout>;

View File

@ -2,9 +2,11 @@ import { parse } from "accept-language-parser";
import { lookup } from "bcp-47-match";
import type { GetTokenParams } from "next-auth/jwt";
import { getToken } from "next-auth/jwt";
import { type ReadonlyHeaders } from "next/dist/server/web/spec-extension/adapters/headers";
import { type ReadonlyRequestCookies } from "next/dist/server/web/spec-extension/adapters/request-cookies";
//@ts-expect-error no type definitions
import { i18n } from "@calcom/web/next-i18next.config";
import { i18n } from "@calcom/config/next-i18next.config";
/**
* This is a slimmed down version of the `getServerSession` function from
@ -17,9 +19,16 @@ import { i18n } from "@calcom/web/next-i18next.config";
* token has expired (30 days). This should be fine as we call `/auth/session`
* frequently enough on the client-side to keep the session alive.
*/
export const getLocale = async (req: GetTokenParams["req"]): Promise<string> => {
export const getLocale = async (
req:
| GetTokenParams["req"]
| {
cookies: ReadonlyRequestCookies;
headers: ReadonlyHeaders;
}
): Promise<string> => {
const token = await getToken({
req,
req: req as GetTokenParams["req"],
});
const tokenLocale = token?.["locale"];

View File

@ -72,7 +72,12 @@ async function getBookingToDelete(id: number | undefined, uid: string | undefine
hideBranding: true,
},
},
teamId: true,
team: {
select: {
id: true,
name: true,
},
},
recurringEvent: true,
title: true,
eventName: true,
@ -151,11 +156,10 @@ async function handler(req: CustomRequest) {
const teamId = await getTeamIdFromEventType({
eventType: {
team: { id: bookingToDelete.eventType?.teamId ?? null },
team: { id: bookingToDelete.eventType?.team?.id ?? null },
parentId: bookingToDelete?.eventType?.parentId ?? null,
},
});
const triggerForUser = !teamId || (teamId && bookingToDelete.eventType?.parentId);
const subscriberOptions = {
@ -255,7 +259,9 @@ async function handler(req: CustomRequest) {
? [bookingToDelete?.user.destinationCalendar]
: [],
cancellationReason: cancellationReason,
...(teamMembers && { team: { name: "", members: teamMembers } }),
...(teamMembers && {
team: { name: bookingToDelete?.eventType?.team?.name || "Nameless", members: teamMembers, id: teamId! },
}),
seatsPerTimeSlot: bookingToDelete.eventType?.seatsPerTimeSlot,
seatsShowAttendees: bookingToDelete.eventType?.seatsShowAttendees,
};
@ -408,7 +414,7 @@ async function handler(req: CustomRequest) {
if (bookingToDelete.location === DailyLocationType) {
bookingToDelete.user.credentials.push({
...FAKE_DAILY_CREDENTIAL,
teamId: bookingToDelete.eventType?.teamId || null,
teamId: bookingToDelete.eventType?.team?.id || null,
});
}
@ -540,10 +546,10 @@ async function handler(req: CustomRequest) {
let eventTypeOwnerId;
if (bookingToDelete.eventType?.owner) {
eventTypeOwnerId = bookingToDelete.eventType.owner.id;
} else if (bookingToDelete.eventType?.teamId) {
} else if (bookingToDelete.eventType?.team?.id) {
const teamOwner = await prisma.membership.findFirst({
where: {
teamId: bookingToDelete.eventType.teamId,
teamId: bookingToDelete.eventType?.team.id,
role: MembershipRole.OWNER,
},
select: {

View File

@ -1079,7 +1079,6 @@ async function handler(
},
};
});
const teamMembers = await Promise.all(teamMemberPromises);
const attendeesList = [...invitee, ...guests];
@ -1887,6 +1886,7 @@ async function handler(
evt.team = {
members: teamMembers,
name: eventType.team?.name || "Nameless",
id: eventType.team?.id ?? 0,
};
}

View File

@ -6,7 +6,7 @@ import { Badge, Button, showToast } from "@calcom/ui";
import { Activity } from "@calcom/ui/components/icon";
export default function WebhookTestDisclosure() {
const subscriberUrl: string = useWatch({ name: "subscriberUrl" });
const [subscriberUrl, webhookSecret]: [string, string] = useWatch({ name: ["subscriberUrl", "secret"] });
const payloadTemplate = useWatch({ name: "payloadTemplate" }) || null;
const { t } = useLocale();
const mutation = trpc.viewer.webhook.testTrigger.useMutation({
@ -27,7 +27,9 @@ export default function WebhookTestDisclosure() {
color="secondary"
disabled={mutation.isLoading || !subscriberUrl}
StartIcon={Activity}
onClick={() => mutation.mutate({ url: subscriberUrl, type: "PING", payloadTemplate })}>
onClick={() =>
mutation.mutate({ url: subscriberUrl, secret: webhookSecret, type: "PING", payloadTemplate })
}>
{t("ping_test")}
</Button>
</div>

View File

@ -106,4 +106,11 @@ export const APP_CREDENTIAL_SHARING_ENABLED =
export const DEFAULT_LIGHT_BRAND_COLOR = "#292929";
export const DEFAULT_DARK_BRAND_COLOR = "#fafafa";
export const AB_TEST_BUCKET_PROBABILITY = Number(process.env.AB_TEST_BUCKET_PROBABILITY ?? "10");
const defaultOnNaN = (testedValue: number, defaultValue: number) =>
!Number.isNaN(testedValue) ? testedValue : defaultValue;
export const AB_TEST_BUCKET_PROBABILITY = defaultOnNaN(
parseInt(process.env.AB_TEST_BUCKET_PROBABILITY ?? "10", 10),
10
);

View File

@ -0,0 +1,23 @@
import i18next from "i18next";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
//@ts-expect-error no type definitions
import config from "@calcom/web/next-i18next.config";
export const create = async (locale: string, ns: string) => {
const { _nextI18Next } = await serverSideTranslations(locale, [ns], config);
const _i18n = i18next.createInstance();
_i18n.init({
lng: locale,
resources: _nextI18Next?.initialI18nStore,
fallbackLng: _nextI18Next?.userConfig?.i18n.defaultLocale,
});
return _i18n;
};
export const getFixedT = async (locale: string, ns: string) => {
const i18n = await create(locale, ns);
return i18n.getFixedT(locale, ns);
};

View File

@ -10,7 +10,7 @@ type TestTriggerOptions = {
};
export const testTriggerHandler = async ({ ctx: _ctx, input }: TestTriggerOptions) => {
const { url, type, payloadTemplate = null } = input;
const { url, type, payloadTemplate = null, secret = null } = input;
const translation = await getTranslation("en", "common");
const language = {
locale: "en",
@ -40,8 +40,8 @@ export const testTriggerHandler = async ({ ctx: _ctx, input }: TestTriggerOption
};
try {
const webhook = { subscriberUrl: url, payloadTemplate, appId: null, secret: null };
return await sendPayload(null, type, new Date().toISOString(), webhook, data);
const webhook = { subscriberUrl: url, appId: null, payloadTemplate };
return await sendPayload(secret, type, new Date().toISOString(), webhook, data);
} catch (_err) {
const error = getErrorFromUnknown(_err);
return {

View File

@ -4,6 +4,7 @@ import { webhookIdAndEventTypeIdSchema } from "./types";
export const ZTestTriggerInputSchema = webhookIdAndEventTypeIdSchema.extend({
url: z.string().url(),
secret: z.string().optional(),
type: z.string(),
payloadTemplate: z.string().optional().nullable(),
});

View File

@ -160,6 +160,7 @@ export interface CalendarEvent {
team?: {
name: string;
members: TeamMember[];
id: number;
};
location?: string | null;
conferenceCredentialId?: number;

368
yarn.lock
View File

@ -3484,7 +3484,7 @@ __metadata:
lodash: ^4.17.21
qs-stringify: ^1.2.1
react-i18next: ^12.2.0
stripe: ^14.3.0
stripe: ^9.16.0
languageName: unknown
linkType: soft
@ -3551,7 +3551,7 @@ __metadata:
postcss: ^8.4.18
react: ^18.2.0
react-dom: ^18.2.0
tailwindcss: ^3.3.1
tailwindcss: ^3.3.3
typescript: ^4.9.4
languageName: unknown
linkType: soft
@ -3629,7 +3629,7 @@ __metadata:
prettier: ^2.8.6
prettier-plugin-tailwindcss: ^0.2.5
tailwind-scrollbar: ^2.0.1
tailwindcss: ^3.3.1
tailwindcss: ^3.3.3
typescript: ^4.9.4
languageName: unknown
linkType: soft
@ -3665,7 +3665,7 @@ __metadata:
react-hook-form: ^7.43.3
react-live-chat-loader: ^2.8.1
swr: ^1.2.2
tailwindcss: ^3.3.1
tailwindcss: ^3.3.3
typescript: ^4.9.4
zod: ^3.22.2
languageName: unknown
@ -3796,7 +3796,7 @@ __metadata:
autoprefixer: ^10.4.12
npm-run-all: ^4.1.5
postcss: ^8.4.18
tailwindcss: ^3.3.1
tailwindcss: ^3.3.3
typescript: ^4.9.4
vite: ^4.1.2
languageName: unknown
@ -4280,7 +4280,7 @@ __metadata:
"@calcom/config": "*"
"@calcom/dayjs": "*"
"@calcom/ui": "*"
"@radix-ui/react-avatar": ^1.0.0
"@radix-ui/react-avatar": ^1.0.4
"@radix-ui/react-collapsible": ^1.0.0
"@radix-ui/react-dialog": ^1.0.4
"@radix-ui/react-dropdown-menu": ^2.0.5
@ -4316,7 +4316,7 @@ __metadata:
storybook-addon-next-router: ^4.0.2
storybook-addon-rtl-direction: ^0.0.19
storybook-react-i18next: ^1.1.2
tailwindcss: ^3.3.1
tailwindcss: ^3.3.3
typescript: ^4.9.4
vite: ^4.1.2
languageName: unknown
@ -4522,7 +4522,7 @@ __metadata:
"@next-auth/prisma-adapter": ^1.0.4
"@next/bundle-analyzer": ^13.1.6
"@playwright/test": ^1.31.2
"@radix-ui/react-avatar": ^1.0.0
"@radix-ui/react-avatar": ^1.0.4
"@radix-ui/react-collapsible": ^1.0.0
"@radix-ui/react-dialog": ^1.0.4
"@radix-ui/react-dropdown-menu": ^2.0.5
@ -4635,7 +4635,7 @@ __metadata:
short-uuid: ^4.2.0
stripe: ^9.16.0
superjson: 1.9.1
tailwindcss: ^3.3.1
tailwindcss: ^3.3.3
tailwindcss-animate: ^1.0.6
tailwindcss-radix: ^2.6.0
ts-node: ^10.9.1
@ -7824,13 +7824,6 @@ __metadata:
languageName: node
linkType: hard
"@next/env@npm:13.4.6":
version: 13.4.6
resolution: "@next/env@npm:13.4.6"
checksum: 65d6cfb68adf5067f5e42f339e46908aca5a14fbc78f1e42e0becec1617da108cf68621c98f5a2c2e18da5a7955e355e98d5c4a7894222401bb374b2ca1c08f4
languageName: node
linkType: hard
"@next/env@npm:13.5.5":
version: 13.5.5
resolution: "@next/env@npm:13.5.5"
@ -7838,6 +7831,13 @@ __metadata:
languageName: node
linkType: hard
"@next/env@npm:13.5.6":
version: 13.5.6
resolution: "@next/env@npm:13.5.6"
checksum: 5e8f3f6f987a15dad3cd7b2bcac64a6382c2ec372d95d0ce6ab295eb59c9731222017eebf71ff3005932de2571f7543bce7e5c6a8c90030207fb819404138dc2
languageName: node
linkType: hard
"@next/eslint-plugin-next@npm:13.2.1":
version: 13.2.1
resolution: "@next/eslint-plugin-next@npm:13.2.1"
@ -7847,13 +7847,6 @@ __metadata:
languageName: node
linkType: hard
"@next/swc-darwin-arm64@npm:13.4.6":
version: 13.4.6
resolution: "@next/swc-darwin-arm64@npm:13.4.6"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
"@next/swc-darwin-arm64@npm:13.5.5":
version: 13.5.5
resolution: "@next/swc-darwin-arm64@npm:13.5.5"
@ -7861,10 +7854,10 @@ __metadata:
languageName: node
linkType: hard
"@next/swc-darwin-x64@npm:13.4.6":
version: 13.4.6
resolution: "@next/swc-darwin-x64@npm:13.4.6"
conditions: os=darwin & cpu=x64
"@next/swc-darwin-arm64@npm:13.5.6":
version: 13.5.6
resolution: "@next/swc-darwin-arm64@npm:13.5.6"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
@ -7875,10 +7868,10 @@ __metadata:
languageName: node
linkType: hard
"@next/swc-linux-arm64-gnu@npm:13.4.6":
version: 13.4.6
resolution: "@next/swc-linux-arm64-gnu@npm:13.4.6"
conditions: os=linux & cpu=arm64 & libc=glibc
"@next/swc-darwin-x64@npm:13.5.6":
version: 13.5.6
resolution: "@next/swc-darwin-x64@npm:13.5.6"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
@ -7889,10 +7882,10 @@ __metadata:
languageName: node
linkType: hard
"@next/swc-linux-arm64-musl@npm:13.4.6":
version: 13.4.6
resolution: "@next/swc-linux-arm64-musl@npm:13.4.6"
conditions: os=linux & cpu=arm64 & libc=musl
"@next/swc-linux-arm64-gnu@npm:13.5.6":
version: 13.5.6
resolution: "@next/swc-linux-arm64-gnu@npm:13.5.6"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
@ -7903,10 +7896,10 @@ __metadata:
languageName: node
linkType: hard
"@next/swc-linux-x64-gnu@npm:13.4.6":
version: 13.4.6
resolution: "@next/swc-linux-x64-gnu@npm:13.4.6"
conditions: os=linux & cpu=x64 & libc=glibc
"@next/swc-linux-arm64-musl@npm:13.5.6":
version: 13.5.6
resolution: "@next/swc-linux-arm64-musl@npm:13.5.6"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
@ -7917,10 +7910,10 @@ __metadata:
languageName: node
linkType: hard
"@next/swc-linux-x64-musl@npm:13.4.6":
version: 13.4.6
resolution: "@next/swc-linux-x64-musl@npm:13.4.6"
conditions: os=linux & cpu=x64 & libc=musl
"@next/swc-linux-x64-gnu@npm:13.5.6":
version: 13.5.6
resolution: "@next/swc-linux-x64-gnu@npm:13.5.6"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
@ -7931,10 +7924,10 @@ __metadata:
languageName: node
linkType: hard
"@next/swc-win32-arm64-msvc@npm:13.4.6":
version: 13.4.6
resolution: "@next/swc-win32-arm64-msvc@npm:13.4.6"
conditions: os=win32 & cpu=arm64
"@next/swc-linux-x64-musl@npm:13.5.6":
version: 13.5.6
resolution: "@next/swc-linux-x64-musl@npm:13.5.6"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
@ -7945,10 +7938,10 @@ __metadata:
languageName: node
linkType: hard
"@next/swc-win32-ia32-msvc@npm:13.4.6":
version: 13.4.6
resolution: "@next/swc-win32-ia32-msvc@npm:13.4.6"
conditions: os=win32 & cpu=ia32
"@next/swc-win32-arm64-msvc@npm:13.5.6":
version: 13.5.6
resolution: "@next/swc-win32-arm64-msvc@npm:13.5.6"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
@ -7959,10 +7952,10 @@ __metadata:
languageName: node
linkType: hard
"@next/swc-win32-x64-msvc@npm:13.4.6":
version: 13.4.6
resolution: "@next/swc-win32-x64-msvc@npm:13.4.6"
conditions: os=win32 & cpu=x64
"@next/swc-win32-ia32-msvc@npm:13.5.6":
version: 13.5.6
resolution: "@next/swc-win32-ia32-msvc@npm:13.5.6"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
@ -7973,6 +7966,13 @@ __metadata:
languageName: node
linkType: hard
"@next/swc-win32-x64-msvc@npm:13.5.6":
version: 13.5.6
resolution: "@next/swc-win32-x64-msvc@npm:13.5.6"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
"@noble/curves@npm:1.1.0, @noble/curves@npm:~1.1.0":
version: 1.1.0
resolution: "@noble/curves@npm:1.1.0"
@ -8807,29 +8807,6 @@ __metadata:
languageName: node
linkType: hard
"@radix-ui/react-avatar@npm:^1.0.0":
version: 1.0.3
resolution: "@radix-ui/react-avatar@npm:1.0.3"
dependencies:
"@babel/runtime": ^7.13.10
"@radix-ui/react-context": 1.0.1
"@radix-ui/react-primitive": 1.0.3
"@radix-ui/react-use-callback-ref": 1.0.1
"@radix-ui/react-use-layout-effect": 1.0.1
peerDependencies:
"@types/react": "*"
"@types/react-dom": "*"
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
"@types/react":
optional: true
"@types/react-dom":
optional: true
checksum: defd6070ca89d64f46017943bc444ac73ca4711f710b8fcb7152f5fb84cb05f39e7944d372695720929fa666cf9bc65ce95725c5a29d81f9e51aba59aed42ca2
languageName: node
linkType: hard
"@radix-ui/react-avatar@npm:^1.0.4":
version: 1.0.4
resolution: "@radix-ui/react-avatar@npm:1.0.4"
@ -12448,15 +12425,6 @@ __metadata:
languageName: node
linkType: hard
"@swc/helpers@npm:0.5.1":
version: 0.5.1
resolution: "@swc/helpers@npm:0.5.1"
dependencies:
tslib: ^2.4.0
checksum: 71e0e27234590435e4c62b97ef5e796f88e786841a38c7116a5e27a3eafa7b9ead7cdec5249b32165902076de78446945311c973e59bddf77c1e24f33a8f272a
languageName: node
linkType: hard
"@swc/helpers@npm:0.5.2":
version: 0.5.2
resolution: "@swc/helpers@npm:0.5.2"
@ -13859,6 +13827,13 @@ __metadata:
languageName: node
linkType: hard
"@types/tough-cookie@npm:*":
version: 4.0.5
resolution: "@types/tough-cookie@npm:4.0.5"
checksum: f19409d0190b179331586365912920d192733112a195e870c7f18d20ac8adb7ad0b0ff69dad430dba8bc2be09593453a719cfea92dc3bda19748fd158fe1498d
languageName: node
linkType: hard
"@types/trusted-types@npm:^2.0.2":
version: 2.0.2
resolution: "@types/trusted-types@npm:2.0.2"
@ -18190,7 +18165,7 @@ __metadata:
languageName: node
linkType: hard
"color-name@npm:^1.1.4, color-name@npm:~1.1.4":
"color-name@npm:~1.1.4":
version: 1.1.4
resolution: "color-name@npm:1.1.4"
checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610
@ -26368,15 +26343,6 @@ __metadata:
languageName: node
linkType: hard
"jiti@npm:^1.17.2":
version: 1.18.2
resolution: "jiti@npm:1.18.2"
bin:
jiti: bin/jiti.js
checksum: 46c41cd82d01c6efdee3fc0ae9b3e86ed37457192d6366f19157d863d64961b07982ab04e9d5879576a1af99cc4d132b0b73b336094f86a5ce9fb1029ec2d29f
languageName: node
linkType: hard
"joi@npm:^17.7.0":
version: 17.10.2
resolution: "joi@npm:17.10.2"
@ -27562,13 +27528,6 @@ __metadata:
languageName: node
linkType: hard
"lilconfig@npm:^2.0.6":
version: 2.0.6
resolution: "lilconfig@npm:2.0.6"
checksum: 40a3cd72f103b1be5975f2ac1850810b61d4053e20ab09be8d3aeddfe042187e1ba70b4651a7e70f95efa1642e7dc8b2ae395b317b7d7753b241b43cef7c0f7d
languageName: node
linkType: hard
"lilconfig@npm:^2.1.0":
version: 2.1.0
resolution: "lilconfig@npm:2.1.0"
@ -30259,29 +30218,27 @@ __metadata:
linkType: hard
"next@npm:^13.4.6":
version: 13.4.6
resolution: "next@npm:13.4.6"
version: 13.5.6
resolution: "next@npm:13.5.6"
dependencies:
"@next/env": 13.4.6
"@next/swc-darwin-arm64": 13.4.6
"@next/swc-darwin-x64": 13.4.6
"@next/swc-linux-arm64-gnu": 13.4.6
"@next/swc-linux-arm64-musl": 13.4.6
"@next/swc-linux-x64-gnu": 13.4.6
"@next/swc-linux-x64-musl": 13.4.6
"@next/swc-win32-arm64-msvc": 13.4.6
"@next/swc-win32-ia32-msvc": 13.4.6
"@next/swc-win32-x64-msvc": 13.4.6
"@swc/helpers": 0.5.1
"@next/env": 13.5.6
"@next/swc-darwin-arm64": 13.5.6
"@next/swc-darwin-x64": 13.5.6
"@next/swc-linux-arm64-gnu": 13.5.6
"@next/swc-linux-arm64-musl": 13.5.6
"@next/swc-linux-x64-gnu": 13.5.6
"@next/swc-linux-x64-musl": 13.5.6
"@next/swc-win32-arm64-msvc": 13.5.6
"@next/swc-win32-ia32-msvc": 13.5.6
"@next/swc-win32-x64-msvc": 13.5.6
"@swc/helpers": 0.5.2
busboy: 1.6.0
caniuse-lite: ^1.0.30001406
postcss: 8.4.14
postcss: 8.4.31
styled-jsx: 5.1.1
watchpack: 2.4.0
zod: 3.21.4
peerDependencies:
"@opentelemetry/api": ^1.1.0
fibers: ">= 3.1.0"
react: ^18.2.0
react-dom: ^18.2.0
sass: ^1.3.0
@ -30307,13 +30264,11 @@ __metadata:
peerDependenciesMeta:
"@opentelemetry/api":
optional: true
fibers:
optional: true
sass:
optional: true
bin:
next: dist/bin/next
checksum: 1d28d4be184b1311c42f01ce12d3636e3439332aebcf211b0b554164966f053a609db529d7194824b68537256625767c5bc9f7655a9d42af72b8c7ce4c0d4104
checksum: c869b0014ae921ada3bf22301985027ec320aebcd6aa9c16e8afbded68bb8def5874cca034c680e8c351a79578f1e514971d02777f6f0a5a1d7290f25970ac0d
languageName: node
linkType: hard
@ -31773,7 +31728,7 @@ __metadata:
languageName: node
linkType: hard
"parse5@npm:^7.1.2":
"parse5@npm:^7.0.0, parse5@npm:^7.1.2":
version: 7.1.2
resolution: "parse5@npm:7.1.2"
dependencies:
@ -32374,19 +32329,6 @@ __metadata:
languageName: node
linkType: hard
"postcss-import@npm:^14.1.0":
version: 14.1.0
resolution: "postcss-import@npm:14.1.0"
dependencies:
postcss-value-parser: ^4.0.0
read-cache: ^1.0.0
resolve: ^1.1.7
peerDependencies:
postcss: ^8.0.0
checksum: cd45d406e90f67cdab9524352e573cc6b4462b790934a05954e929a6653ebd31288ceebc8ce3c3ed7117ae672d9ebbec57df0bceec0a56e9b259c2e71d47ca86
languageName: node
linkType: hard
"postcss-import@npm:^15.1.0":
version: 15.1.0
resolution: "postcss-import@npm:15.1.0"
@ -32400,17 +32342,6 @@ __metadata:
languageName: node
linkType: hard
"postcss-js@npm:^4.0.0":
version: 4.0.0
resolution: "postcss-js@npm:4.0.0"
dependencies:
camelcase-css: ^2.0.1
peerDependencies:
postcss: ^8.3.3
checksum: 14be8a58670b4c5d037d40f179240a4f736d53530db727e2635638fa296bc4bff18149ca860928398aace422e55d07c9f5729eeccd395340944985199cdc82a5
languageName: node
linkType: hard
"postcss-js@npm:^4.0.1":
version: 4.0.1
resolution: "postcss-js@npm:4.0.1"
@ -32422,24 +32353,6 @@ __metadata:
languageName: node
linkType: hard
"postcss-load-config@npm:^3.1.4":
version: 3.1.4
resolution: "postcss-load-config@npm:3.1.4"
dependencies:
lilconfig: ^2.0.5
yaml: ^1.10.2
peerDependencies:
postcss: ">=8.0.9"
ts-node: ">=9.0.0"
peerDependenciesMeta:
postcss:
optional: true
ts-node:
optional: true
checksum: 1c589504c2d90b1568aecae8238ab993c17dba2c44f848a8f13619ba556d26a1c09644d5e6361b5784e721e94af37b604992f9f3dc0483e687a0cc1cc5029a34
languageName: node
linkType: hard
"postcss-load-config@npm:^4.0.1":
version: 4.0.1
resolution: "postcss-load-config@npm:4.0.1"
@ -32573,17 +32486,6 @@ __metadata:
languageName: node
linkType: hard
"postcss-nested@npm:6.0.0":
version: 6.0.0
resolution: "postcss-nested@npm:6.0.0"
dependencies:
postcss-selector-parser: ^6.0.10
peerDependencies:
postcss: ^8.2.14
checksum: 2105dc52cd19747058f1a46862c9e454b5a365ac2e7135fc1015d67a8fe98ada2a8d9ee578e90f7a093bd55d3994dd913ba5ff1d5e945b4ed9a8a2992ecc8f10
languageName: node
linkType: hard
"postcss-nested@npm:^6.0.1":
version: 6.0.1
resolution: "postcss-nested@npm:6.0.1"
@ -32604,7 +32506,7 @@ __metadata:
languageName: node
linkType: hard
"postcss-selector-parser@npm:^6.0.0, postcss-selector-parser@npm:^6.0.10, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4":
"postcss-selector-parser@npm:^6.0.0, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4":
version: 6.0.10
resolution: "postcss-selector-parser@npm:6.0.10"
dependencies:
@ -32638,17 +32540,6 @@ __metadata:
languageName: node
linkType: hard
"postcss@npm:8.4.14, postcss@npm:^8.2.14":
version: 8.4.14
resolution: "postcss@npm:8.4.14"
dependencies:
nanoid: ^3.3.4
picocolors: ^1.0.0
source-map-js: ^1.0.2
checksum: fe58766ff32e4becf65a7d57678995cfd239df6deed2fe0557f038b47c94e4132e7e5f68b5aa820c13adfec32e523b693efaeb65798efb995ce49ccd83953816
languageName: node
linkType: hard
"postcss@npm:8.4.31":
version: 8.4.31
resolution: "postcss@npm:8.4.31"
@ -32670,14 +32561,14 @@ __metadata:
languageName: node
linkType: hard
"postcss@npm:^8.0.9, postcss@npm:^8.3.11":
version: 8.4.21
resolution: "postcss@npm:8.4.21"
"postcss@npm:^8.2.14":
version: 8.4.14
resolution: "postcss@npm:8.4.14"
dependencies:
nanoid: ^3.3.4
picocolors: ^1.0.0
source-map-js: ^1.0.2
checksum: e39ac60ccd1542d4f9d93d894048aac0d686b3bb38e927d8386005718e6793dbbb46930f0a523fe382f1bbd843c6d980aaea791252bf5e176180e5a4336d9679
checksum: fe58766ff32e4becf65a7d57678995cfd239df6deed2fe0557f038b47c94e4132e7e5f68b5aa820c13adfec32e523b693efaeb65798efb995ce49ccd83953816
languageName: node
linkType: hard
@ -32692,6 +32583,17 @@ __metadata:
languageName: node
linkType: hard
"postcss@npm:^8.3.11":
version: 8.4.21
resolution: "postcss@npm:8.4.21"
dependencies:
nanoid: ^3.3.4
picocolors: ^1.0.0
source-map-js: ^1.0.2
checksum: e39ac60ccd1542d4f9d93d894048aac0d686b3bb38e927d8386005718e6793dbbb46930f0a523fe382f1bbd843c6d980aaea791252bf5e176180e5a4336d9679
languageName: node
linkType: hard
"postcss@npm:^8.4.23":
version: 8.4.23
resolution: "postcss@npm:8.4.23"
@ -33363,15 +33265,6 @@ __metadata:
languageName: node
linkType: hard
"qs@npm:^6.11.0":
version: 6.11.2
resolution: "qs@npm:6.11.2"
dependencies:
side-channel: ^1.0.4
checksum: e812f3c590b2262548647d62f1637b6989cc56656dc960b893fe2098d96e1bd633f36576f4cd7564dfbff9db42e17775884db96d846bebe4f37420d073ecdc0b
languageName: node
linkType: hard
"qs@npm:~6.5.2":
version: 6.5.3
resolution: "qs@npm:6.5.3"
@ -37423,16 +37316,6 @@ __metadata:
languageName: node
linkType: hard
"stripe@npm:^14.3.0":
version: 14.3.0
resolution: "stripe@npm:14.3.0"
dependencies:
"@types/node": ">=8.1.0"
qs: ^6.11.0
checksum: 1aa0dec1fe8cd4c0d2a5378b9d3c69f7df505efdc86b8d6352e194d656129db83b9faaf189b5138fb5fd9a0b90e618dfcff854bb4773d289a0de0b65d0a94cb2
languageName: node
linkType: hard
"stripe@npm:^9.16.0":
version: 9.16.0
resolution: "stripe@npm:9.16.0"
@ -37513,23 +37396,6 @@ __metadata:
languageName: node
linkType: hard
"sucrase@npm:^3.29.0":
version: 3.31.0
resolution: "sucrase@npm:3.31.0"
dependencies:
commander: ^4.0.0
glob: 7.1.6
lines-and-columns: ^1.1.6
mz: ^2.7.0
pirates: ^4.0.1
ts-interface-checker: ^0.1.9
bin:
sucrase: bin/sucrase
sucrase-node: bin/sucrase-node
checksum: 333990b1bca57acc010ae07c763dddfd34f01fd38afe9e53cf43f4a5096bd7a66f924fed65770288fba475f914f3aa5277cc4490ed9e74c50b4cea7f147e9e63
languageName: node
linkType: hard
"sucrase@npm:^3.32.0":
version: 3.34.0
resolution: "sucrase@npm:3.34.0"
@ -37909,43 +37775,6 @@ __metadata:
languageName: node
linkType: hard
"tailwindcss@npm:^3.3.1":
version: 3.3.1
resolution: "tailwindcss@npm:3.3.1"
dependencies:
arg: ^5.0.2
chokidar: ^3.5.3
color-name: ^1.1.4
didyoumean: ^1.2.2
dlv: ^1.1.3
fast-glob: ^3.2.12
glob-parent: ^6.0.2
is-glob: ^4.0.3
jiti: ^1.17.2
lilconfig: ^2.0.6
micromatch: ^4.0.5
normalize-path: ^3.0.0
object-hash: ^3.0.0
picocolors: ^1.0.0
postcss: ^8.0.9
postcss-import: ^14.1.0
postcss-js: ^4.0.0
postcss-load-config: ^3.1.4
postcss-nested: 6.0.0
postcss-selector-parser: ^6.0.11
postcss-value-parser: ^4.2.0
quick-lru: ^5.1.1
resolve: ^1.22.1
sucrase: ^3.29.0
peerDependencies:
postcss: ^8.0.9
bin:
tailwind: lib/cli.js
tailwindcss: lib/cli.js
checksum: 966ba175486fb65ef3dd76aa8ec6929ff1d168531843ca7d5faf680b7097c36bf5f9ca385b563cdfdff935bb2bd37ac5998e877491407867503cc129d118bf93
languageName: node
linkType: hard
"tailwindcss@npm:^3.3.3":
version: 3.3.3
resolution: "tailwindcss@npm:3.3.3"
@ -42126,13 +41955,6 @@ __metadata:
languageName: node
linkType: hard
"zod@npm:3.21.4":
version: 3.21.4
resolution: "zod@npm:3.21.4"
checksum: f185ba87342ff16f7a06686767c2b2a7af41110c7edf7c1974095d8db7a73792696bcb4a00853de0d2edeb34a5b2ea6a55871bc864227dace682a0a28de33e1f
languageName: node
linkType: hard
"zod@npm:^3.21.4, zod@npm:^3.22.2":
version: 3.22.2
resolution: "zod@npm:3.22.2"