[Issue]: Sidebar - make headings collapsible #96

Closed
opened 2026-06-23 15:01:06 +00:00 by shad0w · 3 comments
Owner

Raised by

Kaushal Pal Singh (kps@pelagiamarine.com, MANAGER) — via portal Report Issue button

Description

Purchasing, crewing, administration all should be collapsible and collapsed by default. Clicking a link in one heading should collapse other headings, if open.

Priority

P2 — Medium

Context

  • Page: /dashboard
  • Reported at: 2026-06-23T15:01:06.716Z
### Raised by Kaushal Pal Singh (kps@pelagiamarine.com, MANAGER) — via portal Report Issue button ### Description Purchasing, crewing, administration all should be collapsible and collapsed by default. Clicking a link in one heading should collapse other headings, if open. ### Priority P2 — Medium ### Context - Page: `/dashboard` - Reported at: 2026-06-23T15:01:06.716Z
shad0w added the
portal
label 2026-06-23 15:01:06 +00:00
shad0w added the
feature
claude-queue
triaged
labels 2026-06-23 15:11:02 +00:00
Author
Owner

Claude triage

Triage — Issue #96: Sidebar — make headings collapsible

Type: Feature (enhancement to existing navigation behaviour)
Priority: P2 — Medium
Routing: claude-queue

Interpretation

The portal sidebar currently renders section headings (Purchasing, Crewing,
Administration) as static, always-expanded labels via SectionHeader. The reporter
wants each of these headings to be collapsible, collapsed by default, and to behave
as an accordion: opening one heading (or clicking a link within it) collapses any other
open heading.

Note: the top "main" links (Dashboard, New PO, Closed POs, Approvals, Payments, My Profile,
etc.) are not under any heading — they sit above the sections directly. The request only
concerns the three (or fewer, role-dependent) headed sections.

Action items

  1. Make SectionHeader an interactive toggle in App/components/layout/sidebar.tsx:
    • Convert the static <p> label into a <button> row with a chevron indicator
      (e.g. ChevronRight/ChevronDown from lucide-react, already a dependency).
    • Add aria-expanded and appropriate aria-controls/region semantics for accessibility.
  2. Add collapse state to the Sidebar client component (useState), keyed by section
    id ("purchasing" | "crewing" | "administration"). Default all to collapsed.
  3. Accordion behaviour: opening a section sets it as the only open section (single-open
    accordion). Per the issue, clicking a link within a section collapses the others — so
    the active section's links remain visible while siblings close.
  4. Conditionally render each section's NavLink list based on its open state (the headed
    groups in the existing JSX: Purchasing block, Crewing block, both Administration blocks).
  5. Resolve "collapsed by default" vs. discoverability (see open questions) — likely
    auto-expand the section that contains the currently active route on mount, so the user
    isn't left on a page whose nav section is hidden.
  6. Tests: add a component unit test (jsdom + Testing Library, following
    tests/unit/vendors-table.test.tsx / po-status-badge.test.tsx) asserting: sections
    collapsed by default, clicking a header expands it and reveals its links, and opening one
    section collapses another. Run pnpm type-check, pnpm lint, pnpm test.

Files / areas involved

  • App/components/layout/sidebar.tsx — the only source file to change (SectionHeader,
    Sidebar, section render blocks). Single, localized.
  • App/tests/unit/sidebar.test.tsx — new unit test (none exists today).
  • App/tests/e2e/rebrand.spec.ts — existing e2e only checks the "PPMS" brand text in aside;
    unaffected, but worth a glance to ensure the brand text stays outside any collapsible region.

Open questions

  • Discoverability after navigation: since headings are collapsed by default and clicking
    a link navigates to a new page (fresh mount), the user lands with all sections collapsed.
    Should the section containing the active route auto-expand on mount? (Recommended yes —
    otherwise the active link is hidden.) The issue text doesn't specify; sensible default
    chosen above.
  • Persistence: should open/closed state persist across navigations/reloads
    (localStorage)? Not requested; default is no persistence (re-derive from active route).
  • Strict accordion vs. independent toggles: issue implies single-open accordion
    ("collapse other headings, if open"). Assuming single-open.

Routing rationale

Routing: claude-queue — a localized, single-file client-component change (sidebar.tsx) with
clear acceptance criteria, verifiable by type-check/lint plus a component unit test, touching
no DB migrations, auth/permissions, payments, or external systems.

