whisper-money/resources/js/components/transactions
Víctor Falcón ca2e5c09b3
fix(balances): allow saving a zero balance (#664)
## Why

A balance of exactly **0** could not be saved. Zero is a perfectly valid
balance for any account (an emptied wallet, a paid-off loan, a closed
position), so the app was rejecting legitimate input.

## Root cause

The shared `AmountInput` renders a numeric value of `0` as an **empty
string** (so the field shows the `0.00` placeholder instead of a literal
"0.00"). Several balance forms combined that with the native HTML
`required` attribute — which then rejected the *only* value that renders
empty: `0`. `required` on this input never guarded against a missing
value (the state is always numeric; empty == 0), it only ever blocked
zero.

The backend already accepted `0` (`required|integer`, and Laravel's
`required` treats integer `0` as present), so this was purely a frontend
constraint.

## Changes

- Drop `required` from the balance `AmountInput` in the **Update
balance** dialog and the **Balance history** edit modal.
- Remove the explicit `balanceInCents === 0` guard (and `required`) in
the onboarding **Set balance** step.
- Extend the same fix to the CSV-import **reference balance** field
(identical root cause; the compute path already gates on
`referenceBalance !== null`, so an explicit `0` is a valid anchor).
- Remove the now-orphaned `"Please enter a balance"` translation from
`es.json` / `fr.json`.
- Add feature tests asserting a zero balance can be stored and set as
the current balance.

Transaction and budget amount inputs keep `required` — `0` is not a
meaningful value there, so they are intentionally untouched.

## QA

- **Onboarding balance step**: saving with an empty/zero field now
advances instead of showing "Please enter a balance". 
- **Update balance dialog**: set €1,000.00, then overwrote it with €0.00
→ dialog closed and the record persisted. Verified in the DB
(`account_balances.balance = 0`). 
- Backend contract locked by new tests in
`AccountBalanceControllerTest`.

## Demo

<!-- PLACEHOLDER: drag the video here -->

_Video to attach: `~/Downloads/allow-zero-balances-demo.mp4`_
2026-07-10 15:02:38 +02:00
..
ai-upsell-sample.test.ts AI auto-categorization: open to pro + consent, nudge free users (#561) 2026-06-19 14:08:40 +00:00
ai-upsell-sample.ts AI auto-categorization: open to pro + consent, nudge free users (#561) 2026-06-19 14:08:40 +00:00
bulk-actions-bar.tsx Fix label creation dropdown refresh (#363) 2026-05-07 10:26:43 +01:00
bulk-category-select.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
bulk-label-select.tsx Fix label creation dropdown refresh (#363) 2026-05-07 10:26:43 +01:00
categorizer-card.tsx feat(categorize): show debtor and creditor names (#454) 2026-05-30 12:27:59 +02:00
categorizer-command.tsx feat: parent/child category tree (#474) 2026-06-03 19:30:12 +02:00
category-cell.tsx feat(ai): learn from category corrections so the AI stops repeating the same mistake (#608) 2026-06-29 19:12:15 +02:00
category-select.tsx feat(shared): Add CategoryCombobox component 2025-11-14 16:05:53 +01:00
edit-transaction-dialog.test.tsx feat(transactions): refine new transaction form layout and balance toggle (#597) 2026-06-26 17:59:44 +00:00
edit-transaction-dialog.tsx fix(ai): surface learned-rule toast in edit modal and guard weak description keys (#635) 2026-07-04 11:00:15 +00:00
import-step-account.test.tsx Fix transaction importer account preselect (#396) 2026-05-14 12:38:44 +02:00
import-step-account.tsx Fix transaction importer account preselect (#396) 2026-05-14 12:38:44 +02:00
import-step-mapping.tsx fix(balances): allow saving a zero balance (#664) 2026-07-10 15:02:38 +02:00
import-step-preview.tsx feat(transactions): serve import dedup and account ledger from the backend (#631) 2026-07-03 16:49:59 +02:00
import-step-upload.test.tsx Fix transaction importer account preselect (#396) 2026-05-14 12:38:44 +02:00
import-step-upload.tsx Fix transaction importer account preselect (#396) 2026-05-14 12:38:44 +02:00
import-transactions-button.tsx refactor(encryption): strip client-side transaction encryption (#514) 2026-06-20 16:13:26 +00:00
import-transactions-drawer.tsx feat(transactions): serve import dedup and account ledger from the backend (#631) 2026-07-03 16:49:59 +02:00
saved-filters.tsx fix(transactions): keep saved-filter delete button visible on touch and confirm before deleting (#648) 2026-07-06 09:37:38 +00:00
transaction-actions-menu.test.tsx feat(transactions): release transaction analysis to all users (#579) 2026-06-22 16:09:09 +02:00
transaction-actions-menu.tsx feat(transactions): release transaction analysis to all users (#579) 2026-06-22 16:09:09 +02:00
transaction-analysis-drawer.test.tsx feat(analysis): shared bar-list breakdowns in transaction drawer (#517) 2026-06-10 12:36:20 +02:00
transaction-analysis-drawer.tsx feat(analysis): shared bar-list breakdowns in transaction drawer (#517) 2026-06-10 12:36:20 +02:00
transaction-columns.test.tsx fix(transactions): pad Category column when Date column is hidden (#584) 2026-06-22 16:51:50 +00:00
transaction-columns.tsx fix(transactions): let date column size to its content (#610) 2026-06-29 15:51:51 +00:00
transaction-description.test.tsx refactor(encryption): strip client-side transaction encryption (#514) 2026-06-20 16:13:26 +00:00
transaction-description.tsx refactor(encryption): strip client-side transaction encryption (#514) 2026-06-20 16:13:26 +00:00
transaction-filters.test.tsx feat(transactions): reorder filters and switch accounts to a logo dropdown (#598) 2026-06-26 20:09:02 +02:00
transaction-filters.tsx feat(transactions): reorder filters and switch accounts to a logo dropdown (#598) 2026-06-26 20:09:02 +02:00
transaction-list.test.tsx fix(accounts): remove double-skeleton flash on account show (#634) 2026-07-03 15:56:49 +00:00
transaction-list.tsx fix(accounts): remove double-skeleton flash on account show (#634) 2026-07-03 15:56:49 +00:00