Skip to content

feat(quote): optimistic recent-quote mutations with rollback - #733

Merged
mikewheeleer merged 2 commits into
StableRoute-Org:mainfrom
Ayoola-tech2024:feat/swap-optimistic-mutations
Aug 30, 2026
Merged

feat(quote): optimistic recent-quote mutations with rollback#733
mikewheeleer merged 2 commits into
StableRoute-Org:mainfrom
Ayoola-tech2024:feat/swap-optimistic-mutations

Conversation

@Ayoola-tech2024

Copy link
Copy Markdown
Contributor

Summary

Closes #723

Implements optimistic UI for the Recent Quotes list on /quote, per the issue's requirements:

  • Immediate local mutation: a validated quote submission inserts a pending entry into the visible history before the network request starts (cooldown/validation rejections happen earlier, so no mutation occurs on those paths).
  • Server reconcile: on success the optimistic entry is replaced by a canonical entry built from the server response fields (source_asset / dest_asset / amount) — e.g. typed EURC reconciles to the server's canonical casing — and only then is localStorage persisted.
  • Exact rollback: on failure the pending entry is removed and nothing else changes; a polite live-region message announces the rollback (The recent quotes update failed and was rolled back.).
  • Stale-response guard: the existing request-sequence ref is reused — each pending entry is keyed by its request id, an aborted superseded request never touches state, and a newer submission replaces the single pending slot.
  • Concurrent unrelated updates unaffected: rollback only clears the pending slot; form inputs and confirmed history are untouched.

Implementation notes

  • Extracted pure history logic into src/app/quote/historyModel.ts (readHistory, pushHistoryPure, writeHistory, canonicalEntryFromQuote, mergePendingEntry) so it is unit-testable in isolation.
  • QuoteHistory renders the merged view (pending first) with a data-pending row, reduced opacity, and an sr-only "(saving…)" hint for assistive tech; memo behavior preserved via useMemo.
  • The optimistic entry is never persisted to localStorage — persistence happens only with server-canonical data.

Tests

New tests only where possible; one existing test updated:

  • historyModel.test.ts: unit coverage of read/push/dedupe/cap/reconcile/merge.
  • optimistic-history.test.tsx: integration through <QuotePage /> covering all five edge cases from the issue:
    1. success replaces the optimistic value with the server value
    2. error rolls state back exactly
    3. rapid successive edits never let a stale response overwrite newer state
    4. concurrent unrelated updates are unaffected
    5. failure announced to assistive tech
  • page.test.tsx: one test renamed/assertion updated from "clears the announcement on failure" to asserting the rollback message, per the issue's explicit requirement that failures be announced to assistive tech.

Gates

  • npm run lint
  • npm test ✔ 77 suites / 1285 tests
  • npm run build

Out of scope per the issue: server-side conflict merging, offline queueing.

@mikewheeleer
mikewheeleer merged commit 7858af8 into StableRoute-Org:main Aug 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

optimistic UI updates with rollback for swap interface mutations

2 participants