import { useState, useMemo } from 'react'; import { useWallets, useTransactions, useRates, useCreateTransaction, useExchanges, useCreateExchange } from '../hooks/queries'; import { Wallet as WalletIcon, DollarSign, Coins, Bitcoin, MessageCircle, ShieldCheck, Zap, CreditCard, PlusCircle, RefreshCw, MinusCircle } from 'lucide-react'; import { Button } from '../components/ui/button'; import { Input } from '../components/ui/input'; import { AmountInput } from '../components/ui/AmountInput'; import { Select } from '../components/ui/select'; import { Label } from '../components/ui/label'; export default function WalletsView() { const getWalletStyling = (name: string) => { const n = name.toLowerCase(); if (n.includes('dollar')) return { icon: DollarSign, color: 'text-emerald-400', bg: 'bg-emerald-500/20', border: 'border-emerald-500/30' }; if (n.includes('dinnar') || n.includes('dinar')) return { icon: Coins, color: 'text-indigo-400', bg: 'bg-indigo-500/20', border: 'border-indigo-500/30' }; if (n.includes('crypto')) return { icon: Bitcoin, color: 'text-orange-400', bg: 'bg-orange-500/20', border: 'border-orange-500/30' }; if (n.includes('wechat')) return { icon: MessageCircle, color: 'text-green-400', bg: 'bg-green-500/20', border: 'border-green-500/30' }; if (n.includes('alipay')) return { icon: ShieldCheck, color: 'text-blue-400', bg: 'bg-blue-500/20', border: 'border-blue-500/30' }; if (n.includes('fib')) return { icon: Zap, color: 'text-yellow-400', bg: 'bg-yellow-500/20', border: 'border-yellow-500/30' }; if (n.includes('fastpay')) return { icon: Zap, color: 'text-red-400', bg: 'bg-red-500/20', border: 'border-red-500/30' }; if (n.includes('super qi')) return { icon: CreditCard, color: 'text-blue-400', bg: 'bg-blue-500/20', border: 'border-blue-500/30' }; if (n.includes('kj wallets')) return { icon: WalletIcon, color: 'text-purple-400', bg: 'bg-purple-500/20', border: 'border-purple-500/30' }; return { icon: WalletIcon, color: 'text-indigo-400', bg: 'bg-indigo-500/20', border: 'border-indigo-500/30' }; }; const getAllowedDestinations = (sourceName: string) => { const name = sourceName.toLowerCase(); if (name.includes('usd') && !name.includes('usdt')) return ['USDT', 'Cash Dinar', 'Alipay', 'WeChat']; if (name.includes('kj wallets')) return ['Cash USD', 'FIB']; if (name.includes('dinar')) return ['FIB', 'FastPay', 'Super Qi', 'Cash USD']; if (name.includes('usdt')) return ['Cash USD']; if (name.includes('fib')) return ['FastPay', 'Super Qi', 'Cash Dinar']; if (name.includes('fastpay')) return ['FIB', 'Super Qi', 'Cash Dinar']; if (name.includes('qi')) return ['FastPay', 'FIB', 'Cash Dinar']; if (name.includes('wechat')) return ['Alipay', 'Cash USD']; if (name.includes('alipay')) return ['WeChat', 'Cash USD']; return []; }; const { data: rawWallets = [] } = useWallets(); const wallets = useMemo(() => { const order = ['cash usd', 'cash dinar', 'super qi', 'alipay', 'wechat', 'fib', 'fastpay', 'usdt', 'kj wallets']; return [...rawWallets].sort((a: any, b: any) => { const idxA = order.indexOf(a.name.toLowerCase()); const idxB = order.indexOf(b.name.toLowerCase()); return (idxA === -1 ? 999 : idxA) - (idxB === -1 ? 999 : idxB); }); }, [rawWallets]); const { data: transactions = [] } = useTransactions(); const { data: exchanges = [] } = useExchanges(); const { data: rates } = useRates(); const { mutateAsync: createTransaction } = useCreateTransaction(); const { mutateAsync: createExchange } = useCreateExchange(); const [actionState, setActionState] = useState<{type: 'transfer' | 'income' | 'expense' | 'exchange', walletId?: number} | null>(null); const [isSubmitting, setIsSubmitting] = useState(false); // Form States const [amount, setAmount] = useState(''); const [toAmount, setToAmount] = useState(''); const [toWallet, setToWallet] = useState(''); const [note, setNote] = useState(''); const [category, setCategory] = useState('other'); const exchangeRates = rates || { USD: 1, IQD: 1539.5, RMB: 6.86 }; // Calculate Balances dynamically factoring in currency differences const getBalance = (w: any) => { const txBal = transactions.reduce((acc: number, tx: any) => { let effectiveAmount = tx.amount; if (tx.currency !== w.currency) { const txRate = exchangeRates[tx.currency] || 1; const walletRate = exchangeRates[w.currency] || 1; effectiveAmount = (tx.amount / txRate) * walletRate; } if (tx.type === 'income' && tx.wallet_id === w.id) return acc + effectiveAmount; if (tx.type === 'expense' && tx.wallet_id === w.id) return acc - effectiveAmount; if (tx.type === 'transfer') { if (tx.wallet_id === w.id) return acc - effectiveAmount; if (tx.to_wallet_id === w.id) return acc + effectiveAmount; } return acc; }, 0); const exBal = exchanges.reduce((acc: number, ex: any) => { let bal = 0; if (ex.from_wallet_id === w.id) bal -= ex.from_amount; if (ex.to_wallet_id === w.id) bal += ex.to_amount; return acc + bal; }, 0); return txBal + exBal; }; const activeWallet = actionState?.walletId ? wallets.find((w: any) => w.id === actionState.walletId) : null; const currentBalance = activeWallet ? getBalance(activeWallet) : 0; const enteredAmount = parseFloat(amount) || 0; const isInsufficient = (actionState?.type === 'expense' || actionState?.type === 'exchange') && enteredAmount > currentBalance; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (isInsufficient) return; setIsSubmitting(true); try { if (actionState?.type === 'income' || actionState?.type === 'expense') { const targetWallet = wallets.find((w: any) => w.id === actionState.walletId); if (!targetWallet) return; let finalCategory = category; if (actionState.type === 'income' && category === 'other') { // If it was the default 'other' but from a previous expense, and we are in income now, // we might want to ensure it's handled correctly if not changed. // But actually, the state is shared. So we just use 'category' state. } await createTransaction({ type: actionState.type, amount: parseFloat(amount), currency: targetWallet.currency, wallet_id: targetWallet.id, category: finalCategory, note: note || (actionState.type === 'income' ? 'Added Income' : 'Recorded Expense'), date: new Date().toISOString() } as any); } else if (actionState?.type === 'exchange') { const sourceW = wallets.find((w: any) => w.id === actionState.walletId); const destW = wallets.find((w: any) => w.id.toString() === toWallet); if (!sourceW || !destW) return; const fAmt = parseFloat(amount); const tAmt = parseFloat(toAmount); await createExchange({ from_amount: fAmt, from_currency: sourceW.currency, from_wallet_id: sourceW.id, to_amount: tAmt, to_currency: destW.currency, to_wallet_id: destW.id, rate: tAmt / fAmt, note: note || `Exchanged to ${destW.name}`, date: new Date().toISOString() } as any); } setActionState(null); setAmount(''); setToAmount(''); setNote(''); setToWallet(''); setCategory('other'); } finally { setIsSubmitting(false); } }; return (
{w.type}
Current Balance
{balance.toLocaleString(undefined, { maximumFractionDigits: 2 })} {w.currency}