/* @component-map * App — Main container, tab navigation [app.jsx] * Dashboard — Overview stats, running balance, recent transactions [components/Dashboard.jsx] * TransactionForm — Add income/expense form [components/TransactionForm.jsx] * Charts — Pie chart (spending by category) + Line chart (balance over time) [components/Charts.jsx] * TransactionList — Full transaction history with filters [components/TransactionList.jsx] * @end-component-map */ // DEPLOY_CONFIG: {"cron": [{"name": "monthly_ai_spending_summary", "schedule": "0 9 1 * *", "action": "event", "config": {"event_type": "generate_monthly_ai_spending_summary"}}], "triggers": [{"name": "category_spending_80_percent_alert", "on": "collection.add", "collection": "category_spending", "actions": [{"type": "email", "to": "finance-alerts@deplixo.com", "subject": "Spending alert: category budget above 80%", "body": "A category's spending has exceeded 80% of its budget. Please review the category budget and current spend."}]}]} import { useEffect, useMemo, useState } from 'react'; import { Dashboard } from './components/Dashboard.jsx'; import { TransactionForm } from './components/TransactionForm.jsx'; import { Charts } from './components/Charts.jsx'; import { TransactionList } from './components/TransactionList.jsx'; import { exportCSV, exportJSON, useAuth, useCollection } from '@deplixo/sdk'; function App() { const { user, loading: authLoading, login, logout } = useAuth(); const [activeTab, setActiveTab] = useState('dashboard'); const [showAddForm, setShowAddForm] = useState(false); const [exporting, setExporting] = useState(null); const transactionsCollection = useCollection('transactions', { personal: true }); const budgetsCollection = useCollection('budgets', { personal: true }); const isSignedIn = !!user; const appLoading = authLoading || (isSignedIn && (transactionsCollection.loading || budgetsCollection.loading)); const tabs = [ { id: 'dashboard', label: 'Dashboard', icon: '📊' }, { id: 'transactions', label: 'History', icon: '📋' }, { id: 'charts', label: 'Analytics', icon: '📈' }, ]; useEffect(() => { if (activeTab !== 'dashboard' && !isSignedIn) { setActiveTab('dashboard'); } }, [activeTab, isSignedIn]); useEffect(() => { if (!showAddForm) return; if (!isSignedIn) setShowAddForm(false); }, [showAddForm, isSignedIn]); const handleSignIn = async () => { try { await login?.('google'); } catch (error) { console.error('Google sign-in failed:', error); } }; const handleSignOut = async () => { try { await logout?.(); setShowAddForm(false); setActiveTab('dashboard'); } catch (error) { console.error('Sign-out failed:', error); } }; const collectionProps = useMemo(() => ({ transactions: transactionsCollection, budgets: budgetsCollection, }), [transactionsCollection, budgetsCollection]); const normalizeTransactions = (items = []) => items.map(item => item?.value ?? item).filter(Boolean); const formatDate = (value) => { if (!value) return ''; const date = new Date(value); return Number.isNaN(date.getTime()) ? String(value) : date.toISOString(); }; const exportTransactions = (format) => { const items = normalizeTransactions(transactionsCollection.items); if (!items.length) return; const filenameBase = `finflow-transactions-${new Date().toISOString().slice(0, 10)}`; const exportItems = items.map((tx) => ({ date: formatDate(tx.date), type: tx.type || '', category: tx.category || '', amount: tx.amount ?? '', notes: tx.notes || '', emoji: tx.emoji || '', id: tx.id || '', })); if (format === 'csv') { exportCSV(exportItems, { filename: `${filenameBase}.csv`, columns: ['id', 'date', 'type', 'category', 'amount', 'notes', 'emoji'], }); } else { exportJSON(exportItems, { filename: `${filenameBase}.json` }); } }; const handleExport = async (format) => { try { setExporting(format); exportTransactions(format); } catch (error) { console.error(`Export ${format.toUpperCase()} failed:`, error); } finally { setExporting(null); } }; if (!isSignedIn) { return (

💰 FinFlow

📈

Sign in to continue

Use Google sign-in to keep your transactions and budgets private and synced to your account.

); } return (

💰 FinFlow

{user?.name || user?.email || 'Signed in'}
{appLoading &&
Loading your data…
} {!appLoading && activeTab === 'dashboard' && ( setShowAddForm(true)} /> )} {!appLoading && activeTab === 'transactions' && } {!appLoading && activeTab === 'charts' && }
{showAddForm && ( setShowAddForm(false)} /> )}
); } ReactDOM.createRoot(document.getElementById('root')).render();