// ============================================================ // MOORE AI v13 — CONTACTS TAB // Requires: shared/utils.js, shared/components.jsx loaded first // ============================================================ const ContactsView = ({ contacts, loadingTabs, fetchContacts, setSelectedContact, showContactForm, setShowContactForm, contactForm, setContactForm, createContact }) => { const { useState, useEffect } = React; useEffect(() => { if (window.lucide) window.lucide.createIcons(); }); const [search, setSearch] = useState(''); const [activeContact, setActiveContact] = useState(null); const [activity, setActivity] = useState([]); const [loadingActivity, setLoadingActivity] = useState(false); const [noteInput, setNoteInput] = useState(''); const [sendType, setSendType] = useState('SMS'); const [sendMsg, setSendMsg] = useState(''); const [sending, setSending] = useState(false); const [activityTab, setActivityTab] = useState('all'); const [panelExpanded, setPanelExpanded] = useState(false); const filtered = contacts.filter(c => (c.name + c.email + c.phone + (c.tags||[]).join(' ')).toLowerCase().includes(search.toLowerCase()) ); const openContact = async (c) => { setActiveContact(c); setActivity([]); setActivityTab('all'); setPanelExpanded(false); loadActivity(c.id); }; const loadActivity = async (id) => { setLoadingActivity(true); try { const data = await API.fetchContactActivity(id); if (data.success) setActivity(data.activity || []); } catch(e) {} setLoadingActivity(false); }; const addContactNote = async () => { if (!noteInput.trim() || !activeContact) return; await API.addNote(activeContact.id, noteInput); setActivity(prev => [{ type: 'note', body: noteInput, date: new Date().toISOString(), id: Date.now() }, ...prev]); setNoteInput(''); }; const sendMessage = async () => { if (!sendMsg.trim() || !activeContact) return; setSending(true); try { await API.sendConversationMessage({ type: sendType, contactId: activeContact.id, message: sendMsg, subject: `Message from Jake` }); setActivity(prev => [{ type: sendType.toLowerCase(), body: sendMsg, date: new Date().toISOString(), direction: 'outbound', id: Date.now() }, ...prev]); setSendMsg(''); } catch(e) { alert('Send failed: ' + e.message); } setSending(false); }; const filteredActivity = activity.filter(a => { if (activityTab === 'sms') return a.type === 'sms'; if (activityTab === 'email') return a.type === 'email'; if (activityTab === 'notes') return a.type === 'note'; if (activityTab === 'tasks') return a.type === 'task'; if (activityTab === 'event') return a.type === 'event'; return true; }); const activityIcon = (type) => { if (type === 'sms') return 'message-square'; if (type === 'email') return 'mail'; if (type === 'call') return 'phone'; if (type === 'note') return 'file-text'; if (type === 'task') return 'check-square'; if (type === 'event') return 'zap'; return 'activity'; }; const activityColors = (type, direction) => { if (type === 'sms') return direction === 'inbound' ? 'text-emerald-300 bg-emerald-500/5 border-emerald-500/20' : 'text-blue-300 bg-blue-500/5 border-blue-500/20'; if (type === 'email') return direction === 'inbound' ? 'text-cyan-300 bg-cyan-500/5 border-cyan-500/20' : 'text-violet-300 bg-violet-500/5 border-violet-500/20'; if (type === 'call') return 'text-amber-300 bg-amber-500/5 border-amber-500/20'; if (type === 'note') return 'text-slate-300 bg-slate-800/50 border-slate-700/40'; if (type === 'task') return 'text-orange-300 bg-orange-500/5 border-orange-500/20'; if (type === 'event') return 'text-teal-300 bg-teal-500/5 border-teal-500/20'; return 'text-slate-300 bg-slate-800/50 border-slate-700/40'; }; const activityLabel = (item) => { if (item.type === 'sms') return item.direction === 'inbound' ? '← SMS' : '→ SMS'; if (item.type === 'email') return item.direction === 'inbound' ? '← Email' : '→ Email'; if (item.type === 'call') return item.direction === 'inbound' ? '← Call' : '→ Call'; if (item.type === 'note') return 'Note'; if (item.type === 'task') return item.completed ? '✓ Task' : 'Task'; if (item.type === 'event') return item.event || 'Event'; return item.type; }; // Filter tabs include events const ACTIVITY_TABS = [['all','All'],['sms','SMS'],['email','Email'],['notes','Notes'],['tasks','Tasks'],['event','Events']]; return (
| {h} | ))}||||
|---|---|---|---|---|
|
{c.name}
{c.source && {c.source} }
|
{c.email || '—'} | {c.phone || '—'} |
{(c.tags || []).slice(0, 2).map((t, i) => (
{t}
))}
|
{fmtDate(c.createdAt)} |