PageSourceSearch

https://epsmasdash-ms8uwkec.manus.space/assets/MessagesPanel-BsiBgCf3.js

js epsmasdash-ms8uwkec.manus.space collected 2026-10-03 05:01:58 UTC 16,159 bytes, 275 lines download raw bytes

1import { c as createLucideIcon, r as reactExports, t as trpc, ad as Activity, F as FileText, C as CircleAlert, o as RefreshCw, D as DollarSign, _ as TrendingUp, m as Users, ac as Megaphone, j as jsxRuntimeExports, U as USFlag } from './index-CNT5CkK7.js';
2import { C as Card, a as CardContent, b as CardHeader, c as CardTitle } from './card-CV3CzesJ.js';
3import { B as Briefcase } from './briefcase-d8WvXAbR.js';
4import { F as Filter } from './filter-BxjGUbXo.js';
5import { U as User } from './user-B4RG8T6t.js';
6import { C as Clock } from './clock-CjjskDf6.js';
7import { C as CircleCheck } from './circle-check-CqW-unub.js';
8
9/**
10 * @license lucide-react v0.453.0 - ISC
11 *
12 * This source code is licensed under the ISC license.
13 * See the LICENSE file in the root directory of this source tree.
14 */
15
16
17const Workflow = createLucideIcon("Workflow", [
18  ["rect", { width: "8", height: "8", x: "3", y: "3", rx: "2", key: "by2w9f" }],
19  ["path", { d: "M7 11v4a2 2 0 0 0 2 2h4", key: "xkn7yn" }],
20  ["rect", { width: "8", height: "8", x: "13", y: "13", rx: "2", key: "1cgmvn" }]
21]);
22
23const EPS_GOLD = "#B22234";
24const EPS_NAVY = "#1B3A6B";
25const CATEGORIES = [
26  { key: "all", label: "All Activity", icon: Activity, color: EPS_NAVY },
27  { key: "policy_change", label: "Policy Changes", icon: FileText, color: "#1e40af" },
28  { key: "claim", label: "Claims", icon: CircleAlert, color: "#dc2626" },
29  { key: "renewal", label: "Renewals", icon: RefreshCw, color: "#15803d" },
30  { key: "payment", label: "Payments", icon: DollarSign, color: "#0891b2" },
31  { key: "commission", label: "Commissions", icon: TrendingUp, color: "#7c3aed" },
32  { key: "onboarding", label: "Onboarding", icon: Users, color: "#2563eb" },
33  { key: "quote", label: "Quotes", icon: Briefcase, color: "#9333ea" },
34  { key: "marketing", label: "Marketing", icon: Megaphone, color: "#db2777" },
35  { key: "workflow", label: "Workflows", icon: Workflow, color: "#0d9488" }
36];
37function getEventStyle(category, eventType) {
38  const styles = {
39    policy_change: { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(FileText, { className: "w-4 h-4" }), bg: "#eff6ff", border: "#bfdbfe" },
40    claim: { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "w-4 h-4" }), bg: "#fef2f2", border: "#fecaca" },
41    renewal: { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "w-4 h-4" }), bg: "#f0fdf4", border: "#bbf7d0" },
42    payment: { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(DollarSign, { className: "w-4 h-4" }), bg: "#ecfeff", border: "#a5f3fc" },
43    commission: { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(TrendingUp, { className: "w-4 h-4" }), bg: "#faf5ff", border: "#e9d5ff" },
44    onboarding: { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Users, { className: "w-4 h-4" }), bg: "#eff6ff", border: "#bfdbfe" },
45    quote: { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Briefcase, { className: "w-4 h-4" }), bg: "#fdf4ff", border: "#f0abfc" },
46    marketing: { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Megaphone, { className: "w-4 h-4" }), bg: "#fdf2f8", border: "#fbcfe8" },
47    workflow: { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Workflow, { className: "w-4 h-4" }), bg: "#f0fdfa", border: "#99f6e4" },
48    system: { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { className: "w-4 h-4" }), bg: "#f8fafc", border: "#e2e8f0" }
49  };
50  if (eventType?.includes("completed") || eventType?.includes("received") || eventType?.includes("paid")) {
51    return { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-4 h-4" }), bg: "#f0fdf4", border: "#bbf7d0" };
52  }
53  return styles[category] ?? styles.system;
54}
55const AGENT_NAMES = {
56  "greg-fay": "Greg Fay",
57  "stacey-hinkle": "Stacey Hinkle",
58  "josh-hinkle": "Josh Hinkle",
59  "charlie-drain": "Charlie Drain",
60  "michael-jividen": "Michael Jividen",
61  "jon-bucher": "Jon Bucher",
62  "zach-hinkle": "Zach Hinkle",
63  "angie-hinkle": "Angie Hinkle",
64  "adam-kaufman": "Adam Kaufman",
65  "lesley-wiegand": "Lesley Wiegand",
66  system: "System"
67};
68const AGENT_KEYS = Object.keys(AGENT_NAMES).filter((k) => k !== "system");
69function timeAgo(date) {
70  const d = new Date(date);
71  const now = /* @__PURE__ */ new Date();
72  const diff = Math.floor((now.getTime() - d.getTime()) / 1e3);
73  if (diff < 60) return `${diff}s ago`;
74  if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
75  if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`;
76  if (diff < 86400 * 7) return `${Math.floor(diff / 86400)}d ago`;
77  return d.toLocaleDateString();
78}
79function formatDate(date) {
80  return new Date(date).toLocaleString("en-US", {
81    month: "short",
82    day: "numeric",
83    hour: "numeric",
84    minute: "2-digit",
85    hour12: true
86  });
87}
88function MessagesPanel() {
89  const [category, setCategory] = reactExports.useState("all");
90  const [agentFilter, setAgentFilter] = reactExports.useState("");
91  const [search, setSearch] = reactExports.useState("");
92  const { data, isLoading, refetch, isFetching } = trpc.messages.activityFeed.useQuery(
93    { limit: 200, category, agentKey: agentFilter || void 0 },
94    { refetchInterval: 2e4 }
95  );
96  const events = data?.events ?? [];
97  const filtered = search.trim() ? events.filter(
98    (e) => e.description.toLowerCase().includes(search.toLowerCase()) || (e.clientName ?? "").toLowerCase().includes(search.toLowerCase()) || (e.agentKey ? AGENT_NAMES[e.agentKey] ?? e.agentKey : "").toLowerCase().includes(search.toLowerCase())
99  ) : events;
100  const stats = CATEGORIES.filter((c) => c.key !== "all").map((c) => ({
101    ...c,
102    count: events.filter((e) => e.category === c.key).length
103  })).filter((s) => s.count > 0);
104  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [
105    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start justify-between flex-wrap gap-3", children: [
106      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
107        /* @__PURE__ */ jsxRuntimeExports.jsxs("h1", { className: "text-2xl font-bold", style: { fontFamily: "'Playfair Display', serif" }, children: [
108          /* @__PURE__ */ jsxRuntimeExports.jsx(USFlag, { size: 18 }),
109          " Activity Feed"
110        ] }),
111        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-muted-foreground text-sm mt-1", children: "Live audit trail across all agency workflows — policy changes, claims, renewals, payments, and more" })
112      ] }),
113      /* @__PURE__ */ jsxRuntimeExports.jsxs(
114        "button",
115        {
116          onClick: () => refetch(),
117          disabled: isFetching,
118          className: "flex items-center gap-1.5 px-3 py-1.5 rounded-lg border text-xs font-medium hover:bg-muted/40 transition-colors disabled:opacity-50",
119          children: [
120            /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: `w-3.5 h-3.5 ${isFetching ? "animate-spin" : ""}` }),
121            "Refresh"
122          ]
123        }
124      )
125    ] }),
126    stats.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-3", children: stats.slice(0, 5).map((s) => {
127      const Icon = s.icon;
128      return /* @__PURE__ */ jsxRuntimeExports.jsx(
129        Card,
130        {
131          className: "border cursor-pointer hover:shadow-sm transition-shadow",
132          onClick: () => setCategory(s.key),
133          style: { borderColor: category === s.key ? s.color : void 0 },
134          children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "pt-3 pb-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
135            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
136              /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground truncate", children: s.label }),
137              /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xl font-bold", style: { color: s.color }, children: s.count })
138            ] }),
139            /* @__PURE__ */ jsxRuntimeExports.jsx(
140              "div",
141              {
142                className: "w-8 h-8 rounded-lg flex items-center justify-center flex-shrink-0",
143                style: { background: `${s.color}18`, color: s.color },
144                children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { className: "w-4 h-4" })
145              }
146            )
147          ] }) })
148        },
149        s.key
150      );
151    }) }),
152    /* @__PURE__ */ jsxRuntimeExports.jsx(Card, { className: "border", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "pt-4 pb-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap gap-3 items-center", children: [
153      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 flex-wrap", children: [
154        /* @__PURE__ */ jsxRuntimeExports.jsx(Filter, { className: "w-3.5 h-3.5 text-muted-foreground flex-shrink-0" }),
155        CATEGORIES.map((c) => {
156          const Icon = c.icon;
157          const active = category === c.key;
158          return /* @__PURE__ */ jsxRuntimeExports.jsxs(
159            "button",
160            {
161              onClick: () => setCategory(c.key),
162              className: `flex items-center gap-1 px-2.5 py-1 rounded-full text-xs font-medium transition-colors ${active ? "text-white" : "border hover:bg-muted/40"}`,
163              style: active ? { background: c.color, borderColor: c.color } : { borderColor: "var(--border)" },
164              children: [
165                /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { className: "w-3 h-3" }),
166                c.label
167              ]
168            },
169            c.key
170          );
171        })
172      ] }),
173      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 ml-auto", children: [
174        /* @__PURE__ */ jsxRuntimeExports.jsx(User, { className: "w-3.5 h-3.5 text-muted-foreground" }),
175        /* @__PURE__ */ jsxRuntimeExports.jsxs(
176          "select",
177          {
178            value: agentFilter,
179            onChange: (e) => setAgentFilter(e.target.value),
180            className: "text-xs border rounded-md px-2 py-1 focus:outline-none focus:ring-1 bg-background",
181            style: { borderColor: "var(--border)" },
182            children: [
183              /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: "All Agents" }),
184              AGENT_KEYS.map((k) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: k, children: AGENT_NAMES[k] }, k))
185            ]
186          }
187        )
188      ] }),
189      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
190        "input",
191        {
192          type: "text",
193          placeholder: "Search events…",
194          value: search,
195          onChange: (e) => setSearch(e.target.value),
196          className: "text-xs border rounded-md pl-3 pr-3 py-1 focus:outline-none focus:ring-1 w-44 bg-background",
197          style: { borderColor: "var(--border)" }
198        }
199      ) })
200    ] }) }) }),
201    /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "border", children: [
202      /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "pb-2 pt-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(CardTitle, { className: "text-sm flex items-center gap-2", children: [
203        /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { className: "w-4 h-4", style: { color: EPS_GOLD } }),
204        filtered.length,
205        " event",
206        filtered.length !== 1 ? "s" : "",
207        category !== "all" && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground font-normal", children: [
208          "in ",
209          CATEGORIES.find((c) => c.key === category)?.label
210        ] }),
211        agentFilter && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground font-normal", children: [
212          "for ",
213          AGENT_NAMES[agentFilter] ?? agentFilter
214        ] })
215      ] }) }),
216      /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "pb-4", children: isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "py-12 text-center", children: [
217        /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { className: "w-8 h-8 mx-auto mb-3 text-muted-foreground opacity-40 animate-pulse" }),
218        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-muted-foreground", children: "Loading activity feed…" })
219      ] }) : filtered.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "py-12 text-center", children: [
220        /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { className: "w-10 h-10 mx-auto mb-3 text-muted-foreground opacity-40" }),
221        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-muted-foreground", children: "No events found." }),
222        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground mt-1", children: search ? "Try a different search term." : "Activity will appear here as agents process tasks." })
223      ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1.5", children: filtered.map((event) => {
224        const style = getEventStyle(event.category, event.eventType);
225        const agentName = event.agentKey ? AGENT_NAMES[event.agentKey] ?? event.agentKey : event.agentName ?? null;
226        const catConfig = CATEGORIES.find((c) => c.key === event.category);
227        return /* @__PURE__ */ jsxRuntimeExports.jsxs(
228          "div",
229          {
230            className: "flex items-start gap-3 p-3 rounded-lg border transition-colors hover:bg-muted/10",
231            style: { borderColor: style.border, background: style.bg },
232            children: [
233              /* @__PURE__ */ jsxRuntimeExports.jsx(
234                "div",
235                {
236                  className: "w-7 h-7 rounded-md flex items-center justify-center flex-shrink-0 mt-0.5",
237                  style: { background: catConfig ? `${catConfig.color}20` : "#f1f5f9", color: catConfig?.color ?? EPS_NAVY },
238                  children: style.icon
239                }
240              ),
241              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
242                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 flex-wrap mb-0.5", children: [
243                  catConfig && /* @__PURE__ */ jsxRuntimeExports.jsx(
244                    "span",
245                    {
246                      className: "px-1.5 py-0.5 rounded text-xs font-semibold",
247                      style: { background: `${catConfig.color}18`, color: catConfig.color },
248                      children: catConfig.label
249                    }
250                  ),
251                  agentName && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
252                    /* @__PURE__ */ jsxRuntimeExports.jsx(User, { className: "w-3 h-3" }),
253                    agentName
254                  ] }),
255                  event.clientName && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-medium text-foreground truncate max-w-[180px]", children: event.clientName })
256                ] }),
257                /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-foreground leading-snug", children: event.description })
258              ] }),
259              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-end gap-0.5 flex-shrink-0 text-right", children: [
260                /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
261                  /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "w-3 h-3" }),
262                  timeAgo(event.createdAt)
263                ] }),
264                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-muted-foreground/60", children: formatDate(event.createdAt) })
265              ] })
266            ]
267          },
268          event.id
269        );
270      }) }) })
271    ] })
272  ] });
273}
274
275export { MessagesPanel as default };

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.