feat(medications): wire the Verlauf tab onto the dose-history ledger

Replace the Verlauf tab's flat intake table with the per-slot dose-history
ledger the shared band engine mints. The tab now renders EVERY expected slot
with its status — on-time, late, skipped, missed, upcoming — even when the
dose was never taken, and tags every off-schedule intake as a standalone
ad-hoc row at its real time. Rows group by day, most-recent first.

Genommen / Übersprungen sit on the dose row and recompute instantly: the
cached ledger and the headline adherence are mutated optimistically (the
engines are pure, so the client mirrors their accounting) before the write
fires, then the dependent-key invalidation reconciles; a failed write rolls
the optimistic snapshot back. A header add dialog records a dose — including a
backdated or off-schedule one — and an off-window take surfaces the "diesem
Slot zuordnen?" nudge, pinning it onto a chosen slot via forceSlotInstant
rather than orphaning it. A compact took/skipped bar sits at the top of the
tab; the card body still never tints by status.

Adherence is derived from the same ledger the user is reading (taken over
taken + missed; skip, ad-hoc, upcoming excluded), so the history view and the
percentage cannot contradict. New status + dialog copy in all six locales.
This commit is contained in:
Marc-André Bombeck committed 2026-06-08 19:23:25 +02:00
1 parent 895c497f5d
commit 2ee488d541
13 files changed
+1594 -7

No files matched your search

+16
View File
@@ -272,6 +272,22 @@ export const queryKeys = {
*/
medicationInventory: (medicationId: string) =>
["medications", medicationId, "inventory"] as const,
/**
* v1.15.18 — per-medication dose-history ledger
* (`GET /api/medications/[id]/dose-history?from=&to=`), consumed by the
* detail page's Verlauf tab. Keyed by the `(from, to)` window so paging the
* range caches each span independently; rides under the `["medications"]`
* prefix so an intake mutation (take / skip / edit / delete) reaches it
* through `medicationDependentKeys`. The Verlauf tab also mutates this slot
* optimistically on Genommen / Übersprungen so the row status + the
* Übersicht headline % flip in the same paint, then reconciles on the
* authoritative refetch.
*/
medicationDoseHistory: (
medicationId: string,
from: string,
to: string,
) => ["medications", medicationId, "dose-history", from, to] as const,
medicationIntakeDrugLevelChart: (medicationId: string) =>
["medications", medicationId, "intake", "drug-level-chart"] as const,
/**