mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 06:06:10 +00:00
Replace the SectionPlaceholder fallbacks for Account, AI, Integrations, Notifications, Dashboard, API, Advanced, and About with real per-section components. Every /settings/<slug> URL now renders working content; the placeholder only fires for unknown slugs. A2-content extraction - Account: profile + passkeys + password change (account-section.tsx) - AI: insights + per-user provider override (ai-section.tsx) - Integrations: Withings + moodLog (integrations-section.tsx) - Notifications: Telegram + ntfy + Web Push (split into telegram-card, ntfy-card, web-push-card to keep each file under ~600 LOC) - Dashboard: layout + thresholds wrappers (dashboard-section.tsx) - API: endpoints + tokens (api-section.tsx) - Advanced: export + danger zone (advanced-section.tsx) - About (greenfield): version, license, build SHA, repo/changelog/docs links + "Check for updates" against GitHub releases A2-about - Reads /api/version via TanStack Query, surfaces app version, AGPL-3.0 badge, short build SHA, build timestamp, repo/changelog/docs links. - "Check for updates" button compares against api.github.com latest release tag with up-to-date / newer-available / failure feedback. A8-UI test buttons - Shared TestConnectionButton primitive that POSTs to a test endpoint, surfaces ok-with-latency or translated meta.errorCode failures. - Wired into Withings + moodLog (Integrations) and Web Push (Notifications). Glitchtip + Umami remain admin-only. i18n - New settings.about.* and settings.testConnection.* key groups in en.json and de.json. Cleanup - Delete src/app/settings/page.legacy.tsx (3230 LOC monolith). - Convert sync-from-server patterns to the React-recommended prev-payload-id render-time pattern so the strict react-hooks/set-state-in-effect rule passes without a file-level disable. Tests - New src/components/settings/__tests__/sections.test.tsx with 9 SSR smoke tests (one per section) — total suite 514 (was 505).
60 lines
1.8 KiB
TypeScript
60 lines
1.8 KiB
TypeScript
"use client";
|
|
|
|
import { useQuery } from "@tanstack/react-query";
|
|
|
|
import { useAuth } from "@/hooks/use-auth";
|
|
import { useTranslations } from "@/lib/i18n/context";
|
|
import { NtfyCard } from "@/components/settings/ntfy-card";
|
|
import { TelegramCard } from "@/components/settings/telegram-card";
|
|
import { WebPushCard } from "@/components/settings/web-push-card";
|
|
|
|
interface GlobalServiceAvailability {
|
|
telegramGlobal: boolean;
|
|
ntfyGlobal: boolean;
|
|
webPushGlobal: boolean;
|
|
apiGlobal: boolean;
|
|
moodLogGlobal: boolean;
|
|
}
|
|
|
|
export function NotificationsSection() {
|
|
const { t } = useTranslations();
|
|
const { isAuthenticated } = useAuth();
|
|
|
|
const { data: globalServices } = useQuery({
|
|
queryKey: ["settings", "global-services"],
|
|
queryFn: async () => {
|
|
const res = await fetch("/api/settings/global-services");
|
|
if (!res.ok) throw new Error("Failed");
|
|
return (await res.json()).data as GlobalServiceAvailability;
|
|
},
|
|
enabled: isAuthenticated,
|
|
});
|
|
|
|
const showTelegram = globalServices?.telegramGlobal ?? true;
|
|
const showNtfy = globalServices?.ntfyGlobal ?? true;
|
|
const showWebPush = globalServices?.webPushGlobal ?? true;
|
|
|
|
return (
|
|
<section
|
|
aria-labelledby="settings-section-notifications-title"
|
|
className="space-y-6"
|
|
>
|
|
<header className="space-y-1">
|
|
<h1
|
|
id="settings-section-notifications-title"
|
|
className="text-2xl font-semibold tracking-tight"
|
|
>
|
|
{t("settings.sections.notifications.title")}
|
|
</h1>
|
|
<p className="text-muted-foreground text-sm">
|
|
{t("settings.sections.notifications.description")}
|
|
</p>
|
|
</header>
|
|
|
|
{showTelegram && <TelegramCard isAuthenticated={isAuthenticated} />}
|
|
{showNtfy && <NtfyCard isAuthenticated={isAuthenticated} />}
|
|
{showWebPush && <WebPushCard />}
|
|
</section>
|
|
);
|
|
}
|