Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

10 — Interaction Specification (Fees Module)

Platform interaction detail for the Fees screens; extends 00-shared/08. Motion tokens Mo.* = 00-shared/02 §6; F = focus/touch baseline.


1. Phone / touch

  • Dues list: tap row → invoice detail; tap inline "Collect" icon-button (44 dp, tooltip) → record-payment sheet; RefreshIndicator; infinite scroll with bottom AppProgress.
  • Invoices list (student): tap card → detail; pull-to-refresh.
  • Record payment: full-height AppBottomSheet (r-xl, drag handle) with keyboard avoidance (resizeToAvoidBottomInset: true); CTA pinned above keyboard.
  • Generate invoice: AppDialog (format): student dropdown + discounts editor; button "Generate invoice".
  • Receipt view: render + Share action (proposed); long-press number to copy.

2. Keyboard / desktop / mouse

  • Amounts: decimal numeric pad; .next field order; Ctrl/Cmd+Enter submit on forms.
  • Desktop N = new structure (list screen); E = edit (detail) — app-level.
  • Hover states on cards/rows (00-shared/02 §9); hover scale on badges (proposed).
  • Right-click row menu for structure rows (Edit / Delete; Duplicate (planned)).

3. Haptics (mobile)

  • Success payment post: light success tap; error/409: warning buzz (short).
  • Pull-to-refresh: default haptic; new invoice issued: subtle confirmation.

4. Motion language (module extension of 00-shared/08 §4)

  • List transitions Mo.m-entrance stagger 40 ms; card fade for deletion Mo.m-base.
  • Amount changes animate by counting (AnimatedSwitcher/IntrinsicCounter) over Mo.m-base, only when server-confirmed — never optimistic.
  • Status chip swaps: AnimatedSwitcher Mo.fast, cross-fade only.
  • Sheet: standard spring up Mo.m-base; dialog Mo.m-base scale+fade.
  • Reduced-motion: all Mo.m-instant static; no counting animation, no parallax.

5. Micro-interactions catalogue

InteractionTriggerFeedback
Record payment submittap FilledButtonspinner (icon→spinner), disabled inputs, live-region announce
Generate invoicedialog submitspinner; then snackbar "Invoice issued"
Refresh duespullRefreshIndicator; success silent
Overpay attempt (amount > due)edgeinline tertiary banner "Exceeds remaining balance" + preview resulting paidAmount
Amount focusMoneyFieldselect-all, hide grouping suffix until blur
Copy referencelong-press on transactionReference rowssnackbar "Copied {ref}"
Back from dirty sheetsystem-back(proposed) "Discard payment?" dialog
409 duplicate-invoicesubmit responseinline AppBanner(info), dialog stays
409 paid/cancelledsubmit responseclose + snackbar(info)

6. Frustration controls (shared 00-shared/08 §6 + module)

  • Retry always on AppErrorState; 429 → countdown text, no auto-retry (00-shared/07 §4 api 100/min).
  • Snackbar error persists ≥ 4 s (00-shared/03 §A); success < 3 s.
  • Status changes (e.g. invoice → paid) announce via Semantics(liveRegion).
  • (proposed) deeplinks: studylyon://fees/dues, studylyon://fees/structures/:id, studylyon://fees/invoices/:id, studylyon://payments/receipts/:id.
  • Notification tap → invoice detail (when invoice.updated/receipt notification lands; (planned)).
  • Amounts copying: long-press MoneyAmount → copy raw number + currency.

8. Validation of interaction to server semantics

Client interactionServer semantics (must not diverge)
Sheet "Record payment" successserver 201 + recompute paidAmount/status (fees.service.ts:168-176)
Sheet retry with same keyreplay original doc (fees.service.ts:148-152)
Generate invoice successserver 201, _id returned; issuedAt set server-side (fees.service.ts:122-130)
Duplicate generation 409treated as already-exists navigation (fees.service.ts:107-115)
Refund amount reductionserver caps refunds ≤ payment (payments.service.ts:81-86)
Online paymenttransactionReference from server (payments.service.ts:215-217); local refs never sent
Any amount displayedsource of truth = server field; formatting client-side only (06 §0; OQ-1)