Files
HealthLog/src/lib/labs/format-value.ts
T
Marc-André Bombeck 79ac5670c7 feat(labs): offer an explicit no-unit choice for ratios and indices
A ratio (cholesterol/HDL, albumin/globulin) or an index such as INR has
no unit, and every lab write path refuses a numeric value without one.
That refusal stays: an empty unit usually means the extraction dropped
it. Instead the value is stored as the UCUM unity "1", chosen on purpose.

The unit field when a marker is defined, on a scanned report's row and
in the document review edit now carries a "No unit" checkbox that sets
"1". The CSV import takes 1 in the unit column, as the template and the
import sheet say; an empty cell is still refused, and other spellings
such as "ratio" or "-" stay the literal unit they always were.

"1" compares as a unit of its own: it matches only itself, so it is
refused under a marker kept in mg/dL and the other way round.

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

62 lines
2.0 KiB
TypeScript

/**
* Shared lab-value number formatting.
*
* Every surface that prints a lab reading (the list card, the detail history,
* the chart tooltip, the doctor report PDF, the clinician share page) prints
* it through here, so a reading reads the same everywhere. The precision rule
* is the recorded-number rule in `src/lib/format/recorded-number.ts`: a
* reading keeps every digit it was stored with (TSH 0.004, PSA 0.034, a
* troponin of 0.0012 never shortened), and a reading converted from the unit
* its report printed keeps the precision of the printed figure.
*
* The digits themselves come from the caller's locale number formatter, so a
* German reader sees "1,8 mIU/L" where an English one sees "1.8 mIU/L". This
* module only decides the precision.
*/
import { withLabUnit } from "@/lib/labs/dimensionless";
import {
formatRecordedNumber,
type FractionDigitsFormat,
} from "@/lib/format/recorded-number";
/**
* A lab number in the reader's locale. `printed` is the figure the source
* report printed when the number was converted from it (`sourceValue`).
*/
export type LabNumberFormat = (
value: number,
printed?: number | null,
) => string;
export function formatLabValue(
value: number,
formatNumber: FractionDigitsFormat,
printed?: number | null,
): string {
return formatRecordedNumber(value, formatNumber, printed);
}
/**
* Render a reading's display value: a qualitative row (numeric `value` is
* null) shows its `valueText` verbatim; a numeric row shows the formatted
* number plus its unit (none for a dimensionless reading). One helper so the list card, the history rows, and
* the detail header stay consistent.
*/
export function formatLabReading(
reading: {
value: number | null;
valueText: string | null;
unit: string;
sourceValue?: number | null;
},
formatNumber: LabNumberFormat,
): string {
if (reading.value === null) {
return reading.valueText ?? "";
}
return withLabUnit(
formatNumber(reading.value, reading.sourceValue),
reading.unit,
);
}