mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
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:
1 parent
cab0e50fff
commit
d3967bcdd0
9 files changed
+207
-6
No files matched your search
+12
-1
@@ -4665,7 +4665,9 @@
|
||||
"focusPlaceholder": "Z. B. behalte meinen Blutdruck im Blick, motiviere mich zu mehr Bewegung …",
|
||||
"completeness": "{answered} von {total} beantwortet",
|
||||
"questionsTitle": "Der Coach hat Rückfragen",
|
||||
"questionsOpenCoach": "Im Coach beantworten"
|
||||
"questionsOpenCoach": "Im Coach beantworten",
|
||||
"recordsLink": "Allergien, Familienanamnese und deine Vorerkrankungen gehören zu deiner Anamnese.",
|
||||
"recordsLinkCta": "Anamnese öffnen"
|
||||
},
|
||||
"responseTimeoutHeading": "Antwort-Timeout",
|
||||
"responseTimeoutBody": "Wie lange auf die Antwort der KI gewartet wird, bevor abgebrochen wird. Erhöhe den Wert für ein lokales oder selbst gehostetes Modell, das beim ersten Aufruf Zeit zum Laden braucht.",
|
||||
@@ -7774,6 +7776,15 @@
|
||||
"updatedToast": "Eintrag aktualisiert",
|
||||
"saveError": "Der Eintrag konnte nicht gespeichert werden."
|
||||
}
|
||||
},
|
||||
"conditions": {
|
||||
"cardTitle": "Vorerkrankungen",
|
||||
"cardDescription": "Chronische Erkrankungen und worauf der Coach achten soll — aus deinem persönlichen Kontext.",
|
||||
"conditionsLabel": "Chronische Erkrankungen",
|
||||
"focusLabel": "Worauf der Coach achtet",
|
||||
"empty": "Noch nichts hinterlegt.",
|
||||
"editCta": "Im persönlichen Kontext bearbeiten",
|
||||
"loadError": "Vorerkrankungen konnten nicht geladen werden."
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
|
||||
+12
-1
@@ -4665,7 +4665,9 @@
|
||||
"focusPlaceholder": "E.g. keep an eye on my blood pressure, motivate me to move more…",
|
||||
"completeness": "{answered} of {total} answered",
|
||||
"questionsTitle": "The Coach has follow-up questions",
|
||||
"questionsOpenCoach": "Answer them in the Coach"
|
||||
"questionsOpenCoach": "Answer them in the Coach",
|
||||
"recordsLink": "Allergies, family history and your pre-existing conditions are part of your medical history.",
|
||||
"recordsLinkCta": "Open medical history"
|
||||
},
|
||||
"responseTimeoutHeading": "Response timeout",
|
||||
"responseTimeoutBody": "How long to wait for the AI to respond before giving up. Raise it for a local or self-hosted model that needs time to load on the first request.",
|
||||
@@ -7774,6 +7776,15 @@
|
||||
"updatedToast": "Entry updated",
|
||||
"saveError": "Couldn't save the entry."
|
||||
}
|
||||
},
|
||||
"conditions": {
|
||||
"cardTitle": "Pre-existing conditions",
|
||||
"cardDescription": "Chronic conditions and what the Coach watches — from your personal context.",
|
||||
"conditionsLabel": "Chronic conditions",
|
||||
"focusLabel": "What the Coach watches",
|
||||
"empty": "Nothing noted yet.",
|
||||
"editCta": "Edit in personal context",
|
||||
"loadError": "Couldn't load your conditions."
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
|
||||
+12
-1
@@ -4665,7 +4665,9 @@
|
||||
"focusPlaceholder": "P. ej. vigila mi tensión arterial, motívame a moverme más…",
|
||||
"completeness": "{answered} de {total} respondidas",
|
||||
"questionsTitle": "El Coach tiene preguntas",
|
||||
"questionsOpenCoach": "Responderlas en el Coach"
|
||||
"questionsOpenCoach": "Responderlas en el Coach",
|
||||
"recordsLink": "Las alergias, los antecedentes familiares y tus enfermedades preexistentes forman parte de tu historia clínica.",
|
||||
"recordsLinkCta": "Abrir historia clínica"
|
||||
},
|
||||
"responseTimeoutHeading": "Tiempo de espera de la respuesta",
|
||||
"responseTimeoutBody": "Cuánto esperar a que responda la IA antes de cancelar. Aumenta el valor para un modelo local o autoalojado que necesita tiempo para cargarse en la primera solicitud.",
|
||||
@@ -7774,6 +7776,15 @@
|
||||
"updatedToast": "Entrada actualizada",
|
||||
"saveError": "No se ha podido guardar la entrada."
|
||||
}
|
||||
},
|
||||
"conditions": {
|
||||
"cardTitle": "Enfermedades preexistentes",
|
||||
"cardDescription": "Enfermedades crónicas y aquello que el Coach debe vigilar, desde tu contexto personal.",
|
||||
"conditionsLabel": "Enfermedades crónicas",
|
||||
"focusLabel": "Qué vigila el Coach",
|
||||
"empty": "Aún no hay nada anotado.",
|
||||
"editCta": "Editar en el contexto personal",
|
||||
"loadError": "No se pudieron cargar tus enfermedades."
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
|
||||
+12
-1
@@ -4665,7 +4665,9 @@
|
||||
"focusPlaceholder": "P. ex. surveille ma tension, motive-moi à bouger davantage…",
|
||||
"completeness": "{answered} sur {total} renseignés",
|
||||
"questionsTitle": "Le Coach a des questions",
|
||||
"questionsOpenCoach": "Y répondre dans le Coach"
|
||||
"questionsOpenCoach": "Y répondre dans le Coach",
|
||||
"recordsLink": "Les allergies, les antécédents familiaux et vos affections préexistantes font partie de vos antécédents médicaux.",
|
||||
"recordsLinkCta": "Ouvrir les antécédents médicaux"
|
||||
},
|
||||
"responseTimeoutHeading": "Délai de réponse",
|
||||
"responseTimeoutBody": "Durée d'attente de la réponse de l'IA avant d'abandonner. Augmentez-la pour un modèle local ou auto-hébergé qui a besoin de temps pour se charger à la première requête.",
|
||||
@@ -7774,6 +7776,15 @@
|
||||
"updatedToast": "Entrée mise à jour",
|
||||
"saveError": "Impossible d'enregistrer l'entrée."
|
||||
}
|
||||
},
|
||||
"conditions": {
|
||||
"cardTitle": "Affections préexistantes",
|
||||
"cardDescription": "Affections chroniques et ce que le Coach doit surveiller, d'après votre contexte personnel.",
|
||||
"conditionsLabel": "Affections chroniques",
|
||||
"focusLabel": "Ce que le Coach surveille",
|
||||
"empty": "Rien de noté pour l'instant.",
|
||||
"editCta": "Modifier dans le contexte personnel",
|
||||
"loadError": "Impossible de charger vos antécédents."
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
|
||||
+12
-1
@@ -4665,7 +4665,9 @@
|
||||
"focusPlaceholder": "Es. tieni d'occhio la mia pressione, motivami a muovermi di più…",
|
||||
"completeness": "{answered} su {total} compilati",
|
||||
"questionsTitle": "Il Coach ha alcune domande",
|
||||
"questionsOpenCoach": "Rispondi nel Coach"
|
||||
"questionsOpenCoach": "Rispondi nel Coach",
|
||||
"recordsLink": "Allergie, anamnesi familiare e le tue patologie preesistenti fanno parte della tua anamnesi.",
|
||||
"recordsLinkCta": "Apri anamnesi"
|
||||
},
|
||||
"responseTimeoutHeading": "Timeout della risposta",
|
||||
"responseTimeoutBody": "Quanto attendere la risposta dell'IA prima di annullare. Aumentalo per un modello locale o self-hosted che ha bisogno di tempo per caricarsi alla prima richiesta.",
|
||||
@@ -7774,6 +7776,15 @@
|
||||
"updatedToast": "Voce aggiornata",
|
||||
"saveError": "Impossibile salvare la voce."
|
||||
}
|
||||
},
|
||||
"conditions": {
|
||||
"cardTitle": "Patologie preesistenti",
|
||||
"cardDescription": "Patologie croniche e ciò che il Coach deve tenere d'occhio, dal tuo contesto personale.",
|
||||
"conditionsLabel": "Patologie croniche",
|
||||
"focusLabel": "Cosa tiene d'occhio il Coach",
|
||||
"empty": "Ancora nessuna annotazione.",
|
||||
"editCta": "Modifica nel contesto personale",
|
||||
"loadError": "Impossibile caricare le tue patologie."
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
|
||||
+12
-1
@@ -4665,7 +4665,9 @@
|
||||
"focusPlaceholder": "Np. pilnuj mojego ciśnienia, motywuj mnie do ruchu…",
|
||||
"completeness": "Wypełnione: {answered} z {total}",
|
||||
"questionsTitle": "Coach ma pytania",
|
||||
"questionsOpenCoach": "Odpowiedz w Coachu"
|
||||
"questionsOpenCoach": "Odpowiedz w Coachu",
|
||||
"recordsLink": "Alergie, wywiad rodzinny i Twoje choroby przewlekłe są częścią Twojego wywiadu medycznego.",
|
||||
"recordsLinkCta": "Otwórz wywiad medyczny"
|
||||
},
|
||||
"responseTimeoutHeading": "Limit czasu odpowiedzi",
|
||||
"responseTimeoutBody": "Jak długo czekać na odpowiedź AI, zanim nastąpi przerwanie. Zwiększ wartość dla lokalnego lub samodzielnie hostowanego modelu, który potrzebuje czasu na załadowanie przy pierwszym żądaniu.",
|
||||
@@ -7774,6 +7776,15 @@
|
||||
"updatedToast": "Wpis zaktualizowany",
|
||||
"saveError": "Nie udało się zapisać wpisu."
|
||||
}
|
||||
},
|
||||
"conditions": {
|
||||
"cardTitle": "Choroby przewlekłe",
|
||||
"cardDescription": "Choroby przewlekłe i to, na co Coach ma zwracać uwagę — z Twojego kontekstu osobistego.",
|
||||
"conditionsLabel": "Choroby przewlekłe",
|
||||
"focusLabel": "Na co zwraca uwagę Coach",
|
||||
"empty": "Nic jeszcze nie zapisano.",
|
||||
"editCta": "Edytuj w kontekście osobistym",
|
||||
"loadError": "Nie udało się wczytać Twoich chorób."
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in new issue
Block a user