diff --git a/frontend/src/components/WalletBalance.tsx b/frontend/src/components/WalletBalance.tsx index e52c4c5..abfae57 100644 --- a/frontend/src/components/WalletBalance.tsx +++ b/frontend/src/components/WalletBalance.tsx @@ -1,63 +1,76 @@ 'use client'; -/** - * WalletBalance Component - * Displays the connected wallet's STX balance with real-time updates - * @module WalletBalance - * @version 2.3.0 - */ - -import { useState, useEffect, useCallback } from 'react'; +import { useState, useEffect, useCallback, useRef } from 'react'; import { useWallet } from '@/hooks/useWallet'; import { fetchSTXBalance } from '@/lib/api'; +import { toast } from 'react-hot-toast'; -// Balance display configuration const MICROSTX_DIVISOR = 1_000_000; -const BALANCE_DECIMALS = 4; -const LOADING_PLACEHOLDER = '...'; - -/** Auto-refresh interval in milliseconds */ const REFRESH_INTERVAL = 30000; +const BALANCE_DECIMALS = 4; -/** Animation duration for balance updates */ -const UPDATE_ANIMATION_DURATION = 300; - -/** - * Balance display state - */ -type BalanceState = 'idle' | 'loading' | 'success' | 'error'; +const FIAT_OPTIONS = [ + { label: 'USD', rate: 0.42 }, + { label: 'EUR', rate: 0.39 }, + { label: 'GBP', rate: 0.34 }, +]; export default function WalletBalance() { const { address, isConnected } = useWallet(); - const [balance, setBalance] = useState(null); + const [balance, setBalance] = useState(null); + const [displayBalance, setDisplayBalance] = useState(0); const [isLoading, setIsLoading] = useState(true); - const [lastUpdated, setLastUpdated] = useState(null); const [isRefreshing, setIsRefreshing] = useState(false); + const [lastUpdated, setLastUpdated] = useState(null); + const [error, setError] = useState(null); + + // Fiat currency state + const [fiat, setFiat] = useState(FIAT_OPTIONS[0]); + + // Dark mode toggle + const [darkMode, setDarkMode] = useState(true); + + const rafRef = useRef(null); + + const animateBalance = useCallback((from: number, to: number, duration = 300) => { + const start = performance.now(); + const step = (timestamp: number) => { + const progress = Math.min((timestamp - start) / duration, 1); + setDisplayBalance(from + (to - from) * progress); + if (progress < 1) rafRef.current = requestAnimationFrame(step); + }; + rafRef.current = requestAnimationFrame(step); + }, []); const fetchBalance = useCallback(async () => { if (!address) return; - + setIsRefreshing(true); + setError(null); + try { - setIsRefreshing(true); const data = await fetchSTXBalance(address); - const stx = data.balance / 1000000; - setBalance(stx.toFixed(4)); + const stx = data.balance / MICROSTX_DIVISOR; + setBalance(stx); + animateBalance(displayBalance, stx); setLastUpdated(new Date()); - } catch (error) { - console.error('Failed to fetch balance:', error); + } catch (err) { + console.error(err); + setError('Failed to fetch balance. Retry?'); + toast.error('Failed to fetch wallet balance.'); } finally { setIsLoading(false); setIsRefreshing(false); } - }, [address]); + }, [address, displayBalance, animateBalance]); useEffect(() => { if (address) { fetchBalance(); - - // Auto-refresh every 30 seconds const interval = setInterval(fetchBalance, REFRESH_INTERVAL); - return () => clearInterval(interval); + return () => { + clearInterval(interval); + if (rafRef.current) cancelAnimationFrame(rafRef.current); + }; } }, [address, fetchBalance]); @@ -68,16 +81,32 @@ export default function WalletBalance() { return `${minutes}m ago`; }; + const handleCopyAddress = () => { + if (address) { + navigator.clipboard.writeText(address); + toast.success('Address copied to clipboard'); + } + }; + if (!isConnected) return null; - // Mock USD value (in real app, fetch from API) - const usdValue = balance ? (parseFloat(balance) * 0.42).toFixed(2) : '0.00'; + const fiatValue = balance ? (balance * fiat.rate).toFixed(2) : '0.00'; return ( -
- {/* Background decoration */} +
- + + {/* Dark/Light toggle */} +
+ +
+
{/* Header */}
@@ -85,25 +114,34 @@ export default function WalletBalance() {
💰
- Wallet Balance + Wallet Balance
- + + + + + +
- + {/* Balance Display */}
{isLoading ? ( @@ -111,19 +149,35 @@ export default function WalletBalance() {
+ ) : error ? ( +
{error}
) : ( <> -

- {balance || '0.0000'} +

+ {displayBalance.toFixed(BALANCE_DECIMALS)} STX

-

- ≈ ${usdValue} USD +

+ ≈ {fiatValue} {fiat.label}

+ + {/* Fiat selector */} + )}
- + {/* Quick Actions */}
- + {/* Last Updated */} {lastUpdated && ( -

+

Last updated {formatTimeAgo(lastUpdated)}

)}