Files
HealthLog/src/components/settings/section-placeholder.tsx
T
Marc-André Bombeck 43d9610f03 refactor(settings): fold Labs, Vorsorge, and Illness into the shell
Promote the three per-module customise surfaces from standalone
ModuleSettingsFrame pages to first-class Settings sections. They now
render inside the Settings shell — same left nav, heading, and chrome as
account / ai / integrations / notifications — instead of their own
back-button-and-title frame outside it.

Add labs, illness, and vorsorge to the slug registry (after mood) and to
SETTINGS_SECTIONS with FlaskConical / Thermometer / CalendarCheck icons.
labs and illness gate on their toggleable modules; vorsorge has no
module, so its entry is always shown. Three thin section components wrap
the existing LabsSettings / IllnessSettings / VorsorgeSettings content,
mirroring MedicationsSection / CoachSection.

Delete the three standalone /settings/{labs,vorsorge,illness} routes so
the wrench deep links resolve through the dynamic [section] route, and
drop ModuleSettingsFrame now that nothing renders it. Add the section
title / subtitle / description keys across all six locales and remove the
dead per-module *.settings.* blocks the old pages consumed.
2026-06-19 21:06:25 +02:00

106 lines
2.8 KiB
TypeScript

"use client";
/**
* `<SectionPlaceholder>` — the temporary body of every `/settings/[section]`
* route until the matching extraction PR lands.
*
* The shell + routing surface ship in PR A2-shell so reviewers can validate
* the URL structure in isolation. The follow-up PRs (A2-account, A2-about,
* A2-ai, A2-integrations, A2-notifications, A2-rest) replace this placeholder
* with the real content for each slug, copying from
* `src/app/settings/page.legacy.tsx`.
*/
import {
Bell,
Blocks,
Bot,
CalendarCheck,
Download,
FileHeart,
FlaskConical,
Info,
KeyRound,
Layers,
LayoutDashboard,
Link2,
Pill,
Radio,
Settings2,
SlidersHorizontal,
Smile,
Sparkles,
Thermometer,
TrendingUp,
User,
type LucideIcon,
} from "lucide-react";
import { EmptyState } from "@/components/ui/empty-state";
import { useTranslations } from "@/lib/i18n/context";
import type { SettingsSectionSlug } from "./section-slugs";
const SLUG_ICON: Record<SettingsSectionSlug, LucideIcon> = {
account: User,
modules: Blocks,
integrations: Link2,
channels: Radio,
sources: Layers,
notifications: Bell,
layout: LayoutDashboard,
dashboard: LayoutDashboard,
insights: TrendingUp,
medications: Pill,
mood: Smile,
labs: FlaskConical,
illness: Thermometer,
vorsorge: CalendarCheck,
thresholds: SlidersHorizontal,
ai: Sparkles,
coach: Bot,
api: KeyRound,
gesundheitsakte: FileHeart,
export: Download,
advanced: Settings2,
about: Info,
};
export interface SectionPlaceholderProps {
slug: SettingsSectionSlug;
}
export function SectionPlaceholder({ slug }: SectionPlaceholderProps) {
const { t } = useTranslations();
const Icon = SLUG_ICON[slug];
const sectionTitle = t(`settings.sections.${slug}.title`);
const sectionDescription = t(`settings.sections.${slug}.description`);
// v1.4.33 A4 — `<SectionPlaceholder>` is a defensive fallback for
// slugs added to SETTINGS_SECTION_SLUGS without a matching component.
// The type system blocks that path today, so the EmptyState body is
// effectively unreachable. We retire the dedicated locale key
// (`settings.sections.placeholder.coming_soon`) and inherit the
// section's own description so the guard still renders meaningful
// copy if it ever does fire — no more dead-string maintenance across
// six locale files.
return (
<section
aria-labelledby={`settings-section-${slug}-title`}
className="space-y-6"
>
<header className="space-y-1">
<h1 id={`settings-section-${slug}-title`} className="sr-only">
{sectionTitle}
</h1>
<p className="text-muted-foreground text-sm">{sectionDescription}</p>
</header>
<EmptyState
icon={<Icon className="size-6" />}
title={sectionTitle}
description={sectionDescription}
/>
</section>
);
}