Problem
Navigation and route access are inconsistent when no codeplug project is active (activeProjectId === null).
Symptom 1 — Reference (and Settings) unreachable without a project
The entire sidebar is hidden when there is no active project:
// src/App.tsx
const showNav = activeProjectId != null;
showNav gates AppShell.Navbar, the mobile burger, and all nav links — including Reference (/reference, band plan, Maidenhead converter) and Settings (/settings). Those pages are static / app-level utilities and do not depend on an active codeplug, but operators on Home with no active project (or after deleting the last project) have no UI path to reach them except typing the URL.
Symptom 2 — Project-scoped pages reachable by URL without a project
Conversely, project-scoped routes are registered unconditionally in App.tsx and render even when activeProjectId is null. Direct navigation to e.g. /#/channels, /#/zones, /#/summary, /#/export loads list/detail/edit pages with an empty codeplug (useCodeplug() returns empty arrays when no active project — see codeplugStore.tsx). That is confusing: empty CRUD UI with no sidebar context and no clear prompt to import or select a project.
Intended fix
Split always-available navigation from project-scoped navigation. This is not auth — it is a UX guard so operators always know whether they are working inside a codeplug project.
Navigation
- Always show a minimal sidebar (or header links on mobile) with at least:
- Home (
/)
- Reference (
/reference)
- Settings (
/settings)
- When a project is active, show the full nav as today (Summary, Channels, Zones, …, Export) plus ActiveProjectBar.
- Optional polish: when projects exist but none is active, Home already lists them — ensure the minimal nav still appears on Home.
Route guards
Gate project-scoped routes when activeProjectId == null. Redirect to / (Home) with replace, or render a dedicated “select or import a codeplug” empty state — prefer redirect for simplicity.
Project-scoped (gate):
/summary
/channels, /channels/new, /channels/:id, /channels/:id/edit
/zones, /zones/new, /zones/:id, /zones/:id/edit
/talk-groups, /talk-groups/:id
/contacts, /contacts/:id
/rx-group-lists, /rx-group-lists/:id
/export
/map (already redirects to /channels — guard there or at /map)
Always available (no gate):
/
/reference, /reference/band-plan, /reference/maidenhead
/settings
Implement via a small RequireActiveProject layout route wrapper (or equivalent) rather than duplicating checks in every page.
Affected
src/App.tsx — split nav visibility; route guard wrapper
- New component e.g.
src/components/RequireActiveProject.tsx (name TBD)
src/App.test.tsx — add cases: no-project → Reference link visible; no-project → /channels redirects; with project → full nav unchanged
Manual verify
- Clear LocalStorage / no active project → Home shows minimal nav with Reference and Settings; Reference pages load.
- With no active project, navigate to
/#/channels → redirected to Home (or blocked with clear message).
- Import or select a project → full sidebar appears; project routes work.
- Delete active project (or switch to none) → project routes blocked again; Reference still reachable from nav.
Notes
- Related to multi-project work (#31); projects shipped but nav/guard semantics were never split.
useCodeplug() already returns empty data without an active project — the guard is about UX, not data integrity.
Workflow note
Branch from origin/main, atomic conventional commits (nav split → route guard → tests), PR linking Closes #.
Problem
Navigation and route access are inconsistent when no codeplug project is active (
activeProjectId === null).Symptom 1 — Reference (and Settings) unreachable without a project
The entire sidebar is hidden when there is no active project:
showNavgatesAppShell.Navbar, the mobile burger, and all nav links — including Reference (/reference, band plan, Maidenhead converter) and Settings (/settings). Those pages are static / app-level utilities and do not depend on an active codeplug, but operators on Home with no active project (or after deleting the last project) have no UI path to reach them except typing the URL.Symptom 2 — Project-scoped pages reachable by URL without a project
Conversely, project-scoped routes are registered unconditionally in
App.tsxand render even whenactiveProjectIdis null. Direct navigation to e.g./#/channels,/#/zones,/#/summary,/#/exportloads list/detail/edit pages with an empty codeplug (useCodeplug()returns empty arrays when no active project — seecodeplugStore.tsx). That is confusing: empty CRUD UI with no sidebar context and no clear prompt to import or select a project.Intended fix
Split always-available navigation from project-scoped navigation. This is not auth — it is a UX guard so operators always know whether they are working inside a codeplug project.
Navigation
/)/reference)/settings)Route guards
Gate project-scoped routes when
activeProjectId == null. Redirect to/(Home) withreplace, or render a dedicated “select or import a codeplug” empty state — prefer redirect for simplicity.Project-scoped (gate):
/summary/channels,/channels/new,/channels/:id,/channels/:id/edit/zones,/zones/new,/zones/:id,/zones/:id/edit/talk-groups,/talk-groups/:id/contacts,/contacts/:id/rx-group-lists,/rx-group-lists/:id/export/map(already redirects to/channels— guard there or at/map)Always available (no gate):
//reference,/reference/band-plan,/reference/maidenhead/settingsImplement via a small
RequireActiveProjectlayout route wrapper (or equivalent) rather than duplicating checks in every page.Affected
src/App.tsx— split nav visibility; route guard wrappersrc/components/RequireActiveProject.tsx(name TBD)src/App.test.tsx— add cases: no-project → Reference link visible; no-project →/channelsredirects; with project → full nav unchangedManual verify
/#/channels→ redirected to Home (or blocked with clear message).Notes
useCodeplug()already returns empty data without an active project — the guard is about UX, not data integrity.Workflow note
Branch from
origin/main, atomic conventional commits (nav split → route guard → tests), PR linkingCloses #.