import { useEffect, useMemo, useState } from 'react'; import { type Category, type Transaction, createTransaction, getCategories, getTransactions } from '../api'; import AccountPage from './AccountPage'; import AppearancePage from './AppearancePage'; function formatAmount(n: number) { return new Intl.NumberFormat(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(n); } export default function Dashboard({ onLogout }: { onLogout: () => void }) { const [current, setCurrent] = useState<'home' | 'account' | 'appearance'>('home'); const [transactions, setTransactions] = useState([]); const [categories, setCategories] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // New transaction form state const [amount, setAmount] = useState(''); const [description, setDescription] = useState(''); const [selectedCategoryId, setSelectedCategoryId] = useState(''); // Filters const [minAmount, setMinAmount] = useState(''); const [maxAmount, setMaxAmount] = useState(''); const [filterCategoryId, setFilterCategoryId] = useState(''); const [searchText, setSearchText] = useState(''); async function loadAll() { setLoading(true); setError(null); try { const [txs, cats] = await Promise.all([getTransactions(), getCategories()]); setTransactions(txs); setCategories(cats); } catch (err: any) { setError(err?.message || 'Failed to load data'); } finally { setLoading(false); } } useEffect(() => { loadAll(); }, []); const last10 = useMemo(() => { const sorted = [...transactions].sort((a, b) => b.id - a.id); return sorted.slice(0, 10); }, [transactions]); const filtered = useMemo(() => { let arr = last10; const min = minAmount !== '' ? Number(minAmount) : undefined; const max = maxAmount !== '' ? Number(maxAmount) : undefined; if (min !== undefined) arr = arr.filter(t => t.amount >= min); if (max !== undefined) arr = arr.filter(t => t.amount <= max); if (filterCategoryId !== '') arr = arr.filter(t => t.category_ids.includes(filterCategoryId as number)); if (searchText.trim()) arr = arr.filter(t => (t.description || '').toLowerCase().includes(searchText.toLowerCase())); return arr; }, [last10, minAmount, maxAmount, filterCategoryId, searchText]); function categoryNameById(id: number) { return categories.find(c => c.id === id)?.name || `#${id}`; } async function handleCreate(e: React.FormEvent) { e.preventDefault(); if (!amount) return; const payload = { amount: Number(amount), description: description || undefined, category_ids: selectedCategoryId !== '' ? [Number(selectedCategoryId)] : undefined, }; try { const created = await createTransaction(payload); setTransactions(prev => [created, ...prev]); setAmount(''); setDescription(''); setSelectedCategoryId(''); } catch (err: any) { alert(err?.message || 'Failed to create transaction'); } } return (

{current === 'home' ? 'Dashboard' : current === 'account' ? 'Account' : 'Appearance'}

Signed in
{current === 'home' && ( <>

Add Transaction

setAmount(e.target.value)} required /> setDescription(e.target.value)} />

Filters

setMinAmount(e.target.value)} /> setMaxAmount(e.target.value)} /> setSearchText(e.target.value)} />

Latest Transactions (last 10)

{loading ? (
Loading…
) : error ? (
{error}
) : filtered.length === 0 ? (
No transactions
) : ( {filtered.map(t => ( ))}
ID Amount Description Categories
{t.id} {formatAmount(t.amount)} {t.description || ''} {t.category_ids.map(id => categoryNameById(id)).join(', ')}
)}
)} {current === 'account' && ( // lazy import avoided for simplicity )} {current === 'appearance' && ( )}
); }