mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
feat(settings): give the health record its own Gesundheitsakte entry
Lift the full health-record export (PDF + FHIR R4 + zip package) out of Export & Import into a dedicated top-level Gesundheitsakte section. Export & Import keeps the generic CSV/JSON data-out and import paths only. The new section is always available (not module-gated).
This commit is contained in:
1 parent
604778f166
commit
59fea72d8b
15 files changed
+161
-34
No files matched your search
@@ -4121,6 +4121,10 @@
|
||||
"note": "Kernbereich — immer aktiv"
|
||||
},
|
||||
"description": "Lege fest, was HealthLog für dich erfasst. Schalte einzelne Bereiche ein oder aus — die Navigation, Kacheln und Auswertungen passen sich sofort an."
|
||||
},
|
||||
"gesundheitsakte": {
|
||||
"title": "Gesundheitsakte",
|
||||
"description": "Vollständige Gesundheitsakte als PDF, FHIR R4 oder kombiniertes ZIP-Paket exportieren."
|
||||
}
|
||||
},
|
||||
"profile": "Profil",
|
||||
|
||||
@@ -4121,6 +4121,10 @@
|
||||
"note": "Core area — always on"
|
||||
},
|
||||
"description": "Choose what HealthLog tracks for you. Turn individual areas on or off — the navigation, tiles, and insights adapt right away."
|
||||
},
|
||||
"gesundheitsakte": {
|
||||
"title": "Health record",
|
||||
"description": "Export your full health record as PDF, FHIR R4, or a combined ZIP package."
|
||||
}
|
||||
},
|
||||
"profile": "Profile",
|
||||
|
||||
@@ -4121,6 +4121,10 @@
|
||||
"note": "Área esencial — siempre activa"
|
||||
},
|
||||
"description": "Elige qué registra HealthLog por ti. Activa o desactiva áreas concretas: la navegación, los paneles y los análisis se adaptan al instante."
|
||||
},
|
||||
"gesundheitsakte": {
|
||||
"title": "Historial médico",
|
||||
"description": "Exporta tu historial médico completo como PDF, FHIR R4 o un paquete ZIP combinado."
|
||||
}
|
||||
},
|
||||
"profile": "Perfil",
|
||||
|
||||
@@ -4121,6 +4121,10 @@
|
||||
"note": "Domaine essentiel — toujours actif"
|
||||
},
|
||||
"description": "Choisissez ce que HealthLog suit pour vous. Activez ou désactivez chaque domaine : la navigation, les tuiles et les analyses s'adaptent aussitôt."
|
||||
},
|
||||
"gesundheitsakte": {
|
||||
"title": "Dossier médical",
|
||||
"description": "Exportez votre dossier médical complet au format PDF, FHIR R4 ou en paquet ZIP combiné."
|
||||
}
|
||||
},
|
||||
"profile": "Profil",
|
||||
|
||||
@@ -4121,6 +4121,10 @@
|
||||
"note": "Ambito di base — sempre attivo"
|
||||
},
|
||||
"description": "Scegli cosa registra HealthLog per te. Attiva o disattiva i singoli ambiti: navigazione, riquadri e analisi si adattano subito."
|
||||
},
|
||||
"gesundheitsakte": {
|
||||
"title": "Cartella clinica",
|
||||
"description": "Esporta la tua cartella clinica completa in PDF, FHIR R4 o in un pacchetto ZIP combinato."
|
||||
}
|
||||
},
|
||||
"profile": "Profilo",
|
||||
|
||||
@@ -4121,6 +4121,10 @@
|
||||
"note": "Obszar podstawowy — zawsze aktywny"
|
||||
},
|
||||
"description": "Wybierz, co HealthLog ma dla Ciebie śledzić. Włączaj i wyłączaj poszczególne obszary — nawigacja, kafelki i analizy dostosują się od razu."
|
||||
},
|
||||
"gesundheitsakte": {
|
||||
"title": "Dokumentacja zdrowotna",
|
||||
"description": "Wyeksportuj pełną dokumentację zdrowotną jako PDF, FHIR R4 lub łączony pakiet ZIP."
|
||||
}
|
||||
},
|
||||
"profile": "Profil",
|
||||
|
||||
@@ -8,6 +8,7 @@ import { AiSection } from "@/components/settings/ai-section";
|
||||
import { ApiSection } from "@/components/settings/api-section";
|
||||
import { DashboardSection } from "@/components/settings/dashboard-section";
|
||||
import { ExportSection } from "@/components/settings/export-section";
|
||||
import { GesundheitsakteSection } from "@/components/settings/gesundheitsakte-section";
|
||||
import { InsightsSection } from "@/components/settings/insights-section";
|
||||
import { IntegrationsSection } from "@/components/settings/integrations-section";
|
||||
import { LayoutSection } from "@/components/settings/layout-section";
|
||||
@@ -29,8 +30,7 @@ import { SettingsShell } from "@/components/settings/settings-shell";
|
||||
|
||||
/**
|
||||
* Dynamic settings section route. Each of the `SETTINGS_SECTION_SLUGS`
|
||||
* (14 today — 10 nav-visible sections plus the four routable-but-hidden
|
||||
* Layout child editors) is pre-rendered at build via
|
||||
* is pre-rendered at build via
|
||||
* `generateStaticParams()` so the URLs are
|
||||
* statically known to Next.js, while the `dynamicParams = false` flag below
|
||||
* tells the router to 404 (instead of attempting on-demand rendering) for any
|
||||
@@ -61,6 +61,7 @@ const SECTION_COMPONENTS: Record<
|
||||
mood: MoodSection,
|
||||
thresholds: ThresholdsSection,
|
||||
api: ApiSection,
|
||||
gesundheitsakte: GesundheitsakteSection,
|
||||
export: ExportSection,
|
||||
advanced: AdvancedSection,
|
||||
};
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* v1.4.16 Phase B7 — Settings → Export section.
|
||||
*
|
||||
* The consolidated Export page surfaces:
|
||||
* - Health Record export panel (the page hero, v1.12)
|
||||
* - Measurements CSV
|
||||
* - Medications CSV (with optional intake-history toggle)
|
||||
* - Mood CSV
|
||||
@@ -12,10 +11,10 @@
|
||||
* download/generate button. SSR-only smoke test — interaction is
|
||||
* exercised by the e2e suite.
|
||||
*
|
||||
* The health-record export takes the page hero. The doctor-report PDF
|
||||
* now lives under the health-record export and is no longer offered as
|
||||
* a separate card here. The four CSV/JSON tiles stay under a "Weitere
|
||||
* Export-Optionen" / "Other export options" sub-heading. Each component
|
||||
* v1.18.0 (S5) — the full health-record export moved out to its own
|
||||
* top-level "Gesundheitsakte" section; this page keeps only the generic
|
||||
* CSV/JSON data-out paths under a "Weitere Export-Optionen" / "Other
|
||||
* export options" sub-heading plus the import surface. Each component
|
||||
* owns its own contract test; this suite pins the page-level shape.
|
||||
*/
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
@@ -77,12 +76,11 @@ describe("<ExportSection> — SSR smoke", () => {
|
||||
expect(html).not.toContain('data-testid="export-card-cycle"');
|
||||
});
|
||||
|
||||
it("mounts the health-record export panel as the page hero", () => {
|
||||
it("no longer mounts the health-record export panel (moved to Gesundheitsakte)", () => {
|
||||
const html = render(<ExportSection />);
|
||||
// v1.12 — the health-record export owns the hero treatment.
|
||||
expect(html).toContain('data-testid="health-record-export-panel"');
|
||||
expect(html).toContain("hero-gradient");
|
||||
expect(html).toContain("glow-purple");
|
||||
// v1.18.0 (S5) — the full health-record export lives in its own
|
||||
// top-level Gesundheitsakte section now, not on this page.
|
||||
expect(html).not.toContain('data-testid="health-record-export-panel"');
|
||||
});
|
||||
|
||||
it("no longer mounts a separate doctor-report card", () => {
|
||||
@@ -130,7 +128,7 @@ describe("<ExportSection> — SSR smoke", () => {
|
||||
expect(buttonMatches?.length ?? 0).toBe(4);
|
||||
});
|
||||
|
||||
it("German locale renders the DE heading + hero copy", () => {
|
||||
it("German locale renders the DE heading + sub-heading copy", () => {
|
||||
const html = render(<ExportSection />, "de");
|
||||
expect(html).toContain("Export");
|
||||
expect(html).toContain("Weitere Export-Optionen");
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* v1.18.0 (S5) — Settings → Gesundheitsakte section.
|
||||
*
|
||||
* The full health-record export (PDF + FHIR R4 + zip package) lifted out
|
||||
* of Export & Import into its own top-level home. SSR-only smoke test —
|
||||
* interaction is exercised by the panel's own contract test + e2e.
|
||||
*/
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
|
||||
vi.mock("next/navigation", () => ({
|
||||
useRouter: () => ({ push: vi.fn(), replace: vi.fn() }),
|
||||
usePathname: () => "/settings/gesundheitsakte",
|
||||
}));
|
||||
|
||||
vi.mock("@tanstack/react-query", () => ({
|
||||
useQuery: () => ({ data: null, isLoading: false, refetch: vi.fn() }),
|
||||
useQueryClient: () => ({ invalidateQueries: vi.fn() }),
|
||||
useMutation: () => ({ mutate: vi.fn(), isPending: false }),
|
||||
}));
|
||||
|
||||
vi.mock("@/hooks/use-auth", () => ({
|
||||
useAuth: () => ({
|
||||
user: { id: "u1", role: "USER" },
|
||||
isAuthenticated: true,
|
||||
isLoading: false,
|
||||
refetch: vi.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
import { I18nProvider } from "@/lib/i18n/context";
|
||||
import { GesundheitsakteSection } from "../gesundheitsakte-section";
|
||||
|
||||
function render(node: React.ReactElement, locale: "en" | "de" = "en") {
|
||||
return renderToStaticMarkup(
|
||||
<I18nProvider initialLocale={locale}>{node}</I18nProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
describe("<GesundheitsakteSection> — SSR smoke", () => {
|
||||
it("renders the section description and the health-record panel", () => {
|
||||
const html = render(<GesundheitsakteSection />);
|
||||
expect(html).toContain('id="settings-section-gesundheitsakte-title"');
|
||||
expect(html).toContain('data-testid="health-record-export-panel"');
|
||||
// Raw key never leaks past i18n.
|
||||
expect(html).not.toContain("settings.sections.gesundheitsakte.");
|
||||
});
|
||||
|
||||
it("German locale resolves without leaking the raw key", () => {
|
||||
const html = render(<GesundheitsakteSection />, "de");
|
||||
expect(html).toContain('data-testid="health-record-export-panel"');
|
||||
expect(html).not.toContain("settings.sections.gesundheitsakte.");
|
||||
});
|
||||
});
|
||||
@@ -67,6 +67,8 @@ describe("SETTINGS_SECTION_SLUGS", () => {
|
||||
// 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.
|
||||
// v1.18.0 (S5) — `gesundheitsakte` (the full health-record export) lifts
|
||||
// out of Export & Import into its own top-level entry, before `export`.
|
||||
expect([...SETTINGS_SECTION_SLUGS]).toEqual([
|
||||
"account",
|
||||
"modules",
|
||||
@@ -80,6 +82,7 @@ describe("SETTINGS_SECTION_SLUGS", () => {
|
||||
"thresholds",
|
||||
"ai",
|
||||
"api",
|
||||
"gesundheitsakte",
|
||||
"export",
|
||||
"advanced",
|
||||
"about",
|
||||
@@ -204,6 +207,9 @@ describe("<SettingsShell>", () => {
|
||||
// The ampersand is HTML-escaped by React SSR — assert on the encoded
|
||||
// form so we don't accidentally match a parser that double-escapes.
|
||||
expect(html).toContain("API & Tokens");
|
||||
// v1.18.0 (S5) — the health record is its own top-level entry.
|
||||
expect(html).toContain('href="/settings/gesundheitsakte"');
|
||||
expect(html).toContain("Health record");
|
||||
// v1.4.16 phase B7: the consolidated Export section is a top-level
|
||||
// entry in the sidebar; the link must be present in both locales.
|
||||
expect(html).toContain('href="/settings/export"');
|
||||
|
||||
@@ -9,18 +9,14 @@
|
||||
* per export type, each with its own filter inputs and a clear
|
||||
* "Download" / "Generate" button.
|
||||
*
|
||||
* 1. Health Record export — hero panel at the top of the page
|
||||
* (PDF + FHIR R4 + zip package, see
|
||||
* `<HealthRecordExportPanel>`)
|
||||
* 2. Measurements CSV — optional `since`/`until`
|
||||
* 3. Medications CSV — optional intake-history toggle
|
||||
* 4. Mood CSV — optional `since`/`until`
|
||||
* 5. Full JSON Backup — single-file user-scoped dump
|
||||
* 1. Measurements CSV — optional `since`/`until`
|
||||
* 2. Medications CSV — optional intake-history toggle
|
||||
* 3. Mood CSV — optional `since`/`until`
|
||||
* 4. Full JSON Backup — single-file user-scoped dump
|
||||
*
|
||||
* v1.12 — the health-record export is the headline "data out" path; it
|
||||
* takes the page hero. The doctor-report PDF lives under the
|
||||
* health-record export now and is no longer offered as a separate card
|
||||
* here (it used to be a small secondary card at the bottom).
|
||||
* v1.18.0 (S5) — the full health-record export (PDF + FHIR R4 + zip
|
||||
* package) moved out to its own top-level "Gesundheitsakte" section. This
|
||||
* page now keeps only the generic data export/import paths.
|
||||
*
|
||||
* Mobile-first: cards stack on `<md`, two-column grid on `>=md`.
|
||||
*/
|
||||
@@ -42,7 +38,6 @@ import { Button } from "@/components/ui/button";
|
||||
import { DateInput } from "@/components/ui/date-input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { HealthRecordExportPanel } from "@/components/settings/health-record-export-panel";
|
||||
import { ImportPanel } from "@/components/settings/import-panel";
|
||||
import { queryKeys } from "@/lib/query-keys";
|
||||
import { useTranslations } from "@/lib/i18n/context";
|
||||
@@ -87,15 +82,9 @@ export function ExportSection() {
|
||||
</p>
|
||||
</header>
|
||||
|
||||
{/* v1.12 — full health-record export is now the page hero. PDF +
|
||||
FHIR R4 + a combined zip package, with grouped data-section
|
||||
toggles (collapsed by default) and a format switch. This is the
|
||||
headline "data out" path; it carries the primary visual weight. */}
|
||||
<HealthRecordExportPanel />
|
||||
|
||||
{/* v1.12 — secondary export options. The four CSV/JSON
|
||||
destinations live under a dedicated sub-heading.
|
||||
Mobile: single column. Desktop (md+): 2-column grid. */}
|
||||
{/* v1.18.0 (S5) — the full health-record export moved to its own
|
||||
top-level "Gesundheitsakte" section. This page keeps the generic
|
||||
CSV/JSON data-out paths and the import surface. */}
|
||||
<section
|
||||
aria-labelledby="settings-section-export-other-title"
|
||||
className="space-y-3"
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
"use client";
|
||||
|
||||
/**
|
||||
* v1.18.0 (S5) — Settings → Gesundheitsakte (health record).
|
||||
*
|
||||
* The full health-record export was the hero panel at the top of the
|
||||
* Export & Import section. It is a distinct concept — a complete,
|
||||
* clinician-ready record (PDF + FHIR R4 + a combined zip package) — and
|
||||
* earns its own top-level settings home rather than sharing the page with
|
||||
* the generic CSV / JSON data-out paths. Export & Import now keeps only
|
||||
* the generic data export/import surfaces.
|
||||
*
|
||||
* Not module-gated: the health record is always available.
|
||||
*/
|
||||
|
||||
import { HealthRecordExportPanel } from "@/components/settings/health-record-export-panel";
|
||||
import { useTranslations } from "@/lib/i18n/context";
|
||||
|
||||
export function GesundheitsakteSection() {
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<section
|
||||
aria-labelledby="settings-section-gesundheitsakte-title"
|
||||
className="space-y-6"
|
||||
>
|
||||
<header className="space-y-1">
|
||||
<h1
|
||||
id="settings-section-gesundheitsakte-title"
|
||||
className="sr-only"
|
||||
>
|
||||
{t("settings.sections.gesundheitsakte.title")}
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{t("settings.sections.gesundheitsakte.description")}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<HealthRecordExportPanel />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
Bell,
|
||||
Blocks,
|
||||
Download,
|
||||
FileHeart,
|
||||
Info,
|
||||
KeyRound,
|
||||
LayoutDashboard,
|
||||
@@ -46,6 +47,7 @@ const SLUG_ICON: Record<SettingsSectionSlug, LucideIcon> = {
|
||||
thresholds: SlidersHorizontal,
|
||||
ai: Sparkles,
|
||||
api: KeyRound,
|
||||
gesundheitsakte: FileHeart,
|
||||
export: Download,
|
||||
advanced: Settings2,
|
||||
about: Info,
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
// 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).
|
||||
// v1.18.0 (S5) — per-submodule settings split. `gesundheitsakte` (the full
|
||||
// health-record export, always available) lifts out of Export & Import into
|
||||
// its own top-level entry.
|
||||
export const SETTINGS_SECTION_SLUGS = [
|
||||
"account",
|
||||
// v1.18.0 — `modules` ("Was du trackst") sits right after account: the
|
||||
@@ -46,6 +49,7 @@ export const SETTINGS_SECTION_SLUGS = [
|
||||
"thresholds",
|
||||
"ai",
|
||||
"api",
|
||||
"gesundheitsakte",
|
||||
"export",
|
||||
"advanced",
|
||||
"about",
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
Bell,
|
||||
Blocks,
|
||||
Download,
|
||||
FileHeart,
|
||||
Info,
|
||||
KeyRound,
|
||||
LayoutDashboard,
|
||||
@@ -116,6 +117,13 @@ export const SETTINGS_SECTIONS: readonly SettingsSection[] = [
|
||||
},
|
||||
{ slug: "ai", titleKey: "settings.sections.ai.title", icon: Sparkles },
|
||||
{ slug: "api", titleKey: "settings.sections.api.title", icon: KeyRound },
|
||||
// v1.18.0 (S5) — the full health record (PDF + FHIR R4 + zip package)
|
||||
// earns its own home, lifted out of Export & Import. Always available.
|
||||
{
|
||||
slug: "gesundheitsakte",
|
||||
titleKey: "settings.sections.gesundheitsakte.title",
|
||||
icon: FileHeart,
|
||||
},
|
||||
{
|
||||
slug: "export",
|
||||
titleKey: "settings.sections.export.title",
|
||||
|
||||
Reference in new issue
Block a user