06 — Screen Specifications (Payments)
- S1 — Payments list
- S2 — Payment detail
- S3 — New payment form (full-screen)
- S4 — Refund sheet
- S5 — Reconcile sheet
- S6 — Receipt view
- S7 — Receipts list
- Global interaction details
The largest document: precise specs for each payments screen. All tokens referenced from 00-shared/02_Design_Tokens.md; components from 00-shared/03.
S1 — Payments list
Layout
AppBar: title "Payments", actions: receipts icon, search icon.- Body: search field (sticky), filter chips row (All / Completed / Pending / Processing / Failed / Refunded / Partially refunded — client-side), list, load-more footer.
- FAB:
AppFAB.extended"Record payment" — hides on scroll down. - Padding: 16 phone / 24 tablet+. Section gap 24. Card gap 12.
Row composition (AppListTile 72 dp)
- Leading: gateway icon (offline = cash icon) in
primaryContainercircle. - Title:
transactionReference(mono,titleSmall). - Subtitle:
payerName+ date (bodySmall,onSurfaceVariant). - Trailing: amount (
titleMedium, tabular figures) + statusAppBadge. - On tap: ripple + push S2.
Status badge mapping
| Status | Badge color (role) | Icon |
|---|---|---|
| completed | success | check_circle |
| pending / processing | info (primaryContainer) | schedule |
| failed | error | cancel |
| refunded / partially_refunded | tertiary | currency_rupee/replay |
States
- Loading: 8
AppSkeletonrows; shimmerm-slow. - Empty:
AppEmptyState(iconpayments, "No payments yet", CTA "Record payment"). - Error:
AppErrorStatecode-aware (403 → permission empty-state; 5xx → generic + requestId + Retry). - Offline:
AppOfflineBanner; cached last-good list (client cache 5 min). - Pagination: footer "Load more" → spinner → next page; "End of list"
bodySmallwhentotalreached. Server returns{data,total}— client computes hasNext locally.
A11y
- Row: single semantics node "Payment TXN-…, amount, status".
- Chips:
Semantics(selected:); results count live region. - Contrast per 00-shared/09; touch targets ≥ 48.
Animations
- New row entrance: fade+rise stagger 40 ms.
- Status chip change:
AnimatedSwitcher150 ms.
S2 — Payment detail
Layout
- Hero header card: amount
headlineMediumtabular; status badge; transaction referencemonobodySmallwith copy icon. - Info cards (each
AppCarde-1, padding 16, gap 12):- Payer: name, email, payerId.
- Invoice: link (route to invoice), status, paidAmount/totalAmount progress bar
(linear,
m-base). - Gateway: gateway, gatewayTransactionId, gatewayResponse.
- Money: amount, fee, refundedAmount, currency.
- Timeline: createdAt, updatedAt (from BaseSchema).
- Actions row (primary/secondary):
- Receipt (
FilledButton.tonal) → S6. - Refund (
OutlinedButtondestructive) → S4 (visible iffpayments.refund+ status completed). - Reconcile (
OutlinedButton) → S5 (visible iff PENDING/PROCESSING +payments.reconcile).
- Receipt (
States
- Loading: skeleton cards.
- 404:
AppErrorState"Payment not found" (no retry; back offered). - Conflict after action: banner with server message.
A11y
- Copy button: tooltip + semantics "Copy transaction reference"; announce "Copied".
- Amounts:
Semanticsnumeric value.
S3 — New payment form (full-screen)
Layout
AppBartitle "Record payment", close/back.Formcolumn (gap 16): amount*, currency, gateway*, gatewayTransactionId, invoice (searchableAppDropdown), payerName, payerEmail, payerId, description, submitFilledButtonfullWidth (48 dp).- Keyboard:
resizeToAvoidBottomInset; scroll into view on focus; amount → next, submit on last field (action "Done"). - Safe areas: bottom padding = nav/safe area + 16.
Components & tokens
- Amount:
AppTextFieldkeyboardTextInputType.numberWithOptions(decimal:true), formatter decimal 2 places, error "Enter a valid amount (min 0)". - Gateway:
AppDropdownfromPaymentGatewayenum — icons per method. - Invoice: optional; selecting prefills amount (editable after) + payerName from invoice payer when present.
- Submit:
loadingswaps label → spinner; fields disabled while pending; double-tap blocked.
States
- Validation: server 400
detailsmapped to fields; generic banner for others. - Success: navigate-inline to success view: payment + receipt cards + actions (View receipt, Done → S1 refreshed).
- Failure: banner
AppBannererror + Retry; form values preserved.
Dark/light: token-based only.
A11y
- Labels visible; autofill hints (name, email).
- Error announcement via live region; focus first invalid field.
S4 — Refund sheet
AppBottomSheetwith drag handle; title "Refund payment".- Refundable amount info row (
bodyMedium). - Amount field (default full refundable, min 0.01, max refundable).
- Reason
AppTextField(required, 3–200 chars). - Submit
FilledButtondestructive (error colors) loading state; CancelTextButton. - Server 409 messages → inline error under amount / banner.
- Confirm semantics:
Semantics(button, label "Confirm refund of amount"). - Sheet dismiss: back gesture/ESC = cancel; no discard warning (non-destructive form).
S5 — Reconcile sheet
- Title "Reconcile payment".
- Outcome
AppRadiogroup: Success / Failed / Pending. - Gateway response text field (optional).
- Submit → PATCH; result status reflected on S2; errors → banner + retry.
S6 — Receipt view
- Receipt card (centered, max width 480, e-1, padding 24):
- Header: "Receipt" +
receiptNumbermono; school/org name (tenant branding)(planned). - Body: amount large, fee, currency, payment method; payer name/email; description; payment reference; invoice id.
- Footer: issuedAt date (locale), paymentId.
- Header: "Receipt" +
- Actions: Share
(forward-looking); Copy receipt number. - Print:
(planned)reports module PDF. - A11y: receipt is a
Semanticssummary; amounts spoken fully.
S7 — Receipts list
- Mirrors S1; rows: receiptNumber, amount, date, payerName; tap → S6.
- Pagination same
{data,total}handling.
Global interaction details
- Haptics: success
lightImpact; errormediumImpact; refund confirmheavyImpact. - Hover (desktop): row tint
surfaceContainerHigh; destructive hovererrorContainer. - Focus order: search → chips → list → FAB; visible
primaryring. - Hero: invoice → payment amount cross-fade (no shared element needed).
- Reduced motion: all
m-instantfades.