Files
EislM0203andClaude Opus 5 548d640231 fix: balance adjustment silently did nothing on a decimal comma
Pressing Apply on Settings -> Adjust balance did nothing at all: no error, no
request, nothing in the API logs. The cause is in code untouched since
062ba52 (2026-07-01), so this predates the recent releases — it just needs
the right input to show itself.

The form only renders when adjustingAccount?.id === account.id, so
adjustingAccount is never null while Apply is visible. That leaves exactly
one way for the handler to return silently:

    if (!adjustingAccount || !adjustTargetBalance) return

i.e. adjustTargetBalance === "". And the field was <input type="number">,
which reports value === "" for anything the browser judges invalid —
including a decimal comma. Every amount in this app is rendered with
Intl.NumberFormat('de-DE'), so typing 1234,56 is the natural thing to do, and
it left the state empty and the guard swallowed the click.

Fixes both halves:

- The input is now type="text" inputMode="decimal", so what the user types
  actually reaches the handler.
- The guard reports "Enter a target balance, e.g. 1234.56" instead of
  returning silently. A control that does nothing when pressed is the worst
  possible failure mode.

Adds parseDecimal() alongside parseAmount() in lib/utils.ts. Balance targets
differ from expense rows: zero and negative are legitimate, so parseAmount's
n > 0 rule would have been wrong here.

parseDecimal is also stricter than the parseFloat(s.replace(',', '.')) idiom
used across the flows, in two ways that matter on a balance field:

- "1.000,50" parsed as 1 under the old idiom — a silent 1000x error. It now
  reads the rightmost separator as the decimal point, giving 1000.50, and
  handles "1,000.50" the same way.
- "12.5abc" quietly became 12.5 under parseFloat. Number() rejects it.

parseAmount is redefined on top of parseDecimal, so the batch expense grid
picks up both improvements.

Verified: tsc + vite build clean; the 60 backend tests still pass (untouched);
parser checked against .-decimal, ,-decimal, both-separator, negative, zero,
whitespace and trailing-garbage inputs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L3qYLuu9jgXsCRXmJ18YGY
2026-08-23 14:00:07 +00:00
..