Files
HealthLog/src/components/labs/source-range-note.tsx
T
Marc-André Bombeck f9431da64f feat(labs): show a value without a unit as the number alone
Every place a lab unit is printed beside a value now goes through one
helper, so a reading stored in "1" reads "3.6" and not "3.6 1": the
list, history and detail, the chart and its tooltips, the reference bar
and range notes, the trend card, the timeline, the day view, the
clinician page, the doctor-report PDF and the changes card. Where the
unit stands alone (a marker's subtitle, a picker row, the merge preview)
it reads "No unit".

The Coach's lab block, the get_labs history and the visit-prep summary
hand the model an empty unit for such a value, so it never quotes the
"1" either.

Refs #1313
2026-11-02 20:28:34 +01:00

90 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { formatReferenceRange } from "@/lib/labs/reference-range";
import { useTranslations } from "@/lib/i18n/context";
import type { LabResultDto } from "./types";
import { useLabNumber } from "./use-lab-format";
import { withLabUnit } from "@/lib/labs/dimensionless";
/**
* The reference window a reading's own report printed, shown wherever that
* reading is shown.
*
* Renders nothing for a reading with no printed window — most of them — so it
* costs no space on the common row. When the report DID state a window it
* names it, verbatim where the report gave words; and when that window and the
* catalog band disagree it names the catalog band too. A reader told only
* "3,9–5,4" and a reader told only "3,5–5,0" draw different conclusions from
* the same number, so a surface that shows one silently is showing a partial
* answer.
*
* A reading converted into its marker's unit carries bounds that were converted
* with it, but the report's own text is still in the unit it printed. The note
* then states the window in the marker's unit and adds the printed text as
* evidence, labelled with its unit, so no single statement mixes two units.
*
* Neutral by construction: no tint, no icon, muted text. The in/out verdict is
* the badge's job — this element states where the window came from, nothing
* about whether the value is good news.
*/
export function SourceRangeNote({
reading,
className,
}: {
reading: Pick<
LabResultDto,
| "unit"
| "referenceLow"
| "referenceHigh"
| "catalogReferenceLow"
| "catalogReferenceHigh"
| "sourceReferenceText"
| "printedReferenceText"
| "sourceUnit"
| "referenceOrigin"
| "referenceDivergesFromCatalog"
>;
className?: string;
}) {
const { t } = useTranslations();
const labNumber = useLabNumber();
if (reading.referenceOrigin !== "source") return null;
// `sourceReferenceText` is null for a converted reading, so the window is
// then stated from the converted bounds, in the marker's unit.
const inForce =
reading.sourceReferenceText ??
withLabUnit(
formatReferenceRange(
reading.referenceLow,
reading.referenceHigh,
labNumber,
),
reading.unit,
);
const catalog = formatReferenceRange(
reading.catalogReferenceLow,
reading.catalogReferenceHigh,
labNumber,
);
return (
<span className={className}>
{t("labs.sourceRange.fromReport", { range: inForce })}
{reading.printedReferenceText && reading.sourceUnit
? ` · ${t("labs.sourceRange.printed", {
range: reading.printedReferenceText,
unit: reading.sourceUnit,
})}`
: null}
{reading.referenceDivergesFromCatalog && catalog
? ` · ${t("labs.sourceRange.catalogDiffers", {
range: withLabUnit(catalog, reading.unit),
})}`
: null}
</span>
);
}