From 6f5f035b7858edf53437261b9a80ee52d7958e5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Mon, 8 Jun 2026 18:37:42 +0200 Subject: [PATCH] fix(medications): keep the card a constant neutral surface, never tint by dose status The v1.15.9 take-window highlight washed the whole medication card green (ring + tinted background) when a dose was in its on-time window. A card turning green reads as an imperative "take it now" and drowns the rest of the page once several doses fall due. Drop the surface tint entirely so the card stays a constant neutral surface; the take-now / overdue / very-overdue status remains, expressed only through the discreet top status line / pill (text + glyph), never as a background or border colour. Tests assert the neutral surface across every dose status plus the surviving status pill. --- .../medications/__tests__/card-parts.test.tsx | 37 +++++++++++++------ .../card-parts/medication-card-body.tsx | 26 ++++++------- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/components/medications/__tests__/card-parts.test.tsx b/src/components/medications/__tests__/card-parts.test.tsx index f39baaf64..07f351996 100644 --- a/src/components/medications/__tests__/card-parts.test.tsx +++ b/src/components/medications/__tests__/card-parts.test.tsx @@ -373,10 +373,11 @@ describe("streak-token parity — generic vs GLP-1 card", () => { }); /** - * v1.15.9 — the ONE shared `` both cards render. These - * tests pin the state-driven presentation (green take-window highlight, - * overdue / heavily-overdue top line) and the structural identity that makes - * the two variants impossible to diverge — they pass content into THIS body. + * v1.15.18 — the ONE shared `` both cards render. These + * tests pin that the card surface is a CONSTANT neutral surface — dose status + * is never expressed as a background / border tint (Marc, recurring) — while + * status is still surfaced via the discreet top line / pill, plus the + * structural identity that makes the two variants impossible to diverge. */ describe("medication card body — shared shell + dose-state presentation", () => { function renderBody(doseStatus: DoseStatus, active = true) { @@ -406,17 +407,30 @@ describe("medication card body — shared shell + dose-state presentation", () = ); } - it("highlights the card green when the dose is in its take-window", () => { + it("never tints the card surface when the dose is in its take-window", () => { + // Marc (recurring): the whole card washing green reads as "take it now" + // and is a permanent removal. The take-window status survives ONLY as the + // discreet "Take now" pill, never as a card background / ring tint. const html = renderBody("on_time_window"); - // Green ring + tinted background on the Card shell. - expect(html).toContain("ring-success/40"); - expect(html).toContain("bg-success/5"); + expect(html).not.toContain("ring-success/40"); + expect(html).not.toContain("bg-success/5"); + // The discreet status pill still communicates the state. + expect(html).toContain("Take now"); }); - it("stays calm (no green highlight) for upcoming / taken states", () => { - for (const status of ["upcoming", "taken_on_time", "taken_late", "skipped"] as const) { + it("never tints the card surface across any dose status", () => { + for (const status of [ + "on_time_window", + "upcoming", + "taken_on_time", + "taken_late", + "skipped", + "overdue", + "missed", + ] as const) { const html = renderBody(status); expect(html).not.toContain("ring-success/40"); + expect(html).not.toContain("bg-success/5"); } }); @@ -433,9 +447,10 @@ describe("medication card body — shared shell + dose-state presentation", () = expect(html).toContain("text-destructive"); }); - it("never highlights green on an inactive medication", () => { + it("keeps the inactive surface muted without any status tint", () => { const html = renderBody("on_time_window", false); expect(html).not.toContain("ring-success/40"); + expect(html).not.toContain("bg-success/5"); expect(html).toContain("opacity-60"); }); diff --git a/src/components/medications/card-parts/medication-card-body.tsx b/src/components/medications/card-parts/medication-card-body.tsx index 9d34fc9e1..6566c1c9a 100644 --- a/src/components/medications/card-parts/medication-card-body.tsx +++ b/src/components/medications/card-parts/medication-card-body.tsx @@ -35,11 +35,16 @@ import type { MedicationWindowStatus } from "@/lib/medications/window-status"; * the single `mt-auto pt-0` action wrapper — there is no per-variant spacing * left to diverge. * - * State-driven presentation (like the iOS app): - * - `on_time_window` → the card highlights green (`ring` + tinted bg): the - * actionable "take it now" state stands out at a glance. + * State-driven presentation: + * - The card surface itself is a CONSTANT neutral surface — dose status + * never tints the card background or border. A whole card washing green + * reads as "take it now everywhere" and drowns the page; status is shown + * ONLY through the discreet top line / pill below. + * - `on_time_window` → the discreet "Take now" pill (success-toned text + + * glyph), no card wash. * - `overdue` → a calm top status line; `missed` (at / past the miss - * cutoff) escalates to "Stark überfällig" in the destructive tone. + * cutoff) escalates to "Stark überfällig" in the destructive tone — both + * are a single text line with an icon, not a surface tint. * - `upcoming` / `taken_*` / `skipped` → no escalation; the card stays calm. */ export interface MedicationCardBodyProps { @@ -123,10 +128,6 @@ export function MedicationCardBody({ }: MedicationCardBodyProps) { const { t } = useTranslations(); - // Green take-window highlight — the actionable "take it now" state, mirrored - // from the iOS card. Suppressed on an inactive med (it carries no actions). - const inTakeWindow = active && doseStatus === "on_time_window"; - // Overdue escalation line: a dose past its on-time window. `missed` (at / // past the clinical miss cutoff) reads "Stark überfällig"; the still-takeable // `overdue` tail reads the calmer "Überfällig". Both use the destructive @@ -140,11 +141,10 @@ export function MedicationCardBody({ return (