Spaces:
Sleeping
Sleeping
| /** App entry: auth gate, hash router, toast + pending resolve hosts. */ | |
| import { render } from "preact"; | |
| import { useCallback, useEffect, useState } from "preact/hooks"; | |
| import { getMe } from "./api"; | |
| import { PendingResolveProvider } from "./components/PendingResolve"; | |
| import { TabBar } from "./components/TabBar"; | |
| import { ToastProvider } from "./components/Toast"; | |
| import { Home } from "./pages/Home"; | |
| import { History } from "./pages/History"; | |
| import { EntryDetail } from "./pages/EntryDetail"; | |
| import { Daily } from "./pages/Daily"; | |
| import { Plan } from "./pages/Plan"; | |
| import { Stats } from "./pages/Stats"; | |
| import { Remedies } from "./pages/Remedies"; | |
| import { Coach } from "./pages/Coach"; | |
| import { Settings } from "./pages/Settings"; | |
| import { Log } from "./pages/Log"; | |
| import { Login } from "./pages/Login"; | |
| import { navigate, useRoute } from "./router"; | |
| import "./styles/app.css"; | |
| function App() { | |
| const route = useRoute(); | |
| const [ready, setReady] = useState(false); | |
| const [authenticated, setAuthenticated] = useState(false); | |
| const [appName, setAppName] = useState("Habit Journal"); | |
| const refreshAuth = useCallback(async () => { | |
| try { | |
| const me = await getMe(); | |
| setAuthenticated(me.authenticated); | |
| setAppName(me.app_name || "Habit Journal"); | |
| return me.authenticated; | |
| } catch { | |
| setAuthenticated(false); | |
| return false; | |
| } finally { | |
| setReady(true); | |
| } | |
| }, []); | |
| useEffect(() => { | |
| void refreshAuth(); | |
| }, [refreshAuth]); | |
| useEffect(() => { | |
| if (!ready) return; | |
| if (!authenticated && route.name !== "login") { | |
| navigate("/login"); | |
| } | |
| }, [ready, authenticated, route.name]); | |
| if (!ready) { | |
| return <div class="gate-loading">Loading…</div>; | |
| } | |
| if (!authenticated || route.name === "login") { | |
| return ( | |
| <Login | |
| appName={appName} | |
| onAuthenticated={() => { | |
| setAuthenticated(true); | |
| }} | |
| /> | |
| ); | |
| } | |
| let page; | |
| if (route.name === "log") | |
| page = <Log initialRemedy={route.remedy} initialHappened={route.happened} />; | |
| else if (route.name === "home") page = <Home />; | |
| else if (route.name === "history") page = <History />; | |
| else if (route.name === "entry") page = <EntryDetail id={route.id} />; | |
| else if (route.name === "daily") page = <Daily />; | |
| else if (route.name === "plan") page = <Plan initialDate={route.date} />; | |
| else if (route.name === "stats") page = <Stats />; | |
| else if (route.name === "coach") page = <Coach />; | |
| else if (route.name === "remedies") page = <Remedies />; | |
| else if (route.name === "settings") page = <Settings />; | |
| else | |
| page = ( | |
| <div class="app-shell"> | |
| <main class="page stack"> | |
| <p>Unknown page.</p> | |
| <button type="button" class="btn btn-primary" onClick={() => navigate("/")}> | |
| Home | |
| </button> | |
| </main> | |
| </div> | |
| ); | |
| return ( | |
| <PendingResolveProvider> | |
| {page} | |
| <TabBar route={route} /> | |
| </PendingResolveProvider> | |
| ); | |
| } | |
| render( | |
| <ToastProvider> | |
| <App /> | |
| </ToastProvider>, | |
| document.getElementById("app")!, | |
| ); | |
| if ("serviceWorker" in navigator) { | |
| window.addEventListener("load", () => navigator.serviceWorker.register("/sw.js")); | |
| } | |