import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; import { AuthProvider } from "@/contexts/AuthContext"; import { SiteSettingsProvider } from "@/contexts/SiteSettingsContext"; import type { SiteSettings } from "@/contexts/SiteSettingsContext"; import { ToastProvider } from "@/components/shared/ToastProvider"; import { BannerBar } from "@/components/shared/BannerBar"; import { SetupGuard } from "@/components/shared/SetupGuard"; import HelpFab from "@/components/shared/HelpFab"; import { API_BASE, resolveToApiOrigin } from "@/lib/api"; import { buildThemeCssVars } from "@/lib/colorScale"; const geistSans = Geist({ variable: "--font-geist-sans", subsets: ["latin"], }); const geistMono = Geist_Mono({ variable: "--font-geist-mono", subsets: ["latin"], }); const appName = process.env.NEXT_PUBLIC_APP_NAME || 'Cross Code'; /** * Server-side settings fetch, shared by generateMetadata() and RootLayout() * below. Both call this with the identical URL + options so Next's per-request * fetch memoization dedupes them into a single network call. Degrades to `{}` * (static defaults everywhere downstream) if the backend is unreachable at * request time — intentional, not a bug: branding just isn't critical enough * to fail the whole page render over. */ async function getServerSettings(): Promise { try { const res = await fetch(`${API_BASE}/api/settings`, { next: { revalidate: 60 } }); if (!res.ok) return {}; return await res.json(); } catch { return {}; } } export async function generateMetadata(): Promise { const settings = await getServerSettings(); const faviconUrl = settings.favicon_url ? resolveToApiOrigin(settings.favicon_url) : null; const displayName = settings.org_name || appName; return { title: displayName, description: `Manage and register for events with ${displayName}`, icons: { icon: faviconUrl || "/favicon.ico", }, }; } export default async function RootLayout({ children }: { children: React.ReactNode }) { const settings = await getServerSettings(); const cssVars = buildThemeCssVars({ primary: settings.primary_color || settings.accent_color, secondary: settings.secondary_color, accent: settings.primary_color ? settings.accent_color : undefined, }); return ( {cssVars && (