1+ /**
2+ * Connect Wallet Component.
3+ * A standalone button/dropdown component for managing Stellar wallet sessions.
4+ * Displays the connected address and provides a disconnect option.
5+ */
6+
17"use client" ;
8+
29import { useState , useRef , useEffect } from "react" ;
3- import { connectWallet , WalletType , FREIGHTER_ID } from "../lib/stellar" ;
10+ import { connectWallet , WalletType , FREIGHTER_ID , shortenAddress } from "../lib/stellar" ;
411import Button from "./ui/Button" ;
512import { useTokenStore } from "../stores/tokenStore" ;
6- import { LogOut , ChevronDown } from "lucide-react" ;
13+ import { LogOut , ChevronDown , User , ShieldCheck } from "lucide-react" ;
714
15+ /** Key for purging recent token history on logout */
816const RECENT_TOKENS_KEY = "tradeflow_recent_tokens" ;
917
18+ /**
19+ * A component that handles the wallet connection flow and account display.
20+ */
1021export default function ConnectWallet ( ) {
22+ // --- Component State ---
1123 const [ pubKey , setPubKey ] = useState < string | null > ( null ) ;
1224 const [ isDropdownOpen , setIsDropdownOpen ] = useState ( false ) ;
1325 const { setConnected } = useTokenStore ( ) ;
1426 const dropdownRef = useRef < HTMLDivElement > ( null ) ;
1527
16- // Close dropdown when clicking outside
28+ /**
29+ * Effect: Closes the account dropdown when clicking outside.
30+ */
1731 useEffect ( ( ) => {
1832 const handleClickOutside = ( event : MouseEvent ) => {
1933 if ( dropdownRef . current && ! dropdownRef . current . contains ( event . target as Node ) ) {
@@ -24,65 +38,92 @@ export default function ConnectWallet() {
2438 return ( ) => document . removeEventListener ( "mousedown" , handleClickOutside ) ;
2539 } , [ ] ) ;
2640
41+ /**
42+ * Initiates the wallet connection process.
43+ *
44+ * @param {WalletType } walletType - The ID of the wallet provider.
45+ */
2746 const handleConnect = async ( walletType : WalletType = FREIGHTER_ID ) => {
2847 try {
2948 const userInfo = await connectWallet ( walletType ) ;
3049 if ( userInfo . publicKey ) {
3150 setPubKey ( userInfo . publicKey ) ;
3251 setConnected ( true , userInfo . publicKey ) ;
52+ console . log ( `[ConnectWallet] Session started for: ${ userInfo . publicKey } ` ) ;
3353 }
3454 } catch ( e : any ) {
35- console . error ( "Connection error:" , e ) ;
55+ console . error ( "[ConnectWallet] Connection failed:" , e ) ;
56+ // TODO: Use a toast instead of native alert
3657 alert ( e . message || "Failed to connect to wallet!" ) ;
3758 }
3859 } ;
3960
61+ /**
62+ * Terminates the session and clears related data.
63+ */
4064 const handleDisconnect = ( ) => {
4165 setPubKey ( null ) ;
4266 setConnected ( false , undefined ) ;
67+ // Clear local history for privacy/security
4368 localStorage . removeItem ( RECENT_TOKENS_KEY ) ;
4469 setIsDropdownOpen ( false ) ;
70+ console . log ( "[ConnectWallet] Session terminated." ) ;
4571 } ;
4672
73+ // 1. Authenticated UI (Dropdown)
4774 if ( pubKey ) {
4875 return (
4976 < div className = "relative" ref = { dropdownRef } >
5077 < button
5178 onClick = { ( ) => setIsDropdownOpen ( ( prev ) => ! prev ) }
52- className = "flex items-center gap-2 px-4 py-2 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-slate-200 text-sm font-medium transition-colors"
79+ className = "flex items-center gap-2.5 px-4 py-2.5 rounded-xl bg-slate-800/80 hover:bg-slate-700/80 border border-slate-700 text-slate-200 text-sm font-bold transition-all shadow-sm active:scale-[0.98]"
80+ aria-haspopup = "menu"
81+ aria-expanded = { isDropdownOpen }
5382 >
54- < span className = "w-2 h-2 rounded-full bg-green -400 shrink-0" />
55- { ` ${ pubKey . slice ( 0 , 4 ) } ... ${ pubKey . slice ( - 4 ) } ` }
56- < ChevronDown size = { 14 } className = { `transition-transform ${ isDropdownOpen ? "rotate-180" : "" } ` } />
83+ < div className = "w-2 h-2 rounded-full bg-emerald -400 shadow-[0_0_8px_rgba(52,211,153,0.5)] shrink-0" />
84+ < span className = "font-mono tracking-tight" > { shortenAddress ( pubKey , 4 ) } </ span >
85+ < ChevronDown size = { 14 } className = { `text-slate-500 transition-transform duration-300 ${ isDropdownOpen ? "rotate-180" : "" } ` } />
5786 </ button >
5887
5988 { isDropdownOpen && (
60- < div className = "absolute right-0 mt-2 w-48 rounded-lg bg-slate-800 border border-slate-700 shadow-xl z-50 overflow-hidden" >
61- < div className = "px-3 py-2 border-b border-slate-700" >
62- < p className = "text-xs text-slate-400 font-medium" > Connected Wallet</ p >
63- < p className = "text-xs text-slate-300 font-mono truncate mt-0.5" > { pubKey } </ p >
89+ < div
90+ className = "absolute right-0 mt-2 w-64 rounded-2xl bg-slate-800 border border-slate-700 shadow-2xl z-50 overflow-hidden animate-in fade-in slide-in-from-top-2 duration-200"
91+ role = "menu"
92+ >
93+ < div className = "px-4 py-4 border-b border-slate-700 bg-slate-900/50" >
94+ < div className = "flex items-center gap-2 mb-1.5" >
95+ < ShieldCheck size = { 14 } className = "text-blue-400" />
96+ < p className = "text-[10px] text-slate-400 font-black uppercase tracking-widest" > Verified Account</ p >
97+ </ div >
98+ < p className = "text-xs text-slate-200 font-mono break-all leading-relaxed" > { pubKey } </ p >
99+ </ div >
100+ < div className = "p-1.5" >
101+ < button
102+ onClick = { handleDisconnect }
103+ className = "w-full flex items-center gap-3 px-3 py-2.5 text-sm font-bold text-rose-400 hover:bg-rose-500/10 rounded-xl transition-all group"
104+ role = "menuitem"
105+ >
106+ < LogOut size = { 16 } className = "group-hover:translate-x-0.5 transition-transform" />
107+ Disconnect Wallet
108+ </ button >
64109 </ div >
65- < button
66- onClick = { handleDisconnect }
67- className = "w-full flex items-center gap-2 px-3 py-2.5 text-sm text-slate-300 hover:bg-red-500/10 hover:text-red-400 transition-colors"
68- >
69- < LogOut size = { 14 } />
70- Disconnect Wallet
71- </ button >
72110 </ div >
73111 ) }
74112 </ div >
75113 ) ;
76114 }
77115
116+ // 2. Unauthenticated UI (CTA Button)
78117 return (
79118 < div >
80119 < Button
81120 onClick = { ( ) => handleConnect ( FREIGHTER_ID ) }
82- className = "bg-purple -600 hover:bg-purple-700 shadow-lg flex items-center gap-2 px-6 py-3"
121+ className = "bg-indigo -600 hover:bg-indigo-500 shadow-xl shadow-indigo-500/20 flex items-center gap-2 px-7 py-3 rounded-xl font-bold uppercase tracking-widest text-xs transition-all active:scale-95 "
83122 >
123+ < User size = { 16 } />
84124 Connect Wallet
85125 </ Button >
86126 </ div >
87127 ) ;
88128}
129+
0 commit comments