Surface pre-existing conditions in the medical-history section

The chronic-conditions and Coach-focus self-context read as foundational
medical history, so the Anamnese section now surfaces them as a read-only
shared view next to allergies and family history, with a link to their single
editing home in personal context. Personal context links back to the medical
history. The card is coach-gated and reads through the existing
/api/coach/about-me query key, so nothing is moved or duplicated and there is
no schema change.
This commit is contained in:
Marc-André Bombeck committed 2026-06-28 20:29:21 +02:00
1 parent cab0e50fff
commit d3967bcdd0
9 files changed
+207 -6

No files matched your search

@@ -0,0 +1,98 @@
"use client";
/**
* v1.25.1 — pre-existing / chronic conditions, surfaced in the Anamnese
* (medical-history) home.
*
* The chronic-conditions note and the explicit "what should the Coach watch"
* focus the user entered in Settings → Profile → "About me" are foundational
* medical history, so they are surfaced here next to allergies + family history
* to give one coherent medical-history overview.
*
* This is a READ-ONLY shared view of the existing self-context
* (`GET /api/coach/about-me`) — it reads through the same query-key the "About
* me" panel writes, so the two stay in lockstep. Editing keeps its single home
* in personal context (linked below); nothing is moved, no new storage, no
* schema change. Plain text only — values render as React text children, no
* markdown renderer (XSS posture, see contributor notes).
*/
import Link from "next/link";
import { useQuery } from "@tanstack/react-query";
import { Loader2 } from "lucide-react";
import { useTranslations } from "@/lib/i18n/context";
import { queryKeys } from "@/lib/query-keys";
import { apiGet } from "@/lib/api/api-fetch";
interface SelfContext {
conditions: string | null;
coachFocus: string | null;
}
export function ConditionsOverview() {
const { t } = useTranslations();
const { data, isLoading, isError } = useQuery({
queryKey: queryKeys.coachAboutMe(),
queryFn: () => apiGet<SelfContext>("/api/coach/about-me"),
});
const conditions = (data?.conditions ?? "").trim();
const coachFocus = (data?.coachFocus ?? "").trim();
const hasAny = conditions.length > 0 || coachFocus.length > 0;
return (
<div className="space-y-4" data-slot="conditions-overview">
{isLoading && (
<Loader2 className="text-muted-foreground h-5 w-5 animate-spin motion-reduce:animate-none" />
)}
{isError && (
<p role="alert" className="text-destructive text-sm">
{t("records.conditions.loadError")}
</p>
)}
{!isLoading && !isError && (
<>
{hasAny ? (
<dl className="space-y-3">
{conditions.length > 0 && (
<div className="space-y-1">
<dt className="text-sm font-medium">
{t("records.conditions.conditionsLabel")}
</dt>
<dd className="text-muted-foreground text-sm whitespace-pre-wrap">
{conditions}
</dd>
</div>
)}
{coachFocus.length > 0 && (
<div className="space-y-1">
<dt className="text-sm font-medium">
{t("records.conditions.focusLabel")}
</dt>
<dd className="text-muted-foreground text-sm whitespace-pre-wrap">
{coachFocus}
</dd>
</div>
)}
</dl>
) : (
<p className="text-muted-foreground text-sm">
{t("records.conditions.empty")}
</p>
)}
<p className="text-xs">
<Link
href="/settings/account"
className="text-dracula-purple underline-offset-4 hover:underline"
>
{t("records.conditions.editCta")}
</Link>
</p>
</>
)}
</div>
);
}
@@ -350,6 +350,19 @@ export function AboutMeSection({
<p className="text-muted-foreground border-border border-t pt-3 pl-7 text-xs">
{t("settings.ai.aboutMe.hint")} {t("settings.ai.aboutMe.profileHint")}
</p>
{/* v1.25.1 — cross-link to the Anamnese (medical-history) home. The
chronic conditions noted above plus allergies + family history read as
one coherent medical history there. */}
<p className="text-muted-foreground pl-7 text-xs">
{t("settings.ai.aboutMe.recordsLink")}{" "}
<Link
href="/settings/anamnesis"
className="text-dracula-purple underline-offset-4 hover:underline"
>
{t("settings.ai.aboutMe.recordsLinkCta")}
</Link>
</p>
</SettingsCard>
);
}
@@ -8,6 +8,13 @@
* card. These are patient-reported reference records — not a time-series
* signal and not a clinical diagnosis — surfaced alongside the existing
* tracking-domain settings sections (Labs / Illness / Vorsorge).
*
* v1.25.1 — the section also surfaces the pre-existing / chronic conditions the
* Coach watches (the self-context entered under Profile → "About me") as a
* read-only shared view, so conditions + allergies + family history read as one
* coherent medical history. The conditions card is coach-gated (the data only
* feeds the Coach) and links back to its single editing home in personal
* context.
*/
import {
@@ -18,14 +25,31 @@ import {
CardTitle,
} from "@/components/ui/card";
import { useTranslations } from "@/lib/i18n/context";
import { useModuleEnabled } from "@/hooks/use-module-enabled";
import { AllergyManager } from "@/components/records/allergy-manager";
import { ConditionsOverview } from "@/components/records/conditions-overview";
import { FamilyHistoryManager } from "@/components/records/family-history-manager";
export function AnamnesisSection() {
const { t } = useTranslations();
const coachEnabled = useModuleEnabled("coach");
return (
<div className="space-y-6">
{coachEnabled && (
<Card>
<CardHeader>
<CardTitle>{t("records.conditions.cardTitle")}</CardTitle>
<CardDescription>
{t("records.conditions.cardDescription")}
</CardDescription>
</CardHeader>
<CardContent>
<ConditionsOverview />
</CardContent>
</Card>
)}
<Card>
<CardHeader>
<CardTitle>{t("records.allergies.cardTitle")}</CardTitle>