mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
Merge v1.25.3: channels into notifications + Darstellung appearance hub
This commit is contained in:
commit
7eca388f56
18 files changed
+347
-188
No files matched your search
+26
-13
@@ -4036,15 +4036,17 @@
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Benachrichtigungen",
|
||||
"description": "Alle Erinnerungen an einem Ort — was wann erinnert wird. Die Zustellkanäle liegen unter Integrationen.",
|
||||
"channelsHint": "Telegram, ntfy, Web-Push, Webhook und E-Mail richtest du jetzt unter",
|
||||
"channelsHintLink": "Integrationen → Kanäle",
|
||||
"subtitle": "Wähle, welche Erinnerungen du erhältst."
|
||||
"description": "Alle Erinnerungen an einem Ort — was wann erinnert wird und wohin es zugestellt wird.",
|
||||
"subtitle": "Wähle, welche Erinnerungen du erhältst und wohin sie zugestellt werden.",
|
||||
"remindersHeading": "Erinnerungen",
|
||||
"remindersDescription": "Was du erhältst.",
|
||||
"channelsHeading": "Zustellkanäle",
|
||||
"channelsDescription": "Wohin Erinnerungen und Hinweise zugestellt werden."
|
||||
},
|
||||
"layout": {
|
||||
"title": "Dashboard",
|
||||
"description": "Lege fest, wie Dashboard und Insights aufgebaut und angeordnet sind.",
|
||||
"backToHub": "Zurück zu Layout & Personalisierung",
|
||||
"title": "Darstellung",
|
||||
"description": "Lege fest, wie Dashboard, Auswertungen und deine Tracking-Module dargestellt und angeordnet sind.",
|
||||
"backToHub": "Zurück zu Darstellung",
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
"description": "Kachel-Layout und Reihenfolge."
|
||||
@@ -4053,7 +4055,23 @@
|
||||
"title": "Insights",
|
||||
"description": "Reihenfolge der Übersicht und der Navigations-Pills."
|
||||
},
|
||||
"subtitle": "Passe an, wie Dashboard und Insights angeordnet sind."
|
||||
"subtitle": "Lege fest, wie Dashboard, Auswertungen und Tracking-Module dargestellt werden.",
|
||||
"medications": {
|
||||
"title": "Medikamente",
|
||||
"description": "Listenansicht und manuelle Reihenfolge."
|
||||
},
|
||||
"labs": {
|
||||
"title": "Labor",
|
||||
"description": "Ansicht, Sortierung und manuelle Reihenfolge."
|
||||
},
|
||||
"illness": {
|
||||
"title": "Krankheitstagebuch",
|
||||
"description": "Listenansicht und Reihenfolge der Episoden."
|
||||
},
|
||||
"vorsorge": {
|
||||
"title": "Vorsorge",
|
||||
"description": "Listenansicht und Reihenfolge der Erinnerungen."
|
||||
}
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
@@ -4311,11 +4329,6 @@
|
||||
"description": "Coach aktivieren, Ton und Umfang, gespeicherte Erinnerungen.",
|
||||
"subtitle": "Stelle den Coach, seine proaktiven Hinweise und sein Gedächtnis ein."
|
||||
},
|
||||
"channels": {
|
||||
"title": "Kanäle",
|
||||
"description": "Zustellung über Telegram, ntfy, Web-Push, Webhook und E-Mail.",
|
||||
"subtitle": "Wohin Erinnerungen und Hinweise zugestellt werden."
|
||||
},
|
||||
"security": {
|
||||
"title": "Sicherheit",
|
||||
"subtitle": "Zwei-Faktor-Authentifizierung, Wiederherstellungscodes und Passkeys."
|
||||
|
||||
+26
-13
@@ -4036,15 +4036,17 @@
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Notifications",
|
||||
"description": "Every reminder in one place — what gets reminded and when. The delivery channels live under Integrations.",
|
||||
"channelsHint": "Telegram, ntfy, Web Push, Webhook, and Email are now set up under",
|
||||
"channelsHintLink": "Integrations → Channels",
|
||||
"subtitle": "Choose which reminders you receive."
|
||||
"description": "Every reminder in one place — what gets reminded and when, and where it's delivered.",
|
||||
"subtitle": "Choose which reminders you receive and where they're delivered.",
|
||||
"remindersHeading": "Reminders",
|
||||
"remindersDescription": "What you receive.",
|
||||
"channelsHeading": "Delivery channels",
|
||||
"channelsDescription": "Where reminders and alerts are delivered."
|
||||
},
|
||||
"layout": {
|
||||
"title": "Dashboard",
|
||||
"description": "Arrange how the dashboard and insights are laid out.",
|
||||
"backToHub": "Back to Layout & Personalization",
|
||||
"title": "Appearance",
|
||||
"description": "Choose how the dashboard, insights, and your tracking modules look and are arranged.",
|
||||
"backToHub": "Back to Appearance",
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
"description": "Tile layout and order."
|
||||
@@ -4053,7 +4055,23 @@
|
||||
"title": "Insights",
|
||||
"description": "Overview sections and navigation-pill order."
|
||||
},
|
||||
"subtitle": "Personalize how your dashboard and insights are arranged."
|
||||
"subtitle": "Personalize how your dashboard, insights, and tracking modules look.",
|
||||
"medications": {
|
||||
"title": "Medications",
|
||||
"description": "List view and manual order."
|
||||
},
|
||||
"labs": {
|
||||
"title": "Labs",
|
||||
"description": "View, sort, and manual order."
|
||||
},
|
||||
"illness": {
|
||||
"title": "Illness journal",
|
||||
"description": "List view and episode order."
|
||||
},
|
||||
"vorsorge": {
|
||||
"title": "Checkups",
|
||||
"description": "List view and reminder order."
|
||||
}
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
@@ -4311,11 +4329,6 @@
|
||||
"description": "Enable the Coach, tone and scope, stored memories.",
|
||||
"subtitle": "Tune the Coach, its proactive nudges, and its memory."
|
||||
},
|
||||
"channels": {
|
||||
"title": "Channels",
|
||||
"description": "Telegram, ntfy, Web Push, Webhook, and Email delivery.",
|
||||
"subtitle": "Where reminders and alerts are delivered."
|
||||
},
|
||||
"security": {
|
||||
"title": "Security",
|
||||
"subtitle": "Two-factor authentication, recovery codes, and passkeys."
|
||||
|
||||
+26
-13
@@ -4036,15 +4036,17 @@
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Notificaciones",
|
||||
"description": "Todos los recordatorios en un solo lugar: qué se recuerda y cuándo. Los canales de entrega están en Integraciones.",
|
||||
"channelsHint": "Telegram, ntfy, Web Push, Webhook y correo se configuran ahora en",
|
||||
"channelsHintLink": "Integraciones → Canales",
|
||||
"subtitle": "Elige qué recordatorios recibes."
|
||||
"description": "Todos los recordatorios en un solo lugar: qué se recuerda y cuándo, y dónde se entrega.",
|
||||
"subtitle": "Elige qué recordatorios recibes y dónde se entregan.",
|
||||
"remindersHeading": "Recordatorios",
|
||||
"remindersDescription": "Lo que recibes.",
|
||||
"channelsHeading": "Canales de entrega",
|
||||
"channelsDescription": "Dónde se entregan los recordatorios y avisos."
|
||||
},
|
||||
"layout": {
|
||||
"title": "Panel",
|
||||
"description": "Organiza cómo están dispuestos el panel y los análisis.",
|
||||
"backToHub": "Volver a Diseño y personalización",
|
||||
"title": "Apariencia",
|
||||
"description": "Elige cómo se ven y se organizan el panel, los análisis y tus módulos de seguimiento.",
|
||||
"backToHub": "Volver a Apariencia",
|
||||
"dashboard": {
|
||||
"title": "Panel",
|
||||
"description": "Diseño y orden de los mosaicos."
|
||||
@@ -4053,7 +4055,23 @@
|
||||
"title": "Análisis",
|
||||
"description": "Orden de la vista general y de las pestañas de navegación."
|
||||
},
|
||||
"subtitle": "Personaliza cómo se organizan tu panel e insights."
|
||||
"subtitle": "Personaliza cómo se ven tu panel, los análisis y los módulos de seguimiento.",
|
||||
"medications": {
|
||||
"title": "Medicamentos",
|
||||
"description": "Vista de lista y orden manual."
|
||||
},
|
||||
"labs": {
|
||||
"title": "Laboratorio",
|
||||
"description": "Vista, orden y orden manual."
|
||||
},
|
||||
"illness": {
|
||||
"title": "Diario de enfermedades",
|
||||
"description": "Vista de lista y orden de episodios."
|
||||
},
|
||||
"vorsorge": {
|
||||
"title": "Revisiones",
|
||||
"description": "Vista de lista y orden de recordatorios."
|
||||
}
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Panel",
|
||||
@@ -4311,11 +4329,6 @@
|
||||
"description": "Activa el Coach, tono y alcance, recuerdos guardados.",
|
||||
"subtitle": "Ajusta el Coach, sus avisos proactivos y su memoria."
|
||||
},
|
||||
"channels": {
|
||||
"title": "Canales",
|
||||
"description": "Envío por Telegram, ntfy, Web Push, Webhook y correo electrónico.",
|
||||
"subtitle": "Dónde se entregan los recordatorios y avisos."
|
||||
},
|
||||
"security": {
|
||||
"title": "Seguridad",
|
||||
"subtitle": "Autenticación de dos factores, códigos de recuperación y claves de acceso."
|
||||
|
||||
+26
-13
@@ -4036,15 +4036,17 @@
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Notifications",
|
||||
"description": "Tous les rappels au même endroit — quoi et quand. Les canaux de diffusion se trouvent dans Intégrations.",
|
||||
"channelsHint": "Telegram, ntfy, Web Push, Webhook et e-mail se configurent désormais dans",
|
||||
"channelsHintLink": "Intégrations → Canaux",
|
||||
"subtitle": "Choisissez les rappels que vous recevez."
|
||||
"description": "Tous les rappels au même endroit — quoi et quand, et où c'est envoyé.",
|
||||
"subtitle": "Choisissez les rappels que vous recevez et où ils sont envoyés.",
|
||||
"remindersHeading": "Rappels",
|
||||
"remindersDescription": "Ce que vous recevez.",
|
||||
"channelsHeading": "Canaux de diffusion",
|
||||
"channelsDescription": "Où sont envoyés les rappels et alertes."
|
||||
},
|
||||
"layout": {
|
||||
"title": "Tableau de bord",
|
||||
"description": "Organisez la disposition du tableau de bord et des analyses.",
|
||||
"backToHub": "Retour à Disposition et personnalisation",
|
||||
"title": "Apparence",
|
||||
"description": "Choisissez l'apparence et l'agencement du tableau de bord, des analyses et de vos modules de suivi.",
|
||||
"backToHub": "Retour à Apparence",
|
||||
"dashboard": {
|
||||
"title": "Tableau de bord",
|
||||
"description": "Disposition et ordre des tuiles."
|
||||
@@ -4053,7 +4055,23 @@
|
||||
"title": "Analyses",
|
||||
"description": "Ordre de la vue d'ensemble et des onglets de navigation."
|
||||
},
|
||||
"subtitle": "Personnalisez l'agencement de votre tableau de bord et de vos insights."
|
||||
"subtitle": "Personnalisez l'apparence du tableau de bord, des analyses et des modules de suivi.",
|
||||
"medications": {
|
||||
"title": "Médicaments",
|
||||
"description": "Vue en liste et ordre manuel."
|
||||
},
|
||||
"labs": {
|
||||
"title": "Analyses de labo",
|
||||
"description": "Vue, tri et ordre manuel."
|
||||
},
|
||||
"illness": {
|
||||
"title": "Journal des maladies",
|
||||
"description": "Vue en liste et ordre des épisodes."
|
||||
},
|
||||
"vorsorge": {
|
||||
"title": "Examens",
|
||||
"description": "Vue en liste et ordre des rappels."
|
||||
}
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Tableau de bord",
|
||||
@@ -4311,11 +4329,6 @@
|
||||
"description": "Activez le Coach, le ton et la portée, les souvenirs enregistrés.",
|
||||
"subtitle": "Réglez le Coach, ses suggestions proactives et sa mémoire."
|
||||
},
|
||||
"channels": {
|
||||
"title": "Canaux",
|
||||
"description": "Distribution via Telegram, ntfy, Web Push, Webhook et e-mail.",
|
||||
"subtitle": "Où sont envoyés les rappels et alertes."
|
||||
},
|
||||
"security": {
|
||||
"title": "Sécurité",
|
||||
"subtitle": "Authentification à deux facteurs, codes de récupération et clés d'accès."
|
||||
|
||||
+26
-13
@@ -4036,15 +4036,17 @@
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Notifiche",
|
||||
"description": "Tutti i promemoria in un unico posto — cosa e quando. I canali di recapito si trovano in Integrazioni.",
|
||||
"channelsHint": "Telegram, ntfy, Web Push, Webhook ed e-mail ora si configurano in",
|
||||
"channelsHintLink": "Integrazioni → Canali",
|
||||
"subtitle": "Scegli quali promemoria ricevere."
|
||||
"description": "Tutti i promemoria in un unico posto — cosa e quando, e dove vengono recapitati.",
|
||||
"subtitle": "Scegli quali promemoria ricevere e dove vengono recapitati.",
|
||||
"remindersHeading": "Promemoria",
|
||||
"remindersDescription": "Ciò che ricevi.",
|
||||
"channelsHeading": "Canali di recapito",
|
||||
"channelsDescription": "Dove vengono recapitati promemoria e avvisi."
|
||||
},
|
||||
"layout": {
|
||||
"title": "Cruscotto",
|
||||
"description": "Organizza la disposizione del cruscotto e degli approfondimenti.",
|
||||
"backToHub": "Torna a Layout e personalizzazione",
|
||||
"title": "Aspetto",
|
||||
"description": "Scegli l'aspetto e la disposizione di dashboard, approfondimenti e dei tuoi moduli di monitoraggio.",
|
||||
"backToHub": "Torna ad Aspetto",
|
||||
"dashboard": {
|
||||
"title": "Cruscotto",
|
||||
"description": "Layout e ordine dei riquadri."
|
||||
@@ -4053,7 +4055,23 @@
|
||||
"title": "Approfondimenti",
|
||||
"description": "Ordine della panoramica e delle schede di navigazione."
|
||||
},
|
||||
"subtitle": "Personalizza la disposizione di dashboard e insights."
|
||||
"subtitle": "Personalizza l'aspetto di dashboard, approfondimenti e moduli di monitoraggio.",
|
||||
"medications": {
|
||||
"title": "Farmaci",
|
||||
"description": "Vista elenco e ordine manuale."
|
||||
},
|
||||
"labs": {
|
||||
"title": "Analisi di laboratorio",
|
||||
"description": "Vista, ordinamento e ordine manuale."
|
||||
},
|
||||
"illness": {
|
||||
"title": "Diario delle malattie",
|
||||
"description": "Vista elenco e ordine degli episodi."
|
||||
},
|
||||
"vorsorge": {
|
||||
"title": "Controlli",
|
||||
"description": "Vista elenco e ordine dei promemoria."
|
||||
}
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Cruscotto",
|
||||
@@ -4311,11 +4329,6 @@
|
||||
"description": "Attiva il Coach, tono e ambito, ricordi salvati.",
|
||||
"subtitle": "Regola il Coach, i suoi suggerimenti proattivi e la sua memoria."
|
||||
},
|
||||
"channels": {
|
||||
"title": "Canali",
|
||||
"description": "Recapito tramite Telegram, ntfy, Web Push, Webhook ed e-mail.",
|
||||
"subtitle": "Dove vengono recapitati promemoria e avvisi."
|
||||
},
|
||||
"security": {
|
||||
"title": "Sicurezza",
|
||||
"subtitle": "Autenticazione a due fattori, codici di recupero e passkey."
|
||||
|
||||
+26
-13
@@ -4036,15 +4036,17 @@
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Powiadomienia",
|
||||
"description": "Wszystkie przypomnienia w jednym miejscu — co i kiedy. Kanały dostarczania znajdują się w Integracjach.",
|
||||
"channelsHint": "Telegram, ntfy, Web Push, Webhook i e-mail konfigurujesz teraz w",
|
||||
"channelsHintLink": "Integracje → Kanały",
|
||||
"subtitle": "Wybierz, które przypomnienia otrzymujesz."
|
||||
"description": "Wszystkie przypomnienia w jednym miejscu — co i kiedy oraz gdzie są dostarczane.",
|
||||
"subtitle": "Wybierz, które przypomnienia otrzymujesz i gdzie są dostarczane.",
|
||||
"remindersHeading": "Przypomnienia",
|
||||
"remindersDescription": "Co otrzymujesz.",
|
||||
"channelsHeading": "Kanały dostarczania",
|
||||
"channelsDescription": "Gdzie dostarczane są przypomnienia i powiadomienia."
|
||||
},
|
||||
"layout": {
|
||||
"title": "Pulpit",
|
||||
"description": "Ustal, jak rozłożone są pulpit i analizy.",
|
||||
"backToHub": "Powrót do Układ i personalizacja",
|
||||
"title": "Wygląd",
|
||||
"description": "Ustal, jak wyglądają i są rozłożone pulpit, analizy i Twoje moduły śledzenia.",
|
||||
"backToHub": "Powrót do Wygląd",
|
||||
"dashboard": {
|
||||
"title": "Pulpit",
|
||||
"description": "Układ i kolejność kafelków."
|
||||
@@ -4053,7 +4055,23 @@
|
||||
"title": "Analizy",
|
||||
"description": "Kolejność przeglądu i pigułek nawigacyjnych."
|
||||
},
|
||||
"subtitle": "Dostosuj układ pulpitu i analiz."
|
||||
"subtitle": "Dostosuj wygląd pulpitu, analiz i modułów śledzenia.",
|
||||
"medications": {
|
||||
"title": "Leki",
|
||||
"description": "Widok listy i ręczna kolejność."
|
||||
},
|
||||
"labs": {
|
||||
"title": "Laboratorium",
|
||||
"description": "Widok, sortowanie i ręczna kolejność."
|
||||
},
|
||||
"illness": {
|
||||
"title": "Dziennik chorób",
|
||||
"description": "Widok listy i kolejność epizodów."
|
||||
},
|
||||
"vorsorge": {
|
||||
"title": "Badania kontrolne",
|
||||
"description": "Widok listy i kolejność przypomnień."
|
||||
}
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Pulpit",
|
||||
@@ -4311,11 +4329,6 @@
|
||||
"description": "Włącz Coacha, ton i zakres, zapisane wspomnienia.",
|
||||
"subtitle": "Dostosuj Coacha, jego proaktywne podpowiedzi i pamięć."
|
||||
},
|
||||
"channels": {
|
||||
"title": "Kanały",
|
||||
"description": "Dostarczanie przez Telegram, ntfy, Web Push, Webhook i e-mail.",
|
||||
"subtitle": "Gdzie dostarczane są przypomnienia i powiadomienia."
|
||||
},
|
||||
"security": {
|
||||
"title": "Bezpieczeństwo",
|
||||
"subtitle": "Uwierzytelnianie dwuskładnikowe, kody odzyskiwania i klucze dostępu."
|
||||
|
||||
@@ -134,6 +134,17 @@ const nextConfig: NextConfig = {
|
||||
destination: "/settings/notifications",
|
||||
permanent: true,
|
||||
},
|
||||
// v1.25.3 — the standalone delivery-channels page folded into
|
||||
// Notifications as an in-page group. The channels content now lives
|
||||
// under the `#channels` anchor on the Notifications surface, so the old
|
||||
// URL 301-redirects there (mirroring the `/settings/reminders` precedent
|
||||
// above). The per-channel anchors (`#telegram`, `#ntfy`, …) inside the
|
||||
// panel keep resolving.
|
||||
{
|
||||
source: "/settings/channels",
|
||||
destination: "/settings/notifications#channels",
|
||||
permanent: true,
|
||||
},
|
||||
// v1.22.0 — the preventive-care surface moved from the German slug
|
||||
// `/vorsorge` to the English `/checkups` (the feature reads "Checkups"
|
||||
// in every non-German locale now). 301-redirect so bookmarks, the PWA's
|
||||
|
||||
@@ -26,9 +26,8 @@ import { NotificationsSection } from "@/components/settings/notifications-sectio
|
||||
import { PrivacySection } from "@/components/settings/privacy-section";
|
||||
import { SectionPlaceholder } from "@/components/settings/section-placeholder";
|
||||
import { VorsorgeSection } from "@/components/settings/vorsorge-section";
|
||||
// v1.18.1 (D4) — `channels` and `sources` are standalone left-side entries
|
||||
// again (split out of the Integrations sub-tabs).
|
||||
import { ChannelsSection } from "@/components/settings/channels-section";
|
||||
// v1.18.1 (D4) — `sources` is a standalone left-side entry (split out of the
|
||||
// Integrations sub-tabs). v1.25.3 — `channels` folded into Notifications.
|
||||
import { SharingSection } from "@/components/settings/sharing-section";
|
||||
import { SourcesSection } from "@/components/settings/sources-section";
|
||||
import { ThresholdsSection } from "@/components/settings/thresholds-section";
|
||||
@@ -66,7 +65,6 @@ const SECTION_COMPONENTS: Record<
|
||||
ai: AiSection,
|
||||
coach: CoachSection,
|
||||
integrations: IntegrationsSection,
|
||||
channels: ChannelsSection,
|
||||
sources: SourcesSection,
|
||||
notifications: NotificationsSection,
|
||||
layout: LayoutSection,
|
||||
|
||||
@@ -63,7 +63,10 @@ export function VorsorgeSettings() {
|
||||
// `<section>` blocks with `text-sm` headings.
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<SettingsCard>
|
||||
{/* v1.25.3 — `id="vorsorge-view"` + `scroll-mt-28` so the Appearance hub
|
||||
deep-link (`/settings/vorsorge#vorsorge-view`) lands on this card
|
||||
below the sticky page header, mirroring the labs/illness anchors. */}
|
||||
<SettingsCard id="vorsorge-view" className="scroll-mt-28">
|
||||
<SettingsCardHeader
|
||||
icon={LayoutGrid}
|
||||
title={t("moduleList.viewHeading")}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
/**
|
||||
* v1.17.1 (F-2) — the "Layout & Personalization" hub.
|
||||
* v1.17.1 (F-2) — the "Appearance" hub (slug stays `layout`).
|
||||
*
|
||||
* The hub is the single front door for the four personalization editors.
|
||||
* It must link to each of them with consistent framing so the concept
|
||||
* reads as one home rather than four scattered settings sections.
|
||||
* The hub is the single front door for every view/arrangement surface. It must
|
||||
* link to each with consistent framing so "how my app looks" reads as one home
|
||||
* rather than scattered settings sections.
|
||||
*
|
||||
* v1.25.3 — the hub widened from 2 links (dashboard + insights) to 6: it now
|
||||
* also deep-links to the view/sort/order cards of medications, labs, the
|
||||
* illness journal, and checkups. Those cards stay on their own module pages;
|
||||
* the hub only indexes them via anchor deep-links.
|
||||
*/
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
@@ -20,26 +25,34 @@ function render(locale: "en" | "de" = "en") {
|
||||
}
|
||||
|
||||
describe("<LayoutSection>", () => {
|
||||
it("links to the arrangement editors it still hosts", () => {
|
||||
it("links to every view surface it indexes (anchor deep-links)", () => {
|
||||
const html = render();
|
||||
for (const href of ["/settings/dashboard", "/settings/insights"]) {
|
||||
for (const href of [
|
||||
"/settings/dashboard",
|
||||
"/settings/insights",
|
||||
"/settings/medications#medications-view",
|
||||
"/settings/labs#labs-view",
|
||||
"/settings/illness#illness-view",
|
||||
"/settings/vorsorge#vorsorge-view",
|
||||
]) {
|
||||
expect(html).toContain(`href="${href}"`);
|
||||
}
|
||||
// v1.18.0 (S5) — Medications (Medikamente) and Mood (Stimmung)
|
||||
// graduated to their own nav entries and are no longer linked here.
|
||||
expect(html).not.toContain('href="/settings/medications"');
|
||||
expect(html).not.toContain('href="/settings/mood"');
|
||||
});
|
||||
|
||||
it("renders the hub heading and a card per editor", () => {
|
||||
it("renders one card per indexed surface (6 links)", () => {
|
||||
const html = render();
|
||||
// Pin the link count: every hub card is an `<a href="/settings/…">`.
|
||||
const links = html.match(/href="\/settings\//g) ?? [];
|
||||
expect(links.length).toBe(6);
|
||||
expect(html).toContain("Dashboard");
|
||||
expect(html).toContain("Insights");
|
||||
});
|
||||
|
||||
it("resolves its copy in German too", () => {
|
||||
const html = render("de");
|
||||
expect(html).toContain("Layout");
|
||||
// The hub body is the link list; the German module labels resolve.
|
||||
expect(html).toContain("Medikamente");
|
||||
expect(html).toContain("Labor");
|
||||
expect(html).not.toContain("settings.sections.layout.");
|
||||
});
|
||||
});
|
||||
@@ -188,19 +188,25 @@ describe("settings sections — SSR smoke", () => {
|
||||
expect(html).toContain("Withings");
|
||||
});
|
||||
|
||||
it("<NotificationsSection> renders the single reminder-types home", () => {
|
||||
it("<NotificationsSection> renders the reminders + delivery-channels groups", () => {
|
||||
const html = renderFramed("notifications", <NotificationsSection />);
|
||||
// v1.18.6 (W9) — the visible heading comes from the frame; the proactive
|
||||
// Coach nudge moved to Settings → Coach, so it no longer renders here.
|
||||
expect(html).toContain("settings-section-notifications-title");
|
||||
expect(html).not.toContain("Notification channels");
|
||||
expect(html).not.toContain('data-slot="notifications-channels-cross-link"');
|
||||
expect(html).not.toContain('data-slot="notifications-inbox-cross-link"');
|
||||
// The mood card fails OPEN (mock user carries no module map), so both
|
||||
// remaining reminder-type cards render. The coach-nudge card is gone.
|
||||
// reminder-type cards render under the Reminders group. The coach-nudge
|
||||
// card is gone.
|
||||
expect(html).toContain('id="mood-reminder"');
|
||||
expect(html).toContain('id="low-stock"');
|
||||
expect(html).not.toContain('id="coach-nudge"');
|
||||
// v1.25.3 — the delivery-channels group is now part of this surface: the
|
||||
// `#channels` anchor and the embedded channels panel both render.
|
||||
expect(html).toContain('id="channels"');
|
||||
expect(html).toContain('data-slot="notification-channels-panel"');
|
||||
expect(html).toContain("Reminders");
|
||||
expect(html).toContain("Delivery channels");
|
||||
// No raw i18n key leaks past the provider.
|
||||
expect(html).not.toContain("settings.sections.notifications.");
|
||||
});
|
||||
|
||||
@@ -91,6 +91,9 @@ describe("SETTINGS_SECTION_SLUGS", () => {
|
||||
// sits right after `ai`.
|
||||
// v1.18.1 (D4) — `channels` + `sources` split out of the Integrations
|
||||
// sub-tabs into their own left-side entries, right after `integrations`.
|
||||
// v1.25.3 — `channels` folded back into Notifications as an in-page group;
|
||||
// `/settings/channels` 301-redirects to `/settings/notifications#channels`.
|
||||
// `sources` keeps its own entry.
|
||||
// v1.18.7 — `labs`, `illness`, `vorsorge` move into the shell as
|
||||
// first-class sections, right after `mood` (the three were standalone
|
||||
// `ModuleSettingsFrame` pages).
|
||||
@@ -102,7 +105,6 @@ describe("SETTINGS_SECTION_SLUGS", () => {
|
||||
"security",
|
||||
"modules",
|
||||
"integrations",
|
||||
"channels",
|
||||
"sources",
|
||||
"notifications",
|
||||
"layout",
|
||||
@@ -293,14 +295,15 @@ describe("<SettingsShell>", () => {
|
||||
// (single-line; the longer "Notification channels" wrapped). The
|
||||
// `/notifications` inbox now shares the "Notifications" label.
|
||||
expect(html).toContain("Notifications");
|
||||
// v1.17.1 (F-2) — the dashboard + insights arrangement editors are
|
||||
// reached through one hub entry (route stays `/settings/layout`).
|
||||
// v1.19.1 (S3) — the nav label now reads "Dashboard" to match where
|
||||
// it leads; the route is unchanged.
|
||||
// v1.17.1 (F-2) — the view/arrangement editors are reached through one hub
|
||||
// entry (route stays `/settings/layout`). v1.25.3 — the hub is renamed
|
||||
// "Appearance" (DE "Darstellung") and indexes every module's view surface;
|
||||
// the route is unchanged.
|
||||
expect(html).toContain('href="/settings/layout"');
|
||||
expect(html).toContain(">Dashboard</a>");
|
||||
// v1.18.1 (D4) — Channels + Sources are their own left-side entries.
|
||||
expect(html).toContain('href="/settings/channels"');
|
||||
expect(html).toContain(">Appearance</a>");
|
||||
// v1.25.3 — Channels folded into Notifications, so it is no longer a
|
||||
// left-side entry; Sources keeps its own.
|
||||
expect(html).not.toContain('href="/settings/channels"');
|
||||
expect(html).toContain('href="/settings/sources"');
|
||||
// v1.18.0 (S5) — Medications (Medikamente) and Mood (Stimmung, gated;
|
||||
// fail-open mock shows both) are their own nav entries now.
|
||||
@@ -334,15 +337,14 @@ describe("<SettingsShell>", () => {
|
||||
// compound "Benachrichtigungs-Kanäle" wrapped). The `/notifications`
|
||||
// inbox now shares the "Benachrichtigungen" label.
|
||||
expect(html).toContain("Benachrichtigungen");
|
||||
// v1.17.1 (F-2) — the arrangement editors are reached through one hub
|
||||
// entry (route stays `/settings/layout`). v1.19.1 (S3) — the nav label
|
||||
// reads "Dashboard" in every locale to match where it leads.
|
||||
// v1.17.1 (F-2) — the view editors are reached through one hub entry
|
||||
// (route stays `/settings/layout`). v1.25.3 — the German nav label reads
|
||||
// "Darstellung" (Appearance) to match the renamed hub.
|
||||
expect(html).toContain('href="/settings/layout"');
|
||||
expect(html).toContain(">Dashboard</a>");
|
||||
// v1.18.1 (D4) — Channels ("Kanäle") + Sources ("Quellen-Priorität")
|
||||
// are their own left-side entries.
|
||||
expect(html).toContain('href="/settings/channels"');
|
||||
expect(html).toContain("Kanäle");
|
||||
expect(html).toContain(">Darstellung</a>");
|
||||
// v1.25.3 — Channels ("Kanäle") folded into Notifications; Sources keeps
|
||||
// its own left-side entry.
|
||||
expect(html).not.toContain('href="/settings/channels"');
|
||||
// v1.18.0 (S5) — Medications + Mood are their own nav entries now.
|
||||
expect(html).toContain('href="/settings/medications"');
|
||||
expect(html).toContain('href="/settings/mood"');
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
"use client";
|
||||
|
||||
/**
|
||||
* `<ChannelsSection>` — Settings → Kanäle (notification delivery channels).
|
||||
*
|
||||
* v1.18.1 (D4) — split out of the Integrations sub-tabs into its own left-side
|
||||
* entry. A channel (Telegram / ntfy / Web Push / Webhook / Email) is a
|
||||
* delivery provider — the same family as a connected device — and now reads as
|
||||
* a first-class settings home rather than a tab hidden behind Integrationen.
|
||||
*
|
||||
* The content is the existing `<NotificationChannelsPanel>`. v1.18.6 (W9) —
|
||||
* the visible heading + subtitle now come from the shared
|
||||
* `<SettingsSectionFrame>` in the route; this wrapper is the panel only.
|
||||
*/
|
||||
|
||||
import { NotificationChannelsPanel } from "@/components/settings/integrations/notification-channels-panel";
|
||||
|
||||
export function ChannelsSection() {
|
||||
return <NotificationChannelsPanel />;
|
||||
}
|
||||
@@ -2,8 +2,12 @@
|
||||
|
||||
import Link from "next/link";
|
||||
import {
|
||||
CalendarCheck,
|
||||
ChevronRight,
|
||||
FlaskConical,
|
||||
LayoutDashboard,
|
||||
Pill,
|
||||
Thermometer,
|
||||
TrendingUp,
|
||||
type LucideIcon,
|
||||
} from "lucide-react";
|
||||
@@ -12,17 +16,23 @@ import { useTranslations } from "@/lib/i18n/context";
|
||||
import { SettingsCard } from "./settings-card";
|
||||
|
||||
/**
|
||||
* v1.17.1 (F-2) — the one "Layout & Personalization" home.
|
||||
* v1.17.1 (F-2) — the "Appearance" home (slug stays `layout`).
|
||||
*
|
||||
* Before this section, "how my app is laid out" was scattered across
|
||||
* several unrelated settings sections with no shared framing. This
|
||||
* section is the single front door for the arrangement editors: it
|
||||
* presents them as one consistent set of cards and links to each editor,
|
||||
* which keep their own routes and mutation flows intact.
|
||||
* "How my app looks and is arranged" was scattered across several unrelated
|
||||
* settings sections with no shared framing. This section is the single front
|
||||
* door: it presents the view/arrangement surfaces as one consistent set of
|
||||
* cards and links to each editor, which keep their own routes, their own
|
||||
* cards, and their mutation flows intact — the hub indexes them, it does not
|
||||
* own them.
|
||||
*
|
||||
* v1.18.0 (S5) — Medications (Medikamente) and Mood (Stimmung) graduated
|
||||
* to their own top-level nav entries, so the hub now hosts only the
|
||||
* dashboard + insights arrangement editors.
|
||||
* v1.25.3 — the hub widens from the dashboard + insights arrangement editors
|
||||
* to the full set of view surfaces: it now also deep-links to the view/sort/
|
||||
* order cards of medications, labs, the illness journal, and checkups. Each
|
||||
* of those modules keeps its view cards on its own settings page; the links
|
||||
* land on the existing card anchors (`#medications-view`, `#labs-view`,
|
||||
* `#illness-view`, `#vorsorge-view`). Data/behaviour settings (biomarker
|
||||
* catalog, local OCR, injection-site exclusions, per-reminder toggles, the
|
||||
* mood tag/group catalog) stay on their module pages and are NOT indexed here.
|
||||
*/
|
||||
interface LayoutLink {
|
||||
href: string;
|
||||
@@ -44,10 +54,34 @@ const LAYOUT_LINKS: ReadonlyArray<LayoutLink> = [
|
||||
titleKey: "settings.sections.layout.insights.title",
|
||||
descriptionKey: "settings.sections.layout.insights.description",
|
||||
},
|
||||
// v1.18.0 (S5) — Medications (Medikamente) and Mood (Stimmung) graduated
|
||||
// to their own top-level nav entries, so they are no longer linked from
|
||||
// the Layout hub. Only the dashboard + insights arrangement editors
|
||||
// remain here.
|
||||
// v1.25.3 — view/sort/order surfaces of the tracking modules. Each link
|
||||
// deep-links to the module's existing view card anchor; the cards stay on
|
||||
// their own settings page. The module routes resolve regardless of the
|
||||
// module's enabled state, so the link never dead-ends.
|
||||
{
|
||||
href: "/settings/medications#medications-view",
|
||||
icon: Pill,
|
||||
titleKey: "settings.sections.layout.medications.title",
|
||||
descriptionKey: "settings.sections.layout.medications.description",
|
||||
},
|
||||
{
|
||||
href: "/settings/labs#labs-view",
|
||||
icon: FlaskConical,
|
||||
titleKey: "settings.sections.layout.labs.title",
|
||||
descriptionKey: "settings.sections.layout.labs.description",
|
||||
},
|
||||
{
|
||||
href: "/settings/illness#illness-view",
|
||||
icon: Thermometer,
|
||||
titleKey: "settings.sections.layout.illness.title",
|
||||
descriptionKey: "settings.sections.layout.illness.description",
|
||||
},
|
||||
{
|
||||
href: "/settings/vorsorge#vorsorge-view",
|
||||
icon: CalendarCheck,
|
||||
titleKey: "settings.sections.layout.vorsorge.title",
|
||||
descriptionKey: "settings.sections.layout.vorsorge.description",
|
||||
},
|
||||
];
|
||||
|
||||
export function LayoutSection() {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { useTranslations } from "@/lib/i18n/context";
|
||||
import { LowStockCard } from "@/components/settings/low-stock-card";
|
||||
import { MoodReminderCard } from "@/components/settings/mood-reminder-card";
|
||||
import { NotificationChannelsPanel } from "@/components/settings/integrations/notification-channels-panel";
|
||||
|
||||
/**
|
||||
* `<NotificationsSection>` — Settings → Notifications ("Benachrichtigungen").
|
||||
@@ -19,41 +21,77 @@ import { MoodReminderCard } from "@/components/settings/mood-reminder-card";
|
||||
* (a toggleable fail-open module since D3, so a missing key reads as enabled
|
||||
* and a stale `/me` payload never blanks a card).
|
||||
*
|
||||
* v1.18.1 (D5) — the page is intentionally lean: the section blurb, the
|
||||
* channels / inbox cross-links, and the embedded Vorsorge (preventive-care)
|
||||
* editor were all removed. Vorsorge has its own `/vorsorge` page, so embedding
|
||||
* it here was a duplicate. Delivery CHANNELS (Telegram / ntfy / Web Push /
|
||||
* Webhook / Email) live under Settings → Integrations → Channels.
|
||||
* v1.25.3 — the standalone "Channels" entry folds back in here. The page is
|
||||
* now one Notifications surface with two sequential, labelled groups, ordered
|
||||
* the way a user reasons about it: **Reminders** ("what you receive") first,
|
||||
* then **Delivery channels** ("where it's delivered") = the existing
|
||||
* `<NotificationChannelsPanel>`. This is two distinct-but-related concepts
|
||||
* sequenced under one roof, not one concept split top/bottom — the
|
||||
* channels group carries `id="channels"` so `/settings/channels` can
|
||||
* 301-redirect to `/settings/notifications#channels`, and the per-channel
|
||||
* anchors (`#telegram`, `#ntfy`, …) inside the panel keep working.
|
||||
*
|
||||
* v1.18.6 (W9) — the visible heading + subtitle now come from the shared
|
||||
* `<SettingsSectionFrame>`. The proactive-Coach nudge card moved to Settings →
|
||||
* Coach (it is a Coach setting, not a generic notification), so this screen
|
||||
* carries the mood + low-stock reminder cards only.
|
||||
* v1.18.6 (W9) — the page heading + subtitle come from the shared
|
||||
* `<SettingsSectionFrame>`. The proactive-Coach nudge card lives under
|
||||
* Settings → Coach (it is a Coach setting, not a generic notification).
|
||||
*/
|
||||
export function NotificationsSection() {
|
||||
const { isAuthenticated, user } = useAuth();
|
||||
const { t } = useTranslations();
|
||||
|
||||
// v1.18.0 (S4) — module-gated per-type visibility. Fail OPEN (`!== false`)
|
||||
// so a stale `/me` payload without the module map keeps every card visible.
|
||||
const moodEnabled = user?.modules?.mood !== false;
|
||||
const medsEnabled = user?.modules?.medications !== false;
|
||||
const anyReminder = moodEnabled || medsEnabled;
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Mood check-in reminder — only when the mood module is enabled. */}
|
||||
{moodEnabled ? (
|
||||
<div id="mood-reminder" className="scroll-mt-28">
|
||||
<MoodReminderCard isAuthenticated={isAuthenticated} />
|
||||
</div>
|
||||
<div className="space-y-10">
|
||||
{/* Group 1 — Reminders ("what you receive"). Rendered only when at
|
||||
least one reminder-type card is visible, so a fully-disabled
|
||||
account never shows an empty heading. */}
|
||||
{anyReminder ? (
|
||||
<section className="space-y-4">
|
||||
<div className="space-y-0.5">
|
||||
<h2 className="text-foreground text-lg font-semibold">
|
||||
{t("settings.sections.notifications.remindersHeading")}
|
||||
</h2>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{t("settings.sections.notifications.remindersDescription")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Mood check-in reminder — only when the mood module is enabled. */}
|
||||
{moodEnabled ? (
|
||||
<div id="mood-reminder" className="scroll-mt-28">
|
||||
<MoodReminderCard isAuthenticated={isAuthenticated} />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{/* Medication low-stock runway — only when the medications module
|
||||
is enabled (toggleable, fail-open, since D3). */}
|
||||
{medsEnabled ? (
|
||||
<div id="low-stock" className="scroll-mt-28">
|
||||
<LowStockCard isAuthenticated={isAuthenticated} />
|
||||
</div>
|
||||
) : null}
|
||||
</section>
|
||||
) : null}
|
||||
|
||||
{/* Medication low-stock runway — only when the medications module is
|
||||
enabled (toggleable, fail-open, since D3). */}
|
||||
{medsEnabled ? (
|
||||
<div id="low-stock" className="scroll-mt-28">
|
||||
<LowStockCard isAuthenticated={isAuthenticated} />
|
||||
{/* Group 2 — Delivery channels ("where it's delivered"). The existing
|
||||
channels panel, unchanged. `id="channels"` anchors the group for the
|
||||
`/settings/channels` redirect. */}
|
||||
<section id="channels" className="scroll-mt-28 space-y-4">
|
||||
<div className="space-y-0.5">
|
||||
<h2 className="text-foreground text-lg font-semibold">
|
||||
{t("settings.sections.notifications.channelsHeading")}
|
||||
</h2>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{t("settings.sections.notifications.channelsDescription")}
|
||||
</p>
|
||||
</div>
|
||||
) : null}
|
||||
<NotificationChannelsPanel />
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -29,7 +29,6 @@ import {
|
||||
Link2,
|
||||
Lock,
|
||||
Pill,
|
||||
Radio,
|
||||
Settings2,
|
||||
Share2,
|
||||
ShieldCheck,
|
||||
@@ -51,7 +50,6 @@ const SLUG_ICON: Record<SettingsSectionSlug, LucideIcon> = {
|
||||
security: ShieldCheck,
|
||||
modules: Blocks,
|
||||
integrations: Link2,
|
||||
channels: Radio,
|
||||
sources: Layers,
|
||||
notifications: Bell,
|
||||
layout: LayoutDashboard,
|
||||
|
||||
@@ -57,9 +57,10 @@ export const SETTINGS_SECTION_SLUGS = [
|
||||
// single front door for enabling/disabling secondary tracking domains.
|
||||
"modules",
|
||||
"integrations",
|
||||
// v1.18.1 (D4) — Kanäle (delivery channels) + Quellen (source weighting)
|
||||
// split out of the Integrations tabs into their own left-side entries.
|
||||
"channels",
|
||||
// v1.18.1 (D4) — Quellen (source weighting) split out of the Integrations
|
||||
// tabs into its own left-side entry. v1.25.3 — Kanäle (delivery channels)
|
||||
// folded back into Notifications as an in-page group; `/settings/channels`
|
||||
// 301-redirects to `/settings/notifications#channels` (next.config.ts).
|
||||
"sources",
|
||||
"notifications",
|
||||
"layout",
|
||||
|
||||
@@ -30,12 +30,11 @@ import {
|
||||
Info,
|
||||
KeyRound,
|
||||
Plug,
|
||||
LayoutDashboard,
|
||||
Layers,
|
||||
Link2,
|
||||
Lock,
|
||||
Palette,
|
||||
Pill,
|
||||
Radio,
|
||||
Settings2,
|
||||
Share2,
|
||||
ShieldCheck,
|
||||
@@ -123,13 +122,9 @@ export const SETTINGS_SECTIONS: readonly SettingsSection[] = [
|
||||
titleKey: "settings.sections.integrations.title",
|
||||
icon: Link2,
|
||||
},
|
||||
// v1.18.1 (D4) — Kanäle (delivery channels) split out of the Integrations
|
||||
// sub-tabs into its own entry. A channel is a delivery provider.
|
||||
{
|
||||
slug: "channels",
|
||||
titleKey: "settings.sections.channels.title",
|
||||
icon: Radio,
|
||||
},
|
||||
// v1.25.3 — the standalone Kanäle (delivery channels) entry folded back
|
||||
// into Notifications as a labelled in-page group; `/settings/channels`
|
||||
// 301-redirects to `/settings/notifications#channels`.
|
||||
// v1.18.1 (D4) — Quellen (source weighting) split out into its own entry:
|
||||
// which connection wins when two report the same metric.
|
||||
{
|
||||
@@ -145,15 +140,17 @@ export const SETTINGS_SECTIONS: readonly SettingsSection[] = [
|
||||
titleKey: "settings.sections.notifications.title",
|
||||
icon: Bell,
|
||||
},
|
||||
// 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
|
||||
// the hub's own links all work); they are simply reached through the
|
||||
// Layout hub now, so "how my app is laid out" reads as one home.
|
||||
// v1.17.1 (F-2) — one nav entry replaces the four scattered Dashboard /
|
||||
// Insights / Medications / Mood "arrange" entries. Those routes still
|
||||
// resolve (deep links, page-header cogs, and the hub's own links all work);
|
||||
// they are reached through this hub now, so "how my app looks" reads as one
|
||||
// home. v1.25.3 — renamed to "Appearance"/"Darstellung" and widened into the
|
||||
// index for every module's view/sort/order surface. The slug stays `layout`
|
||||
// so every route + deep link is untouched.
|
||||
{
|
||||
slug: "layout",
|
||||
titleKey: "settings.sections.layout.title",
|
||||
icon: LayoutDashboard,
|
||||
icon: Palette,
|
||||
},
|
||||
// v1.18.0 (S5) — Medikamente: medication-specific settings (list view +
|
||||
// order + injection sites). Was a hidden child of the Layout hub.
|
||||
|
||||
Reference in new issue
Block a user