"use client"; import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react"; import { usePathname } from "next/navigation"; import { api } from "@/lib/client-api"; import { defaultSiteSettings, siteSettingsSchema, type SiteSettings, } from "@/shared/site-settings"; const SettingsContext = createContext({ settings: defaultSiteSettings, updateSettings: (_settings: SiteSettings) => {}, }); export function SiteSettingsProvider({ initialSettings, children, }: { initialSettings: SiteSettings; children: React.ReactNode; }) { const [settings, setSettings] = useState(initialSettings); const version = useRef(0); const pending = useRef(false); const pathname = usePathname(); const previousPathname = useRef(pathname); const updateSettings = useCallback((next: SiteSettings) => { version.current++; setSettings(next); }, []); const refresh = useCallback(async () => { if (pending.current || document.visibilityState === "hidden") return; pending.current = true; const requestVersion = version.current; try { const next = siteSettingsSchema.parse(await api("site-settings")); // An older poll must not overwrite a moderator's just-saved setting. if (requestVersion === version.current) setSettings(next); } catch { // Keep the last known setting while disconnected. } finally { pending.current = false; } }, []); useEffect(() => { // SSR already supplied fresh settings for the initial page. if (previousPathname.current === pathname) return; previousPathname.current = pathname; void refresh(); }, [pathname, refresh]); useEffect(() => { const timer = window.setInterval(() => { void refresh(); }, 30000); const resume = () => { void refresh(); }; document.addEventListener("visibilitychange", resume); window.addEventListener("focus", resume); return () => { window.clearInterval(timer); document.removeEventListener("visibilitychange", resume); window.removeEventListener("focus", resume); }; }, [refresh]); const value = useMemo( () => ({ settings, updateSettings }), [settings, updateSettings], ); return ( {children} ); } export function useSiteSettings() { return useContext(SettingsContext); }