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 */ + } +}