whisper-money/resources/js/components
Víctor Falcón 8df44c2ef4
feat(transactions): save and reuse transaction filters (#496)
## What

Adds **saved filters** on the transactions page so users can name a set
of filters and reuse them later. The whole feature is gated behind a new
\`transaction-analysis\` Pennant feature flag (off by default).

## Why

Reusing the same filter combinations (e.g. "Japan trip", "Utilities") is
currently manual every time. This ports the saved-filters work from the
\`analysis-page\` branch, scoped down to **only** the transactions page
— the analysis screen and unrelated query changes from that branch are
intentionally left out.

## Changes

**Feature flag**
- \`App\Features\TransactionAnalysis\` — class-based flag, resolves
\`false\` by default.
- Shared to the frontend as \`features.transactionAnalysis\` and added
to the \`Features\` type.

**Backend (saved filters)**
- \`SavedFilter\` model (UUID, \`filters\` json cast, user belongsTo) +
migration + factory.
- \`Api\SavedFilterController\` — user-scoped index/store/update/destroy
under \`/api/saved-filters\`, ownership enforced with \`abort_unless\`.
- \`StoreSavedFilterRequest\` / \`UpdateSavedFilterRequest\` — name
unique per user, snake_case filter rules.

**Frontend**
- \`transaction-filter-serialization.ts\` —
serialize/deserialize/fingerprint between UI filter state and the
persisted snake_case shape.
- \`SavedFilters\` dropdown — load/save/update/delete with active +
dirty indicators.
- Integrated into the filter bar via an opt-in \`enableSavedFilters\`
prop, so it renders **only** on the transactions page (budgets/accounts
reuse the same component and stay unchanged). Render is also gated by
the feature flag.

**Filter bar UX**
- Split search + filters + saved searches onto their own row, separate
from the actions row (Categorize / Add transactions / columns), which
were getting cramped.
- On mobile, the text search moves into the filters popover.

## Reviewer notes
- Backend endpoints are **not** flag-gated; only the UI is, per the
request.
- Two-layer scoping: page opt-in prop **and** feature flag — flag off
means no UI anywhere.
- Translation keys fall back to the key (English); \`es.json\` entries
not added, matching the source branch.

## Testing
- \`tests/Feature/SavedFilterTest.php\` — 9 passing (auth, per-user
listing/uniqueness, ownership on update/delete).
- Pint, Prettier, ESLint clean. No new TypeScript errors introduced.
2026-06-05 18:00:14 +02:00
..
accounts fix(import): honor selected date format for CSV imports (#494) 2026-06-05 15:10:48 +02:00
automation-rules refactor(js): use InputError for inline form errors (#483) 2026-06-03 19:01:21 +02:00
budgets feat: parent/child category tree (#474) 2026-06-03 19:30:12 +02:00
cashflow feat: expand parent categories inline in breakdowns (#486) 2026-06-04 11:19:21 +02:00
categories feat: enable category tree for all users, remove flag (#488) 2026-06-04 13:44:57 +02:00
charts feat: single-open Sankey expand, fit overflowing children (#487) 2026-06-04 11:35:26 +02:00
dashboard feat: expand parent categories inline in breakdowns (#486) 2026-06-04 11:19:21 +02:00
icons Subscriptions (#15) 2025-12-06 19:09:56 +01:00
labels refactor(js): use InputError for inline form errors (#483) 2026-06-03 19:01:21 +02:00
landing feat(landing): redirect signed-in users (#429) 2026-05-25 20:28:45 +02:00
onboarding refactor(js): extract shared getCsrfToken util (#475) 2026-06-03 17:26:09 +02:00
open-banking refactor(js): extract shared getCsrfToken util (#475) 2026-06-03 17:26:09 +02:00
partials chore: update Discord invite link (#452) 2026-05-29 15:56:48 +02:00
shared feat: parent/child category tree (#474) 2026-06-03 19:30:12 +02:00
transactions feat(transactions): save and reuse transaction filters (#496) 2026-06-05 18:00:14 +02:00
ui feat: expand parent categories inline in breakdowns (#486) 2026-06-04 11:19:21 +02:00
alert-error.tsx Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
app-content.tsx Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
app-logo-icon.tsx Automated rules labels (#30) 2025-12-15 12:11:55 +01:00
app-logo.tsx Add animated logo icon that transitions based on encryption key state 2025-12-12 11:24:42 +01:00
app-shell.tsx Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
app-sidebar-header.tsx fix: keep iOS content below the notch (#280) 2026-04-13 13:59:05 +01:00
app-sidebar.tsx fix: move community link to user menu (#442) 2026-05-27 17:39:26 +02:00
appearance-tabs.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
bank-logo.tsx feat: Integrate EnableBanking as open banking provider (#106) 2026-02-12 09:09:28 +01:00
breadcrumbs.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
delete-user.tsx fix(accounts): translate update button in edit account modal (#455) 2026-05-30 16:09:30 +02:00
encrypted-text.tsx fix: make encryption key storage SSR-safe to prevent 502 errors 2025-12-08 17:13:45 +01:00
encryption-key-button.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
heading-small.tsx Add Budgeting Feature to Track and Manage Spending (#36) 2026-01-21 15:25:50 +01:00
heading.tsx Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
icon.tsx Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
input-error.tsx Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
mobile-back-button.tsx fix(haptics): use a local WebHaptics wrapper (#225) 2026-03-16 11:26:04 +00:00
nav-footer.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
nav-main.tsx fix(haptics): use a local WebHaptics wrapper (#225) 2026-03-16 11:26:04 +00:00
nav-user.tsx Format + Open transactions on row click 2025-12-08 15:58:50 +01:00
text-link.tsx Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
two-factor-recovery-codes.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
two-factor-setup-modal.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
unlock-message-dialog.tsx Remove encryption from bank account names (#104) 2026-02-09 14:15:26 +01:00
user-info.tsx feat: Update facehash and enable blink 2026-02-24 15:54:49 +01:00
user-menu-content.test.tsx chore: update Discord invite link (#452) 2026-05-29 15:56:48 +02:00
user-menu-content.tsx chore: update Discord invite link (#452) 2026-05-29 15:56:48 +02:00