import { useState, useEffect, useCallback, useRef } from "react"; import { Link } from "react-router-dom"; import api from "../../api/client"; import { useAuth } from "../../auth/AuthContext"; import MailViewModal from "../components/MailViewModal"; import ComposeEmailModal from "../components/ComposeEmailModal"; import { CommTypeIconBadge, CommDirectionIcon } from "../components/CommIcons"; // Inline SVG icons — all use currentColor so tinting via CSS color works const IconExpand = () => ; const IconReply = () => ; const IconEdit = () => ; const IconDelete = () => ; // Display labels for transport types - always lowercase const TYPE_LABELS = { email: "e-mail", whatsapp: "whatsapp", call: "phonecall", sms: "sms", note: "note", in_person: "in person", }; const COMMS_TYPES = ["email", "whatsapp", "call", "sms", "note", "in_person"]; const DIRECTIONS = ["inbound", "outbound", "internal"]; const COMM_TIME_FMT = new Intl.DateTimeFormat("en-US", { hour: "numeric", minute: "2-digit", hour12: true }); const COMM_FULL_DATE_FMT = new Intl.DateTimeFormat("en-GB", { day: "numeric", month: "long", year: "numeric" }); function formatRelativeTime(value) { if (!value) return ""; const d = new Date(value); if (Number.isNaN(d.getTime())) return ""; const diffMs = Date.now() - d.getTime(); const diffSec = Math.floor(diffMs / 1000); if (diffSec < 60) return "just now"; const diffMin = Math.floor(diffSec / 60); if (diffMin < 60) return `${diffMin}m ago`; const diffHr = Math.floor(diffMin / 60); if (diffHr < 24) return `${diffHr}h ago`; const diffDay = Math.floor(diffHr / 24); if (diffDay < 7) return diffDay === 1 ? "yesterday" : `${diffDay} days ago`; const diffWk = Math.floor(diffDay / 7); if (diffWk < 5) return diffWk === 1 ? "1 week ago" : `${diffWk} weeks ago`; const diffMo = Math.floor(diffDay / 30); if (diffMo < 12) return diffMo === 1 ? "1 month ago" : `${diffMo} months ago`; const diffYr = Math.floor(diffDay / 365); return diffYr === 1 ? "1 year ago" : `${diffYr} years ago`; } function formatFullDateTime(value) { if (!value) return ""; const d = new Date(value); if (Number.isNaN(d.getTime())) return ""; return `${COMM_FULL_DATE_FMT.format(d)}, ${COMM_TIME_FMT.format(d).toLowerCase()}`; } 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", }; // Customer search mini modal (replaces the giant dropdown) function CustomerPickerModal({ open, onClose, customers, value, onChange }) { const [q, setQ] = useState(""); const inputRef = useRef(null); useEffect(() => { if (open) { setQ(""); setTimeout(() => inputRef.current?.focus(), 60); } }, [open]); // ESC to close useEffect(() => { if (!open) return; const handler = (e) => { if (e.key === "Escape") onClose(); }; window.addEventListener("keydown", handler); return () => window.removeEventListener("keydown", handler); }, [open, onClose]); if (!open) return null; const lower = q.trim().toLowerCase(); const filtered = customers.filter((c) => !lower || (c.name || "").toLowerCase().includes(lower) || (c.surname || "").toLowerCase().includes(lower) || (c.organization || "").toLowerCase().includes(lower) || (c.contacts || []).some((ct) => (ct.value || "").toLowerCase().includes(lower)) ); return (
All customer communications across all channels
{entry.body}