Files
HealthLog/src/components/settings/record-anamnesis-section.tsx
T
Marc-André Bombeck 715b733164 feat(shell): add a command palette for pages, settings, modules and actions
Cmd/Ctrl+K or the search control at the end of the top bar opens a
combobox over a client-side index built from the lists the navigation
already renders: pages, Insights pages, every Settings section and card
(deep-linked by a new anchor prop on SettingsCardHeader), the Appearance
sub-pages, module switches and a few actions. Entries follow the module
map, the Coach capability, the admin role and a shared record's grant;
inside somebody else's record no cards, switches or backup are offered.

Ranking is prefix, then word start, then substring, then a small edit
distance, then subsequence, with a short multilingual synonym list. The
empty state shows recent places (per account, in localStorage) and the
main actions. The palette is its own lazily loaded chunk; the top bar
shows a search field where it has room and a magnifier otherwise. The
module switch mutation moves into a shared hook used by the Modules hub
and the palette.
2026-10-09 16:35:21 +02:00

83 lines
3.4 KiB
TypeScript

"use client";
import { ShieldAlert, Users } from "lucide-react";
import { SettingsCard } from "@/components/settings/settings-card";
import { SettingsCardHeader } from "@/components/settings/_card-header";
import { AllergyManager } from "@/components/records/allergy-manager";
import { FamilyHistoryManager } from "@/components/records/family-history-manager";
import { useTranslations } from "@/lib/i18n/context";
/**
* v1.37.0 — Settings → Anamnese, inside somebody else's record.
*
* ## Why a second component instead of the personal one
*
* `AnamnesisSection` renders five managers, and only two of them belong to the
* record. The other three write through `/api/coach/about-me` and
* `/api/anamnesis/facts`, both of which resolve a bare `requireAuth()` and
* therefore refuse outright under a switch. Mounting the personal section here
* would put three forms on screen that answer 403 on submit — the precise
* failure `useRecordCapabilities` was written to end ("a control that appeared
* before its route answered"). So this surface is the intersection of the
* section and what the record routes admit, and it is a separate component so
* that intersection is visible rather than expressed as four conditionals
* inside the personal one.
*
* ## What is here
*
* Allergies and family history. Both post to routes that resolve
* `requireRecordAuth("manage", "profile")`, so both land under the record
* owner with the delegate named as actor, and a READ or WRITE delegate is
* refused by the route as well as never reaching this page.
*
* Family history is the one admitted write where third-party health
* information is present by design — the row describes the record subject's
* relatives, and often enough the delegate IS that relative, asserting a
* condition about themselves into somebody else's record. The route's own
* comment named that discomfort and left it for the surface to say out loud,
* because no route comment can. The sentence at the top of the card body,
* above the list, is where it gets said.
*
* The cache is not a concern here and the reason is worth naming: switching
* records clears the whole query client, so the allergy and family-history
* lists cannot carry one record's rows into another's view.
*/
export function RecordAnamnesisSection() {
const { t } = useTranslations();
return (
<div className="space-y-6" data-slot="record-anamnesis-section">
<SettingsCard>
<SettingsCardHeader
anchor="allergies"
icon={ShieldAlert}
title={t("records.allergies.cardTitle")}
description={t("records.allergies.cardDescription")}
/>
<AllergyManager />
</SettingsCard>
<SettingsCard>
<SettingsCardHeader
anchor="family-history"
icon={Users}
title={t("records.family.cardTitle")}
description={t("records.family.cardDescription")}
/>
{/* Above the list: the manager closes with its action row, and
nothing follows a card's actions (design standards §12). */}
<p
data-slot="record-anamnesis-relative-note"
className="text-foreground text-sm"
>
{t("recordSharing.anamnesis.relativeNote")}
</p>
<FamilyHistoryManager />
</SettingsCard>
<p className="text-muted-foreground text-xs">{t("records.disclaimer")}</p>
</div>
);
}