import { useEffect, useState } from 'react'; import { Navigate, Route, Routes } from 'react-router-dom'; import { RequireAnonymous, RequireAuth, RequireSiteAdmin } from './auth/guards'; import { PondGraphPage } from './graph/PondGraphPage'; import { MAINTENANCE_EVENT } from './lib/api'; import { MaintenancePage } from './pages/MaintenancePage'; import { AppLayout } from './layout/AppLayout'; import { AdminSettingsPage } from './pages/AdminSettingsPage'; import { AdminSystemPage } from './pages/AdminSystemPage'; import { FontCatalogPage } from './pages/FontCatalogPage'; import { HomePage } from './pages/HomePage'; import { LegalPage } from './pages/LegalPage'; import { NotFoundPage } from './pages/NotFoundPage'; import { PageEditorPage } from './pages/PageEditorPage'; import { PluginPreviewPage } from './pages/PluginPreviewPage'; import { PondHomePage } from './pages/PondHomePage'; import { PondSettingsPage } from './pages/PondSettingsPage'; import { PublicPageView } from './pages/PublicPageView'; import { SettingsPage } from './pages/SettingsPage'; import { TrashPage } from './pages/TrashPage'; import { ForgotPasswordPage } from './pages/auth/ForgotPasswordPage'; import { LoginPage } from './pages/auth/LoginPage'; import { ResetPasswordPage } from './pages/auth/ResetPasswordPage'; import { SignupPage } from './pages/auth/SignupPage'; import { VerifyEmailPage } from './pages/auth/VerifyEmailPage'; import { SetupPendingPage } from './setup/SetupPendingPage'; import { SetupWizardPage } from './setup/SetupWizardPage'; import { useSetupStatus } from './setup/use-setup-status'; export function App(): React.JSX.Element { const setup = useSetupStatus(); // Maintenance gate (issue #103): once any api call answers 503 // maintenance_mode — a backup restore is running — the whole UI becomes // the maintenance screen, which polls the exempt status endpoint and // reloads when the instance is back. const [maintenance, setMaintenance] = useState(false); useEffect(() => { const onMaintenance = (): void => setMaintenance(true); window.addEventListener(MAINTENANCE_EVENT, onMaintenance); return () => window.removeEventListener(MAINTENANCE_EVENT, onMaintenance); }, []); if (maintenance) return ; // First-run gate (issue #81): while setup is pending the api 503s almost // everything, so the SPA offers only the wizard, the login (to resume a // started wizard as the Site Admin), and a pending notice — without the // regular chrome, whose pond/search queries would all fail. If the status // probe itself fails (offline reload, #38), fall through to the app. if (setup.isPending) return <>; if (setup.data?.status === 'required') { return (
} /> } /> } />
); } return ( }> } /> }> } /> } /> } /> {/* Verify/reset work regardless of session state (mail links). */} } /> } /> {/* Public read-only page view — reachable without a session (issue #56). */} } /> {/* Legal pages — public, no session required (issue #82). */} } /> {/* Setup is done exactly once — afterwards the wizard url just goes home. */} } /> }> } /> } /> } /> {/* Static segment "trash" wins react-router's ranking over the dynamic :pageSlug sibling below — a page slugged "trash" would be unreachable via direct URL, an accepted v1 gap. */} } /> {/* Static "settings" wins over :pageSlug, like "trash" above. */} } /> {/* Static "graph" wins over :pageSlug, like "trash" above (#112). */} } /> } /> }> } /> } /> {/* Sandbox preview of one installed plugin (issue #73). */} } /> } /> ); }