/* fraud-app.jsx — Main app with state management and data fetching */ const FraudApp = () => { const [activeTab, setActiveTab] = React.useState('Dashboard'); const [transactions, setTransactions] = React.useState(MOCK_TRANSACTIONS); const [alerts, setAlerts] = React.useState(MOCK_ALERTS); const [version, setVersion] = React.useState(null); const [demoRegion, setDemoRegion] = React.useState(null); const mobile = useIsMobile(); const [metrics, setMetrics] = React.useState({ totalScanned: 1847, alertsToday: MOCK_ALERTS.length, flaggedRate: 3.2, avgLatencyMs: 16, byRegion: { NA: 742, EU: 583, APAC: 522 }, byRisk: { low: 1498, medium: 214, high: 98, critical: 37 }, blockedAmount: 24892.00, }); // Fetch version from API on mount React.useEffect(() => { fetch('/api/version') .then(r => r.json()) .then(data => { setVersion(data.version); if (data.demoRegion) setDemoRegion(data.demoRegion); }) .catch(() => setVersion('1.0.0')); }, []); // Fetch live data if backend is available React.useEffect(() => { const fetchData = () => { fetch('/api/transactions').then(r => r.json()).then(setTransactions).catch(() => {}); fetch('/api/alerts').then(r => r.json()).then(setAlerts).catch(() => {}); fetch('/api/metrics').then(r => r.json()).then(setMetrics).catch(() => {}); }; fetchData(); const interval = setInterval(fetchData, 3000); return () => clearInterval(interval); }, []); // SSE for real-time updates React.useEffect(() => { let es; try { es = new EventSource('/api/events'); es.onmessage = (event) => { const txn = JSON.parse(event.data); setTransactions(prev => [txn, ...prev].slice(0, 50)); if (txn.flagged) { setAlerts(prev => [{ id: `ALT-${txn.id.split('-')[1]}`, type: txn.reason || 'Suspicious activity', severity: txn.riskScore >= 0.85 ? 'critical' : txn.riskScore >= 0.75 ? 'high' : 'medium', accountId: txn.accountId, description: `${txn.reason} — ${txn.merchant}`, amount: txn.amount, region: txn.region, status: 'open', timestamp: txn.timestamp, }, ...prev].slice(0, 20)); } }; } catch (e) { // SSE not available — fall back to polling only } return () => es && es.close(); }, []); const regionCfg = REGION_CONFIG[demoRegion]; return (