From cd1eaa1a4e67296990746b937fe03040c2436662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Mon, 1 Jun 2026 23:04:46 +0200 Subject: [PATCH] chore(targets): deprecate the targets page and drop it from the menu Target editing now lives inline on the insights pages, so the standalone targets page is no longer a navigation destination. Remove its sidebar and bottom-nav (overflow) entries and add a top deprecation banner that points the user at the insights pages and notes the page will be removed in a future release. The page stays routable: the /zielwerte to /targets redirect remains and the route still renders. Removal later is UI-only because the insights panel consumes the same targets read and threshold-override write. New deprecation strings land across all six locales. --- .planning/v1.8.6-targets-eol-tracker.md | 3 + messages/de.json | 4 + messages/en.json | 4 + messages/es.json | 4 + messages/fr.json | 4 + messages/it.json | 4 + messages/pl.json | 4 + src/app/targets/__tests__/page.test.tsx | 93 +++++++++++++++++++ src/app/targets/page.tsx | 33 +++++++ .../layout/__tests__/bottom-nav.test.tsx | 16 +++- .../layout/__tests__/sidebar-nav.test.tsx | 12 +++ src/components/layout/bottom-nav.tsx | 9 +- src/components/layout/sidebar-nav.tsx | 7 -- 13 files changed, 185 insertions(+), 12 deletions(-) create mode 100644 .planning/v1.8.6-targets-eol-tracker.md create mode 100644 src/app/targets/__tests__/page.test.tsx diff --git a/.planning/v1.8.6-targets-eol-tracker.md b/.planning/v1.8.6-targets-eol-tracker.md new file mode 100644 index 000000000..67786c6d1 --- /dev/null +++ b/.planning/v1.8.6-targets-eol-tracker.md @@ -0,0 +1,3 @@ +# Targets (Zielwerte) page EOL tracker + +- `/targets` deprecated in v1.8.6 — target-range editing moved inline into Insights (per-metric reference panel mounts ``); page dropped from nav, kept routable via the `/zielwerte`→`/targets` proxy redirect; remove candidate after ~10 releases (UI-only removal — `GET /api/insights/targets`, `PUT/DELETE /api/user/thresholds`, and `src/components/targets/*` all stay because Insights consumes them). diff --git a/messages/de.json b/messages/de.json index 0243c0b60..b7043af03 100644 --- a/messages/de.json +++ b/messages/de.json @@ -4001,6 +4001,10 @@ "targets": { "title": "Zielwerte", "introText": "Deine aktuellen Werte im Vergleich zu empfohlenen Zielbereichen. Quellen der Leitlinien sind auf jeder Karte verlinkt.", + "deprecation": { + "title": "Diese Seite wird eingestellt", + "body": "Zielbereiche werden jetzt direkt in den Insights bearbeitet, im Referenzbereich jeder Metrik. Diese Seite bleibt vorerst erreichbar und wird in einem künftigen Release entfernt." + }, "bmi": "BMI", "average30d": "30-Tage-Schnitt:", "consistency": { diff --git a/messages/en.json b/messages/en.json index 57ba8ed86..ab4fb72b3 100644 --- a/messages/en.json +++ b/messages/en.json @@ -4001,6 +4001,10 @@ "targets": { "title": "Targets", "introText": "Your current values compared to recommended target ranges. Guideline sources are linked on each card.", + "deprecation": { + "title": "This page is being retired", + "body": "Target ranges are now edited directly from the Insights pages, on each metric's reference panel. This page stays available for now and will be removed in a future release." + }, "bmi": "BMI", "average30d": "30-day average:", "consistency": { diff --git a/messages/es.json b/messages/es.json index 2fc29b772..7ae81e64d 100644 --- a/messages/es.json +++ b/messages/es.json @@ -4001,6 +4001,10 @@ "targets": { "title": "Valores objetivo", "introText": "Tus valores actuales frente a los rangos objetivo recomendados. Las fuentes de las guías clínicas están enlazadas en cada tarjeta.", + "deprecation": { + "title": "Esta página se va a retirar", + "body": "Los rangos objetivo ahora se editan directamente desde las páginas de Insights, en el panel de referencia de cada métrica. Esta página sigue disponible por ahora y se eliminará en una versión futura." + }, "bmi": "IMC", "average30d": "Media 30 días:", "consistency": { diff --git a/messages/fr.json b/messages/fr.json index 91e3234ae..30635a52f 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -4001,6 +4001,10 @@ "targets": { "title": "Valeurs cibles", "introText": "Tes valeurs actuelles face aux plages cibles recommandées. Les sources des recommandations sont liées sur chaque carte.", + "deprecation": { + "title": "Cette page va être retirée", + "body": "Les plages cibles se modifient désormais directement depuis les pages Insights, sur le panneau de référence de chaque métrique. Cette page reste accessible pour l'instant et sera supprimée dans une prochaine version." + }, "bmi": "IMC", "average30d": "Moy. 30 jours :", "consistency": { diff --git a/messages/it.json b/messages/it.json index a16f384dd..dba26913b 100644 --- a/messages/it.json +++ b/messages/it.json @@ -4001,6 +4001,10 @@ "targets": { "title": "Valori obiettivo", "introText": "I tuoi valori attuali rispetto agli intervalli obiettivo consigliati. Le fonti delle linee guida sono collegate su ogni card.", + "deprecation": { + "title": "Questa pagina verrà rimossa", + "body": "Gli intervalli obiettivo ora si modificano direttamente dalle pagine Insights, nel pannello di riferimento di ogni metrica. Questa pagina resta disponibile per ora e verrà rimossa in una versione futura." + }, "bmi": "IMC", "average30d": "Media 30 giorni:", "consistency": { diff --git a/messages/pl.json b/messages/pl.json index b50585323..b5cd296ad 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -4001,6 +4001,10 @@ "targets": { "title": "Wartości docelowe", "introText": "Twoje aktualne wartości na tle zalecanych zakresów docelowych. Źródła wytycznych podlinkowane na każdej karcie.", + "deprecation": { + "title": "Ta strona zostanie wycofana", + "body": "Zakresy docelowe edytuje się teraz bezpośrednio na stronach Insights, w panelu referencyjnym każdej metryki. Ta strona pozostaje na razie dostępna i zostanie usunięta w przyszłej wersji." + }, "bmi": "BMI", "average30d": "Średnia 30-dniowa:", "consistency": { diff --git a/src/app/targets/__tests__/page.test.tsx b/src/app/targets/__tests__/page.test.tsx new file mode 100644 index 000000000..1fcbe607e --- /dev/null +++ b/src/app/targets/__tests__/page.test.tsx @@ -0,0 +1,93 @@ +import { describe, it, expect, vi } from "vitest"; +import { renderToStaticMarkup } from "react-dom/server"; + +import { I18nProvider } from "@/lib/i18n/context"; + +/** + * v1.8.6 — `/targets` deprecation banner. + * + * The Targets (Zielwerte) page is deprecated: target-range editing moved + * inline into the Insights category pages. The page stays routable but + * carries a top banner telling the user where editing lives now and that + * the page will be removed in a future release. This SSR test pins the + * banner copy + structure. + * + * The page leans on `useAuth`, two `useQuery` reads, `useFeatureFlags` + * and `useCoachHandoff`; all are stubbed so the render reaches the + * banner without standing up an App-Router runtime or a QueryClient. + */ + +vi.mock("@/hooks/use-auth", () => ({ + useAuth: () => ({ + isAuthenticated: true, + user: { id: "u1", disableCoach: false }, + }), +})); + +// The page issues two `useQuery` reads (targets payload + provider +// chain). Drive both off the same stub: the first call resolves the +// targets payload, the rest return a null provider chain. +let queryCall = 0; +const TARGETS_PAYLOAD = { + targets: [], + bpDiastolic: { current: null, average30: null, range: null }, + profile: { heightCm: 175, age: 40, gender: "male", glucoseUnit: "mg/dL" }, +}; +vi.mock("@tanstack/react-query", () => ({ + useQuery: () => { + queryCall += 1; + if (queryCall === 1) { + return { data: TARGETS_PAYLOAD, isLoading: false }; + } + return { data: null, isLoading: false }; + }, +})); + +// Turn Coach off so the page never mounts the SSE drawer machinery. +vi.mock("@/hooks/use-feature-flags", () => ({ + useFeatureFlags: () => ({ + enabled: false, + coach: false, + briefing: false, + insightStatus: false, + correlations: false, + healthScoreExplainer: false, + }), +})); + +vi.mock("@/hooks/use-coach-handoff", () => ({ + useCoachHandoff: () => ({ + coachOpen: false, + setCoachOpen: vi.fn(), + coachPrefill: null, + coachScope: null, + askCoach: vi.fn(), + }), +})); + +const { default: TargetsPage } = await import("../page"); + +function render(locale: "en" | "de" = "en") { + queryCall = 0; + return renderToStaticMarkup( + + + , + ); +} + +describe(" deprecation banner", () => { + it("renders the deprecation banner with title + body", () => { + const html = render(); + expect(html).toContain('data-slot="targets-deprecation"'); + expect(html).toContain("This page is being retired"); + expect(html).toContain("Insights"); + // Reuses the warning-card visual pattern. + expect(html).toContain("border-warning"); + }); + + it("localises the banner copy", () => { + const html = render("de"); + expect(html).toContain("Diese Seite wird eingestellt"); + }); +}); diff --git a/src/app/targets/page.tsx b/src/app/targets/page.tsx index 9d6a9e49a..e09739f5c 100644 --- a/src/app/targets/page.tsx +++ b/src/app/targets/page.tsx @@ -1,5 +1,21 @@ "use client"; +// DEPRECATED since v1.8.6. Target-range editing moved inline into the +// Insights category pages (the per-metric reference panel now mounts the +// same ), so this standalone page no longer appears in +// the navigation. It stays routable behind the `/zielwerte`→`/targets` +// proxy redirect and is a remove candidate after ~10 releases. +// +// What stays in place because Insights consumes the same API: +// • GET /api/insights/targets — the read powering this page is the +// same payload the Insights panel reads (`queryKeys.insightsTargets()`). +// • PUT/DELETE /api/user/thresholds — the threshold override write the +// inline calls. +// • src/components/targets/* — TargetCard, TargetEditSheet, RangeBar, +// ConsistencyStrip, TargetStatusPill, source-link helper are all +// reused by the inline Insights panel. +// Removing the page later is a UI-only change; no data or API moves. + import { useMemo } from "react"; import { useQuery } from "@tanstack/react-query"; import { AlertCircle, Loader2 } from "lucide-react"; @@ -200,6 +216,23 @@ export default function TargetsPage() {

{t("targets.introText")}

+ {/* v1.8.6 — deprecation banner. Target editing moved inline into + the Insights category pages; this page stays reachable but will + be removed in a future release. */} + + + +
+

+ {t("targets.deprecation.title")} +

+

+ {t("targets.deprecation.body")} +

+
+
+
+ {/* Profile incomplete hint */} {profileIncomplete && ( diff --git a/src/components/layout/__tests__/bottom-nav.test.tsx b/src/components/layout/__tests__/bottom-nav.test.tsx index 4a7985167..b161d41c3 100644 --- a/src/components/layout/__tests__/bottom-nav.test.tsx +++ b/src/components/layout/__tests__/bottom-nav.test.tsx @@ -5,9 +5,12 @@ * - exactly five primary links + one "More" button render in the strip * - the More button is keyboard-reachable as a `