feat(insights): state Rest Mode on the health-score card

During an active illness episode the server suppresses (never penalises)
the health score, but the card gave no sign of it, so a held number read
as a silent decline. The card now carries an explicit 'paused during
illness — not being judged today' line when Rest Mode is active, driven
from the value-free annotation already on the analytics payload. Adds
insights.healthScore.restModePaused across all six locales.
This commit is contained in:
Marc-André Bombeck committed 2026-06-18 19:11:58 +02:00
1 parent cd816607e4
commit ef1fbb8396
8 files changed
+39 -1

No files matched your search

+1
View File
@@ -1966,6 +1966,7 @@
"progressAria": "Gesundheitsscore-Fortschritt",
"deltaVsLastWeek": "{delta} im Vergleich zur Vorwoche",
"deltaUnavailable": "Noch keine Historie — schau nächste Woche wieder vorbei.",
"restModePaused": "Während einer Krankheitsphase pausiert — dein Score wird heute nicht bewertet.",
"componentBp": "Blutdruck",
"componentWeight": "Gewicht",
"componentMood": "Stimmung",
+1
View File
@@ -1966,6 +1966,7 @@
"progressAria": "Health Score progress",
"deltaVsLastWeek": "{delta} vs last week",
"deltaUnavailable": "No history yet — check back next week.",
"restModePaused": "Paused during illness — your score isn't being judged today.",
"componentBp": "BP",
"componentWeight": "Weight",
"componentMood": "Mood",
+1
View File
@@ -1966,6 +1966,7 @@
"progressAria": "Progreso de la puntuación de salud",
"deltaVsLastWeek": "{delta} respecto a la semana anterior",
"deltaUnavailable": "Aún no hay historial — vuelve la semana que viene.",
"restModePaused": "En pausa durante la enfermedad — hoy tu puntuación no se evalúa.",
"componentBp": "PA",
"componentWeight": "Peso",
"componentMood": "Estado de ánimo",
+1
View File
@@ -1966,6 +1966,7 @@
"progressAria": "Progression du score de santé",
"deltaVsLastWeek": "{delta} par rapport à la semaine précédente",
"deltaUnavailable": "Pas encore d’historique — reviens la semaine prochaine.",
"restModePaused": "En pause pendant la maladie — ton score n'est pas évalué aujourd'hui.",
"componentBp": "TA",
"componentWeight": "Poids",
"componentMood": "Humeur",
+1
View File
@@ -1966,6 +1966,7 @@
"progressAria": "Avanzamento del punteggio di salute",
"deltaVsLastWeek": "{delta} rispetto alla settimana scorsa",
"deltaUnavailable": "Ancora nessuno storico — ripassa la prossima settimana.",
"restModePaused": "In pausa durante la malattia — oggi il tuo punteggio non viene valutato.",
"componentBp": "PA",
"componentWeight": "Peso",
"componentMood": "Umore",
+1
View File
@@ -1966,6 +1966,7 @@
"progressAria": "Postęp wyniku zdrowia",
"deltaVsLastWeek": "{delta} w porównaniu z ubiegłym tygodniem",
"deltaUnavailable": "Brak historii — zajrzyj w przyszłym tygodniu.",
"restModePaused": "Wstrzymane podczas choroby — Twój wynik nie jest dziś oceniany.",
"componentBp": "RR",
"componentWeight": "Waga",
"componentMood": "Nastrój",
+26 -1
View File
@@ -1,7 +1,7 @@
"use client";
import { useId, useMemo, useState } from "react";
import { ArrowDown, ArrowUp, ChevronDown, Minus } from "lucide-react";
import { ArrowDown, ArrowUp, ChevronDown, Minus, Moon } from "lucide-react";
import { useTranslations } from "@/lib/i18n/context";
import { cn } from "@/lib/utils";
import { HealthScoreDeltaExplainer } from "./health-score-delta-explainer";
@@ -87,6 +87,15 @@ export interface HealthScoreCardProps {
* four-row layout for the common (mood-enabled) case.
*/
moodEnabled?: boolean;
/**
* v1.18.6 — Rest Mode annotation. When an illness episode is active the
* server suppresses (never penalises) the score; the card itself then
* carries an explicit "paused during illness — not being judged today"
* line so a frozen/held number reads as intentional rather than as a
* silent drop. Value-free: the card only needs to know that it is
* active, not the episode details. Default off (the common case).
*/
restModeActive?: boolean;
}
type ComponentKey = keyof HealthScoreCardProps["components"];
@@ -174,6 +183,7 @@ export function HealthScoreCard({
onAskCoach: _onAskCoach,
initiallyExpanded = false,
moodEnabled = true,
restModeActive = false,
}: HealthScoreCardProps) {
const { t, locale } = useTranslations();
// The asOf timestamps render under the source pill as a tooltip
@@ -404,6 +414,21 @@ export function HealthScoreCard({
)}
</p>
{/* v1.18.6 — Rest Mode legibility. While an illness episode is
active the server suppresses (never penalises) the score, so
the card states plainly that the number is paused and not being
judged today. Without this the held score reads as a silent
decline. */}
{restModeActive && (
<p
data-slot="health-score-card-rest-mode"
className="text-muted-foreground inline-flex items-start gap-1.5 text-[11px] leading-relaxed"
>
<Moon className="mt-0.5 size-3 shrink-0" aria-hidden="true" />
<span>{t("insights.healthScore.restModePaused")}</span>
</p>
)}
<ul
data-slot="health-score-card-components"
// v1.8.5 W4a — the always-visible "Zusammensetzung" breakdown is
+7
View File
@@ -90,6 +90,12 @@ interface HeroStripProps {
band: HealthScoreCardProps["band"];
components: HealthScoreCardProps["components"];
delta: HealthScoreCardProps["delta"];
/**
* v1.18.6 — value-free Rest Mode annotation off the analytics
* payload. When present + active the score card states it is paused
* during illness (suppressed, not penalised).
*/
restMode?: { active: boolean } | null;
} | null;
/**
* v1.16.8 — true while the analytics payload that carries
@@ -346,6 +352,7 @@ export function HeroStrip({
components={healthScore.components}
delta={healthScore.delta}
moodEnabled={moodEnabled}
restModeActive={healthScore.restMode?.active ?? false}
onAskCoach={
// v1.4.37 W5 — short-circuit the prop drilling even
// though `HealthScoreCard` retired its inline button in