"use client"; import React, { createContext, useContext, useEffect, useState } from "react"; import { apiFetch } from "@/lib/api"; export type SiteSettings = { org_name?: string; org_tagline?: string; org_email?: string; org_phone?: string; org_address?: string; // Branding — 3-color system. accent_color is the tertiary/highlight color; // primary_color falls back to accent_color's legacy value if unset (see // settingsController.js PUBLIC_KEYS comment). primary_color?: string; secondary_color?: string; accent_color?: string; logo_url?: string; favicon_url?: string; setup_complete?: string; // Legal pages legal_operator_name?: string; legal_io_name?: string; legal_io_email?: string; legal_website_url?: string; legal_effective_date?: string; }; type SiteSettingsContextValue = { settings: SiteSettings; loading: boolean; reload: () => void; }; const SiteSettingsContext = createContext({ settings: {}, loading: true, reload: () => {}, }); export function SiteSettingsProvider({ children, initialSettings, }: { children: React.ReactNode; /** Server-fetched settings from layout.tsx's generateMetadata/RootLayout — seeds state so there's no loading flash for anything reading useSiteSettings() (e.g. the navbar logo). */ initialSettings?: SiteSettings; }) { const [settings, setSettings] = useState(initialSettings || {}); const [loading, setLoading] = useState(!initialSettings); const load = async () => { try { const data = await apiFetch("/api/settings"); setSettings(data || {}); } catch { // Non-fatal — use defaults } finally { setLoading(false); } }; // Always refreshes in the background (cheap, 60s-cached server-side) even // when seeded from initialSettings — self-heals if the SSR fetch in // layout.tsx failed, and picks up any change since that request. useEffect(() => { load(); }, []); return ( {children} ); } export function useSiteSettings() { return useContext(SiteSettingsContext); }