/* ============================================ APP — Router & screen orchestrator ============================================ */ const { useState: useStateApp } = React; function App() { const [screen, setScreen] = useStateApp(null); const [user, setUser] = useStateApp(null); const [ready, setReady] = useStateApp(false); // Boot: validate token via /api/auth/me, then resolve initial screen. React.useEffect(() => { let cancelled = false; (async () => { if (window.API.getToken()) { try { const { user: u } = await window.API.me(); if (cancelled) return; setUser(u); } catch (_) { /* fall through to login */ } } if (cancelled) return; const hash = window.location.hash.replace("#", ""); const initial = hash && (SCREEN_META[hash] || hash === "login") ? hash : "workspace"; setScreen(initial); setReady(true); })(); return () => { cancelled = true; }; }, []); // Keep screen in sync with URL hash. React.useEffect(() => { const onHash = () => { const h = window.location.hash.replace("#", ""); if (h && (SCREEN_META[h] || h === "login")) setScreen(h); }; window.addEventListener("hashchange", onHash); return () => window.removeEventListener("hashchange", onHash); }, []); const navigate = (s) => { setScreen(s); window.location.hash = s; window.scrollTo(0, 0); }; const handleLogin = (u) => { setUser(u); navigate("workspace"); }; const handleLogout = async () => { await window.API.logout(); setUser(null); navigate("login"); }; // Still validating the saved token — render nothing to avoid flashing the login screen. if (!ready) return null; // Route guard: any screen other than login requires an authed user. if (screen === "login" || !user) { return ; } let body = null; switch (screen) { case "workspace": body = ; break; case "chat-history": body = ; break; case "knowledge": body = ; break; case "ingestion": body = ; break; case "inspector": body = ; break; case "analytics": body = ; break; case "cost": body = ; break; case "system-health": body = ; break; case "users": body = ; break; case "prompt-tuning": body = ; break; case "profile": body = ; break; default: body = ; } return (
{body}
); } ReactDOM.createRoot(document.getElementById("root")).render();