import { useState, useEffect, useRef } from "react";
import { useNavigate } from "react-router-dom";
import api from "../../../api/client";
import { CommTypeIconBadge, CommDirectionIcon } from "../../components/CommIcons";
import { REL_STATUS_LABELS, REL_STATUS_STYLES, OrderStatusChip, fmtDate } from "./shared";
import clientIcon from "../../../assets/customer-status/client.svg?raw";
import inactiveIcon from "../../../assets/customer-status/inactive.svg?raw";
import churnedIcon from "../../../assets/customer-status/churned.svg?raw";
import exclamationIcon from "../../../assets/customer-status/exclamation.svg?raw";
import wrenchIcon from "../../../assets/customer-status/wrench.svg?raw";
import orderIcon from "../../../assets/customer-status/order.svg?raw";
const LANGUAGE_LABELS = {
af:"Afrikaans",sq:"Albanian",am:"Amharic",ar:"Arabic",hy:"Armenian",az:"Azerbaijani",
eu:"Basque",be:"Belarusian",bn:"Bengali",bs:"Bosnian",bg:"Bulgarian",ca:"Catalan",
zh:"Chinese",hr:"Croatian",cs:"Czech",da:"Danish",nl:"Dutch",en:"English",
et:"Estonian",fi:"Finnish",fr:"French",ka:"Georgian",de:"German",el:"Greek",
gu:"Gujarati",he:"Hebrew",hi:"Hindi",hu:"Hungarian",id:"Indonesian",it:"Italian",
ja:"Japanese",kn:"Kannada",kk:"Kazakh",ko:"Korean",lv:"Latvian",lt:"Lithuanian",
mk:"Macedonian",ms:"Malay",ml:"Malayalam",mt:"Maltese",mr:"Marathi",mn:"Mongolian",
ne:"Nepali",no:"Norwegian",fa:"Persian",pl:"Polish",pt:"Portuguese",pa:"Punjabi",
ro:"Romanian",ru:"Russian",sr:"Serbian",si:"Sinhala",sk:"Slovak",sl:"Slovenian",
es:"Spanish",sw:"Swahili",sv:"Swedish",tl:"Tagalog",ta:"Tamil",te:"Telugu",
th:"Thai",tr:"Turkish",uk:"Ukrainian",ur:"Urdu",uz:"Uzbek",vi:"Vietnamese",
cy:"Welsh",yi:"Yiddish",zu:"Zulu",
};
const CONTACT_TYPE_ICONS = { email:"๐ง", phone:"๐", whatsapp:"๐ฌ", other:"๐" };
const COMM_TYPE_LABELS = {
email:"e-mail", whatsapp:"whatsapp", call:"phonecall", sms:"sms", note:"note", in_person:"in person",
};
const labelStyle = { fontSize: 11, fontWeight: 600, color: "var(--text-muted)", textTransform: "uppercase", letterSpacing: "0.06em", marginBottom: 4 };
function AddressField({ loc }) {
if (!loc) return null;
const parts = [loc.address, loc.city, loc.postal_code, loc.region, loc.country].filter(Boolean);
if (!parts.length) return null;
return (
Address
{parts.join(", ")}
);
}
function TagsField({ tags }) {
if (!tags || !tags.length) return null;
return (
Tags
{tags.map((tag) => (
{tag}
))}
);
}
// Verbose description per relationship status
const REL_STATUS_DESCRIPTIONS = {
lead: "This contact is a potential new lead. No active engagement yet.",
prospect: "Actively engaged โ exploring possibilities before a formal order.",
active: "Active customer with ongoing or recent commercial activity.",
inactive: "No recent engagement. May need a follow-up to re-activate.",
churned: "Customer has disengaged. Orders declined or no activity for a long period.",
};
// Icon per relationship status (same logic as CustomerList resolveStatusIcon base cases)
const REL_STATUS_ICONS = {
lead: clientIcon,
prospect: clientIcon,
active: clientIcon,
inactive: inactiveIcon,
churned: churnedIcon,
};
// Status badge: shows current status + gear icon to open inline change dropdown
function RelStatusSelector({ customer, onUpdated, canEdit }) {
const statuses = ["lead", "prospect", "active", "inactive", "churned"];
const current = customer.relationship_status || "lead";
const [open, setOpen] = useState(false);
const ref = useRef(null);
useEffect(() => {
const handler = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
document.addEventListener("mousedown", handler);
return () => document.removeEventListener("mousedown", handler);
}, []);
const handleClick = async (status) => {
if (!canEdit || status === current) return;
setOpen(false);
try {
const updated = await api.patch(`/crm/customers/${customer.id}/relationship-status`, { status });
onUpdated(updated);
} catch (err) {
alert(err.message);
}
};
const st = REL_STATUS_STYLES[current] || REL_STATUS_STYLES.lead;
const icon = REL_STATUS_ICONS[current];
const description = REL_STATUS_DESCRIPTIONS[current] || "";
ensureShimmer();
const shimmerGradient = `linear-gradient(120deg, ${st.border}44 0%, ${st.border}cc 40%, ${st.border}ff 50%, ${st.border}cc 60%, ${st.border}44 100%)`;
return (
{open && (
{statuses.map((s) => {
const sst = REL_STATUS_STYLES[s] || {};
const isActive = s === current;
return (
);
})}
)}
);
}
const STAT_CARD_STYLES = {
issue: { bg: "var(--crm-issue-active-bg,rgba(224,53,53,0.12))", color: "var(--crm-issue-active-text)", border: "rgba(224,53,53,0.35)" },
support: { bg: "var(--crm-support-active-bg,rgba(247,103,7,0.12))", color: "var(--crm-support-active-text)", border: "rgba(247,103,7,0.35)" },
order: { bg: "var(--badge-blue-bg,rgba(59,130,246,0.12))", color: "var(--badge-blue-text)", border: "rgba(59,130,246,0.35)" },
};
const STAT_ICONS = {
issue: exclamationIcon,
support: wrenchIcon,
order: orderIcon,
};
const STAT_LABELS = {
issue: "Open Issues",
support: "Support Assists",
order: "Open Orders",
};
// Shared shimmer keyframes injected once
let _shimmerInjected = false;
function ensureShimmer() {
if (_shimmerInjected) return;
_shimmerInjected = true;
const style = document.createElement("style");
style.textContent = `
@keyframes crm-border-shimmer {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
.crm-shimmer-card {
position: relative;
border-radius: 10px;
overflow: visible;
}
.crm-shimmer-card::before {
content: "";
position: absolute;
inset: -1.5px;
border-radius: 11px;
padding: 1.5px;
background: var(--crm-shimmer-gradient);
background-size: 200% 200%;
animation: crm-border-shimmer 3s ease infinite;
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
pointer-events: none;
z-index: 0;
}
`;
document.head.appendChild(style);
}
function renderMaskedIconOv(icon, color, size = 16) {
const svgMarkup = icon
.replace(/<\?xml[\s\S]*?\?>/gi, "")
.replace(//gi, "")
.replace(//g, "")
.replace(
/