"use client"; import { useSession } from "next-auth/react"; import { usePathname, useRouter } from "next/navigation"; import type { Dispatch, ReactElement, ReactNode, SetStateAction } from "react"; import React, { cloneElement } from "react"; import { Toaster } from "sonner"; import { useRedirectToLoginIfUnauthenticated } from "@calcom/features/auth/lib/hooks/useRedirectToLoginIfUnauthenticated"; import { useRedirectToOnboardingIfNeeded } from "@calcom/features/auth/lib/hooks/useRedirectToOnboardingIfNeeded"; import { KBarContent, KBarRoot } from "@calcom/features/kbar/Kbar"; import TimezoneChangeDialog from "@calcom/features/settings/TimezoneChangeDialog"; import classNames from "@calcom/lib/classNames"; import { APP_NAME } from "@calcom/lib/constants"; import { useFormbricks } from "@calcom/lib/formbricks-client"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { useNotifications } from "@calcom/lib/hooks/useNotifications"; import { Button, ErrorBoundary, HeadSeo, SkeletonText } from "@calcom/ui"; import { SideBarContainer } from "./SideBar"; import { TopNavContainer } from "./TopNav"; import { BannerContainer } from "./banners/LayoutBanner"; import { useBanners } from "./banners/useBanners"; import { MobileNavigationContainer } from "./navigation/Navigation"; import { useAppTheme } from "./useAppTheme"; const Layout = (props: LayoutProps) => { const { banners, bannersHeight } = useBanners(); const pathname = usePathname(); const isFullPageWithoutSidebar = pathname?.startsWith("/apps/routing-forms/reporting/"); const pageTitle = typeof props.heading === "string" && !props.title ? props.heading : props.title; const withoutSeo = props.withoutSeo ?? props.withoutMain ?? false; useFormbricks(); return ( <> {!withoutSeo && ( )}
{banners && !props.isPlatformUser && !isFullPageWithoutSidebar && ( )}
{props.SidebarContainer ? ( cloneElement(props.SidebarContainer, { bannersHeight }) ) : ( )}
); }; type DrawerState = [isOpen: boolean, setDrawerOpen: Dispatch>]; export type LayoutProps = { centered?: boolean; title?: string; description?: string; heading?: ReactNode; subtitle?: ReactNode; headerClassName?: string; children: ReactNode; CTA?: ReactNode; large?: boolean; MobileNavigationContainer?: ReactNode; SidebarContainer?: ReactElement; TopNavContainer?: ReactNode; drawerState?: DrawerState; HeadingLeftIcon?: ReactNode; backPath?: string | boolean; // renders back button to specified path // use when content needs to expand with flex flexChildrenContainer?: boolean; isPublic?: boolean; withoutMain?: boolean; // Gives you the option to skip HeadSEO and render your own. withoutSeo?: boolean; // Gives the ability to include actions to the right of the heading actions?: JSX.Element; beforeCTAactions?: JSX.Element; afterHeading?: ReactNode; smallHeading?: boolean; isPlatformUser?: boolean; }; const KBarWrapper = ({ children, withKBar = false }: { withKBar: boolean; children: React.ReactNode }) => withKBar ? ( {children} ) : ( <>{children} ); const PublicShell = (props: LayoutProps) => { const { status } = useSession(); return ( ); }; export default function Shell(props: LayoutProps) { // if a page is unauthed and isPublic is true, the redirect does not happen. useRedirectToLoginIfUnauthenticated(props.isPublic); useRedirectToOnboardingIfNeeded(); useAppTheme(); return !props.isPublic ? ( ) : ( ); } export function ShellMain(props: LayoutProps) { const router = useRouter(); const { isLocaleReady, t } = useLocale(); const { buttonToShow, isLoading, enableNotifications, disableNotifications } = useNotifications(); return ( <> {(props.heading || !!props.backPath) && (
{!!props.backPath && ( )} */} )}
)} {props.afterHeading && <>{props.afterHeading}}
{props.children}
); } function MainContainer({ isPlatformUser, MobileNavigationContainer: MobileNavigationContainerProp = ( ), TopNavContainer: TopNavContainerProp = , ...props }: LayoutProps) { return (
{/* show top navigation for md and smaller (tablet and phones) */} {TopNavContainerProp}
{!props.withoutMain ? {props.children} : props.children} {/* show bottom navigation for md and smaller (tablet and phones) on pages where back button doesn't exist */} {!props.backPath ? MobileNavigationContainerProp : null}
); }