ui: drop restrictive step on monetary inputs + round NW autofill
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
step={1000}/step={10000} on £ inputs blocked any non-multiple value
from passing browser validation. Surfaced when the Wealthfolio
autofill landed `1050195.09` into the NW field — Chrome rejected
it: "the two nearest valid values are 1050000 and 1060000". Same
class as the n_paths bug from earlier today.
- Remove step on spending_gbp / nw_seed_gbp / savings_per_year_gbp /
floor_gbp across What-If, ScenarioNew, ScenarioEdit. Default step=1
(any positive integer).
- Round NW autofill to whole pounds (Math.round) since the user
doesn't think in pence at this scale and the rounded value
satisfies any integer step.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
b40defacf0
commit
7602f9040e
3 changed files with 6 additions and 12 deletions
|
|
@ -130,7 +130,6 @@ export function ScenarioEdit() {
|
||||||
value={Number(form.spending_gbp)}
|
value={Number(form.spending_gbp)}
|
||||||
onChange={(v) => update('spending_gbp', String(v))}
|
onChange={(v) => update('spending_gbp', String(v))}
|
||||||
min={0}
|
min={0}
|
||||||
step={1000}
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
<Field label="NW seed (£)">
|
<Field label="NW seed (£)">
|
||||||
|
|
@ -138,7 +137,6 @@ export function ScenarioEdit() {
|
||||||
value={Number(form.nw_seed_gbp)}
|
value={Number(form.nw_seed_gbp)}
|
||||||
onChange={(v) => update('nw_seed_gbp', String(v))}
|
onChange={(v) => update('nw_seed_gbp', String(v))}
|
||||||
min={0}
|
min={0}
|
||||||
step={10000}
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
<Field label="Annual savings (£)">
|
<Field label="Annual savings (£)">
|
||||||
|
|
@ -146,7 +144,6 @@ export function ScenarioEdit() {
|
||||||
value={Number(form.savings_per_year_gbp ?? 0)}
|
value={Number(form.savings_per_year_gbp ?? 0)}
|
||||||
onChange={(v) => update('savings_per_year_gbp', String(v))}
|
onChange={(v) => update('savings_per_year_gbp', String(v))}
|
||||||
min={0}
|
min={0}
|
||||||
step={1000}
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
<Field label="Horizon (years)">
|
<Field label="Horizon (years)">
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,8 @@ export function ScenarioNew() {
|
||||||
const nw = useQuery({ queryKey: ['networth', 'current'], queryFn: api.networth.current });
|
const nw = useQuery({ queryKey: ['networth', 'current'], queryFn: api.networth.current });
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (nwAutoFilled || !nw.data || nw.data.accounts.length === 0) return;
|
if (nwAutoFilled || !nw.data || nw.data.accounts.length === 0) return;
|
||||||
setForm((f) => ({ ...f, nw_seed_gbp: nw.data!.total_gbp }));
|
const rounded = String(Math.round(Number(nw.data.total_gbp)));
|
||||||
|
setForm((f) => ({ ...f, nw_seed_gbp: rounded }));
|
||||||
setNwAutoFilled(true);
|
setNwAutoFilled(true);
|
||||||
}, [nw.data, nwAutoFilled]);
|
}, [nw.data, nwAutoFilled]);
|
||||||
|
|
||||||
|
|
@ -121,7 +122,6 @@ export function ScenarioNew() {
|
||||||
value={Number(form.spending_gbp)}
|
value={Number(form.spending_gbp)}
|
||||||
onChange={(v) => update('spending_gbp', String(v))}
|
onChange={(v) => update('spending_gbp', String(v))}
|
||||||
min={0}
|
min={0}
|
||||||
step={1000}
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
<Field label="NW seed (£)">
|
<Field label="NW seed (£)">
|
||||||
|
|
@ -129,7 +129,6 @@ export function ScenarioNew() {
|
||||||
value={Number(form.nw_seed_gbp)}
|
value={Number(form.nw_seed_gbp)}
|
||||||
onChange={(v) => update('nw_seed_gbp', String(v))}
|
onChange={(v) => update('nw_seed_gbp', String(v))}
|
||||||
min={0}
|
min={0}
|
||||||
step={10000}
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
<Field label="Annual savings (£)">
|
<Field label="Annual savings (£)">
|
||||||
|
|
@ -137,7 +136,6 @@ export function ScenarioNew() {
|
||||||
value={Number(form.savings_per_year_gbp ?? 0)}
|
value={Number(form.savings_per_year_gbp ?? 0)}
|
||||||
onChange={(v) => update('savings_per_year_gbp', String(v))}
|
onChange={(v) => update('savings_per_year_gbp', String(v))}
|
||||||
min={0}
|
min={0}
|
||||||
step={1000}
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
<Field label="Horizon (years)">
|
<Field label="Horizon (years)">
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,10 @@ export function WhatIf() {
|
||||||
const nw = useQuery({ queryKey: ['networth', 'current'], queryFn: api.networth.current });
|
const nw = useQuery({ queryKey: ['networth', 'current'], queryFn: api.networth.current });
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (nwAutoFilled || !nw.data || nw.data.accounts.length === 0) return;
|
if (nwAutoFilled || !nw.data || nw.data.accounts.length === 0) return;
|
||||||
setForm((f) => ({ ...f, nw_seed_gbp: nw.data!.total_gbp }));
|
// Round to whole pounds — pence from the API don't survive HTML5
|
||||||
|
// step validation, and the user doesn't think in pence at this scale.
|
||||||
|
const rounded = String(Math.round(Number(nw.data.total_gbp)));
|
||||||
|
setForm((f) => ({ ...f, nw_seed_gbp: rounded }));
|
||||||
setNwAutoFilled(true);
|
setNwAutoFilled(true);
|
||||||
}, [nw.data, nwAutoFilled]);
|
}, [nw.data, nwAutoFilled]);
|
||||||
|
|
||||||
|
|
@ -134,7 +137,6 @@ export function WhatIf() {
|
||||||
value={Number(form.spending_gbp)}
|
value={Number(form.spending_gbp)}
|
||||||
onChange={(v) => update('spending_gbp', String(v))}
|
onChange={(v) => update('spending_gbp', String(v))}
|
||||||
min={0}
|
min={0}
|
||||||
step={1000}
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
<Field label="NW seed (£)">
|
<Field label="NW seed (£)">
|
||||||
|
|
@ -142,7 +144,6 @@ export function WhatIf() {
|
||||||
value={Number(form.nw_seed_gbp)}
|
value={Number(form.nw_seed_gbp)}
|
||||||
onChange={(v) => update('nw_seed_gbp', String(v))}
|
onChange={(v) => update('nw_seed_gbp', String(v))}
|
||||||
min={0}
|
min={0}
|
||||||
step={10000}
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
<Field label="Annual savings (£)">
|
<Field label="Annual savings (£)">
|
||||||
|
|
@ -150,7 +151,6 @@ export function WhatIf() {
|
||||||
value={Number(form.savings_per_year_gbp ?? 0)}
|
value={Number(form.savings_per_year_gbp ?? 0)}
|
||||||
onChange={(v) => update('savings_per_year_gbp', String(v))}
|
onChange={(v) => update('savings_per_year_gbp', String(v))}
|
||||||
min={0}
|
min={0}
|
||||||
step={1000}
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
<Field label="Horizon (years)">
|
<Field label="Horizon (years)">
|
||||||
|
|
@ -167,7 +167,6 @@ export function WhatIf() {
|
||||||
value={Number(form.floor_gbp ?? 40000)}
|
value={Number(form.floor_gbp ?? 40000)}
|
||||||
onChange={(v) => update('floor_gbp', String(v))}
|
onChange={(v) => update('floor_gbp', String(v))}
|
||||||
min={0}
|
min={0}
|
||||||
step={1000}
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue