// Customers view — list customers derived from transactions and show their alerts/cases/transactions. const { useState: useCustState } = React; function formatAmount(n) { return "$" + Number(n || 0).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); } function formatDate(iso) { if (!iso) return "—"; const d = new Date(iso); return d.toLocaleString(undefined, { month: "short", day: "numeric", year: "numeric", hour: "2-digit", minute: "2-digit" }); } function CustomerDetail({ customer, onBack }) { const [tab, setTab] = useCustState("transactions"); const [transactions, setTransactions] = useCustState([]); const [alerts, setAlerts] = useCustState([]); const [cases, setCases] = useCustState([]); const [loading, setLoading] = useCustState(false); useEffectC(() => { let cancelled = false; const load = async () => { if (!customer?.customer_id || !window.mossadApi) return; setLoading(true); try { const [txns, alrts, cs] = await Promise.all([ window.mossadApi.fetchCustomerTransactions(customer.customer_id, 100).catch(() => []), window.mossadApi.fetchCustomerAlerts(customer.customer_id, 100).catch(() => []), window.mossadApi.fetchCustomerCases(customer.customer_id, 100).catch(() => []), ]); if (!cancelled) { setTransactions(Array.isArray(txns) ? txns : []); setAlerts(Array.isArray(alrts) ? alrts.map(window.mossadApi.mapAlert) : []); setCases(Array.isArray(cs) ? cs.map(window.mossadApi.mapCase) : []); } } catch (err) { console.error("Failed to load customer details:", err); } finally { if (!cancelled) setLoading(false); } }; load(); return () => { cancelled = true; }; }, [customer?.customer_id]); return (

{customer.customer_id}

{customer.transaction_count} transactions {formatAmount(customer.total_volume)} volume Last seen {formatDate(customer.last_seen)} {customer.alert_count || 0} alerts {customer.case_count || 0} cases
{["transactions", "alerts", "cases"].map(t => ( ))}
{loading &&
Loading…
} {!loading && tab === "transactions" && ( {transactions.map(t => ( ))}
Txn ID Timestamp Type Originator Beneficiary Amount
{t.external_id} {formatDate(t.timestamp)} {t.transaction_type} {t.originator_id} {t.beneficiary_id} {formatAmount(t.amount)}
)} {!loading && tab === "alerts" && ( {alerts.map(a => ( ))}
Alert ID Severity Typology Amount Status
{a.external_id} {a.severity} {a.typology} {formatAmount(a.amount)} {a.status}
)} {!loading && tab === "cases" && ( {cases.map(c => ( ))}
Case ID Status Alerts Amount
{c.external_id} {c.alert_count} {formatAmount(c.total_amount)}
)}
); } function CaseStatusPill({ status }) { const map = { open: { cls: "pill info", label: "Open" }, in_review: { cls: "pill med", label: "In review" }, escalated: { cls: "pill high", label: "Escalated" }, closed: { cls: "pill low", label: "Closed" }, }; const m = map[status] || { cls: "pill", label: status }; return {m.label}; } function CustomersView({ data, initialQuery }) { const initialCustomers = data?.customers || window.CUSTOMERS_API || []; const [customers, setCustomers] = useCustState(initialCustomers); const [search, setSearch] = useCustState(""); const [loading, setLoading] = useCustState(false); const [selected, setSelected] = useCustState(null); useEffectC(() => { setCustomers(initialCustomers); }, [initialCustomers]); useEffectC(() => { if (initialQuery) setSearch(initialQuery); }, [initialQuery]); useEffectC(() => { let cancelled = false; const timer = setTimeout(async () => { if (!window.mossadApi) return; setLoading(true); try { const res = await window.mossadApi.fetchCustomers(500, search.trim()); if (!cancelled) setCustomers(Array.isArray(res) ? res : []); } catch (err) { console.error("Failed to search customers:", err); if (!cancelled) setCustomers([]); } finally { if (!cancelled) setLoading(false); } }, 250); return () => { cancelled = true; clearTimeout(timer); }; }, [search]); if (selected) { return setSelected(null)} />; } return (

Customers

{loading ? "Searching…" : `${customers.length.toLocaleString()} derived from transactions`}
setSearch(e.target.value)} placeholder="Search customer ID across all transactions…" style={{ minWidth: 240, width: 360 }} />
{customers.map(c => ( setSelected(c)} style={{ cursor: "pointer" }}> ))}
Customer ID Transactions Total volume Last seen Alerts Cases
{c.customer_id} {c.transaction_count.toLocaleString()} {formatAmount(c.total_volume)} {formatDate(c.last_seen)} {(c.alert_count ?? 0).toLocaleString()} {(c.case_count ?? 0).toLocaleString()}
{customers.length === 0 && (
No customers found.
)}
); } Object.assign(window, { CustomersView });