diff --git a/messages/de.json b/messages/de.json index 4d9862a6c..a0e5d4797 100644 --- a/messages/de.json +++ b/messages/de.json @@ -871,6 +871,7 @@ "sourcesFresh": "Aktuell", "sourcesStale": "Veraltet", "sourcesFooter": "Der Coach liest nur Daten, die du verbunden hast.", + "evidenceLabel": "Worauf bezieht sich das?", "metric": { "bp": "Blutdruck", "weight": "Gewicht", diff --git a/messages/en.json b/messages/en.json index f1d8af3d6..aefd41155 100644 --- a/messages/en.json +++ b/messages/en.json @@ -871,6 +871,7 @@ "sourcesFresh": "Fresh", "sourcesStale": "Stale", "sourcesFooter": "The Coach reads only the data you've connected.", + "evidenceLabel": "What I'm looking at", "metric": { "bp": "Blood pressure", "weight": "Weight", diff --git a/src/components/insights/coach-panel/__tests__/message-thread.test.tsx b/src/components/insights/coach-panel/__tests__/message-thread.test.tsx index cb4c72274..b18e6747e 100644 --- a/src/components/insights/coach-panel/__tests__/message-thread.test.tsx +++ b/src/components/insights/coach-panel/__tests__/message-thread.test.tsx @@ -216,4 +216,107 @@ describe("", () => { "Frag mich etwas zu deinen Trends, Medikamenten oder Messwerten", ); }); + + it("renders the evidence-block disclosure when keyValues is non-empty (EN)", () => { + // v1.4.22 — the Coach surfaces load-bearing numbers in a + // collapsible "What I'm looking at" disclosure under the assistant + // bubble. Verify the structure renders correctly and the entries + // show label / value / unit / window. + const withKeyValues: CoachConversationDetailDTO = { + ...baseConversation, + messages: [ + baseConversation.messages[0], + { + ...baseConversation.messages[1], + metricSource: { + windows: ["last30days"], + metrics: ["bp"], + keyValues: [ + { + label: "avg7 systolic", + value: "138", + unit: "mmHg", + window: "last7days", + }, + { + label: "avg30 systolic", + value: "134", + unit: "mmHg", + window: "last30days", + }, + ], + }, + }, + ], + }; + const html = render(); + expect(html).toContain('data-slot="coach-evidence"'); + expect(html).toContain("What I'm looking at"); + expect(html).toContain('data-slot="coach-evidence-list"'); + const rows = (html.match(/data-slot="coach-evidence-row"/g) ?? []).length; + expect(rows).toBe(2); + expect(html).toContain("avg7 systolic"); + expect(html).toContain("138 mmHg"); + expect(html).toContain("(last7days)"); + expect(html).toContain("avg30 systolic"); + expect(html).toContain("134 mmHg"); + // Disclosure is collapsed by default (no `open` attribute). + expect(html).not.toMatch(/]*\bopen\b/); + }); + + it("renders the evidence-block label in German under 'de' locale", () => { + const withKeyValues: CoachConversationDetailDTO = { + ...baseConversation, + messages: [ + baseConversation.messages[0], + { + ...baseConversation.messages[1], + metricSource: { + windows: ["last30days"], + metrics: ["bp"], + keyValues: [ + { + label: "avg30 systolisch", + value: "138", + unit: "mmHg", + window: "last30days", + }, + ], + }, + }, + ], + }; + const html = render(, "de"); + expect(html).toContain("Worauf bezieht sich das?"); + }); + + it("renders entries without unit or window cleanly", () => { + const withKeyValues: CoachConversationDetailDTO = { + ...baseConversation, + messages: [ + baseConversation.messages[0], + { + ...baseConversation.messages[1], + metricSource: { + windows: [], + metrics: ["compliance"], + keyValues: [{ label: "30-day adherence", value: "96" }], + }, + }, + ], + }; + const html = render(); + expect(html).toContain("30-day adherence"); + // No stray empty unit/window markup. + expect(html).not.toMatch(/30-day adherence:\s*<\/span>\s*]*>\s* { + // baseConversation.messages[1].metricSource has no `keyValues` + // field — the source chips still render but the disclosure does + // not appear at all. + const html = render(); + expect(html).not.toContain('data-slot="coach-evidence"'); + expect(html).not.toContain("What I'm looking at"); + }); }); diff --git a/src/components/insights/coach-panel/message-thread.tsx b/src/components/insights/coach-panel/message-thread.tsx index f277213ba..e89685f69 100644 --- a/src/components/insights/coach-panel/message-thread.tsx +++ b/src/components/insights/coach-panel/message-thread.tsx @@ -1,7 +1,7 @@ "use client"; import { useEffect, useRef } from "react"; -import { Bot, Sparkles, User } from "lucide-react"; +import { Bot, ChevronRight, Sparkles, User } from "lucide-react"; import { cn } from "@/lib/utils"; import { useTranslations } from "@/lib/i18n/context"; @@ -202,6 +202,8 @@ function ChatBubble({ ? t("insights.coach.errorProvider") : null; + const keyValues = metricSource?.keyValues ?? []; + return (
{safeError}

)} {metricSource && } + {keyValues.length > 0 && ( +
+ + +
    + {keyValues.map((kv, idx) => ( +
  • + {kv.label}:{" "} + + {kv.value} + {kv.unit ? ` ${kv.unit}` : ""} + + {kv.window && ( + + {" "} + ({kv.window}) + + )} +
  • + ))} +
+
+ )}
);