/* shared-data.jsx — UI helpers, icons, shared components. Data comes from the API; mock generators are NOT included. */ const STYLES = [ "Trash Polka", "Geometrico", "Blackwork", "Neotraditional", "Abstract", "Etching", "Fineline", "Realistic", "Old School", "Japanese", "Dotwork", "Lettering" ]; const STATUS_LABELS = { "da-inviare": "Da inviare", "in-attesa": "In attesa", "lasciata": "Recensione lasciata", "nessuna": "Nessuna risposta", "rifiutata": "Rifiutata", "non-richiesta":"Non richiesta", }; const RESULT_LABELS = { "in-attesa": "In attesa", "lasciata": "Recensione lasciata", "nessuna": "Nessuna risposta", "rifiutata": "Rifiutata", }; const SATISFACTION = { "molto": { label: "Molto soddisfatto", short: "Molto soddisf.", color: "var(--ok)", bg: "rgba(74, 222, 128, 0.14)" }, "soddisfatto": { label: "Soddisfatto", short: "Soddisfatto", color: "#a5d96b", bg: "rgba(165, 217, 107, 0.14)" }, "neutro": { label: "Neutro", short: "Neutro", color: "var(--warn)", bg: "rgba(251, 191, 36, 0.14)" }, "insoddisfatto": { label: "Insoddisfatto", short: "Insoddisf.", color: "var(--bad)", bg: "rgba(248, 113, 113, 0.14)" }, }; const SAT_OPTIONS = ["molto", "soddisfatto", "neutro", "insoddisfatto"]; const MODALITY = { "manuale": { label: "Manuale", color: "var(--ink-1)", bg: "var(--bg-3)" }, "automatica": { label: "Automatica", color: "var(--coral)", bg: "var(--coral-soft)" }, }; // ── Helpers ────────────────────────────────────────────────────────────────── function initials(c) { const f = (c.first || "?")[0].toUpperCase(); const l = (c.last || "")[0] ? c.last[0].toUpperCase() : ""; return f + l; } function fullName(c) { return (c.first + " " + c.last).trim(); } function methodLabel(m) { return { wa: "WhatsApp", mail: "Email", call: "Chiamata" }[m] || m; } function fmtDate(d) { if (!d) return "—"; const date = d instanceof Date ? d : new Date(d); const today = new Date(); const diff = Math.floor((today - date) / 86400000); if (diff === 0) return "Oggi"; if (diff === 1) return "Ieri"; if (diff < 7) return diff + "g fa"; return date.toLocaleDateString("it-IT", { day: "2-digit", month: "short" }); } function applyVars(body, c) { if (!body) return ""; return body .replace(/\{\{nome\}\}/g, c ? c.first : "{{nome}}") .replace(/\{\{cognome\}\}/g, c ? c.last : "{{cognome}}") .replace(/\{\{tatuatore\}\}/g, c ? c.artist : "{{tatuatore}}") .replace(/\{\{stile\}\}/g, c ? (c.style || "") : "{{stile}}"); } function buildContactURL(client, message) { const text = encodeURIComponent(applyVars(message ? message.body : "", client)); if (client.method === "wa") { let digits = client.phone.replace(/\D/g, ""); // Prepend Italy country code if number is local (≤ 10 digits) if (digits.length <= 10) digits = "39" + digits; return "https://wa.me/" + digits + (text ? "?text=" + text : ""); } if (client.method === "mail") { const subj = encodeURIComponent("Una recensione per MENOUNO? 🖤"); return "mailto:" + client.email + "?subject=" + subj + (text ? "&body=" + text : ""); } return "tel:" + client.phone.replace(/\s/g, ""); } async function copyToClipboard(text) { try { await navigator.clipboard.writeText(text); return true; } catch { return false; } } // ── Icons ───────────────────────────────────────────────────────────────────── const Icon = ({ name, size = 16 }) => { const s = { width: size, height: size, display: "inline-block", flexShrink: 0 }; const stroke = { fill: "none", stroke: "currentColor", strokeWidth: 1.7, strokeLinecap: "round", strokeLinejoin: "round" }; switch (name) { case "wa": return ( ); case "mail": return ( ); case "call": return ( ); case "search": return ( ); case "send": return ( ); case "copy": return ( ); case "edit": return ( ); case "trash": return ( ); case "plus": return ( ); case "check": return ( ); case "close": return ( ); case "filter": return ( ); case "star": return ( ); case "more": return ( ); case "chevron": return ( ); case "refresh": return ( ); } return null; }; function MethodIcon({ method, size = 14 }) { return ; } // StatusPill: status → pill with dot + label function StatusPill({ status }) { const map = { "da-inviare": ["dainviare", "Da inviare"], "in-attesa": ["attesa", "In attesa"], "lasciata": ["lasciata", "Lasciata"], "nessuna": ["nessuna", "Nessuna risp."], "rifiutata": ["rifiutata", "Rifiutata"], "non-richiesta": ["nonrichiesta", "Non richiesta"], }; const [cls, label] = map[status] || ["dainviare", status]; return ( {label} ); } function Stars({ value, max = 5 }) { if (!value) return —; return ( {Array.from({ length: max }).map((_, i) => ★ )} ); } function StarInput({ value, onChange, size = 15 }) { const [hover, setHover] = React.useState(0); const shown = hover || value || 0; return ( setHover(0)} style={{ cursor: "pointer" }}> {[1,2,3,4,5].map(i => ( setHover(i)} onClick={e => { e.stopPropagation(); onChange(i); }} >★ ))} ); } function SatisfactionSelect({ value, onChange, compact }) { const [open, setOpen] = React.useState(false); const ref = React.useRef(null); React.useEffect(() => { if (!open) return; const close = e => { if (!ref.current?.contains(e.target)) setOpen(false); }; document.addEventListener("mousedown", close); return () => document.removeEventListener("mousedown", close); }, [open]); const cfg = value ? SATISFACTION[value] : null; return ( { e.stopPropagation(); setOpen(o => !o); }} style={cfg ? { color: cfg.color, background: cfg.bg, borderColor: "transparent" } : undefined}> {cfg ? (compact ? cfg.short : cfg.label) : "— seleziona"} {open && ( {SAT_OPTIONS.map(k => { const c = SATISFACTION[k]; return ( { e.stopPropagation(); onChange(k); setOpen(false); }}> {c.label} ); })} )} ); } function ModalityTag({ value }) { if (!value) return —; const m = MODALITY[value]; if (!m) return {value}; return {m.label}; } function PhotoTag({ has }) { if (has) return Sì; return No; } function useToast() { const [toast, setToast] = React.useState(null); const show = React.useCallback(msg => { setToast(msg); clearTimeout(window.__toastT); window.__toastT = setTimeout(() => setToast(null), 2400); }, []); const node = toast ? ( {toast} ) : null; return [node, show]; } Object.assign(window, { STATUS_LABELS, RESULT_LABELS, SATISFACTION, SAT_OPTIONS, MODALITY, initials, fullName, methodLabel, fmtDate, applyVars, buildContactURL, Icon, MethodIcon, StatusPill, Stars, StarInput, SatisfactionSelect, ModalityTag, PhotoTag, useToast, copyToClipboard, });