Files
HealthLog/src/components/settings/ai-section.tsx
T
Marc-André Bombeck 3d85445e50 feat(settings): explain operator switches and keep the Coach memory reachable
Settings, AI says which AI features the server's operator switched off and
shows the one setup hint while no provider is configured. The consent
withdrawal says what it deletes and what stays, and a document-reading
consent on file gets its own withdrawal. Regenerate follows the briefing
capability and the connection test names an operator refusal.

The Coach memory (facts and stored conversations) is never gated on the
Coach: Settings, Coach always shows it, and Settings, AI shows it while
the Coach page is out of reach, whenever rows exist.

Onboarding offers AI only where it can be set up here: the done-screen
panel and the getting-started row go away while the operator has AI off
or inside somebody else's record.
2026-09-24 11:05:54 +02:00

63 lines
2.7 KiB
TypeScript

"use client";
/**
* Settings → AI section wrapper.
*
* v1.16.4 — the former 2k-LOC monolith is split into per-provider
* subcomponents under `src/components/settings/ai/` (one file per
* provider form, plus the chain / runtime cards). This file only owns
* the section frame and the card order; behaviour lives in the parts.
*
* v1.18.0 (S5) — the Coach preference cards (disable toggle, preferences,
* memory) moved out to the dedicated Coach section. The AI section keeps
* only provider / model / BYOK configuration.
*
* v1.18.1 (D8) — the "About me" context moved to Settings → Account (under
* Profil, before Zyklus-Tracking). It is personal medical context the daily
* briefing reads too, so it belongs with the account profile rather than the
* provider-configuration screen.
*/
import { AiInsightsCard } from "@/components/settings/ai/ai-insights-card";
import { OperatorOffNotice } from "@/components/settings/ai/operator-off-notice";
import { StoredCoachMemory } from "@/components/settings/coach-memory-section";
import { AiSetupHint } from "@/components/insights/ai-setup-hint";
import { useAuth } from "@/hooks/use-auth";
import { useMounted } from "@/hooks/use-mounted";
import { isSurfaceVisible } from "@/lib/modules/surface";
export function AiSection() {
const { isAuthenticated, user } = useAuth();
// v1.16.6 — the auth query can resolve before this boundary
// hydrates; every `disabled={!isAuthenticated}` binding in the child
// cards would then disagree with the SSR HTML (React #418). Gate the
// prop on `useMounted()` so the hydration render matches the
// server-rendered "not yet authenticated" state and the cards enable
// on the first client re-render.
const mounted = useMounted();
const authed = mounted && isAuthenticated;
// v1.18.6 (W9) — the visible heading + subtitle now come from the shared
// `<SettingsSectionFrame>` in the route; this body is the single provider
// card. (The "About me" context moved to Settings → Account in v1.18.1 D8.)
//
// v1.39 — above the provider card: what the operator has switched off (so
// nothing below reads as broken), and the one calm setup hint while no
// provider is configured. Below it: what the Coach stored, while Settings →
// Coach is not reachable, so it can always be read and deleted.
const coachSettingsReachable = isSurfaceVisible(
"settings:coach",
user?.modules,
);
return (
<div className="space-y-6">
<OperatorOffNotice />
<AiSetupHint surface="settings" />
<AiInsightsCard isAuthenticated={authed} />
{authed && !coachSettingsReachable ? (
<StoredCoachMemory isAuthenticated={authed} />
) : null}
</div>
);
}