From d323d01c9330d09acbeca1fc71a68fd04f114112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 5 Jul 2026 14:49:22 +0200 Subject: [PATCH 01/10] fix(medications): drop the duplicated overdue line below the streak row The injection/GLP-1 card showed an overdue dose twice: once on the next-intake value line (the destructive escalation with the due time) and again as the open-cycle status line below the compliance bars. The cycle line's missed tier is retired; the due-today tier stays. The reserved min-h slot in the shared card body is untouched, so card heights stay symmetric across medication types. --- messages/de.json | 1 - messages/en.json | 1 - messages/es.json | 1 - messages/fr.json | 1 - messages/it.json | 1 - messages/pl.json | 1 - .../medications/__tests__/card-parts.test.tsx | 9 ++-- .../card-parts/medication-cycle-status.tsx | 46 +++++++------------ 8 files changed, 22 insertions(+), 39 deletions(-) diff --git a/messages/de.json b/messages/de.json index 28604c9b1..f4a562b0b 100644 --- a/messages/de.json +++ b/messages/de.json @@ -870,7 +870,6 @@ "dayStreak": "Tage Serie", "dayStreakOne": "Tag Serie", "cycleDueToday": "Heute fällig", - "cycleOverdue": "Überfällig", "cycleNoClosedCycles": "Noch keine abgeschlossenen Dosiszyklen", "taken": "Genommen", "skipped": "Übersprungen", diff --git a/messages/en.json b/messages/en.json index df45fbd25..ff2929c9b 100644 --- a/messages/en.json +++ b/messages/en.json @@ -870,7 +870,6 @@ "dayStreak": "day streak", "dayStreakOne": "day streak", "cycleDueToday": "Due today", - "cycleOverdue": "Overdue", "cycleNoClosedCycles": "No closed dose cycles yet", "taken": "Taken", "skipped": "Skipped", diff --git a/messages/es.json b/messages/es.json index 35f95049a..277dc4bb5 100644 --- a/messages/es.json +++ b/messages/es.json @@ -870,7 +870,6 @@ "dayStreak": "días de racha", "dayStreakOne": "día de racha", "cycleDueToday": "Pendiente hoy", - "cycleOverdue": "Atrasada", "cycleNoClosedCycles": "Aún no hay ciclos de dosis completados", "taken": "Tomada", "skipped": "Omitida", diff --git a/messages/fr.json b/messages/fr.json index 92682f7a4..e01c96195 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -870,7 +870,6 @@ "dayStreak": "jours de série", "dayStreakOne": "jour de série", "cycleDueToday": "À prendre aujourd'hui", - "cycleOverdue": "En retard", "cycleNoClosedCycles": "Aucun cycle de dose terminé pour l'instant", "taken": "Pris", "skipped": "Sauté", diff --git a/messages/it.json b/messages/it.json index 6a20cc358..ad61b14ae 100644 --- a/messages/it.json +++ b/messages/it.json @@ -870,7 +870,6 @@ "dayStreak": "giorni di serie", "dayStreakOne": "giorno di serie", "cycleDueToday": "In scadenza oggi", - "cycleOverdue": "In ritardo", "cycleNoClosedCycles": "Ancora nessun ciclo di dose completato", "taken": "Assunta", "skipped": "Saltata", diff --git a/messages/pl.json b/messages/pl.json index 179663f05..79dc93b9b 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -870,7 +870,6 @@ "dayStreak": "dni serii", "dayStreakOne": "dzień serii", "cycleDueToday": "Termin dzisiaj", - "cycleOverdue": "Zaległa", "cycleNoClosedCycles": "Brak zakończonych cykli dawkowania", "taken": "Przyjęte", "skipped": "Pominięte", diff --git a/src/components/medications/__tests__/card-parts.test.tsx b/src/components/medications/__tests__/card-parts.test.tsx index 3e91933c3..12e01579f 100644 --- a/src/components/medications/__tests__/card-parts.test.tsx +++ b/src/components/medications/__tests__/card-parts.test.tsx @@ -288,7 +288,10 @@ describe("medication cycle status — open-cycle line", () => { expect(html).toContain("lucide-calendar-clock"); }); - it("missed reads the destructive overdue line", () => { + it("missed renders nothing — the overdue escalation already reads on the next-intake line", () => { + // v1.27.5 — the card's next-intake value line carries the destructive + // overdue escalation; a second overdue line below the streak row doubled + // the signal and is retired. const html = render( { }} />, ); - expect(html).toContain("Overdue"); - expect(html).toContain("text-destructive"); - expect(html).toContain("lucide-triangle-alert"); + expect(html).toBe(""); }); }); diff --git a/src/components/medications/card-parts/medication-cycle-status.tsx b/src/components/medications/card-parts/medication-cycle-status.tsx index c364b379f..46b12c585 100644 --- a/src/components/medications/card-parts/medication-cycle-status.tsx +++ b/src/components/medications/card-parts/medication-cycle-status.tsx @@ -1,4 +1,4 @@ -import { AlertTriangle, CalendarClock, CircleDashed } from "lucide-react"; +import { CalendarClock, CircleDashed } from "lucide-react"; import type { CurrentCycle } from "@/lib/analytics/compliance"; import { useTranslations } from "@/lib/i18n/context"; @@ -20,13 +20,15 @@ interface MedicationCycleStatusProps { * * The calm `on_track` "next dose in N days" phrasing is intentionally NOT * rendered here: the upcoming-dose timing already reads on the card's - * next-intake slot at the top, so repeating it would be a duplicate. Only the - * actionable due / overdue tiers (and the neutral no-closed-cycles note) earn - * this line. + * next-intake slot at the top, so repeating it would be a duplicate. The same + * reasoning retired the `missed` tier in v1.27.5 — an overdue dose already + * escalates on the next-intake value line (the destructive "Überfällig" / + * "Stark überfällig" row), so a second overdue line below the streak row + * doubled the signal. Only the `due` tier (and the neutral no-closed-cycles + * note) earns this line. * * Driven by `currentCycle.state` (`on_track` / `due` / `missed` / `none`) plus - * `hasClosedCycles`. Colour follows the same semantic ramp the status pill - * uses (warning / destructive) and pairs every tier with a Lucide glyph so + * `hasClosedCycles`. The due tier uses the warning tone + a Lucide glyph so * colour-blind users can disambiguate — WCAG 1.4.1 (Use of Color). It * complements the compliance number; it does not replace it. */ @@ -49,31 +51,17 @@ export function MedicationCycleStatus({ cycle }: MedicationCycleStatusProps) { ); } - // on_track — the next dose simply hasn't come round yet. The upcoming-dose - // timing already reads on the card's next-intake slot at the top, so a second - // "next dose in N days" line here is a duplicate. Render nothing for the - // on-track case; only the actionable due / overdue tiers earn this line. - if (cycle.state !== "missed" && cycle.state !== "due") return null; - - let tone: string; - let icon: React.ReactNode; - let label: string; - - if (cycle.state === "missed") { - tone = "text-destructive"; - icon =