diff --git a/src/lib/labs/__tests__/value-update.test.ts b/src/lib/labs/__tests__/value-update.test.ts index dcc98d4c8..c952d06ad 100644 --- a/src/lib/labs/__tests__/value-update.test.ts +++ b/src/lib/labs/__tests__/value-update.test.ts @@ -12,6 +12,18 @@ describe("valueEditSeed", () => { expect(valueEditSeed(110)).toBe("110"); expect(valueEditSeed(4.567)).toBe("4.57"); }); + + it("never opens a small nonzero value as zero", () => { + expect(valueEditSeed(0.004)).toBe("0.004"); + expect(valueEditSeed(0.0123456)).toBe("0.0123"); + expect(valueEditSeed(0.87)).toBe("0.87"); + expect(valueEditSeed(0.123456)).toBe("0.123"); + expect(valueEditSeed(-0.004)).toBe("-0.004"); + expect(valueEditSeed(0.0000004)).toBe("0.0000004"); + for (const v of [0.004, 0.0004, 0.00004, 1e-9]) { + expect(Number(valueEditSeed(v))).not.toBe(0); + } + }); }); describe("resolveValueForUpdate", () => { diff --git a/src/lib/labs/value-update.ts b/src/lib/labs/value-update.ts index 5cbbad305..7dd945dc5 100644 --- a/src/lib/labs/value-update.ts +++ b/src/lib/labs/value-update.ts @@ -1,18 +1,33 @@ -import { formatLabValue } from "./format-value"; - /** * The numeric value of a lab reading in the edit sheet. * * A converted reading is stored at full precision (5.6 mmol/L of glucose is * 100.90191999999999 mg/dL), and the sheet must not open with that tail. The - * field starts from the value as every lab surface shows it: whole numbers - * bare, at most two decimals. Written with a dot, which the sheet's parser - * reads, rather than in the reader's locale, which an input cannot round-trip. + * field starts from the value at the precision every lab surface shows it: + * whole numbers bare, two decimals. Two decimals carry too little of a small + * value, though (a TSH of 0.004 would open as "0"), so below 1 the field keeps + * three significant figures instead. Written with a dot, which the sheet's + * parser reads, rather than in the reader's locale, which an input cannot + * round-trip, and never in exponent notation. */ export function valueEditSeed(value: number): string { - return formatLabValue(value, String); + if (Number.isInteger(value)) return String(value); + const magnitude = Math.floor(Math.log10(Math.abs(value))); + const decimals = Math.min( + MAX_SEED_DECIMALS, + Math.max(DISPLAY_DECIMALS, SEED_SIGNIFICANT_FIGURES - 1 - magnitude), + ); + return value + .toFixed(decimals) + .replace(/(\.\d*?)0+$/, "$1") + .replace(/\.$/, ""); } +const DISPLAY_DECIMALS = 2; +const SEED_SIGNIFICANT_FIGURES = 3; +/** `toFixed` accepts up to 100; no lab value needs more than this. */ +const MAX_SEED_DECIMALS = 20; + /** * What the edit PUT sends for the value. A field the person did not touch is * omitted (`undefined`), so the stored full-precision number stays as it is and