Fastwhisper / frontend /src /main.tsx
Mbonea's picture
Close P1 arch-code gaps: loop summary, template-echo Rules, Move now, proof kinds.
57ed4c2
Raw
History Blame Contribute Delete
3.23 kB
/** 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"));
}