Routing: claude-queue | Type: feature

## Claude triage # Triage — Issue #96: Sidebar — make headings collapsible **Type:** Feature (enhancement to existing navigation behaviour) **Priority:** P2 — Medium **Routing:** claude-queue ## Interpretation The portal sidebar currently renders section headings (**Purchasing**, **Crewing**, **Administration**) as static, always-expanded labels via `SectionHeader`. The reporter wants each of these headings to be **collapsible**, **collapsed by default**, and to behave as an **accordion**: opening one heading (or clicking a link within it) collapses any other open heading. Note: the top "main" links (Dashboard, New PO, Closed POs, Approvals, Payments, My Profile, etc.) are **not** under any heading — they sit above the sections directly. The request only concerns the three (or fewer, role-dependent) headed sections. ## Action items 1. **Make `SectionHeader` an interactive toggle** in `App/components/layout/sidebar.tsx`: - Convert the static `<p>` label into a `<button>` row with a chevron indicator (e.g. `ChevronRight`/`ChevronDown` from `lucide-react`, already a dependency). - Add `aria-expanded` and appropriate `aria-controls`/region semantics for accessibility. 2. **Add collapse state** to the `Sidebar` client component (`useState`), keyed by section id (`"purchasing" | "crewing" | "administration"`). Default all to **collapsed**. 3. **Accordion behaviour:** opening a section sets it as the only open section (single-open accordion). Per the issue, **clicking a link within a section collapses the others** — so the active section's links remain visible while siblings close. 4. **Conditionally render each section's `NavLink` list** based on its open state (the headed groups in the existing JSX: Purchasing block, Crewing block, both Administration blocks). 5. **Resolve "collapsed by default" vs. discoverability** (see open questions) — likely auto-expand the section that contains the currently active route on mount, so the user isn't left on a page whose nav section is hidden. 6. **Tests:** add a component unit test (jsdom + Testing Library, following `tests/unit/vendors-table.test.tsx` / `po-status-badge.test.tsx`) asserting: sections collapsed by default, clicking a header expands it and reveals its links, and opening one section collapses another. Run `pnpm type-check`, `pnpm lint`, `pnpm test`. ## Files / areas involved - `App/components/layout/sidebar.tsx` — the only source file to change (`SectionHeader`, `Sidebar`, section render blocks). Single, localized. - `App/tests/unit/sidebar.test.tsx` — new unit test (none exists today). - `App/tests/e2e/rebrand.spec.ts` — existing e2e only checks the "PPMS" brand text in `aside`; unaffected, but worth a glance to ensure the brand text stays outside any collapsible region. ## Open questions - **Discoverability after navigation:** since headings are collapsed by default and clicking a link navigates to a new page (fresh mount), the user lands with all sections collapsed. Should the section containing the active route auto-expand on mount? (Recommended yes — otherwise the active link is hidden.) The issue text doesn't specify; sensible default chosen above. - **Persistence:** should open/closed state persist across navigations/reloads (localStorage)? Not requested; default is no persistence (re-derive from active route). - **Strict accordion vs. independent toggles:** issue implies single-open accordion ("collapse other headings, if open"). Assuming single-open. ## Routing rationale Routing: claude-queue — a localized, single-file client-component change (`sidebar.tsx`) with clear acceptance criteria, verifiable by type-check/lint plus a component unit test, touching no DB migrations, auth/permissions, payments, or external systems. **Routing:** `claude-queue` | **Type:** `feature`
shad0w added
claude-working
and removed
claude-queue
labels 2026-06-23 15:11:03 +00:00
Author
Owner

[Claude] Started working on this issue on branch claude/issue-96.

<!-- ppms-bot --> [Claude] Started working on this issue on branch `claude/issue-96`.
shad0w added
claude-pr
and removed
claude-working
labels 2026-06-23 15:14:51 +00:00
Author
Owner

[Claude] Opened PR #97 with a proposed fix. Review and merge it, then create a release tag to deploy.

<!-- ppms-bot --> [Claude] Opened PR [#97](https://git.pelagiamarine.com/shad0w/pelagia-portal/pulls/97) with a proposed fix. Review and merge it, then create a release tag to deploy.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: shad0w/pelagia-portal#96
No description provided.