import { createRoot } from "react-dom/client";
import { lazy, Suspense, useEffect, useState } from "react";
import { createBrowserRouter, Link, NavLink, Outlet, RouterProvider, useLocation, type RouteObject } from "react-router-dom";
import type { AuthUser } from "@stc/contracts";
import { AppShell } from "@stc/ui";
import { webFeatures } from "./features";
import { visibleNav } from "./nav";
function Home() {
return
No features installed yet
;
}
/** The signed-in user (GET /api/me), refreshed on navigation so sign-in and sign-out update the nav. */
function useSessionUser(): AuthUser | null {
const { pathname } = useLocation();
const [user, setUser] = useState(null);
useEffect(() => {
let live = true;
fetch("/api/me", { credentials: "same-origin" })
.then((r) => (r.ok ? r.json() : { user: null }))
.then((b: { user: AuthUser | null }) => { if (live) setUser(b.user ?? null); })
.catch(() => { if (live) setUser(null); });
return () => { live = false; };
}, [pathname]);
return user;
}
function Layout() {
// Links the user cannot use are hidden; the pages and APIs still enforce access themselves.
const nav = visibleNav(webFeatures, useSessionUser());
const header = (
<>
STCourses
{nav.length ? (
) : null}
>
);
return (
);
}
const featureRoutes: RouteObject[] = webFeatures.flatMap((f) =>
f.routes.map((r) => {
const Element = lazy(r.element);
return { path: r.path, element: };
}),
);
const router = createBrowserRouter([
{ element: , children: [...featureRoutes, ...(featureRoutes.some((r) => r.path === "/") ? [] : [{ path: "*", element: }])] },
]);
createRoot(document.getElementById("root")!).render();