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
Conversation
|
@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! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Four independent UX / correctness improvements, one commit each:
/my-intentsCloses #300
Closes #301
Closes #302
Closes #303
Changes
#302 – Multi-tab wallet reconciliation
store/wallet.ts: newsyncFromStorage(persisted)action. A cross-tabdisconnect (
persisted.isConnected === false) is trusted directly; a changedaccount is adopted optimistically and then re-verified with
hydrate(); analready-in-sync snapshot is a no-op (this is what prevents a reconciliation
loop). Exports
PERSIST_KEYand aPersistedWalletStatetype.WalletHydrator.tsx: registers awindowstoragelistener (once, next tothe mount-time
hydrate()), parses the zustand-persist envelope, and forwardsthe slice to
syncFromStorage. Cleaned up on unmount.docs/wallet-hydration.md: new "Multi-tab reconciliation" section.wallet.test.ts(+3),WalletHydrator.test.tsx(rewritten, +3).#303 – Onboarding hints
src/components/OnboardingHints.tsx: dependency-free 3-step coach-markoverlay with a spotlight ring around each target. Shown once per browser
(
localStoragevortex-onboarding-seen), only when every target element ispresent. 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 asolver-portal-linkin the hero (newhome.hero.solverCtakey inen/es).OnboardingHints.test.tsx(6),page.test.tsx(+1, existing shelltests suppress the sequence via
localStorage).#300 – Column visibility on
/my-intentssrc/hooks/useColumnVisibility.ts: a persisted per-column show/hide map.alwaysVisiblecolumns are forced on and non-toggleable; unknown / non-booleankeys in a stale persisted value are ignored.
my-intents/page.tsx: a "Columns" dropdown (checkboxes) in the filter bar.pair,status, andsubmittedare always visible;chainandsolvertoggle. Rows now show a "submitted … ago" line.
useColumnVisibility.test.ts(5),my-intents/page.test.tsx(+4).#301 – Swap-failure classification + help
useSwapSubmission.ts: newclassifySwapError(err): SwapErrorKind(
network/no-solver/balance/user-rejected/generic), mirroringuseSolverRegistration'sRegistrationErrorMessageand keying offApiError.status/TimeoutError. The hook now also returnserrorKind; theraw
errormessage is kept unchanged so no backend detail is lost.SwapCard.tsx: for a classified failure, shows one line of actionableguidance (
SWAP_ERROR_GUIDANCE); forgeneric, an expandable"Why did this happen?"
<details>with troubleshooting steps.useSwapSubmission.test.ts(+6), newSwapCard.errors.test.tsx(4).Testing
npm run build/npx tsc --noEmit– blocked by pre-existing breakage (below)wallet.test.ts14/14,WalletHydrator.test.tsx6/6OnboardingHints.test.tsx6/6,page.test.tsx7/7 (was 0/6)useColumnVisibility.test.ts5/5,my-intents/page.test.tsx21/22useSwapSubmission.test.ts11/11,SwapCard.test.tsx14/14 (was 0 – file didn't collect),SwapCard.errors.test.tsx4/4pre-existing failures fixed as a side effect of repairing files these features touch).
(see below). Covered by a simulated
storageevent inwallet.test.ts.Pre-existing breakage (not introduced here)
maindoes not build, typecheck, lint, or pass its own tests atc87dc14,from botched
Merge branch main into feature/…conflict resolutions inPRs #217–219. A full
tscis blocked by three files with literalmerge-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– deaderrorKeyreference,wasSessionClearedmissing fromthe state type; restored
errorKey: WalletErrorKey | nulland thestale-session preservation of
lastKnownAddressits own tests require.SwapCard.tsx– ~42 type errors (duplicatechainPickerRef/chainToggleRef/
closeChainPicker/useEffect; undefineddstAddress,slippagePct,quoteFetchedAt,STALE_QUOTE_THRESHOLD_MS,quoteErrorType). The droppedslippage-tolerance field + min-out line were restored (they have
en/eskeys and are required by the existing
SwapCard.test.tsx); the amount inputis now
type="text" inputMode="decimal"so 18-dp values aren't reformatted.my-intents/page.tsx–downloadCsv/buildIntentsCsvnot 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 thetouched test suites); the i18n catalog key-parity gap;
*.stories.tsx.my-intents/page.test.tsx's "retry button" case references undefineduser/mutateMockin its own body and can't pass without a test rewrite.Checklist