page.tsx
1 'use client' 2 3 import { useEffect, useState } from 'react' 4 import { useAppStore } from '@/stores/use-app-store' 5 import { WalletList } from '@/components/wallets/wallet-list' 6 import { api } from '@/lib/app/api-client' 7 import type { SafeWallet } from '@/types' 8 9 export default function WalletsPage() { 10 const agents = useAppStore((s) => s.agents) 11 const loadAgents = useAppStore((s) => s.loadAgents) 12 const loadWallets = useAppStore((s) => s.loadWallets) 13 const [generating, setGenerating] = useState(false) 14 const [showPicker, setShowPicker] = useState(false) 15 const [error, setError] = useState<string | null>(null) 16 17 useEffect(() => { 18 loadAgents() 19 loadWallets() 20 }, [loadAgents, loadWallets]) 21 22 const agentList = Object.values(agents) 23 24 const handleGenerate = async (agentId?: string) => { 25 const targetId = agentId || agentList[0]?.id 26 if (!targetId) { 27 setError('Create an agent first') 28 setTimeout(() => setError(null), 3000) 29 return 30 } 31 setGenerating(true) 32 setShowPicker(false) 33 setError(null) 34 try { 35 await api<SafeWallet>('POST', '/wallets/generate', { agentId: targetId }) 36 loadWallets() 37 } catch (err) { 38 setError(err instanceof Error ? err.message : 'Failed to generate wallet') 39 setTimeout(() => setError(null), 4000) 40 } finally { 41 setGenerating(false) 42 } 43 } 44 45 return ( 46 <div className="flex-1 flex flex-col h-full"> 47 <div className="flex items-center px-6 pt-5 pb-3 shrink-0"> 48 <h2 className="font-display text-[14px] font-600 text-text-2 tracking-[-0.01em] capitalize flex-1"> 49 Wallets 50 </h2> 51 <div className="relative"> 52 <button 53 onClick={() => { 54 if (agentList.length <= 1) { 55 handleGenerate() 56 } else { 57 setShowPicker(!showPicker) 58 } 59 }} 60 disabled={generating} 61 className="flex items-center gap-1.5 px-2.5 py-1.5 rounded-[8px] text-[11px] font-600 text-accent-bright bg-accent-soft hover:bg-accent-bright/15 transition-all cursor-pointer disabled:opacity-50" 62 style={{ fontFamily: 'inherit' }} 63 > 64 {generating ? ( 65 <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" className="animate-spin"> 66 <path d="M21 12a9 9 0 1 1-6.219-8.56" /> 67 </svg> 68 ) : ( 69 <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"> 70 <line x1="12" y1="5" x2="12" y2="19" /><line x1="5" y1="12" x2="19" y2="12" /> 71 </svg> 72 )} 73 {generating ? 'Generating...' : 'Generate Wallet'} 74 </button> 75 76 {/* Agent picker dropdown */} 77 {showPicker && ( 78 <> 79 <div className="fixed inset-0 z-40" onClick={() => setShowPicker(false)} /> 80 <div className="absolute right-0 top-full mt-1 z-50 w-56 rounded-[12px] bg-surface border border-white/[0.08] shadow-xl overflow-hidden"> 81 <div className="px-3 py-2 border-b border-white/[0.06]"> 82 <span className="text-[11px] font-600 text-text-3">Select Agent</span> 83 </div> 84 <div className="max-h-48 overflow-y-auto py-1"> 85 {agentList.map((agent) => ( 86 <button 87 key={agent.id} 88 onClick={() => handleGenerate(agent.id)} 89 className="w-full text-left px-3 py-2 flex items-center gap-2 hover:bg-white/[0.04] transition-colors cursor-pointer" 90 style={{ fontFamily: 'inherit' }} 91 > 92 <span className="text-[14px]">{agent.emoji || '🤖'}</span> 93 <span className="text-[12px] font-600 text-text truncate">{agent.name}</span> 94 </button> 95 ))} 96 </div> 97 </div> 98 </> 99 )} 100 </div> 101 </div> 102 103 {error && ( 104 <div className="mx-6 mb-2 px-3 py-2 rounded-[10px] bg-red-500/10 border border-red-500/20 text-[12px] text-red-400 font-600"> 105 {error} 106 </div> 107 )} 108 109 <WalletList /> 110 </div> 111 ) 112 }