Files
HealthLog/src/components
Marc-André Bombeck 3e176db5b7 fix(encounters): stop offering the visit edit sheet to a delegate who may not save it
`VisitsSection` asked the grant about its add button and nothing else. Every row
underneath stayed tappable into the edit sheet, whose Save is `PATCH
/api/encounters/{id}` and whose Delete is `DELETE` on the same path — both
`("manage", "profile")`. So a READ delegate opened a form that could not be
saved, and a WRITE delegate, who may file a new visit, opened one that could not
be changed. Reachable wherever the checkups page is, which is every
`profile`-scoped grant.

The row now takes its open callback only when `canManageDomain("profile")`
answers, and the card renders its content as content rather than as a button
when it does not. The add button keeps asking the write question, because that
is a different question with a different answer.

Four legs in the affordances suite over the same scoped fixtures the
immunization log uses: the owner opens the sheet, a READ and a WRITE delegate
see the row and cannot open it, a WRITE delegate still gets the add button, and
a MANAGE delegate opens it only while holding the section. Two of them fail
against the previous section.
2026-09-10 10:39:46 +02:00
..

src/components/

React components. The UI primitives are shadcn/ui (new-york style, zinc base) over Radix + Tailwind 4 + Lucide; everything above the primitives is feature-grouped by surface. Components are server components unless they need a hook, state, or browser API, in which case they open with "use client". Charts use Recharts 3 — replacing the chart library requires explicit approval.

Primitives and shell

  • ui/ — shadcn/ui primitives (button, dialog, sheet, table, …). Generated by the shadcn CLI; keep edits minimal and on-style.
  • layout/ — the app shell: sidebar, topbar, bottom nav.
  • providers.tsx, version-poller.tsx — top-level context providers and the self-healing stale-shell poller.
  • i18n/ — translation context + locale switcher.

Feature groups

  • insights/ — insight status, assessment cards, Coach surface, advisor cards (the largest group).
  • medications/ — medication cards, the schedule wizard, intake timeline, detail history.
  • settings/ — the section components behind each settings page.
  • measurements/, mood/, dashboard/ — entry forms, lists, dashboard tiles.
  • charts/ — Recharts wrappers.
  • monitoring/ — Umami / GlitchTip client bootstrap.
  • gamification/, targets/, comparison/, doctor-report/, clinician/, onboarding/, admin/ — the remaining per-surface groups.

Conventions

Kebab-case filenames; React component exports stay PascalCase regardless. (A handful of PascalCase-filename outliers under medications/ + onboarding/ are pre-existing drift, noted in ../../CLAUDE.md.) Every t() call needs a matching key in messages/en.json — guarded by i18n-call-site-coverage.test.ts. Data reads go through TanStack Query with keys from @/lib/query-keys and unwrap (await res.json()).data. Tests live in __tests__/.