// ─── CRM Contacts Page ─────────────────────────────────────────────────────── function CRMPage() { const [contacts, setContacts] = React.useState([]); const [loading, setLoading] = React.useState(true); const [search, setSearch] = React.useState(''); const [statusFilter, setStatusFilter] = React.useState('all'); const [selected, setSelected] = React.useState(null); const { toasts, addToast } = C.useToast(); const handleCall = async (phoneNumber, contactName) => { addToast(`Dispatching call to ${phoneNumber}…`, 'info'); try { const res = await fetch('/api/call/single', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ phone: phoneNumber, caller_name: contactName || '' }), }); const data = await res.json(); if (res.ok && data.status !== 'error') addToast(`Call dispatched to ${phoneNumber}`, 'success'); else addToast(data.message || data.detail || 'Call dispatch failed', 'error'); } catch (e) { addToast('Call dispatch error: ' + e.message, 'error'); } }; React.useEffect(() => { fetch('/api/contacts') .then(r => r.json()) .then(data => { setContacts(Array.isArray(data) ? data : []); setLoading(false); }) .catch(() => setLoading(false)); }, []); const filtered = contacts.filter(c => { const hot = c.is_booked; const warm = !c.is_booked && (c.total_calls || 0) > 1; const cold = !c.is_booked && (c.total_calls || 0) <= 1; const status = hot ? 'hot' : warm ? 'warm' : 'cold'; if (statusFilter !== 'all' && status !== statusFilter) return false; if (search) { const q = search.toLowerCase(); return (c.phone_number || '').includes(q) || (c.caller_name || '').toLowerCase().includes(q); } return true; }); const contact = contacts.find(c => c.phone_number === selected); const getStatus = c => c.is_booked ? 'hot' : (c.total_calls || 0) > 1 ? 'warm' : 'cold'; const STATUS_C = { hot: 'red', warm: 'amber', cold: 'blue' }; return (