From 9531bbdcecf183a9b5b3112c61edcbd54c90b6f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sat, 18 Jul 2026 03:47:15 +0200 Subject: [PATCH] fix(measurements): remember the last-used type on the add form The add form always defaulted to BLOOD_PRESSURE regardless of what a user actually logs day to day, forcing a re-pick from a 15-entry select on every entry unless arriving via a ?add= deep link. Seed the default from the last manually-saved type (localStorage, client-only) when no deep link overrides it, and record the type on every successful save. --- .../measurements/measurement-form.tsx | 19 +++++++- src/lib/measurements/last-used-type.ts | 43 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/lib/measurements/last-used-type.ts diff --git a/src/components/measurements/measurement-form.tsx b/src/components/measurements/measurement-form.tsx index 972036a3d..91e528e79 100644 --- a/src/components/measurements/measurement-form.tsx +++ b/src/components/measurements/measurement-form.tsx @@ -31,6 +31,10 @@ import { } from "@/lib/query-keys"; import { ApiError, apiPost } from "@/lib/api/api-fetch"; import { MEASUREMENT_NOTES_MAX_LENGTH } from "@/lib/validations/measurement"; +import { + getLastUsedMeasurementType, + setLastUsedMeasurementType, +} from "@/lib/measurements/last-used-type"; const MAX_COMMENT_LENGTH = MEASUREMENT_NOTES_MAX_LENGTH; @@ -234,7 +238,16 @@ export function MeasurementForm({ ? "BLOOD_PRESSURE" : defaultType; - const [type, setType] = useState(normalizedDefault || "BLOOD_PRESSURE"); + // v1.30.1 M3 — an explicit deep-link default always wins; absent one, + // seed from the last type the user actually saved rather than always + // landing on BLOOD_PRESSURE. Lazy initializer so the localStorage read + // happens once, at mount, not on every render. + const [type, setType] = useState( + () => + normalizedDefault || + getLastUsedMeasurementType(MEASUREMENT_FORM_TYPE_VALUES) || + "BLOOD_PRESSURE", + ); const [value, setValue] = useState(""); const [sysBp, setSysBp] = useState(""); const [diaBp, setDiaBp] = useState(""); @@ -323,6 +336,10 @@ export function MeasurementForm({ }); } + // v1.30.1 M3 — remember this type as the next mount's smart + // default (deep links still override it). + setLastUsedMeasurementType(type); + // Reset form setValue(""); setSysBp(""); diff --git a/src/lib/measurements/last-used-type.ts b/src/lib/measurements/last-used-type.ts new file mode 100644 index 000000000..d61e33372 --- /dev/null +++ b/src/lib/measurements/last-used-type.ts @@ -0,0 +1,43 @@ +/** + * v1.30.1 (M3 QoL fix) — remember the last manually-saved measurement + * type so the add form doesn't default to BLOOD_PRESSURE for a daily + * weight/glucose logger. Client-only convenience persisted in + * `localStorage`, mirroring the `mood/recent-tags.ts` MRU pattern: it + * never touches the API, and a cleared/disabled store just degrades + * to the pre-existing BLOOD_PRESSURE default. + * + * A `defaultType` deep link (`?add=`, the Vorsorge card, an + * Insights empty-state CTA) always wins over this — callers only + * consult `getLastUsedMeasurementType()` when no explicit default was + * supplied. + */ + +const STORAGE_KEY = "healthlog:measurement:last-used-type"; + +/** + * Read the last-saved type, validated against the caller-supplied set + * of currently selectable form values so a type retired from the + * catalog (or a corrupt/foreign value) never gets selected silently. + */ +export function getLastUsedMeasurementType( + validValues: readonly string[], +): string | null { + if (typeof window === "undefined") return null; + try { + const raw = window.localStorage.getItem(STORAGE_KEY); + if (raw && validValues.includes(raw)) return raw; + } catch { + /* storage disabled — fall through to no memory */ + } + return null; +} + +/** Record a successfully-saved type as the new "last used" value. */ +export function setLastUsedMeasurementType(type: string): void { + if (typeof window === "undefined") return; + try { + window.localStorage.setItem(STORAGE_KEY, type); + } catch { + /* storage full / disabled — nothing to remember */ + } +}