feat(doctor-report): mark screener totals answered in an unvalidated translation

The report data counts, per screener score type, how many of the
window's results were answered in a translation that has not been
validated (`screenerUnvalidatedTranslations`, read only when a screener
total is in the report). The PDF marks such a row with an asterisk and
says under the vitals table how many of how many read as orientation;
the clinician share view says the same under the row.

To keep the aggregator and the PDF section from growing, the wellness
summary and the per-context glucose rows move into helpers; the size
ratchets only fall.
This commit is contained in:
Marc-André Bombeck committed 2026-10-23 08:14:32 +02:00
1 parent 02cc0631fa
commit 14273051db
22 files changed
+369 -85

No files matched your search

@@ -328,6 +328,28 @@ describe("<ClinicianView>", () => {
expect(html).toContain("0.495");
});
it("notes a screener total answered in an unvalidated translation under its row", () => {
const stats = {
SCI_SCORE: { avg: 18, min: 14, max: 22, count: 3, latest: 20 },
PHQ9_SCORE: { avg: 6, min: 4, max: 8, count: 2, latest: 4 },
};
const selection = selectionFromLeaves(["SCI_SCORE", "PHQ9_SCORE"]);
const marked = render(
makeReport({ stats, screenerUnvalidatedTranslations: { SCI_SCORE: 2 } }),
{ selection },
);
expect(
marked.split('data-slot="clinician-screener-translation-note"').length -
1,
).toBe(1);
expect(marked).toContain("2 of 3 results were answered in a translation");
const plain = render(
makeReport({ stats, screenerUnvalidatedTranslations: null }),
{ selection },
);
expect(plain).not.toContain("clinician-screener-translation-note");
});
it("renders the fenced wellness card with the descriptive disclaimer", () => {
const html = render(makeReport());
expect(html).toContain("Wellness scores");
+28 -10
View File
@@ -245,17 +245,35 @@ export function MeasurementGroups({
>
{group.rows.map(({ type, stat }) => {
const digits = reportStatFractionDigits(type, stat!, glucoseUnit);
const label = t(reportMeasurementLabelKey(type));
// A screener total answered in a translation that has not been
// validated says so under its row, as the PDF does.
const unvalidated =
report.screenerUnvalidatedTranslations?.[type] ?? 0;
return (
<StatRow
key={type}
label={t(reportMeasurementLabelKey(type))}
value={statSummary(t, reportStatUnit(type, glucoseUnit, t), {
latest: show(type, stat!.latest, digits),
avg: show(type, stat!.avg, digits),
min: show(type, stat!.min, digits),
max: show(type, stat!.max, digits),
})}
/>
<Fragment key={type}>
<StatRow
label={label}
value={statSummary(t, reportStatUnit(type, glucoseUnit, t), {
latest: show(type, stat!.latest, digits),
avg: show(type, stat!.avg, digits),
min: show(type, stat!.min, digits),
max: show(type, stat!.max, digits),
})}
/>
{unvalidated > 0 && (
<p
className="text-muted-foreground text-xs"
data-slot="clinician-screener-translation-note"
>
{t("doctorReport.screenerUnvalidated", {
label,
count: unvalidated,
total: stat!.count,
})}
</p>
)}
</Fragment>
);
})}
</Section>