diff --git a/messages/de.json b/messages/de.json index a39f15431..aaa5c0714 100644 --- a/messages/de.json +++ b/messages/de.json @@ -6422,6 +6422,10 @@ "dashboard": { "empty": "Keine anstehenden Vorsorge-Erinnerungen.", "openLink": "Vorsorge öffnen" + }, + "showMeasurements": "Messergebnisse anzeigen", + "trendStrip": { + "label": "Verlauf der letzten 7 Tage" } }, "moduleList": { diff --git a/messages/en.json b/messages/en.json index 6c8e829fb..7eb1d9c5b 100644 --- a/messages/en.json +++ b/messages/en.json @@ -6422,6 +6422,10 @@ "dashboard": { "empty": "No upcoming preventive-care reminders.", "openLink": "Open preventive care" + }, + "showMeasurements": "Show measurements", + "trendStrip": { + "label": "Last 7 days" } }, "moduleList": { diff --git a/messages/es.json b/messages/es.json index 31455b452..63c332c30 100644 --- a/messages/es.json +++ b/messages/es.json @@ -6422,6 +6422,10 @@ "dashboard": { "empty": "No hay recordatorios de prevención próximos.", "openLink": "Abrir prevención" + }, + "showMeasurements": "Ver mediciones", + "trendStrip": { + "label": "Últimos 7 días" } }, "moduleList": { diff --git a/messages/fr.json b/messages/fr.json index 0a88a045f..5758907bf 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -6422,6 +6422,10 @@ "dashboard": { "empty": "Aucun rappel de prévention à venir.", "openLink": "Ouvrir la prévention" + }, + "showMeasurements": "Afficher les mesures", + "trendStrip": { + "label": "7 derniers jours" } }, "moduleList": { diff --git a/messages/it.json b/messages/it.json index dfd76eb32..688f8c7f9 100644 --- a/messages/it.json +++ b/messages/it.json @@ -6422,6 +6422,10 @@ "dashboard": { "empty": "Nessun promemoria di prevenzione in arrivo.", "openLink": "Apri prevenzione" + }, + "showMeasurements": "Mostra le misurazioni", + "trendStrip": { + "label": "Ultimi 7 giorni" } }, "moduleList": { diff --git a/messages/pl.json b/messages/pl.json index b6d2457e5..05addbcd7 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -6422,6 +6422,10 @@ "dashboard": { "empty": "Brak nadchodzących przypomnień profilaktycznych.", "openLink": "Otwórz profilaktykę" + }, + "showMeasurements": "Pokaż pomiary", + "trendStrip": { + "label": "Ostatnie 7 dni" } }, "moduleList": { diff --git a/src/app/measurements/page.tsx b/src/app/measurements/page.tsx index 57fc95791..8411579ba 100644 --- a/src/app/measurements/page.tsx +++ b/src/app/measurements/page.tsx @@ -10,6 +10,7 @@ import { resolveAddToken, } from "@/components/measurements/measurement-form"; import { MeasurementList } from "@/components/measurements/measurement-list"; +import { MEASUREMENT_TYPE_LABEL_KEYS } from "@/components/measurements/measurement-list-meta"; import { Button } from "@/components/ui/button"; import { PullToRefreshIndicator } from "@/components/ui/pull-to-refresh-indicator"; import { ResponsiveSheet } from "@/components/ui/responsive-sheet"; @@ -41,6 +42,18 @@ export default function MeasurementsPage() { // effect, so that path stays render-driven. const addParam = searchParams.get("add"); const initialAdd = addParam ? resolveAddToken(addParam) : null; + // v1.18.7 (Wave E) — a `?type=` deep link (e.g. the + // Vorsorge card's "Show measurements") seeds the list's type filter on + // first paint. Captured once via a lazy initializer so the value is + // stable even after the effect below strips the query string; an unknown + // token is dropped (validated against the canonical type-label map), so a + // stale link never traps the user on a broken filter. + const typeParam = searchParams.get("type"); + const [initialType] = useState(() => + typeParam && typeParam in MEASUREMENT_TYPE_LABEL_KEYS + ? typeParam + : undefined, + ); const [dialogOpen, setDialogOpen] = useState(() => initialAdd != null); const [defaultType, setDefaultType] = useState( () => initialAdd ?? undefined, @@ -82,11 +95,14 @@ export default function MeasurementsPage() { } // Drop the query string so the back-button leaves the user on - // `/measurements` rather than re-opening the dialog. Effect-driven - // (client-only) because `router.replace` is not callable during SSR. + // `/measurements` rather than re-opening the dialog (or re-seeding the + // type filter). The type filter is already seeded into the list's own + // state via `initialType`, so stripping the param doesn't lose it. + // Effect-driven (client-only) because `router.replace` is not callable + // during SSR. useEffect(() => { - if (addParam) router.replace("/measurements"); - }, [addParam, router]); + if (addParam || typeParam) router.replace("/measurements"); + }, [addParam, typeParam, router]); useEffect(() => { if (!isLoading && !isAuthenticated) { @@ -157,7 +173,10 @@ export default function MeasurementsPage() { /> - setDialogOpen(true)} /> + setDialogOpen(true)} + initialType={initialType} + /> ); } diff --git a/src/components/measurement-reminders/__tests__/vorsorge-section.test.tsx b/src/components/measurement-reminders/__tests__/vorsorge-section.test.tsx index 748b7999e..d9ad228cd 100644 --- a/src/components/measurement-reminders/__tests__/vorsorge-section.test.tsx +++ b/src/components/measurement-reminders/__tests__/vorsorge-section.test.tsx @@ -1,5 +1,6 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { renderToStaticMarkup } from "react-dom/server"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { I18nProvider } from "@/lib/i18n/context"; import type { MeasurementReminder } from "@/hooks/use-measurement-reminders"; @@ -27,8 +28,16 @@ vi.mock("@/hooks/use-measurement-reminders", () => ({ import { VorsorgeSection } from "../vorsorge-section"; function render(node: React.ReactNode) { + // v1.18.7 (Wave E) — a measurement-linked card now mounts the 7-day + // trend strip, which reads via TanStack Query; wrap in a client so the + // static-markup render resolves (the query stays idle on the server). + const queryClient = new QueryClient({ + defaultOptions: { queries: { retry: false } }, + }); return renderToStaticMarkup( - {node}, + + {node} + , ); } diff --git a/src/components/measurement-reminders/vorsorge-dashboard-card.tsx b/src/components/measurement-reminders/vorsorge-dashboard-card.tsx index 817439aab..0c03f88ef 100644 --- a/src/components/measurement-reminders/vorsorge-dashboard-card.tsx +++ b/src/components/measurement-reminders/vorsorge-dashboard-card.tsx @@ -25,6 +25,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { ResponsiveSheet } from "@/components/ui/responsive-sheet"; import { Skeleton } from "@/components/ui/skeleton"; import { MeasurementForm } from "@/components/measurements/measurement-form"; +import { VorsorgeTrendStrip } from "@/components/measurement-reminders/vorsorge-trend-strip"; import { useMeasurementReminders, useMeasurementReminderMutations, @@ -122,13 +123,19 @@ export function VorsorgeDashboardCard() { key={reminder.id} className="flex items-center justify-between gap-3 rounded-md border p-2.5" > -
+

{resolveLabel(reminder, t)}

{t(`measurementReminders.${due.key}`, { days: due.days })} + {/* v1.18.7 (Wave E) — discreet 7-day strip under the + metric context; renders nothing for a free-text + reminder or a too-thin window. */} +