Skip to content

bug: split always-available nav (Reference/Settings) from project-scoped routes #76

Description

@pskillen

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

  1. Clear LocalStorage / no active project → Home shows minimal nav with Reference and Settings; Reference pages load.
  2. With no active project, navigate to /#/channels → redirected to Home (or blocked with clear message).
  3. Import or select a project → full sidebar appears; project routes work.
  4. 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 #.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions