13 — State Management (Payments)
Bloc/Cubit per screen following 00-shared/06 conventions (proposed architecture).
Cubits
PaymentsListCubit
- State:
{LoadState, List<PaymentDto>, total, page, hasNext, filters: (status, query), busy}. - Events:
LoadList,Refresh(bypass cache),LoadMore,FilterChanged,Retry,PaymentCreated(append/refresh). - Behaviours: server returns
{data,total}→hasNext = data.length + current < total; client-side filtering via local search + status chips; pull-to-refresh re-fetches. - Realtime: subscribes
tenantWS room, filter topicpayment.processed/payment. refunded→ refresh or insert.
PaymentDetailCubit
Load(id)→{data, LoadState}; on WS event for sametransactionReference→ re-fetch.- Actions emit
Refund(submit)→ success → reload + snackbar;Reconcile(status)→ reload.
NewPaymentCubit
- State machine (Mermaid):
stateDiagram-v2
[*] --> Idle
Idle --> Submitting : RecordPayment(valid payload)
Submitting --> Success : server {payment,receipt}
Submitting --> Idle : validation/network error
Success --> [*]
- No optimistic state; values preserved across
Failed. - Uploads: none (no file uploads in payments).
ReceiptsListCubit
- Mirrors PaymentsList (paged
{data,total}).
Shared selectors
InvoiceStatusSelector(from fees) — used on MoneyProgress.PermissionsSelector— gates action visibility.
Cache
sl:payments:list:{page}5 min;sl:payments:{id}1 min; refresh bypasses.- Clear payments cache when an invoice reaches PAID (fees event) so dues views refresh.
Realtime
- WS channel
tenant:{tenantId}: onPaymentProcessed→ refresh invoice dues + list (debounced 500 ms).
Error handling (client table)
| Code | Behaviour |
|---|---|
| 400 | map details → fields |
| 409 | banner with server message; refresh list/detail |
| 404 | empty/not-found state |
| 429 | countdown; disable submit |
| 5xx/network | retry UI; form preserved |