feat(insights): adopt the canonical per-metric detail template and terminology

Bring the web per-metric Insights detail pages to structural parity with
the canonical metric template: a single top-to-bottom spine, every block
self-suppressing when its data is absent.

New spine (above the chart): header (title + target gear + Coach circle)
→ intro → primary tile → Letzte Messung → stat strip; then the chart,
the range controls + period delta, the per-metric correlation card, and
the Einschätzung assessment last.

- Add the primary tile (headline value + 30-day average + an In-range
  bar shown only when the metric carries a per-metric in-target pct).
  Blood pressure keeps its richer target panel as its primary tile.
- Add the Letzte Messung card (labeled heading + last-reading date),
  reading the last-seen timestamp the slim analytics slice already
  carries — no extra fetch.
- Relocate the owning correlation onto its metric page: weight × weekday
  on Weight, mood × pulse on Pulse. The card reads the correlations
  already on the analytics payload and self-gates below the surfacing
  bar; it is now the canonical home for those relationships.
- Move the headline value, 30-day average and in-target share out of the
  target reference panel so each figure appears in exactly one place;
  the panel stays the band reference (range, status, positional bar,
  consistency strip, source). Blood pressure keeps its stitched S/D
  30-day average inline.
- Order the Einschätzung last on every page.

Terminology: adopt the canonical labels — rename the mood patterns
surface to "Was auffällt", pluralise the deviation-count card to
"Signale des Tages", and align the settings section labels to
"Über diese App" and "Quellen-Priorität". New In-range /
30-day-average / Letzte Messung strings land in all six locales.

Web charts are unchanged — Recharts and the existing chart tokens
stay; the iOS monochrome chart doctrine is not applied.
This commit is contained in:
Marc-André Bombeck committed 2026-06-04 23:03:05 +02:00
1 parent 6ad0a8a5cf
commit d5eb887757
19 files changed
+564 -78

No files matched your search

+11
View File
@@ -41,6 +41,17 @@ import type { CorrelationResult } from "@/lib/insights/correlations";
export interface SubPageAnalyticsData {
/** `Record<MeasurementType, DataSummary>` — sentinel value for "not loaded yet" is `undefined`. */
summaries: Record<string, DataSummary>;
/**
* v1.12.0 — per-type freshness map, also carried on the slim
* `?slice=summaries` branch (`computeSummariesSlice`). The metric
* detail page's "Letzte Messung" card reads
* `lastSeenByType[type]?.lastSeenAt` to caption when the latest
* reading landed, without paying for the thick analytics slice.
*/
lastSeenByType?: Record<
string,
{ lastSeenAt: string; daysAgo: number } | null
>;
}
/**