mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 13:52:20 +00:00
fix(settings): finish the D0-D8 settings/admin frame cleanup
- Drop the leading blurb paragraph from the Channels + Integrations connection panels so each body starts at its first card (D0 alignment). - Correct three stale CORE/always-on comments: medications has been a fail-open toggleable module since D3; CORE is now weight/BP/pulse only. - Remove the dead variant/isSubtab branch from SourcesSection — no callers after the D4 split; render the standalone header unconditionally. - Render the admin AI-quality card frame + header once and branch only the body across loading/error/empty/data, matching the coach-feedback card. - Rename the Coach activation card's section id from the legacy settings-ai-* namespace to settings-coach-activate-* after the S5 move. - Gate the medication low-stock reminder card on the medications module so it hides when the account turns medications off, mirroring mood/coach.
This commit is contained in:
1 parent
a3217ff767
commit
dadb6e2d34
8 files changed
+99
-122
No files matched your search
@@ -65,64 +65,56 @@ export function AiQualitySection() {
|
||||
},
|
||||
});
|
||||
|
||||
if (query.isLoading) {
|
||||
return (
|
||||
<div className="bg-card border-border flex items-center gap-2 rounded-xl border p-4 sm:p-6">
|
||||
<Loader2 className="h-4 w-4 animate-spin motion-reduce:animate-none" />
|
||||
<span className="text-muted-foreground text-sm">
|
||||
{t("admin.aiQuality.loading")}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (query.isError) {
|
||||
return (
|
||||
<div
|
||||
role="alert"
|
||||
className="text-destructive bg-destructive/10 border-destructive/30 rounded-xl border p-4 text-sm"
|
||||
>
|
||||
{t("admin.aiQuality.loadError")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const summary = query.data;
|
||||
|
||||
if (!summary || summary.buckets.length === 0) {
|
||||
return (
|
||||
<div className="bg-card border-border rounded-xl border p-4 sm:p-6">
|
||||
<SettingsCardHeader
|
||||
icon={Sparkles}
|
||||
title={t("admin.aiQuality.title")}
|
||||
/>
|
||||
<p className="text-muted-foreground mt-3 pl-7 text-sm">
|
||||
{t("admin.aiQuality.empty")}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const summary = query.data ?? null;
|
||||
const buckets = summary?.buckets ?? [];
|
||||
const hasData = !!summary && buckets.length > 0;
|
||||
|
||||
// v1.18.1 — keep the outer card + header rendered across every query
|
||||
// state (loading / error / empty / data) so the heading baseline stays at
|
||||
// a constant Y-offset and the section never snaps downward when the data
|
||||
// resolves. Mirrors <CoachFeedbackSection> (header outside the
|
||||
// fetch-state branch).
|
||||
return (
|
||||
<div className="bg-card border-border space-y-4 rounded-xl border p-4 sm:p-6">
|
||||
<SettingsCardHeader
|
||||
icon={Sparkles}
|
||||
title={t("admin.aiQuality.title")}
|
||||
status={
|
||||
<p className="text-muted-foreground text-xs">
|
||||
{t("admin.aiQuality.windowLabel", {
|
||||
days: String(summary.windowDays),
|
||||
})}
|
||||
{" · "}
|
||||
{t("admin.aiQuality.generatedAtLabel")}{" "}
|
||||
{fmt.dateTime(summary.generatedAt)}
|
||||
</p>
|
||||
hasData && summary ? (
|
||||
<p className="text-muted-foreground text-xs">
|
||||
{t("admin.aiQuality.windowLabel", {
|
||||
days: String(summary.windowDays),
|
||||
})}
|
||||
{" · "}
|
||||
{t("admin.aiQuality.generatedAtLabel")}{" "}
|
||||
{fmt.dateTime(summary.generatedAt)}
|
||||
</p>
|
||||
) : null
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm" data-slot="ai-quality-table">
|
||||
<thead>
|
||||
{query.isLoading ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<Loader2 className="h-4 w-4 animate-spin motion-reduce:animate-none" />
|
||||
<span className="text-muted-foreground text-sm">
|
||||
{t("admin.aiQuality.loading")}
|
||||
</span>
|
||||
</div>
|
||||
) : query.isError ? (
|
||||
<div
|
||||
role="alert"
|
||||
className="text-destructive bg-destructive/10 border-destructive/30 rounded-md border p-3 text-sm"
|
||||
>
|
||||
{t("admin.aiQuality.loadError")}
|
||||
</div>
|
||||
) : !hasData ? (
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{t("admin.aiQuality.empty")}
|
||||
</p>
|
||||
) : (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm" data-slot="ai-quality-table">
|
||||
<thead>
|
||||
<tr className="text-muted-foreground border-border border-b text-left text-xs tracking-wider uppercase">
|
||||
<th className="py-2 pr-3 font-medium">
|
||||
{t("admin.aiQuality.colSeverity")}
|
||||
@@ -148,7 +140,7 @@ export function AiQualitySection() {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{summary.buckets.map((bucket, idx) => {
|
||||
{buckets.map((bucket, idx) => {
|
||||
const ratePct = Math.round(bucket.helpfulRate * 100);
|
||||
return (
|
||||
<tr
|
||||
@@ -184,7 +176,8 @@ export function AiQualitySection() {
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user