Implement the Payments management page under /payments.
Priority: P1
API endpoints used
| Method |
Endpoint |
Description |
| GET |
/finance/balances |
List all member balances (Balance[]) |
| GET |
/finance/balances/{member_id} |
Get balance for a specific member |
| GET |
/finance/transactions |
List all transactions (Transaction[]) |
| POST |
/finance/transactions |
Create a new transaction (TransactionCreate) |
| GET |
/finance/transactions/{transaction_id} |
Get transaction details |
| PATCH |
/finance/transactions/{transaction_id} |
Update a transaction (TransactionPartialUpdate) |
| DELETE |
/finance/transactions/{transaction_id} |
Delete a transaction |
Tasks
- Add
src/features/payments/api/queries.ts with useListBalances, useGetMemberBalance, useListTransactions, and useGetTransaction hooks using TanStack Query; expose query options for route loaders
- Add
src/features/payments/api/mutations.ts with useCreateTransaction, useUpdateTransaction, and useDeleteTransaction hooks; on success invalidate both transactionListQueryOptions and balanceListQueryOptions
- Add
src/features/payments/api/query-keys.ts for structured query keys
- Wire a React Router v7 loader on the
/payments route that prefetches both balances and transactions
- Add Zod schema for
TransactionCreate and TransactionPartialUpdate derived from the generated types in src/api.ts
- Add Zustand slice for UI state only: selected transaction ID, active tab (balances / transactions)
- Build a balances overview table (columns:
member, balance_cents formatted as currency)
- Build a transactions table on a separate tab (columns:
title, member, amount_cents, created_at)
- Add a "New Transaction" Dialog with a React Hook Form + Zod validated form for
TransactionCreate (required: member, amount_cents, title)
- Support edit (PATCH) and delete with confirmation from the transaction row
Acceptance criteria
- Balances and transactions load before the page renders (via loader prefetch)
- Creating, editing, and deleting a transaction reflects in both the transaction list and the affected member's balance
amount_cents is displayed as a formatted currency value (e.g. 1050 -> EUR 10.50)
- Form validates required fields (
member, amount_cents, title) before submitting and shows inline errors
- Invalid amount formats are blocked client-side with field errors
Implement the Payments management page under
/payments.Priority: P1
API endpoints used
Balance[])Transaction[])TransactionCreate)TransactionPartialUpdate)Tasks
src/features/payments/api/queries.tswithuseListBalances,useGetMemberBalance,useListTransactions, anduseGetTransactionhooks using TanStack Query; expose query options for route loaderssrc/features/payments/api/mutations.tswithuseCreateTransaction,useUpdateTransaction, anduseDeleteTransactionhooks; on success invalidate bothtransactionListQueryOptionsandbalanceListQueryOptionssrc/features/payments/api/query-keys.tsfor structured query keys/paymentsroute that prefetches both balances and transactionsTransactionCreateandTransactionPartialUpdatederived from the generated types insrc/api.tsmember,balance_centsformatted as currency)title,member,amount_cents,created_at)TransactionCreate(required:member,amount_cents,title)Acceptance criteria
amount_centsis displayed as a formatted currency value (e.g. 1050 -> EUR 10.50)member,amount_cents,title) before submitting and shows inline errors