Skip to content

feat(frontend): multi-tab wallet sync, onboarding hints, column visibility & swap-error help (#300 #301 #302 #303) - #368

Open
samuelisi wants to merge 5 commits into
stellar-vortex-protocol:mainfrom
samuelisi:feature/300-303-my-intents-swap-ux
Open

feat(frontend): multi-tab wallet sync, onboarding hints, column visibility & swap-error help (#300 #301 #302 #303)#368
samuelisi wants to merge 5 commits into
stellar-vortex-protocol:mainfrom
samuelisi:feature/300-303-my-intents-swap-ux

Conversation

@samuelisi

Copy link
Copy Markdown

Summary

Four independent UX / correctness improvements, one commit each:

Closes #300
Closes #301
Closes #302
Closes #303

Changes

#302 – Multi-tab wallet reconciliation

  • store/wallet.ts: new syncFromStorage(persisted) action. A cross-tab
    disconnect (persisted.isConnected === false) is trusted directly; a changed
    account is adopted optimistically and then re-verified with hydrate(); an
    already-in-sync snapshot is a no-op (this is what prevents a reconciliation
    loop). Exports PERSIST_KEY and a PersistedWalletState type.
  • WalletHydrator.tsx: registers a window storage listener (once, next to
    the mount-time hydrate()), parses the zustand-persist envelope, and forwards
    the slice to syncFromStorage. Cleaned up on unmount.
  • docs/wallet-hydration.md: new "Multi-tab reconciliation" section.
  • Tests: wallet.test.ts (+3), WalletHydrator.test.tsx (rewritten, +3).

#303 – Onboarding hints

  • New src/components/OnboardingHints.tsx: dependency-free 3-step coach-mark
    overlay with a spotlight ring around each target. Shown once per browser
    (localStorage vortex-onboarding-seen), only when every target element is
    present. Skippable at any step (Skip button, backdrop click, Escape),
    keyboard-operable, and skips the entrance animation when data-motion="reduce".
  • app/page.tsx: mounts it and adds stable ids (swap-card-region,
    live-feed-region) plus a solver-portal-link in the hero (new
    home.hero.solverCta key in en/es).
  • Tests: new OnboardingHints.test.tsx (6), page.test.tsx (+1, existing shell
    tests suppress the sequence via localStorage).

#300 – Column visibility on /my-intents

  • New src/hooks/useColumnVisibility.ts: a persisted per-column show/hide map.
    alwaysVisible columns are forced on and non-toggleable; unknown / non-boolean
    keys in a stale persisted value are ignored.
  • my-intents/page.tsx: a "Columns" dropdown (checkboxes) in the filter bar.
    pair, status, and submitted are always visible; chain and solver
    toggle. Rows now show a "submitted … ago" line.
  • Tests: new useColumnVisibility.test.ts (5), my-intents/page.test.tsx (+4).

#301 – Swap-failure classification + help

  • useSwapSubmission.ts: new classifySwapError(err): SwapErrorKind
    (network / no-solver / balance / user-rejected / generic), mirroring
    useSolverRegistration's RegistrationErrorMessage and keying off
    ApiError.status / TimeoutError. The hook now also returns errorKind; the
    raw error message is kept unchanged so no backend detail is lost.
  • SwapCard.tsx: for a classified failure, shows one line of actionable
    guidance (SWAP_ERROR_GUIDANCE); for generic, an expandable
    "Why did this happen?" <details> with troubleshooting steps.
  • Tests: useSwapSubmission.test.ts (+6), new SwapCard.errors.test.tsx (4).

Testing

  • npm run build / npx tsc --noEmitblocked by pre-existing breakage (below)
  • New / touched suites green in isolation:
    • wallet.test.ts 14/14, WalletHydrator.test.tsx 6/6
    • OnboardingHints.test.tsx 6/6, page.test.tsx 7/7 (was 0/6)
    • useColumnVisibility.test.ts 5/5, my-intents/page.test.tsx 21/22
    • useSwapSubmission.test.ts 11/11, SwapCard.test.tsx 14/14 (was 0 – file didn't collect),
      SwapCard.errors.test.tsx 4/4
  • Full suite: ~72 failed → 52 failed (+51 new tests, all green; ~20
    pre-existing failures fixed as a side effect of repairing files these features touch).
  • Manual two-tab check for Build resilient multi-tab wallet session synchronization #302 – not done; the app does not currently run
    (see below). Covered by a simulated storage event in wallet.test.ts.

Pre-existing breakage (not introduced here)

main does not build, typecheck, lint, or pass its own tests at c87dc14,
from botched Merge branch main into feature/… conflict resolutions in
PRs #217–219. A full tsc is blocked by three files with literal
merge-conflict debris (explore/page.tsx, solve/page.tsx,
solve/[address]/page.test.tsx).

Files this PR had to repair just enough to compile / render (their existing
suites are exercised above):

  • store/wallet.ts – dead errorKey reference, wasSessionCleared missing from
    the state type; restored errorKey: WalletErrorKey | null and the
    stale-session preservation of lastKnownAddress its own tests require.
  • SwapCard.tsx – ~42 type errors (duplicate chainPickerRef / chainToggleRef
    / closeChainPicker / useEffect; undefined dstAddress, slippagePct,
    quoteFetchedAt, STALE_QUOTE_THRESHOLD_MS, quoteErrorType). The dropped
    slippage-tolerance field + min-out line were restored (they have en/es
    keys and are required by the existing SwapCard.test.tsx); the amount input
    is now type="text" inputMode="decimal" so 18-dp values aren't reformatted.
  • my-intents/page.tsxdownloadCsv / buildIntentsCsv not imported,
    duplicate status badge, over-riding aria-labels.

Still red and left untouched (out of scope): the 3 merge-debris files;
Nav.tsx / ConnectWalletButton.tsx / ActivityFeed.tsx (mocked in the
touched test suites); the i18n catalog key-parity gap; *.stories.tsx.
my-intents/page.test.tsx's "retry button" case references undefined
user / mutateMock in its own body and can't pass without a test rewrite.

Checklist

  • Self-reviewed the diff
  • Added or updated tests for new behaviour
  • No secrets or credentials committed
  • PR title follows conventional commits

@drips-wave

drips-wave Bot commented Aug 30, 2026

Copy link
Copy Markdown

@samuelisi Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant