feat: real-time escrow status timeline with optimistic updates (#26) - #46
Conversation
…an-labs#26) Render a live escrow lifecycle timeline that reflects on-chain state changes, applies user actions optimistically, and rolls back gracefully on failure. - escrowTimeline.ts: pure lifecycle model (funded -> completed | cancelled | disputed -> resolved, mirroring the Soroban escrow contract's Status) as an append-only event log with a single pure reducer handling submit / confirm / fail / sync, plus buildTimelineNodes. - escrowChain.ts: isolated simulated on-chain source (latency, occasional failure, in-memory ledger) so the flow is exercised today; swap its two functions for a real endpoint when the backend Soroban integration lands. - useEscrowTimeline: wires the reducer to the chain with optimistic submit and visibility-aware polling for real-time reconciliation. - EscrowTimeline / EscrowTimelinePanel: accessible vertical timeline, action buttons derived from the legal transitions, live-sync indicator, and inline rollback error with retry. - Route /escrow/[bookingRef]/timeline; "Track escrow status" link from the funding wizard's funded state. - 22 reducer/metadata unit tests (110 total pass); lint, typecheck and production build clean. Closes workman-labs#26
|
@jayteemoney is attempting to deploy a commit to the Meshack Yaro's projects Team on Vercel. A member of the Team first needs to authorize it. |
meshackyaro
left a comment
There was a problem hiding this comment.
Excellent work on this PR! This is a thoughtfully architected implementation that demonstrates strong full-stack thinking.
Standout observations:
-
Event-sourced architecture — modeling the timeline as an append-only event log is elegant and directly mirrors the on-chain escrow contract lifecycle. Optimistic updates and rollback become natural state transitions rather than ad-hoc mutations.
-
Stale-safe reconciliation — the
SYNCaction thoughtfully handles real-world timing issues (visibility changes, network delays). Dropping stale confirmations by submission-id and reconciling external changes without corrupting optimistic nodes shows maturity in thinking about distributed systems. -
Zero new dependencies** — a polished, accessible UI using only React, existing primitives, and Tailwind. The visibility-aware polling is a nice touch for both UX and backend load.
-
Test coverage — 22 new tests for the reducer and metadata are well-earned; verification walkthrough from funded → disputed → resolved shows care for actual usage.
-
Documentation —
docs/escrow-status-timeline.md+ clear inline comments make the design intent obvious, lowering the maintenance burden for the team.
The transition from stubs to real Soroban calls is well-isolated; the follow-up swap will be straightforward. Clean build, no hydration warnings, and the PR description is unusually thorough.
Really solid contribution. Well done!
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Summary
Implements #26 — a real-time escrow status timeline with optimistic updates. The new route
/escrow/[bookingRef]/timelinerenders the escrow's on-chain lifecycle as a live, chronological timeline. User actions apply optimistically and either confirm into the history (with a tx hash + timestamp) or roll back gracefully on failure; a visibility-aware background poll keeps the timeline in sync with the authoritative status.The lifecycle mirrors the Soroban
escrowcontract'sStatusinguildworkman-core:What's included
src/lib/escrowTimeline.ts— pure lifecycle model: statuses, legal actions (actionsFor), and a single puretimelineReducer(SUBMIT/CONFIRMED/FAILED/SYNC/DISMISS_ERROR) over an append-only event log, so optimistic-apply-then-rollback is a modeled transition, not ad-hocuseState. PlusbuildTimelineNodes.src/lib/escrowChain.ts— an isolated simulated on-chain source (latency, an occasional failed submission, an in-memory ledger the poll reads). Same rationale as the existingfundEscrow()stub: the Sorobanescrowcontract has the methods, but no backend REST/RPC endpoint exposes them to the web app yet. Swap these two functions for real calls and nothing else changes.src/components/escrow/useEscrowTimeline.ts— wires the reducer to the chain: optimistic submit + confirm/rollback, and visibility-aware polling (pauses on hidden tab, refreshes on return).EscrowTimeline.tsx/EscrowTimelinePanel.tsx— accessible vertical timeline (aria-liveoptimistic node,role="alert"rollback, live-sync indicator); action buttons are derived from the legal transitions and disabled while a submission is in flight./escrow/[bookingRef]/timeline, plus a "Track escrow status" link from the funding wizard's funded state.docs/escrow-status-timeline.md+ a README "Known limitations" entry documenting the architecture and the stub follow-up.Architecture notes
history: ConfirmedEntry[]is the source of truth and the optimistic action is a singlependingnode appended after it. Rollback is "drop the pending node"; the confirmed history is untouched by construction.SYNCcommits an in-flight action whose target it observes, adopts a legal external change (dropping any now-impossible optimistic node and noting the snap-back), and ignores states it can't reconcile; stale confirmations/failures are dropped by submission-id matching.useSyncExternalStorefor hydration-safe timestamps),react-icons, the existingui/*primitives and Tailwind tokens (light/dark both work).Tasks / acceptance criteria
actions/setup-nodecache: npm)npm run lint— clean (no new warnings),npm run typecheck— no errorsnpm run build— production build succeeds;/escrow/[bookingRef]/timelineemittedVerification
npm run typecheck→ no errorsnpm run lint→ 0 errors (pre-existing warnings only, none in new code)npm test→ 110 passed (incl. 22 new reducer/metadata tests)npm run build→ successfunded → disputed → resolvedin the running app: optimistic nodes, tx-hash confirmation, action narrowing, and terminal state all correct.Closes #26
🤖 Generated with Claude Code