Files
HealthLog/src/components/admin/services-section.tsx
T
Marc-André Bombeck 6da94280b5 feat(admin): extract per-section components from admin page monolith (#145)
The admin page was a single 2,702-line client component with
nineteen inline functions covering everything from system status
to feedback inbox. The status-card grid foundation in #133 already
moved the at-a-glance dashboard out; this commit moves the inner
panels.

Split into one file per logical section in src/components/admin/:

  _shared.tsx                         276 LOC  shared types, hooks,
                                                primitives (PasswordInput,
                                                StatusItem, SettingsToggle,
                                                useAdminSettings,
                                                useUpdateSettings,
                                                useSystemStatus,
                                                getApiErrorMessage)
  system-status-section.tsx           155
  general-settings-section.tsx         54
  services-section.tsx                 68
  umami-section.tsx                   173
  glitchtip-section.tsx               172
  web-push-vapid-section.tsx          148
  bug-report-section.tsx              109
  reminders-section.tsx               318
  user-management-section.tsx         341
  api-token-overview-section.tsx      144
  login-overview-section.tsx          181
  danger-zone-section.tsx             118
  feedback-inbox-section.tsx          511 (inbox + category badge
                                            + detail dialog)

src/app/admin/page.tsx is now a 77-line shell that imports the
14 sections and the existing status-card-grid.tsx. No behavior
change — every section keeps the same DOM, the same query keys,
the same i18n keys, the same id="…" anchors so deep-links from
the sidebar still scroll into place. UserManagementSection no
longer takes a queryClient prop; it grabs its own via
useQueryClient() like every other section does.
2026-05-08 15:58:06 +02:00

69 lines
2.2 KiB
TypeScript

"use client";
import { Bell, Globe, Key, MessageCircle } from "lucide-react";
import { useTranslations } from "@/lib/i18n/context";
import { SettingsToggle, useAdminSettings, useUpdateSettings } from "./_shared";
export function ServicesSection({ id }: { id: string }) {
const { t } = useTranslations();
const { data: settings } = useAdminSettings();
const updateSettings = useUpdateSettings();
return (
<div
id={id}
className="bg-card border-border scroll-mt-28 rounded-xl border p-6"
>
<div className="flex items-center gap-2">
<Globe className="text-primary h-5 w-5" />
<h2 className="text-lg font-semibold">{t("admin.servicesGlobal")}</h2>
</div>
<p className="text-muted-foreground mt-1 text-xs">
{t("admin.servicesGlobalDescription")}
</p>
<div className="mt-4 space-y-3">
<SettingsToggle
label="Telegram"
description={t("admin.telegramGlobal")}
icon={MessageCircle}
checked={settings?.telegramGlobal ?? true}
onCheckedChange={(checked) =>
updateSettings.mutate({ telegramGlobal: checked })
}
disabled={updateSettings.isPending}
/>
<SettingsToggle
label="ntfy"
description={t("admin.ntfyGlobal")}
icon={Bell}
checked={settings?.ntfyGlobal ?? true}
onCheckedChange={(checked) =>
updateSettings.mutate({ ntfyGlobal: checked })
}
disabled={updateSettings.isPending}
/>
<SettingsToggle
label={t("admin.integrationWebPush")}
description={t("admin.webPushGlobal")}
icon={Globe}
checked={settings?.webPushGlobal ?? true}
onCheckedChange={(checked) =>
updateSettings.mutate({ webPushGlobal: checked })
}
disabled={updateSettings.isPending}
/>
<SettingsToggle
label="API"
description={t("admin.apiGlobal")}
icon={Key}
checked={settings?.apiGlobal ?? true}
onCheckedChange={(checked) =>
updateSettings.mutate({ apiGlobal: checked })
}
disabled={updateSettings.isPending}
/>
</div>
</div>
);
}