mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 14:32:03 +00:00
fix(records): let the smoking history fields take keystrokes
The quit month only accepted text that was already a whole YYYY-MM month and the start year clamped every keystroke into 1900..now, so neither could be typed into. Both keep a draft while typing and commit a valid value. Dependabot also stops proposing Node majors for the image. Refs #1334
This commit is contained in:
1 parent
25770912ce
commit
40200b55a7
3 files changed
+126
-18
No files matched your search
@@ -281,6 +281,11 @@ function NumberField({
|
||||
onChange: (value: number | null) => void;
|
||||
disabled: boolean;
|
||||
}) {
|
||||
// What the person is typing. A year passes through "1", "19" and "198" on
|
||||
// its way to "1985", so clamping each keystroke turned the first digit into
|
||||
// the minimum and the field could not be typed into. A value is committed
|
||||
// once it is in range, and leaving the field puts the committed one back.
|
||||
const [draft, setDraft] = useState<string | null>(null);
|
||||
return (
|
||||
<Field id={id} label={label}>
|
||||
<Input
|
||||
@@ -290,21 +295,74 @@ function NumberField({
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
value={value ?? ""}
|
||||
value={draft ?? (value === null ? "" : String(value))}
|
||||
disabled={disabled}
|
||||
onChange={(event) => {
|
||||
const raw = event.target.value;
|
||||
setDraft(raw);
|
||||
if (raw === "") return onChange(null);
|
||||
const parsed = Number(raw);
|
||||
if (Number.isFinite(parsed)) {
|
||||
onChange(Math.min(max, Math.max(min, parsed)));
|
||||
if (Number.isFinite(parsed) && parsed >= min && parsed <= max) {
|
||||
onChange(parsed);
|
||||
}
|
||||
}}
|
||||
onBlur={() => setDraft(null)}
|
||||
/>
|
||||
</Field>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A month typed as YYYY-MM. Only a complete month is committed, so the field
|
||||
* keeps what is being typed on its own: holding it to the committed value
|
||||
* threw away every keystroke until the text was a whole month, and only a
|
||||
* paste got through. Leaving the field pads "2019-3" to "2019-03" and puts
|
||||
* the committed month back over anything that is not one.
|
||||
*/
|
||||
function QuitMonthInput({
|
||||
id,
|
||||
value,
|
||||
onChange,
|
||||
disabled,
|
||||
}: {
|
||||
id: string;
|
||||
value: string | null;
|
||||
onChange: (value: string | null) => void;
|
||||
disabled: boolean;
|
||||
}) {
|
||||
const [draft, setDraft] = useState<string | null>(null);
|
||||
return (
|
||||
<Input
|
||||
id={id}
|
||||
placeholder="YYYY-MM"
|
||||
inputMode="numeric"
|
||||
maxLength={7}
|
||||
value={draft ?? value ?? ""}
|
||||
disabled={disabled}
|
||||
onChange={(event) => {
|
||||
const raw = event.target.value;
|
||||
setDraft(raw);
|
||||
const month = completeMonth(raw);
|
||||
if (month !== undefined) onChange(month);
|
||||
}}
|
||||
onBlur={() => {
|
||||
if (draft !== null) {
|
||||
const short = /^(\d{4})-([1-9])$/.exec(draft.trim());
|
||||
if (short) onChange(`${short[1]}-0${short[2]}`);
|
||||
}
|
||||
setDraft(null);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/** A whole month, null for an emptied field, undefined while still typing. */
|
||||
function completeMonth(raw: string): string | null | undefined {
|
||||
const text = raw.trim();
|
||||
if (text === "") return null;
|
||||
return /^\d{4}-(0[1-9]|1[0-2])$/.test(text) ? text : undefined;
|
||||
}
|
||||
|
||||
function MultiField<T extends string>({
|
||||
id,
|
||||
label,
|
||||
@@ -544,23 +602,13 @@ function SectionBody({
|
||||
id={id("quit")}
|
||||
label={t("records.life.fields.quitMonth")}
|
||||
>
|
||||
<Input
|
||||
<QuitMonthInput
|
||||
id={id("quit")}
|
||||
placeholder="YYYY-MM"
|
||||
inputMode="numeric"
|
||||
maxLength={7}
|
||||
value={v.quitMonth ?? ""}
|
||||
value={v.quitMonth}
|
||||
disabled={disabled}
|
||||
onChange={(event) => {
|
||||
const raw = event.target.value.trim();
|
||||
patch("TOBACCO_DETAIL", {
|
||||
quitMonth: /^\d{4}-(0[1-9]|1[0-2])$/.test(raw)
|
||||
? raw
|
||||
: raw === ""
|
||||
? null
|
||||
: v.quitMonth,
|
||||
});
|
||||
}}
|
||||
onChange={(quitMonth) =>
|
||||
patch("TOBACCO_DETAIL", { quitMonth })
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
) : null}
|
||||
|
||||
Reference in new issue
Block a user