mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
fix(labs): never present a converted reading's printed range in the wrong unit
A converted reading's bounds move with its value, but the printed range text stays in the unit the report used, and every reader preferred that text: the list showed "Report range 3.9 to 5.5" beside 100.9 mg/dL, and the doctor report and the FHIR referenceRange.text did the same. The text is still stored verbatim. The range resolver now takes the reading's sourceUnit (as a required field, so no reader can forget to select it) and, for a converted reading, leaves the window's text empty so every surface states the converted bounds in the marker's unit, and hands the printed text over separately with its unit. The lab DTO carries it as printedReferenceText, and the note beside a reading shows it as "as printed in mmol/L: ...".
This commit is contained in:
1 parent
cc0313c955
commit
47a91d6922
29 files changed
+365
-20
No files matched your search
@@ -78,6 +78,7 @@ function reading(id: string, value: number, takenAt: string): LabResultDto {
|
||||
sourceReferenceLow: null,
|
||||
sourceReferenceHigh: null,
|
||||
sourceReferenceText: null,
|
||||
printedReferenceText: null,
|
||||
referenceOrigin: "catalog",
|
||||
referenceDivergesFromCatalog: false,
|
||||
takenAt,
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { I18nProvider } from "@/lib/i18n/context";
|
||||
|
||||
import { SourceRangeNote } from "../source-range-note";
|
||||
|
||||
type Reading = Parameters<typeof SourceRangeNote>[0]["reading"];
|
||||
|
||||
function render(reading: Reading) {
|
||||
return renderToStaticMarkup(
|
||||
<I18nProvider initialLocale="en">
|
||||
<SourceRangeNote reading={reading} />
|
||||
</I18nProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
const STATED: Reading = {
|
||||
unit: "mg/dL",
|
||||
referenceLow: 70,
|
||||
referenceHigh: 99,
|
||||
catalogReferenceLow: 70,
|
||||
catalogReferenceHigh: 99,
|
||||
sourceReferenceText: "70 - 99",
|
||||
printedReferenceText: null,
|
||||
sourceUnit: null,
|
||||
referenceOrigin: "source",
|
||||
referenceDivergesFromCatalog: false,
|
||||
};
|
||||
|
||||
// 5.6 mmol/L stored as 100.9 mg/dL, with the report's 3.9 to 5.5 mmol/L window
|
||||
// converted alongside it.
|
||||
const CONVERTED: Reading = {
|
||||
unit: "mg/dL",
|
||||
referenceLow: 70.27,
|
||||
referenceHigh: 99.1,
|
||||
catalogReferenceLow: 70,
|
||||
catalogReferenceHigh: 100,
|
||||
sourceReferenceText: null,
|
||||
printedReferenceText: "3.9 - 5.5",
|
||||
sourceUnit: "mmol/L",
|
||||
referenceOrigin: "source",
|
||||
referenceDivergesFromCatalog: true,
|
||||
};
|
||||
|
||||
describe("<SourceRangeNote>", () => {
|
||||
it("names a stated reading's window verbatim", () => {
|
||||
const html = render(STATED);
|
||||
expect(html).toContain("Report range 70 - 99");
|
||||
expect(html).not.toContain("as printed");
|
||||
});
|
||||
|
||||
it("states a converted reading's window in the marker's unit", () => {
|
||||
const html = render(CONVERTED);
|
||||
expect(html).toContain("Report range 70.27–99.1 mg/dL");
|
||||
});
|
||||
|
||||
it("keeps the printed text as evidence, labelled with the unit it is in", () => {
|
||||
const html = render(CONVERTED);
|
||||
expect(html).toContain("as printed in mmol/L: 3.9 - 5.5");
|
||||
});
|
||||
|
||||
it("never puts the printed numbers in the statement about the stored unit", () => {
|
||||
const html = render(CONVERTED);
|
||||
// The window in force is followed by the marker's unit, not the printed text.
|
||||
expect(html).not.toContain("Report range 3.9 - 5.5");
|
||||
expect(html).toContain("your range 70–100 mg/dL");
|
||||
});
|
||||
|
||||
it("renders nothing when the window in force is not the report's", () => {
|
||||
expect(render({ ...CONVERTED, referenceOrigin: "catalog" })).toBe("");
|
||||
});
|
||||
});
|
||||
@@ -18,6 +18,11 @@ import { useLabNumber } from "./use-lab-format";
|
||||
* 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.
|
||||
@@ -34,6 +39,8 @@ export function SourceRangeNote({
|
||||
| "catalogReferenceLow"
|
||||
| "catalogReferenceHigh"
|
||||
| "sourceReferenceText"
|
||||
| "printedReferenceText"
|
||||
| "sourceUnit"
|
||||
| "referenceOrigin"
|
||||
| "referenceDivergesFromCatalog"
|
||||
>;
|
||||
@@ -43,7 +50,9 @@ export function SourceRangeNote({
|
||||
const labNumber = useLabNumber();
|
||||
if (reading.referenceOrigin !== "source") return null;
|
||||
|
||||
const printed =
|
||||
// `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 ??
|
||||
`${formatReferenceRange(
|
||||
reading.referenceLow,
|
||||
@@ -59,7 +68,13 @@ export function SourceRangeNote({
|
||||
|
||||
return (
|
||||
<span className={className}>
|
||||
{t("labs.sourceRange.fromReport", { range: printed })}
|
||||
{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: `${catalog} ${reading.unit}`.trim(),
|
||||
|
||||
@@ -38,6 +38,11 @@ export interface LabResultDto {
|
||||
sourceReferenceLow: number | null;
|
||||
sourceReferenceHigh: number | null;
|
||||
sourceReferenceText: string | null;
|
||||
/**
|
||||
* A converted reading's printed range text, verbatim and in `sourceUnit`;
|
||||
* `sourceReferenceText` is then null. Null for every other reading.
|
||||
*/
|
||||
printedReferenceText: string | null;
|
||||
/** Which window is in force. */
|
||||
referenceOrigin: ReferenceRangeOrigin;
|
||||
/** True when the report's window and the catalog band state different limits. */
|
||||
|
||||
Reference in new issue
Block a user