import { useState, useEffect, useCallback } from "react"; import { Link } from "react-router-dom"; import api from "../../api/client"; const TYPE_COLORS = { email: { bg: "var(--badge-blue-bg)", color: "var(--badge-blue-text)" }, whatsapp: { bg: "#dcfce7", color: "#166534" }, call: { bg: "#fef9c3", color: "#854d0e" }, sms: { bg: "#fef3c7", color: "#92400e" }, note: { bg: "var(--bg-card-hover)", color: "var(--text-secondary)" }, in_person: { bg: "#ede9fe", color: "#5b21b6" }, }; const COMMS_TYPES = ["email", "whatsapp", "call", "sms", "note", "in_person"]; const DIRECTIONS = ["inbound", "outbound", "internal"]; function TypeBadge({ type }) { const s = TYPE_COLORS[type] || TYPE_COLORS.note; return ( {type} ); } function DirectionIcon({ direction }) { if (direction === "inbound") return ; if (direction === "outbound") return ; return ; } export default function InboxPage() { const [entries, setEntries] = useState([]); const [customers, setCustomers] = useState({}); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); const [typeFilter, setTypeFilter] = useState(""); const [dirFilter, setDirFilter] = useState(""); const [custFilter, setCustFilter] = useState(""); const [expanded, setExpanded] = useState({}); const [syncing, setSyncing] = useState(false); const [syncResult, setSyncResult] = useState(null); // { new_count } | null const loadAll = useCallback(async () => { setLoading(true); setError(""); try { const params = new URLSearchParams({ limit: 200 }); if (typeFilter) params.set("type", typeFilter); if (dirFilter) params.set("direction", dirFilter); const [commsData, custsData] = await Promise.all([ api.get(`/crm/comms/all?${params}`), api.get("/crm/customers"), ]); setEntries(commsData.entries || []); // Build id→name map const map = {}; for (const c of custsData.customers || []) { map[c.id] = c; } setCustomers(map); } catch (err) { setError(err.message); } finally { setLoading(false); } }, [typeFilter, dirFilter]); useEffect(() => { loadAll(); }, [loadAll]); const syncEmails = async () => { setSyncing(true); setSyncResult(null); try { const data = await api.post("/crm/comms/email/sync", {}); setSyncResult(data); await loadAll(); } catch (err) { setSyncResult({ error: err.message }); } finally { setSyncing(false); } }; const toggleExpand = (id) => setExpanded((prev) => ({ ...prev, [id]: !prev[id] })); // Client-side customer filter const filtered = custFilter ? entries.filter((e) => e.customer_id === custFilter) : entries; const customerOptions = Object.values(customers).sort((a, b) => (a.name || "").localeCompare(b.name || "") ); const selectStyle = { backgroundColor: "var(--bg-input)", borderColor: "var(--border-primary)", color: "var(--text-primary)", fontSize: 13, padding: "6px 10px", borderRadius: 6, border: "1px solid", cursor: "pointer", }; return (
{/* Header */}

Inbox

All communications across all customers

{syncResult && ( {syncResult.error ? syncResult.error : `${syncResult.new_count} new email${syncResult.new_count !== 1 ? "s" : ""}`} )}
{/* Filters */}
{(typeFilter || dirFilter || custFilter) && ( )}
{error && (
{error}
)} {loading ? (
Loading...
) : filtered.length === 0 ? (
No communications found.
) : (
{filtered.length} entr{filtered.length !== 1 ? "ies" : "y"}
{/* Timeline */}
{/* Connector line */}
{filtered.map((entry) => { const customer = customers[entry.customer_id]; const isExpanded = !!expanded[entry.id]; const typeStyle = TYPE_COLORS[entry.type] || TYPE_COLORS.note; return (
{/* Dot */}
entry.body && toggleExpand(entry.id)} > {/* Entry header */}
{entry.direction} {customer ? ( e.stopPropagation()} > {customer.name} {customer.organization ? ` · ${customer.organization}` : ""} ) : ( {entry.customer_id} )} {entry.occurred_at ? new Date(entry.occurred_at).toLocaleString() : ""} {entry.body && ( {isExpanded ? "▲" : "▼"} )}
{/* Subject / body preview */} {(entry.subject || entry.body) && (
{entry.subject && (

{entry.subject}

)} {entry.body && (

{entry.body}

)}
)} {/* Footer */} {(entry.logged_by || (entry.attachments && entry.attachments.length > 0)) && (
{entry.logged_by && ( by {entry.logged_by} )} {entry.attachments && entry.attachments.length > 0 && ( {entry.attachments.length} attachment{entry.attachments.length !== 1 ? "s" : ""} )}
)}
); })}
)}
); }