diff --git a/next.config.ts b/next.config.ts index a279dd6e0..b4f889925 100644 --- a/next.config.ts +++ b/next.config.ts @@ -130,6 +130,16 @@ const nextConfig: NextConfig = { destination: "/settings/integrations", permanent: true, }, + // v1.18.0 (S4) — the standalone "Erinnerungen" hub at + // `/settings/reminders` was a link-only page that duplicated the + // canonical editors. Reminder TYPES now live in Notifications, each + // gated on its module. 301-redirect so bookmarks, the PWA's cached + // navigation, and the old cross-links keep resolving. + { + source: "/settings/reminders", + destination: "/settings/notifications", + permanent: true, + }, ]; }, async headers() { diff --git a/src/app/settings/[section]/page.tsx b/src/app/settings/[section]/page.tsx index 0d5e60a15..bc1193242 100644 --- a/src/app/settings/[section]/page.tsx +++ b/src/app/settings/[section]/page.tsx @@ -15,7 +15,6 @@ import { MedicationsSection } from "@/components/settings/medications-section"; import { ModulesSection } from "@/components/settings/modules-section"; import { MoodSection } from "@/components/settings/mood-section"; import { NotificationsSection } from "@/components/settings/notifications-section"; -import { RemindersSection } from "@/components/settings/reminders-section"; import { SectionPlaceholder } from "@/components/settings/section-placeholder"; // v1.18.0 (S3) — `sources` no longer has a standalone route; source priority // renders inside Settings → Integrations as the "Sources" sub-tab. @@ -30,7 +29,7 @@ import { SettingsShell } from "@/components/settings/settings-shell"; /** * Dynamic settings section route. Each of the `SETTINGS_SECTION_SLUGS` - * (15 today — 11 nav-visible sections plus the four routable-but-hidden + * (14 today — 10 nav-visible sections plus the four routable-but-hidden * Layout child editors) is pre-rendered at build via * `generateStaticParams()` so the URLs are * statically known to Next.js, while the `dynamicParams = false` flag below @@ -55,7 +54,6 @@ const SECTION_COMPONENTS: Record< ai: AiSection, integrations: IntegrationsSection, notifications: NotificationsSection, - reminders: RemindersSection, layout: LayoutSection, dashboard: DashboardSection, insights: InsightsSection, diff --git a/src/components/settings/__tests__/reminders-section.test.tsx b/src/components/settings/__tests__/reminders-section.test.tsx deleted file mode 100644 index 3305f95d1..000000000 --- a/src/components/settings/__tests__/reminders-section.test.tsx +++ /dev/null @@ -1,67 +0,0 @@ -/** - * v1.17.1 — the "Reminders & Notifications" hub. - * - * The hub is the single front door for every reminder concept. It groups the - * reminder CATEGORIES (medication / Vorsorge / mood / low-stock / coach) and - * links to the notification CHANNELS, with each link deep-linking into the - * canonical editor so nothing is rewritten — only gathered in one place. - */ -import { describe, expect, it } from "vitest"; -import { renderToStaticMarkup } from "react-dom/server"; - -import { I18nProvider } from "@/lib/i18n/context"; -import { RemindersSection } from "../reminders-section"; - -function render(locale: "en" | "de" = "en") { - return renderToStaticMarkup( - - - , - ); -} - -describe("", () => { - it("deep-links to every canonical reminder editor", () => { - const html = render(); - for (const href of [ - "/medications", - "/vorsorge", - "/settings/notifications#mood-reminder", - "/settings/notifications#low-stock", - "/settings/notifications#coach-nudge", - ]) { - expect(html).toContain(`href="${href}"`); - } - }); - - it("links to the notification channels screen (the how/where)", () => { - const html = render(); - expect(html).toContain('href="/settings/notifications"'); - expect(html).toContain('data-testid="reminders-link-channels"'); - }); - - it("renders a card for each reminder category", () => { - const html = render(); - for (const testId of [ - "reminders-link-medication", - "reminders-link-vorsorge", - "reminders-link-mood", - "reminders-link-low-stock", - "reminders-link-coach", - ]) { - expect(html).toContain(`data-testid="${testId}"`); - } - }); - - it("separates categories (what/when) from channels (how/where)", () => { - const html = render(); - expect(html).toContain("Reminders"); - expect(html).toContain("Delivery channels"); - }); - - it("resolves its copy in German too", () => { - const html = render("de"); - expect(html).toContain("Medikamenten-Erinnerungen"); - expect(html).toContain("Zustellkanäle"); - }); -}); diff --git a/src/components/settings/__tests__/settings-shell.test.tsx b/src/components/settings/__tests__/settings-shell.test.tsx index e9513b823..d83647fc4 100644 --- a/src/components/settings/__tests__/settings-shell.test.tsx +++ b/src/components/settings/__tests__/settings-shell.test.tsx @@ -62,8 +62,9 @@ describe("SETTINGS_SECTION_SLUGS", () => { // slugs (`dashboard`, `insights`, `medications`, `mood`) keep their // routes so deep links resolve, but they are reached through the // Layout hub instead of four standalone nav entries. - // v1.17.1 — `reminders` is the one "Reminders & Notifications" home and - // sits right after `notifications`. + // v1.18.0 (S4) — the standalone `reminders` hub is gone; reminder TYPES + // live in `notifications`, each gated on its module. `/settings/reminders` + // 301-redirects to `/settings/notifications`. // v1.18.0 — `modules` ("Was du trackst") sits right after `account` as // the single front door for enabling/disabling secondary domains. expect([...SETTINGS_SECTION_SLUGS]).toEqual([ @@ -71,7 +72,6 @@ describe("SETTINGS_SECTION_SLUGS", () => { "modules", "integrations", "notifications", - "reminders", "layout", "dashboard", "insights", diff --git a/src/components/settings/reminders-section.tsx b/src/components/settings/reminders-section.tsx deleted file mode 100644 index 698465751..000000000 --- a/src/components/settings/reminders-section.tsx +++ /dev/null @@ -1,176 +0,0 @@ -"use client"; - -import Link from "next/link"; -import { - Bell, - ChevronRight, - HeartPulse, - MessageCircle, - Package, - Pill, - Smile, - Stethoscope, - type LucideIcon, -} from "lucide-react"; - -import { cn } from "@/lib/utils"; -import { useTranslations } from "@/lib/i18n/context"; - -/** - * v1.17.1 — the one "Reminders & Notifications" home. - * - * Before this section, "what gets reminded and when" was scattered across - * three unrelated homes: medication reminders lived per-medication on the med - * cards, mood + low-stock + coach-nudge lived inside the Notifications channel - * screen, and the new Vorsorge (preventive-care) reminders had their own - * page. There was no single place that answered "was erinnert mich woran, - * wann, und worüber". - * - * This hub is the single front door. It draws a clean line between two - * genuinely different concepts (so the maintainer rule "never split the same - * concept across a page" still holds): - * - * - CHANNELS — the *how/where* a reminder is delivered (APNs / Telegram / - * ntfy / Web Push / Webhook / Email). These keep living on the - * Notifications channel screen; this hub links to them. - * - CATEGORIES — the *what/when*: medication, mood, Vorsorge, low-stock - * runway, and the proactive Coach nudge. Each keeps its own canonical - * editor and deep link; the hub just gathers them so the concept reads - * as one place. - * - * Consolidation by linking — every existing editor stays intact and - * deep-linkable; nothing here is a rewrite. - */ -interface ReminderLink { - href: string; - icon: LucideIcon; - titleKey: string; - descriptionKey: string; - /** External-to-settings link (opens a feature page, not a settings tab). */ - testId: string; -} - -const CHANNEL_LINKS: ReadonlyArray = [ - { - href: "/settings/notifications", - icon: Bell, - titleKey: "settings.sections.reminders.channels.title", - descriptionKey: "settings.sections.reminders.channels.description", - testId: "reminders-link-channels", - }, -]; - -const CATEGORY_LINKS: ReadonlyArray = [ - { - href: "/medications", - icon: Pill, - titleKey: "settings.sections.reminders.medication.title", - descriptionKey: "settings.sections.reminders.medication.description", - testId: "reminders-link-medication", - }, - { - href: "/vorsorge", - icon: Stethoscope, - titleKey: "settings.sections.reminders.vorsorge.title", - descriptionKey: "settings.sections.reminders.vorsorge.description", - testId: "reminders-link-vorsorge", - }, - { - href: "/settings/notifications#mood-reminder", - icon: Smile, - titleKey: "settings.sections.reminders.mood.title", - descriptionKey: "settings.sections.reminders.mood.description", - testId: "reminders-link-mood", - }, - { - href: "/settings/notifications#low-stock", - icon: Package, - titleKey: "settings.sections.reminders.lowStock.title", - descriptionKey: "settings.sections.reminders.lowStock.description", - testId: "reminders-link-low-stock", - }, - { - href: "/settings/notifications#coach-nudge", - icon: MessageCircle, - titleKey: "settings.sections.reminders.coach.title", - descriptionKey: "settings.sections.reminders.coach.description", - testId: "reminders-link-coach", - }, -]; - -function ReminderLinkCard({ link }: { link: ReminderLink }) { - const { t } = useTranslations(); - const Icon = link.icon; - return ( -
  • - -
  • - ); -} - -export function RemindersSection() { - const { t } = useTranslations(); - - return ( -
    -
    -

    - {t("settings.sections.reminders.title")} -

    -

    - {t("settings.sections.reminders.description")} -

    -
    - - {/* CATEGORIES — the what/when. */} -
    -
    -
    -
      - {CATEGORY_LINKS.map((link) => ( - - ))} -
    -
    - - {/* CHANNELS — the how/where. */} -
    -
    -
    -
      - {CHANNEL_LINKS.map((link) => ( - - ))} -
    -
    -
    - ); -} diff --git a/src/components/settings/section-placeholder.tsx b/src/components/settings/section-placeholder.tsx index 9bf8765b0..c09c9c459 100644 --- a/src/components/settings/section-placeholder.tsx +++ b/src/components/settings/section-placeholder.tsx @@ -12,7 +12,6 @@ */ import { - AlarmClock, Bell, Blocks, Download, @@ -39,7 +38,6 @@ const SLUG_ICON: Record = { modules: Blocks, integrations: Link2, notifications: Bell, - reminders: AlarmClock, layout: LayoutDashboard, dashboard: LayoutDashboard, insights: TrendingUp, diff --git a/src/components/settings/section-slugs.ts b/src/components/settings/section-slugs.ts index 96dc02271..5be9037d5 100644 --- a/src/components/settings/section-slugs.ts +++ b/src/components/settings/section-slugs.ts @@ -26,11 +26,11 @@ // `layout` entry instead of four scattered "arrange" entries, so the // concept reads as one place. The four editor slugs stay in this list so // their routes still resolve; they are simply not listed in the shell nav. -// v1.17.1 — `reminders` sits right after `notifications`: the one -// "Reminders & Notifications" home that gathers the scattered reminder -// categories (medication, mood, Vorsorge, low-stock, coach nudge) and links -// to the notification channels. The canonical editors keep their own routes; -// the hub is consolidation by linking. +// v1.18.0 (S4) — the standalone `reminders` hub is gone. It was a +// link-only page ("doppelt gemoppelt") that merely deep-linked into the +// canonical editors; reminder TYPES now live centrally in `notifications`, +// each row gated on its module. `/settings/reminders` 301-redirects to +// `/settings/notifications` (next.config.ts). export const SETTINGS_SECTION_SLUGS = [ "account", // v1.18.0 — `modules` ("Was du trackst") sits right after account: the @@ -38,7 +38,6 @@ export const SETTINGS_SECTION_SLUGS = [ "modules", "integrations", "notifications", - "reminders", "layout", "dashboard", "insights", diff --git a/src/components/settings/settings-shell.tsx b/src/components/settings/settings-shell.tsx index 12f28598a..22a9a7e22 100644 --- a/src/components/settings/settings-shell.tsx +++ b/src/components/settings/settings-shell.tsx @@ -18,7 +18,6 @@ import * as React from "react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { - AlarmClock, Bell, Blocks, Download, @@ -92,20 +91,14 @@ export const SETTINGS_SECTIONS: readonly SettingsSection[] = [ titleKey: "settings.sections.integrations.title", icon: Link2, }, + // v1.18.0 (S4) — "Benachrichtigungen" is now the single module-gated + // reminder-types home. The separate "Erinnerungen" hub (a link-only page) + // is gone; reminder TYPES live here, each row gated on its module. { slug: "notifications", titleKey: "settings.sections.notifications.title", icon: Bell, }, - // v1.17.1 — the one "Reminders & Notifications" home. Gathers the - // scattered reminder categories (medication / mood / Vorsorge / low-stock - // / coach nudge) and links to the notification channels. The canonical - // editors keep their own routes; this nav entry is the single front door. - { - slug: "reminders", - titleKey: "settings.sections.reminders.title", - icon: AlarmClock, - }, // v1.17.1 (F-2) — one "Layout & Personalization" nav entry replaces the // four scattered Dashboard / Insights / Medications / Mood "arrange" // entries. Those routes still resolve (deep links, page-header cogs, and