mirror of
https://github.com/luxfi/wallet.git
synced 2026-07-27 03:37:41 +00:00
fix(web): dashboard quick-actions use SPA soft-nav so the session survives
The wallet keeps `isUnlocked` + the plaintext mnemonic in memory ONLY (never persisted — see the auth store's partialize), so ANY full-document reload wipes the session and bounces the user back to onboarding. On mobile this made the wallet unusable: every full-reload dashboard action effectively logged you out. - Portfolio dashboard: render the Send / Cross-Chain / Earn / Manage Keys quick-action cards as react-router <Link> (client-side soft-nav) instead of full-reload <a href>. A tap pushState-navigates and the in-memory unlock + mnemonic survive. - Audit for other session-dropping full-reload links: Callback's "Back to wallet" recovery link was a raw <a href="/"> — converted to <Link to="/">. Verified at 390x844 (iPhone-class): the 4 cards render with no horizontal overflow (documentElement.scrollWidth == 390); tapping Send soft-navigates to /send with NO document reload (a page sentinel + the zustand auth store both survive, isUnlocked stays true); a full-reload navigation (the prior behavior) wipes the in-memory session — confirming the fix. Co-authored-by: Hanzo Dev <dev@hanzo.ai>
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
* GPL-3.0-or-later — inherited from the wallet monorepo.
|
||||
*/
|
||||
import { useEffect, useState } from "react"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import { Link, useNavigate } from "react-router-dom"
|
||||
import { useBrand } from "../../hooks/useBrand"
|
||||
import { useSession } from "../../store/session"
|
||||
|
||||
@@ -43,9 +43,9 @@ export default function Callback(): React.JSX.Element {
|
||||
<>
|
||||
<h1 style={title}>Sign-in failed</h1>
|
||||
<p style={msg}>{error}</p>
|
||||
<a href="/" style={link}>
|
||||
<Link to="/" replace style={link}>
|
||||
Back to {brand.walletName || "wallet"}
|
||||
</a>
|
||||
</Link>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
* placeholders rather than crashing the screen.
|
||||
*/
|
||||
import { lazy, Suspense, useMemo } from "react"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import { Link, useNavigate } from "react-router-dom"
|
||||
import { mnemonicToAccount, type Address } from "viem/accounts"
|
||||
import { Button, Card, Text, XStack, YStack } from "@hanzo/gui"
|
||||
import { useAuth } from "../../store/auth"
|
||||
@@ -67,6 +67,35 @@ function useActiveChainId(): number {
|
||||
return 96369
|
||||
}
|
||||
|
||||
/**
|
||||
* Dashboard quick actions. Each is a react-router <Link> (SPA soft-nav) — NOT
|
||||
* an <a href>. The unlock state + plaintext mnemonic live ONLY in memory (the
|
||||
* auth store never persists them), so a full document reload wipes them and
|
||||
* bounces the user back to onboarding. Soft-nav keeps the session alive.
|
||||
*/
|
||||
const QUICK_ACTIONS: ReadonlyArray<{ to: string; label: string; icon: string }> = [
|
||||
{ to: "/send", label: "Send", icon: "↑" },
|
||||
{ to: "/bridge", label: "Cross-Chain", icon: "⇄" },
|
||||
{ to: "/stake", label: "Earn", icon: "%" },
|
||||
{ to: "/settings/security", label: "Manage Keys", icon: "⚿" },
|
||||
]
|
||||
|
||||
const quickActionStyle: React.CSSProperties = {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 6,
|
||||
minWidth: 0,
|
||||
padding: "14px 6px",
|
||||
borderRadius: 12,
|
||||
border: "1px solid var(--surface3, #222)",
|
||||
background: "var(--surface2, #111)",
|
||||
color: "var(--neutral1, #fff)",
|
||||
textDecoration: "none",
|
||||
textAlign: "center",
|
||||
}
|
||||
|
||||
export default function Portfolio() {
|
||||
const navigate = useNavigate()
|
||||
const isUnlocked = useAuth((s) => s.isUnlocked)
|
||||
@@ -119,6 +148,20 @@ export default function Portfolio() {
|
||||
</YStack>
|
||||
</Card>
|
||||
|
||||
<nav
|
||||
aria-label="Quick actions"
|
||||
style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 8 }}
|
||||
>
|
||||
{QUICK_ACTIONS.map((a) => (
|
||||
<Link key={a.to} to={a.to} style={quickActionStyle}>
|
||||
<span aria-hidden="true" style={{ fontSize: 20, lineHeight: 1 }}>
|
||||
{a.icon}
|
||||
</span>
|
||||
<span style={{ fontSize: 12, fontWeight: 600 }}>{a.label}</span>
|
||||
</Link>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
<Suspense fallback={null}>
|
||||
<ChainSwitcher />
|
||||
</Suspense>
|
||||
|
||||
Reference in New Issue
Block a user