3.0 KiB
plan, phase, title, status, completed
| plan | phase | title | status | completed |
|---|---|---|---|---|
| 36-02 | 36 | Client /admin route, admin shell with sidebar, UserMenu admin link | complete | 2026-04-19 |
What Was Built
Client-side admin foundation for Phase 36:
-
AuthState.isAdmin —
src/client/hooks/useAuth.tsAuthStateinterface updated withisAdmin?: booleanin the user object type. The hook fetches from/api/auth/mewhich now returns this field after plan 36-01. -
Admin layout route —
src/client/routes/admin.tsxwithcreateFileRoute("/admin"):useEffectguard redirects non-admin users to/(chosen overbeforeLoadbecause router context is{}— no queryClient available at route load time).- Returns
nullwhile loading or if not admin — no flash of admin shell. - Sidebar with "Admin" heading and two disabled nav items: "Items" (package icon, "Soon" badge) and "Tags" (tag icon, "Soon" badge).
<Outlet />renders child routes in the main content area.
-
Admin index placeholder —
src/client/routes/admin/index.tsxwithcreateFileRoute("/admin/"):- Centered placeholder with shield icon, "Admin Panel" text, and "Select a section from the sidebar" subtext.
-
UserMenu Admin link —
src/client/components/UserMenu.tsx:- Conditional
{auth?.user?.isAdmin && (...)}block renders an Admin link (shield icon,to="/admin") at the top of the dropdown menu. - Followed by a
border-t border-gray-100 my-1divider before the existing Profile link. - Non-admin users see no Admin link or divider.
- Conditional
-
Route tree regenerated —
src/client/routeTree.gen.tsupdated with/adminand/admin/routes. -
__root.tsx unchanged —
/adminis correctly absent fromisPublicRoute, so unauthenticated users hitting/adminare redirected to/loginby the root guard. The admin route's own guard handles non-admin authenticated users.
Key Files
src/client/hooks/useAuth.ts— isAdmin? in AuthState interfacesrc/client/routes/admin.tsx— admin layout with sidebar shell and guardsrc/client/routes/admin/index.tsx— admin index placeholdersrc/client/components/UserMenu.tsx— conditional Admin linksrc/client/routeTree.gen.ts— regenerated with /admin routes
Deviations
- Used
useEffect + navigateguard instead ofbeforeLoad— the plan's primary recommendation.beforeLoadwas documented as an alternative but requires queryClient in router context which is not configured (context: {}). TheuseEffectapproach is functionally equivalent and rendersnullduring the auth check so no flash occurs.
Self-Check: PASSED
- src/client/routes/admin.tsx exists with createFileRoute("/admin") and guard logic
- src/client/routes/admin/index.tsx exists with placeholder UI
- Admin sidebar renders "Items" (package icon) and "Tags" (tag icon) both disabled with "Soon" badge
- Non-admin redirect implemented via useEffect
- UserMenu shows Admin link when auth.user.isAdmin is true
- bun run build exits 0
- routeTree.gen.ts includes /admin and /admin/ routes