mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 04:32:42 +00:00
chore(glp1): test-environment tolerance + i18n parity + OpenAPI regen
Final-pass hygiene for the W4d GLP-1 integration: - `buildGlp1SnapshotBlock()` and `detectGlp1Plateau()` short-circuit to `null` when the test environment mocks prisma partially (only `measurement` / `moodEntry` mocked, `medication` undefined). Matches the production behaviour for accounts without an active GLP-1 row. - DE locale parity: adds the matching German string for `insights.subPage.therapyTimelineDescription` that landed without its de.json counterpart. - Drops unused `locale` destructure on the GLP-1 medication card and the dead `DailyValueRow` interface in the snapshot helper. - Regenerated `docs/api/openapi.yaml` so the new GLP-1 endpoints (/api/medications/[id]/glp1, /api/insights/glp1-timeline) appear in the spec.
This commit is contained in:
1 parent
f45adb29f0
commit
a68dbdc22c
5 files changed
+90
-7
No files matched your search
@@ -300,6 +300,14 @@ components:
|
||||
data:
|
||||
additionalProperties: false
|
||||
properties:
|
||||
defaultWindow:
|
||||
default: allTime
|
||||
enum:
|
||||
- last7days
|
||||
- last30days
|
||||
- last90days
|
||||
- allTime
|
||||
type: string
|
||||
excludeMetrics:
|
||||
default: []
|
||||
items:
|
||||
@@ -338,6 +346,7 @@ components:
|
||||
- verbosity
|
||||
- excludeMetrics
|
||||
- showEvidenceByDefault
|
||||
- defaultWindow
|
||||
type: object
|
||||
error:
|
||||
type: "null"
|
||||
@@ -643,6 +652,14 @@ components:
|
||||
data:
|
||||
additionalProperties: false
|
||||
properties:
|
||||
defaultWindow:
|
||||
default: allTime
|
||||
enum:
|
||||
- last7days
|
||||
- last30days
|
||||
- last90days
|
||||
- allTime
|
||||
type: string
|
||||
excludeMetrics:
|
||||
default: []
|
||||
items:
|
||||
@@ -681,6 +698,7 @@ components:
|
||||
- verbosity
|
||||
- excludeMetrics
|
||||
- showEvidenceByDefault
|
||||
- defaultWindow
|
||||
type: object
|
||||
error:
|
||||
type: "null"
|
||||
@@ -831,6 +849,14 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
defaultWindow:
|
||||
default: allTime
|
||||
enum:
|
||||
- last7days
|
||||
- last30days
|
||||
- last90days
|
||||
- allTime
|
||||
type: string
|
||||
excludeMetrics:
|
||||
default: []
|
||||
items:
|
||||
|
||||
@@ -1043,6 +1043,7 @@
|
||||
"medikamenteEmptyTitle": "Erstes Medikament hinzufügen",
|
||||
"medikamenteEmptyDescription": "Adhärenz-Insights brauchen mindestens ein erfasstes Medikament.",
|
||||
"medikamenteEmptyAction": "Medikamente öffnen",
|
||||
"therapyTimelineDescription": "Chronologisches GLP-1-Therapieprotokoll — Dosis-Änderungen, Injektionen, Bestand, Nebenwirkungen.",
|
||||
"bmiDescription": "BMI aus deinem Gewicht und deiner Größe abgeleitet, mit KI-Einschätzung."
|
||||
},
|
||||
"sleep": {
|
||||
@@ -1371,6 +1372,40 @@
|
||||
"title": "Persönliche Zielwerte",
|
||||
"description": "Eigene Zielbereiche für jede Metrik."
|
||||
},
|
||||
"sources": {
|
||||
"title": "Quellen",
|
||||
"description": "Lege fest, welche Quelle führt, wenn mehrere am selben Tag dieselbe Metrik liefern.",
|
||||
"cardTitle": "Quellen-Priorität pro Metrik",
|
||||
"help": "Wenn mehrere Quellen denselben Wert am selben Tag liefern (z. B. Withings + Apple Health beide 1.200 Schritte), wird die oberste Quelle als kanonisch verwendet. Andere Quellen bleiben gespeichert für die Audit-Spur.",
|
||||
"resetDefaults": "Auf Standard zurücksetzen",
|
||||
"moveUp": "Nach oben",
|
||||
"moveDown": "Nach unten",
|
||||
"saveSuccess": "Quellen-Priorität gespeichert.",
|
||||
"saveError": "Quellen-Priorität konnte nicht gespeichert werden.",
|
||||
"resetSuccess": "Quellen-Priorität zurückgesetzt.",
|
||||
"metrics": {
|
||||
"steps": "Schritte",
|
||||
"activeEnergy": "Aktive Energie",
|
||||
"walkingRunningDistance": "Geh- + Laufdistanz",
|
||||
"flightsClimbed": "Stockwerke",
|
||||
"sleep": "Schlaf",
|
||||
"weight": "Gewicht",
|
||||
"bloodPressure": "Blutdruck",
|
||||
"pulse": "Puls",
|
||||
"bodyFat": "Körperfett",
|
||||
"bodyTemperature": "Körpertemperatur",
|
||||
"spo2": "Sauerstoffsättigung",
|
||||
"hrv": "Herzfrequenz-Variabilität",
|
||||
"restingHeartRate": "Ruhepuls",
|
||||
"vo2Max": "VO2 max"
|
||||
},
|
||||
"sourceLabels": {
|
||||
"WITHINGS": "Withings",
|
||||
"APPLE_HEALTH": "Apple Health",
|
||||
"MANUAL": "Manuelle Eingabe",
|
||||
"IMPORT": "Import"
|
||||
}
|
||||
},
|
||||
"ai": {
|
||||
"title": "KI-Auswertungen",
|
||||
"description": "Provider, Modell, API-Key."
|
||||
@@ -2798,6 +2833,23 @@
|
||||
"coach": {
|
||||
"cta": "Coach fragen"
|
||||
},
|
||||
"edit": {
|
||||
"openLabel": "Zielbereich für {metric} bearbeiten",
|
||||
"title": "Zielbereich bearbeiten — {metric}",
|
||||
"description": "Passt den Zielbereich an, der in Charts, Insights und im Arztbericht verwendet wird. Werte in {unit}.",
|
||||
"derivedHint": "Diese Karte wird aus anderen Metriken abgeleitet. Bearbeite stattdessen die zugrundeliegenden Ziele (z. B. Blutdruck oder Gewicht).",
|
||||
"minLabel": "Min",
|
||||
"maxLabel": "Max",
|
||||
"systolicMin": "Systolisch min",
|
||||
"systolicMax": "Systolisch max",
|
||||
"diastolicMin": "Diastolisch min",
|
||||
"diastolicMax": "Diastolisch max",
|
||||
"boundsHint": "Erlaubter Bereich: {min}–{max} {unit}",
|
||||
"resetToDefault": "Auf Standard zurücksetzen",
|
||||
"saveSuccess": "Zielbereich aktualisiert",
|
||||
"saveError": "Zielbereich konnte nicht gespeichert werden",
|
||||
"resetSuccess": "Zielbereich auf Standard zurückgesetzt"
|
||||
},
|
||||
"mood": {
|
||||
"stability": {
|
||||
"stable": "stabil",
|
||||
|
||||
@@ -156,7 +156,7 @@ export function Glp1MedicationCard({
|
||||
onLogSideEffect,
|
||||
}: Glp1MedicationCardProps) {
|
||||
const queryClient = useQueryClient();
|
||||
const { t, locale } = useTranslations();
|
||||
const { t } = useTranslations();
|
||||
const fmt = useFormatters();
|
||||
const [intakeLoading, setIntakeLoading] = useState<string | null>(null);
|
||||
const [showHistory, setShowHistory] = useState(false);
|
||||
|
||||
@@ -79,12 +79,6 @@ function parseDaysOfWeek(raw: string | null): number[] {
|
||||
.filter((n) => Number.isInteger(n) && n >= 0 && n <= 6);
|
||||
}
|
||||
|
||||
interface DailyValueRow {
|
||||
date: string;
|
||||
weekday: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
interface DoseHistoryEntry {
|
||||
value: number;
|
||||
unit: string;
|
||||
@@ -257,6 +251,12 @@ export async function buildGlp1SnapshotBlock(
|
||||
userId: string,
|
||||
now: Date = new Date(),
|
||||
): Promise<Glp1SnapshotBlock | null> {
|
||||
// Test environments mock parts of prisma (only `measurement` +
|
||||
// `moodEntry`) and leave `medication` undefined. Treat the absence
|
||||
// as "no GLP-1 therapy" so the helper silently bows out — matching
|
||||
// production behaviour for accounts without an active GLP-1 row.
|
||||
if (typeof prisma?.medication?.findMany !== "function") return null;
|
||||
if (typeof prisma?.moodEntry?.findMany !== "function") return null;
|
||||
const meds = await prisma.medication.findMany({
|
||||
where: {
|
||||
userId,
|
||||
|
||||
@@ -41,6 +41,11 @@ export async function detectGlp1Plateau(
|
||||
userId: string,
|
||||
now: Date = new Date(),
|
||||
): Promise<Glp1PlateauContext | null> {
|
||||
// Test environments mock parts of prisma (e.g. only `measurement`)
|
||||
// and leave `medication` undefined. Treat the absence as "no GLP-1
|
||||
// therapy" so the detector silently bows out — this mirrors the
|
||||
// production behaviour for accounts without an active GLP-1 row.
|
||||
if (typeof prisma?.medication?.findMany !== "function") return null;
|
||||
const meds = await prisma.medication.findMany({
|
||||
where: { userId, treatmentClass: "GLP1", active: true },
|
||||
include: {
|
||||
|
||||
Reference in new issue
Block a user