Files
calendar/apps/web/app/layout.tsx
T
8ad442f2be feat: Upgrade to Next 15 (#18834)
* wip

* update layoutHOC

* wip

* remove app router related code no longer used

* remove more

* await cookies, headers, params, serachparams

* update yarn.lock

* await cookies, headers, params, serachparams more

* update yarn lock again

* downgrade next-auth to 4.22.1

* update yarn lock

* fix

* update yarn lock

* fix type checks

* update yarn lock

* await headers and cookies

* restore pages folder

* restore yarn.lock

* update yarn.lock

* await headers and cookies

* remove

* await params in API routes

* updates

* restore next.config.js

* remove i18n from next.config.js

* Fixed tests

* Fixed types

* Removed duplicate favicon.ico

* Fixing more types

* ImageResponse moved to next/og

* Fixed prisma import issues

* dynamic import for @ewsjs/xhr

* remove deasync dep

* dynamic import for @tryvital/vital-node

* fix type checks

* add back turbopack command

* Type fix

* Removed unneeded file

* fix turbopack relative path errors

* add comments

* remove unneeded code

* Fixed build errors

* await apis

* use Promise<Params> type in defaultResponderForAppDir util

* refactor scim api route

* fix type checks

* separate app-routing.config into client-config and server-config

* wip

* refactor routing forms components

* revert unneeded changes for easier review

* fix

* fix

* use CustomTrans

* fix type

* fix unit tests

* fix type error

* fix build error

* fix build error

* fix build error

* fix warnings

* fix warnings

* upgrade @tremor/react and tailwindcss

* numCols -> numItems

* fix forgot-password e2e test

* fix 1 more e2e test

* fix login e2e test

* fix e2e tests

* fix e2e tests

* clean up

* remove error

* use tremor/react 2.11.0

* fix

* rename CustomTrans to ServerTrans

* address comment

* fix test

* fix ServerTrans

* fix

* fix type

* fix ServerTrans usages 1

* fix translations

* fix type checks

* fix type checks

* link styling

* fix

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2025-03-20 21:30:51 -03:00

186 lines
5.2 KiB
TypeScript

import { dir } from "i18next";
import { Inter } from "next/font/google";
import localFont from "next/font/local";
import { headers, cookies } from "next/headers";
import React from "react";
import { getLocale } from "@calcom/features/auth/lib/getLocale";
import { IconSprites } from "@calcom/ui/components/icon";
import { NotificationSoundHandler } from "@calcom/web/components/notification-sound-handler";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { ssrInit } from "@server/lib/ssr";
import "../styles/globals.css";
import { SpeculationRules } from "./SpeculationRules";
import { Providers } from "./providers";
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: "block",
weight: "600",
});
export const viewport = {
width: "device-width",
initialScale: 1.0,
maximumScale: 1.0,
userScalable: false,
viewportFit: "cover",
themeColor: [
{
media: "(prefers-color-scheme: light)",
color: "#f9fafb",
},
{
media: "(prefers-color-scheme: dark)",
color: "#1C1C1C",
},
],
};
export const metadata = {
icons: {
icon: "/favicon.ico",
apple: "/api/logo?type=apple-touch-icon",
other: [
{
rel: "icon-mask",
url: "/safari-pinned-tab.svg",
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",
other: {
"application-TileColor": "#ff0000",
},
twitter: {
site: "@calcom",
creator: "@calcom",
card: "summary_large_image",
},
robots: {
index: true,
follow: true,
},
};
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");
const req = { headers: await headers(), cookies: await 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 h = await headers();
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 ssr = await ssrInit(buildLegacyCtx(h, await cookies(), {}, {}));
return (
<html
lang={locale}
dir={direction}
style={embedColorScheme ? { colorScheme: embedColorScheme as string } : undefined}
suppressHydrationWarning
data-nextjs-router="app">
<head nonce={nonce}>
{!!process.env.NEXT_PUBLIC_HEAD_SCRIPTS && (
<script
nonce={nonce}
id="injected-head-scripts"
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
__html: process.env.NEXT_PUBLIC_HEAD_SCRIPTS,
}}
/>
)}
<style>{`
:root {
--font-inter: ${interFont.style.fontFamily.replace(/\'/g, "")};
--font-cal: ${calFont.style.fontFamily.replace(/\'/g, "")};
}
`}</style>
</head>
<body
className="dark:bg-default bg-subtle antialiased"
style={
isEmbed
? {
background: "transparent",
// Keep the embed hidden till parent initializes and
// - gives it the appropriate styles if UI instruction is there.
// - gives iframe the appropriate height(equal to document height) which can only be known after loading the page once in browser.
// - Tells iframe which mode it should be in (dark/light) - if there is a a UI instruction for that
visibility: "hidden",
}
: {}
}>
<IconSprites />
{!!process.env.NEXT_PUBLIC_BODY_SCRIPTS && (
<script
nonce={nonce}
id="injected-head-scripts"
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
__html: process.env.NEXT_PUBLIC_BODY_SCRIPTS,
}}
/>
)}
<SpeculationRules
// URLs In Navigation
prerenderPathsOnHover={[
"/event-types",
"/availability",
"/bookings/upcoming",
"/teams",
"/apps",
"/apps/routing-forms/forms",
"/workflows",
"/insights",
]}
/>
<Providers dehydratedState={ssr.dehydrate()}>{children}</Providers>
{!isEmbed && <NotificationSoundHandler />}
<NotificationSoundHandler />
</body>
</html>
);
}