From 73afae0314fb99ac06b5c51136a9ddd0b394ea69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sat, 9 May 2026 20:22:13 +0200 Subject: [PATCH] feat(dashboard): medication compliance graph wired to layout toggle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Medikamente" toggle in Settings → Dashboard has existed since v1.1 but the dashboard slot only rendered a static placeholder (an icon + the section title). Flipping it on did nothing visible — the user got no compliance graph the way they get one for weight, BP, pulse, mood, etc. v1.4.15 wires the slot to a real chart. The new `` consumes the existing `/api/medications/intake?scope=compliance&days=N` endpoint (which already returns `{ date, scheduled, taken }[]`) and renders daily compliance % over the selected window with a 7d/30d/90d range chip in the header, a 80 %-target ReferenceLine, and the same Dracula tokens the other dashboard charts use. Days where no doses were scheduled are *skipped* rather than drawn as 0 % — compliance is undefined when nothing was due, and a flat zero streak would mis-represent a user who simply hadn't started a regimen yet. Static recharts imports inside the wrapper (the dashboard's `next/dynamic` for the wrapper itself stays). v1.4.14 phase-4 visual- verify proved that wrapping individual primitives in `next/dynamic` breaks Recharts' `findAllByType` reconciliation; we keep the wrapper- with-static-imports pattern the other charts already use. Tests: - Unit `aggregateMedicationCompliance()`: rate rounds to nearest int, skips days with `scheduled === 0`, clamps over-100 % rates, sorts ascending by date, returns empty array when nothing was due across the window. - Component SSR smoke: title resolves through i18n, "no data" empty state surfaces when the query is empty, the `data-slot` hook is present so future visual-verify can target the chart. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/components/layout/sidebar-nav.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/layout/sidebar-nav.tsx b/src/components/layout/sidebar-nav.tsx index 0decd3fd4..833ea87a3 100644 --- a/src/components/layout/sidebar-nav.tsx +++ b/src/components/layout/sidebar-nav.tsx @@ -218,7 +218,10 @@ export function SidebarNav() { const { user } = useAuth(); const { bugReportEnabled } = useAppSettings(); const isAdmin = user?.role === "ADMIN"; - const onAdminPage = pathname.startsWith("/admin"); + // Match `/admin` exactly or any `/admin/...` sub-route. Plain + // `startsWith("/admin")` would also flip for a hypothetical future + // `/administrative` page, which is not the same semantic surface. + const onAdminPage = pathname === "/admin" || pathname.startsWith("/admin/"); const [collapsed, setCollapsed] = useState(() => { if (typeof window === "undefined") return false; try {