import type { LucideIcon } from 'lucide-react'; import type { WalletSummary } from './shared'; import { useState } from 'react'; import { Link, NavLink } from 'react-router'; import { ArrowDownLeft, ArrowUpRight, Bitcoin, Coins, Gauge, Plus, Receipt, Settings, Star, Zap } from 'lucide-react'; import { toneFill } from '@/components/Data/tone'; import { KIND_LABELS, NETWORK_TONE, WALLET_SECTIONS, sectionAvailable, walletSectionPath, type WalletSectionId, } from './shared'; import { Amount, UnitToggle } from './Amount'; import { LockBadge } from './LockBadge'; import { useWalletSection } from './useWalletSection'; import { useSelectedWallet } from './useSelectedWallet'; import { useBalances, usePermissions, useWalletConfig, useWalletLifecycle } from './useWalletData'; import { CreateWalletDialog } from './dialogs/CreateWalletDialog'; // Left panel of /wallet: the balance, the wallets, the sections, the lock state. // // Wallet rows are real links carrying `?wallet=` — cmd-click, back button and reload all work, and the // id is in the DOM rather than an onClick closure (docs/navigation-audit.md). "Make active" is a sibling // button, not nested inside the anchor, because it mutates rather than navigates. // // Sections are filtered by the backend's declared capabilities: an on-chain wallet has no Lightning tab at // all, an lndhub account has no coin control. Better a shorter nav than a control that answers 501. const ICONS: Record = { overview: Gauge, receive: ArrowDownLeft, send: ArrowUpRight, transactions: Receipt, coins: Coins, lightning: Zap, settings: Settings, }; const ROW = 'group relative flex items-center gap-3 rounded-lg px-3 py-2 text-left text-sm transition-colors'; export const WalletNav = () => { const section = useWalletSection(); const { config } = useWalletConfig(); const { wallet, wallets, walletId, isPinned, isLoading } = useSelectedWallet(); const { capabilities } = usePermissions(walletId); const { balances } = useBalances(walletId); const [createOpen, setCreateOpen] = useState(false); // Preserve an explicitly pinned wallet across section changes; leave a bare URL bare so it keeps // meaning "whichever wallet is active". const linkWalletId = isPinned ? walletId : null; const total = balances ? balances.onchainConfirmed + (balances.lightningBalance ?? 0) : null; const network = wallet?.network ?? config?.network ?? null; return (
Wallet {network && network !== 'bitcoin' && ( {network} )}
Wallets
{isLoading && wallets.length === 0 && (
Loading wallets…
)} {!isLoading && wallets.length === 0 && (
No wallets yet. Add one to get started — a self-custodial seed, or a connection to your node.
)} {wallets.map((w) => ( ))}
{config && {config.network}}
{createOpen && }
); }; type WalletRowProps = { wallet: WalletSummary; section: WalletSectionId; selected: boolean }; const WalletRow = ({ wallet, section, selected }: WalletRowProps) => { const { activate } = useWalletLifecycle(); return (
{wallet.name} {KIND_LABELS[wallet.kind]} {/* Sibling of the anchor, never nested inside it — this mutates, it does not navigate. */} {wallet.isActive ? ( ) : ( )}
); };