Skip to content

feat: add optimistic UI update for buy transaction before on-chain confirmation (#571) - #614

Merged
Chucks1093 merged 3 commits into
accesslayerorg:devfrom
Hollujay:feat/571-optimistic-buy-transaction-ui
Jul 26, 2026
Merged

feat: add optimistic UI update for buy transaction before on-chain confirmation (#571)#614
Chucks1093 merged 3 commits into
accesslayerorg:devfrom
Hollujay:feat/571-optimistic-buy-transaction-ui

Conversation

@Hollujay

Copy link
Copy Markdown
Contributor

Closes #571.

Summary

Implements an optimistic UI update pattern for buy transactions so holdings reflect immediately in the UI after a user submits a purchase, rather than waiting for on-chain confirmation.

Changes

src/utils/portfolioValue.utils.ts

  • Added pending?: boolean field to the HeldKeyPosition interface to support optimistic state tracking per holding entry.

src/hooks/useWallet.ts

  • Added TradeVariables interface for typed mutation input (creatorId, amount, priceStroops, price).
  • Added useTradeMutation(address: string) hook using @tanstack/react-query useMutation:
    • mutationFn: Simulates on-chain transaction (900ms delay placeholder, swappable for real contract call).
    • onMutate: Cancels in-flight refetches, snapshots the previous holdings cache, then optimistically updates the cache with the new quantity and pending: true. If the creator is not yet held, a new entry is created.
    • onError: Rolls back to the previous cache snapshot and displays error toast via getSignatureErrorMessage.
    • onSuccess: Removes the pending flag from the cache and shows a success toast with the amount.
    • onSettled: Invalidates the holdings query to sync with server state after completion.
  • Added type parameter <HeldKeyPosition[]> to useWalletHoldings.

src/pages/LandingPage.tsx

  • Buy flow now delegates to tradeMutation.mutateAsync(...) instead of local state simulation.
  • heldKeyPositions memo merges React Query cache data (with pending state) with local demo holdings, falling back to local state when the cache is empty.
  • Holdings cards render a pending badge (amber spinner + "Pending" label) and apply reduced opacity (opacity-60) when pending: true.
  • Sell flow remains unchanged.

Test files (4 files)

  • Added vi.mock("@/hooks/useWallet") in LandingPage.holdings.test.tsx, LandingPage.holdingsCount.integration.test.tsx, LandingPage.holdingsEmptyState.test.tsx, and LandingPage.apiErrorToast.integration.test.tsx to provide mock useTradeMutation and useWalletHoldings since these tests render LandingPage without a QueryClientProvider.

Acceptance Criteria

  • Holding count updates immediately on buy submission (optimistic cache write via onMutate)
  • Pending state visually distinguishable from confirmed holdings (amber spinner badge + muted opacity)
  • Confirmed state matches server data after refetch (onSettled invalidates the query)
  • Optimistic update rolled back on failure (onError restores previous cache snapshot)

Notes

  • The mutationFn currently uses a placeholder 900ms delay. Replace with the real contract interaction when available.
  • The sell flow still uses local state and is unaffected by these changes.

Hollujay added 3 commits July 26, 2026 00:36
Add optimistic update to immediately reflect pending purchases in the
React Query holdings cache before on-chain confirmation.

Changes:
- Add  field to  interface
- Create  hook with onMutate/onError/onSuccess/onSettled
  lifecycle for optimistic cache updates and rollback
- Wire buy flow in LandingPage to use the mutation
- Show pending badge (spinner badge + muted opacity) on unconfirmed holdings
- Merge cache data with local demo state for holdings display
- Mock useWallet in affected test files to support new hook dependencies
mutationFn's body doesn't use creatorId/amount (it's a simulated
delay), so destructuring them (even with underscore-prefixed names)
tripped @typescript-eslint/no-unused-vars — this project's ESLint
config doesn't have an argsIgnorePattern exception for that
convention. Dropped the parameter entirely since it's unused.
@Chucks1093
Chucks1093 merged commit 773343e into accesslayerorg:dev Jul 26, 2026
1 check passed
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.

Add optimistic UI update for buy transaction before on-chain confirmation

2 participants