"use client"; // ============================================================ // Support Center // Overview (5 channel cards + team) · Message Center · // New Ticket · My Tickets (+ timeline modal) · Help Center // plus Live Chat handshake & Callback/Email modals. // ============================================================ import { useEffect, useMemo, useRef, useState } from "react"; import { supportChannels, supportTeam, ticketCategories, tickets as ticketSeed, supportThreads as threadSeed, helpTopics, contactTimes, countryCodes, type Ticket, type TicketStatus, type SupportThread, type ChatMsg, } from "./account-data"; import { Avatar, Btn, Field, Icon, Modal, PageHead, Pill, Segmented, StatusDot, useToast, } from "./ui"; const SECTIONS = [ { value: "overview", label: "Overview", icon: "chat" }, { value: "messages", label: "Messages", icon: "mail" }, { value: "new", label: "New Ticket", icon: "ticket" }, { value: "tickets", label: "My Tickets", icon: "book" }, { value: "help", label: "Help Center", icon: "info" }, ]; const STATUS_META: Record = { created: { label: "Created", tone: "muted" }, open: { label: "Open", tone: "blue" }, "in-progress": { label: "In Progress", tone: "orange" }, "awaiting-customer": { label: "Awaiting You", tone: "purple" }, resolved: { label: "Resolved", tone: "green" }, closed: { label: "Closed", tone: "muted" }, }; export function Support() { const [section, setSection] = useState("overview"); const [chatOpen, setChatOpen] = useState(false); const [callbackOpen, setCallbackOpen] = useState(false); const [emailOpen, setEmailOpen] = useState(false); function onChannel(id: string) { if (id === "chat") setChatOpen(true); else if (id === "ticket") setSection("new"); else if (id === "callback") setCallbackOpen(true); else if (id === "email") setEmailOpen(true); else if (id === "help") setSection("help"); } return (
setChatOpen(true)}>Start live chat} />
{section === "overview" && } {section === "messages" && } {section === "new" && setSection("tickets")} />} {section === "tickets" && } {section === "help" && }
setChatOpen(false)} /> setCallbackOpen(false)} /> setEmailOpen(false)} />
); } /* ============================================================ */ /* Overview — channel cards + support team */ /* ============================================================ */ const MINI_AREA: Record = { ticket: "ticket", callback: "call", email: "email", help: "help" }; function Overview({ onChannel, onSection }: { onChannel: (id: string) => void; onSection: (s: string) => void }) { const online = supportTeam.filter((a) => a.status === "online"); const mini = supportChannels.filter((c) => ["ticket", "callback", "email", "help"].includes(c.id)); const recent = ticketSeed.slice(0, 4); // Derived "live" metrics so the command-center ribbon stays in sync with data. const openCount = ticketSeed.filter((t) => !["resolved", "closed"].includes(t.status)).length; const avgRating = (supportTeam.reduce((s, a) => s + a.rating, 0) / supportTeam.length).toFixed(1); const pulse = [ { icon: "people", value: String(online.length), label: "Agents online", live: true }, { icon: "clock", value: "< 2m", label: "Avg wait time" }, { icon: "ticket", value: String(openCount), label: "Open tickets" }, { icon: "star", value: avgRating, label: "Avg CSAT rating" }, ]; return (
{/* Live command-center ribbon */}
All systems operational Support · Live status
{pulse.map((p) => (
{p.value}{p.icon === "star" && } {p.label}
{p.live && }
))}
{/* Hero — live chat */} {/* Support team */}

Your support team

{online.length} online
{supportTeam.map((a) => (
{a.name}
{a.role}
{a.team}
{a.rating}
))}
{/* Mini channel tiles */} {mini.map((c) => ( ))} {/* Recent tickets */}

Recent tickets

{recent.map((t) => ( ))}
); } /* ============================================================ */ /* Message Center — inbox + live thread + typing */ /* ============================================================ */ function MessageCenter() { const [threads, setThreads] = useState(threadSeed); const [activeId, setActiveId] = useState(threadSeed[0].id); const [draft, setDraft] = useState(""); const endRef = useRef(null); const active = threads.find((t) => t.id === activeId)!; function send() { const text = draft.trim(); if (!text) return; const msg: ChatMsg = { id: `m${Date.now()}`, from: "me", text, at: "Now" }; setThreads((ts) => ts.map((t) => t.id === activeId ? { ...t, messages: [...t.messages, msg], typing: true, preview: text } : t)); setDraft(""); // simulate agent typing → reply setTimeout(() => { const reply: ChatMsg = { id: `m${Date.now() + 1}`, from: "agent", text: "Thanks — noted. I'll update the ticket and get back to you shortly.", at: "Now" }; setThreads((ts) => ts.map((t) => t.id === activeId ? { ...t, messages: [...t.messages, reply], typing: false } : t)); endRef.current?.scrollIntoView({ behavior: "smooth" }); }, 1800); setTimeout(() => endRef.current?.scrollIntoView({ behavior: "smooth" }), 50); } function openThread(id: string) { setActiveId(id); setThreads((ts) => ts.map((t) => t.id === id ? { ...t, unread: 0 } : t)); } const agent = supportTeam.find((a) => a.id === active.agentId)!; return (
{agent.name}
{active.typing ? typing… : `${agent.role} · ${agent.team}`}
{active.subject}
{active.messages.map((m) => (
{m.from === "agent" && }

{m.text}

{m.at}
))} {active.typing && (
)}
setDraft(e.target.value)} onKeyDown={(e) => e.key === "Enter" && send()} /> Send
); } /* ============================================================ */ /* New Ticket — category → department routing + attachment rules */ /* ============================================================ */ function NewTicket({ onDone }: { onDone: () => void }) { const { push } = useToast(); const [catId, setCatId] = useState(""); const [subject, setSubject] = useState(""); const [desc, setDesc] = useState(""); const [priority, setPriority] = useState("medium"); const [file, setFile] = useState(null); const cat = ticketCategories.find((c) => c.id === catId) ?? null; const needAttachment = cat?.requiresAttachment && !file; const canSubmit = catId && subject.trim() && desc.trim() && !needAttachment; function submit() { push({ tone: "success", title: "Ticket created", desc: `Routed to ${cat?.department}. We'll reply within ${cat?.sla}.` }); onDone(); } return (

Raise a new ticket

{cat && (
Routes to {cat.department} SLA {cat.sla}
)} setSubject(e.target.value)} />