@snksergio/design-system 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +260 -0
  2. package/dist-lib/chunks/app-shell-BNTvOETJ.mjs +2681 -0
  3. package/dist-lib/chunks/app-shell-BNTvOETJ.mjs.map +1 -0
  4. package/dist-lib/chunks/app-shell-CDy42aNI.mjs +2663 -0
  5. package/dist-lib/chunks/app-shell-CDy42aNI.mjs.map +1 -0
  6. package/dist-lib/chunks/app-shell-mocks-kWIVSzLs.mjs +208 -0
  7. package/dist-lib/chunks/app-shell-mocks-kWIVSzLs.mjs.map +1 -0
  8. package/dist-lib/chunks/app-shell-mocks-oO_IV3Gw.mjs +207 -0
  9. package/dist-lib/chunks/app-shell-mocks-oO_IV3Gw.mjs.map +1 -0
  10. package/dist-lib/chunks/badge-B_2Zt52o.mjs +797 -0
  11. package/dist-lib/chunks/badge-B_2Zt52o.mjs.map +1 -0
  12. package/dist-lib/chunks/badge-DKpXURa1.mjs +813 -0
  13. package/dist-lib/chunks/badge-DKpXURa1.mjs.map +1 -0
  14. package/dist-lib/chunks/chat-v2-mocks-BV9Wha_Z.mjs +192 -0
  15. package/dist-lib/chunks/chat-v2-mocks-BV9Wha_Z.mjs.map +1 -0
  16. package/dist-lib/chunks/chat-v2-mocks-DvZRkhmz.mjs +193 -0
  17. package/dist-lib/chunks/chat-v2-mocks-DvZRkhmz.mjs.map +1 -0
  18. package/dist-lib/chunks/chip-group-CsKBBHW2.mjs +796 -0
  19. package/dist-lib/chunks/chip-group-CsKBBHW2.mjs.map +1 -0
  20. package/dist-lib/chunks/chip-group-D3D0i72q.mjs +780 -0
  21. package/dist-lib/chunks/chip-group-D3D0i72q.mjs.map +1 -0
  22. package/dist-lib/chunks/clientes-showcase-mocks-BMfbNNJh.mjs +185 -0
  23. package/dist-lib/chunks/clientes-showcase-mocks-BMfbNNJh.mjs.map +1 -0
  24. package/dist-lib/chunks/clientes-showcase-mocks-Cq9u3nGZ.mjs +169 -0
  25. package/dist-lib/chunks/clientes-showcase-mocks-Cq9u3nGZ.mjs.map +1 -0
  26. package/dist-lib/chunks/input-374MpdBL.mjs +72 -0
  27. package/dist-lib/chunks/input-374MpdBL.mjs.map +1 -0
  28. package/dist-lib/chunks/input-DF4XAWmr.mjs +56 -0
  29. package/dist-lib/chunks/input-DF4XAWmr.mjs.map +1 -0
  30. package/dist-lib/chunks/page-header-Dw-3wqAG.mjs +75 -0
  31. package/dist-lib/chunks/page-header-Dw-3wqAG.mjs.map +1 -0
  32. package/dist-lib/chunks/page-header-mC1gGtOI.mjs +76 -0
  33. package/dist-lib/chunks/page-header-mC1gGtOI.mjs.map +1 -0
  34. package/dist-lib/chunks/panel-Ds15whqp.mjs +9717 -0
  35. package/dist-lib/chunks/panel-Ds15whqp.mjs.map +1 -0
  36. package/dist-lib/chunks/panel-bzNmFlEZ.mjs +9737 -0
  37. package/dist-lib/chunks/panel-bzNmFlEZ.mjs.map +1 -0
  38. package/dist-lib/chunks/useTheme-BUPLZBMs.mjs +66 -0
  39. package/dist-lib/chunks/useTheme-BUPLZBMs.mjs.map +1 -0
  40. package/dist-lib/chunks/useTheme-Dee4mo-A.mjs +65 -0
  41. package/dist-lib/chunks/useTheme-Dee4mo-A.mjs.map +1 -0
  42. package/dist-lib/index.cjs +1207 -0
  43. package/dist-lib/index.cjs.map +1 -0
  44. package/dist-lib/index.d.ts +2 -0
  45. package/dist-lib/index.mjs +1209 -0
  46. package/dist-lib/index.mjs.map +1 -0
  47. package/dist-lib/preview/chat.cjs +1120 -0
  48. package/dist-lib/preview/chat.cjs.map +1 -0
  49. package/dist-lib/preview/chat.d.ts +6 -0
  50. package/dist-lib/preview/chat.mjs +1120 -0
  51. package/dist-lib/preview/chat.mjs.map +1 -0
  52. package/dist-lib/preview/clientes.cjs +897 -0
  53. package/dist-lib/preview/clientes.cjs.map +1 -0
  54. package/dist-lib/preview/clientes.d.ts +6 -0
  55. package/dist-lib/preview/clientes.mjs +897 -0
  56. package/dist-lib/preview/clientes.mjs.map +1 -0
  57. package/dist-lib/preview/dashboard.cjs +733 -0
  58. package/dist-lib/preview/dashboard.cjs.map +1 -0
  59. package/dist-lib/preview/dashboard.d.ts +4 -0
  60. package/dist-lib/preview/dashboard.mjs +733 -0
  61. package/dist-lib/preview/dashboard.mjs.map +1 -0
  62. package/dist-lib/preview/mocks.cjs +15 -0
  63. package/dist-lib/preview/mocks.cjs.map +1 -0
  64. package/dist-lib/preview/mocks.d.ts +2 -0
  65. package/dist-lib/preview/mocks.mjs +15 -0
  66. package/dist-lib/preview/mocks.mjs.map +1 -0
  67. package/dist-lib/theme.css +668 -0
  68. package/dist-lib/tokens.cjs +915 -0
  69. package/dist-lib/tokens.cjs.map +1 -0
  70. package/dist-lib/tokens.d.ts +2 -0
  71. package/dist-lib/tokens.mjs +915 -0
  72. package/dist-lib/tokens.mjs.map +1 -0
  73. package/package.json +142 -0
@@ -0,0 +1,897 @@
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
+ import { useState, useEffect, useRef, useCallback, useMemo } from "react";
3
+ import { u as useTheme } from "../chunks/useTheme-BUPLZBMs.mjs";
4
+ import { Pencil, Trash2, ChevronDown, MoreHorizontal, Plus, Download, Maximize2, Copy, Upload, RotateCcw, MessageSquare, Archive, Clock } from "lucide-react";
5
+ import { S as STATUSES, a as STATUS_DOT, C as CATEGORIES, b as CITIES, A as AGENTS, d as CATEGORY_KIND, f as formatBRL, e as formatShortDate, g as CLIENTS_87, K as KANBAN_COLUMNS, h as STATUS_OPTIONS, i as CATEGORY_OPTIONS, j as AGENTS_LOOKUP, k as AGENT_OPTIONS } from "../chunks/clientes-showcase-mocks-Cq9u3nGZ.mjs";
6
+ import { P as Panel, F as FormFieldInput, a as FormField, b as FormFieldSelect, c as FormFieldTextarea, d as FloatingPanel, p as presetView, D as DataTable, B as BulkActionButton, A as AlertModal } from "../chunks/panel-Ds15whqp.mjs";
7
+ import { t as tv, a as ChipGroup, b as ChipGroupItem, B as Button, C as Chip } from "../chunks/chip-group-D3D0i72q.mjs";
8
+ import { a as Avatar, b as AvatarFallback, A as AppShell } from "../chunks/app-shell-CDy42aNI.mjs";
9
+ import "../chunks/input-DF4XAWmr.mjs";
10
+ import "../chunks/badge-B_2Zt52o.mjs";
11
+ import { P as PageHeader } from "../chunks/page-header-mC1gGtOI.mjs";
12
+ import { b as APP_SHELL_LAYOUT_OPTIONS, f as APP_SHELL_USER, e as APP_SHELL_THEME_OPTIONS, c as APP_SHELL_MESSAGES, d as APP_SHELL_NOTIFICATIONS, A as APP_SHELL_COMMANDS, a as APP_SHELL_CONTEXTS } from "../chunks/app-shell-mocks-kWIVSzLs.mjs";
13
+ const drawerFormStyles = tv({
14
+ slots: {
15
+ twoCols: "grid grid-cols-2 gap-gp-xl",
16
+ fieldLabel: "text-[12.5px] font-semibold tracking-[0.01em] leading-none text-fg-default dark:text-fg-muted select-none",
17
+ statusDot: "inline-block size-[8px] rounded-radius-full mr-gp-xs shrink-0"
18
+ }
19
+ });
20
+ const INITIAL_FORM = {
21
+ name: "",
22
+ email: "",
23
+ whatsapp: "",
24
+ statusId: "active",
25
+ categoryId: "lead",
26
+ city: "",
27
+ value: 0,
28
+ notes: ""
29
+ };
30
+ function NovoClienteDrawer({
31
+ open,
32
+ onOpenChange,
33
+ onSubmit
34
+ }) {
35
+ const s = drawerFormStyles();
36
+ const [form, setForm] = useState(INITIAL_FORM);
37
+ useEffect(() => {
38
+ if (open) setForm(INITIAL_FORM);
39
+ }, [open]);
40
+ const canSubmit = form.name.trim().length > 0;
41
+ const handleSubmit = () => {
42
+ if (!canSubmit) return;
43
+ onSubmit?.(form);
44
+ onOpenChange(false);
45
+ };
46
+ return /* @__PURE__ */ jsxs(
47
+ Panel,
48
+ {
49
+ open,
50
+ onOpenChange,
51
+ title: "Novo cliente",
52
+ side: "right",
53
+ size: "md",
54
+ footer: /* @__PURE__ */ jsxs(Fragment, { children: [
55
+ /* @__PURE__ */ jsx(
56
+ Button,
57
+ {
58
+ variant: "outline",
59
+ color: "secondary",
60
+ size: "md",
61
+ onClick: () => onOpenChange(false),
62
+ children: "Cancelar"
63
+ }
64
+ ),
65
+ /* @__PURE__ */ jsx(
66
+ Button,
67
+ {
68
+ variant: "filled",
69
+ color: "primary",
70
+ size: "md",
71
+ disabled: !canSubmit,
72
+ onClick: handleSubmit,
73
+ children: "Criar cliente"
74
+ }
75
+ )
76
+ ] }),
77
+ children: [
78
+ /* @__PURE__ */ jsx(
79
+ FormFieldInput,
80
+ {
81
+ label: "Nome",
82
+ required: true,
83
+ placeholder: "Maria Silva",
84
+ value: form.name,
85
+ onChange: (e) => setForm((f) => ({ ...f, name: e.target.value }))
86
+ }
87
+ ),
88
+ /* @__PURE__ */ jsxs("div", { className: s.twoCols(), children: [
89
+ /* @__PURE__ */ jsx(
90
+ FormFieldInput,
91
+ {
92
+ label: "Email",
93
+ type: "email",
94
+ placeholder: "cliente@exemplo.com",
95
+ value: form.email,
96
+ onChange: (e) => setForm((f) => ({ ...f, email: e.target.value }))
97
+ }
98
+ ),
99
+ /* @__PURE__ */ jsx(
100
+ FormFieldInput,
101
+ {
102
+ label: "WhatsApp",
103
+ type: "tel",
104
+ placeholder: "55 11 99999-9999",
105
+ value: form.whatsapp,
106
+ onChange: (e) => setForm((f) => ({ ...f, whatsapp: e.target.value }))
107
+ }
108
+ )
109
+ ] }),
110
+ /* @__PURE__ */ jsx(FormField, { label: "Status", children: () => /* @__PURE__ */ jsx(
111
+ ChipGroup,
112
+ {
113
+ type: "single",
114
+ value: form.statusId,
115
+ onValueChange: (v) => v && setForm((f) => ({
116
+ ...f,
117
+ statusId: v
118
+ })),
119
+ size: "md",
120
+ shape: "pill",
121
+ ariaLabel: "Status do cliente",
122
+ children: Object.entries(STATUSES).map(([id, st]) => /* @__PURE__ */ jsxs(ChipGroupItem, { value: id, children: [
123
+ /* @__PURE__ */ jsx(
124
+ "span",
125
+ {
126
+ className: s.statusDot(),
127
+ style: { background: STATUS_DOT[id] ?? st.color },
128
+ "aria-hidden": true
129
+ }
130
+ ),
131
+ st.label
132
+ ] }, id))
133
+ }
134
+ ) }),
135
+ /* @__PURE__ */ jsx(FormField, { label: "Categoria", children: () => /* @__PURE__ */ jsx(
136
+ ChipGroup,
137
+ {
138
+ type: "single",
139
+ value: form.categoryId,
140
+ onValueChange: (v) => v && setForm((f) => ({
141
+ ...f,
142
+ categoryId: v
143
+ })),
144
+ size: "md",
145
+ shape: "pill",
146
+ ariaLabel: "Categoria do cliente",
147
+ children: Object.entries(CATEGORIES).map(([id, cat]) => /* @__PURE__ */ jsx(ChipGroupItem, { value: id, children: cat.label }, id))
148
+ }
149
+ ) }),
150
+ /* @__PURE__ */ jsxs("div", { className: s.twoCols(), children: [
151
+ /* @__PURE__ */ jsx(
152
+ FormFieldSelect,
153
+ {
154
+ label: "Cidade",
155
+ placeholder: "Selecionar...",
156
+ value: form.city || void 0,
157
+ onValueChange: (v) => setForm((f) => ({ ...f, city: v })),
158
+ options: CITIES.map((c) => ({ value: c, label: c }))
159
+ }
160
+ ),
161
+ /* @__PURE__ */ jsx(
162
+ FormFieldInput,
163
+ {
164
+ label: "Valor (R$)",
165
+ type: "number",
166
+ startAddon: "R$",
167
+ value: String(form.value),
168
+ onChange: (e) => setForm((f) => ({ ...f, value: Number(e.target.value) })),
169
+ min: 0,
170
+ step: 0.01
171
+ }
172
+ )
173
+ ] }),
174
+ /* @__PURE__ */ jsx(
175
+ FormFieldTextarea,
176
+ {
177
+ label: "Notas",
178
+ placeholder: "Observações sobre o cliente...",
179
+ rows: 4,
180
+ value: form.notes,
181
+ onChange: (e) => setForm((f) => ({ ...f, notes: e.target.value }))
182
+ }
183
+ )
184
+ ]
185
+ }
186
+ );
187
+ }
188
+ const detailDrawerStyles = tv({
189
+ slots: {
190
+ section: "border-b border-border-default last:border-b-0",
191
+ sectionHead: [
192
+ "flex items-center justify-between w-full",
193
+ "px-[18px] py-[14px]",
194
+ "bg-transparent border-0 cursor-pointer text-left",
195
+ "text-[13px] font-semibold text-fg-default",
196
+ "transition-colors duration-150",
197
+ "hover:bg-bg-muted",
198
+ "focus-visible:outline-none focus-visible:bg-bg-muted"
199
+ ],
200
+ sectionChev: "size-[14px] text-fg-muted transition-transform duration-200",
201
+ sectionChevOpen: "rotate-180",
202
+ sectionBody: "flex flex-col gap-gp-md px-[18px] pb-pad-2xl",
203
+ field: "flex items-baseline justify-between gap-gp-md text-[13px]",
204
+ fieldLabel: "text-[12px] text-fg-muted shrink-0",
205
+ fieldValue: "text-fg-default text-right break-words min-w-0"
206
+ }
207
+ });
208
+ function formatLongDate(ms) {
209
+ if (!ms) return "—";
210
+ const d = new Date(ms);
211
+ return d.toLocaleDateString("pt-BR", {
212
+ day: "numeric",
213
+ month: "long",
214
+ year: "numeric"
215
+ });
216
+ }
217
+ function DetailField({ label, value, s }) {
218
+ return /* @__PURE__ */ jsxs("div", { className: s.field(), children: [
219
+ /* @__PURE__ */ jsx("span", { className: s.fieldLabel(), children: label }),
220
+ /* @__PURE__ */ jsx("span", { className: s.fieldValue(), children: value || "—" })
221
+ ] });
222
+ }
223
+ function DetailSection({
224
+ id,
225
+ title,
226
+ open,
227
+ onToggle,
228
+ children,
229
+ s
230
+ }) {
231
+ return /* @__PURE__ */ jsxs("section", { className: s.section(), children: [
232
+ /* @__PURE__ */ jsxs(
233
+ "button",
234
+ {
235
+ type: "button",
236
+ className: s.sectionHead(),
237
+ onClick: () => onToggle(id),
238
+ "aria-expanded": open,
239
+ children: [
240
+ /* @__PURE__ */ jsx("span", { children: title }),
241
+ /* @__PURE__ */ jsx(
242
+ ChevronDown,
243
+ {
244
+ className: [s.sectionChev(), open ? s.sectionChevOpen() : ""].join(" ")
245
+ }
246
+ )
247
+ ]
248
+ }
249
+ ),
250
+ open && /* @__PURE__ */ jsx("div", { className: s.sectionBody(), children })
251
+ ] });
252
+ }
253
+ function DetailDrawer({
254
+ row,
255
+ onClose,
256
+ onEdit,
257
+ onDelete,
258
+ onSave
259
+ }) {
260
+ const s = detailDrawerStyles();
261
+ const [openSections, setOpenSections] = useState(
262
+ () => /* @__PURE__ */ new Set(["contact", "meta", "notes"])
263
+ );
264
+ const toggle = (id) => {
265
+ setOpenSections((prev) => {
266
+ const next = new Set(prev);
267
+ if (next.has(id)) next.delete(id);
268
+ else next.add(id);
269
+ return next;
270
+ });
271
+ };
272
+ if (!row) return null;
273
+ const status = STATUSES[row.statusId];
274
+ const cat = CATEGORIES[row.categoryId];
275
+ const agent = AGENTS[row.agentId];
276
+ const agentInitials = agent?.name.split(" ").map((p) => p[0]).join("").slice(0, 2) ?? "?";
277
+ return /* @__PURE__ */ jsxs(
278
+ FloatingPanel,
279
+ {
280
+ open: row !== null,
281
+ onOpenChange: (open) => {
282
+ if (!open) onClose();
283
+ },
284
+ side: "right",
285
+ size: "md",
286
+ resizable: true,
287
+ maximizable: true,
288
+ resizableStorageKey: "clientes-showcase.detail-drawer.width",
289
+ titleSlot: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-gp-md min-w-0", children: [
290
+ /* @__PURE__ */ jsx(
291
+ Avatar,
292
+ {
293
+ className: "size-[40px] shrink-0",
294
+ style: { background: row.avatarColor },
295
+ children: /* @__PURE__ */ jsx(AvatarFallback, { className: "bg-transparent text-white text-[14px] font-bold", children: row.initials })
296
+ }
297
+ ),
298
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
299
+ /* @__PURE__ */ jsx("div", { className: "text-[15px] font-semibold text-fg-default whitespace-nowrap overflow-hidden text-ellipsis", children: row.name }),
300
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-[6px] mt-[2px] text-[12px] text-fg-muted", children: [
301
+ /* @__PURE__ */ jsx("span", { children: row.id }),
302
+ /* @__PURE__ */ jsx("span", { className: "opacity-50", children: "·" }),
303
+ /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-[6px]", children: [
304
+ /* @__PURE__ */ jsx(
305
+ "span",
306
+ {
307
+ className: "inline-block size-[8px] rounded-radius-full shrink-0",
308
+ style: { background: STATUS_DOT[row.statusId] ?? status?.color },
309
+ "aria-hidden": true
310
+ }
311
+ ),
312
+ status?.label
313
+ ] })
314
+ ] })
315
+ ] })
316
+ ] }),
317
+ headerActions: /* @__PURE__ */ jsxs(Fragment, { children: [
318
+ /* @__PURE__ */ jsx(
319
+ Button,
320
+ {
321
+ variant: "soft",
322
+ color: "secondary",
323
+ size: "icon-sm",
324
+ "aria-label": "Editar",
325
+ onClick: () => onEdit?.(row),
326
+ children: /* @__PURE__ */ jsx(Pencil, {})
327
+ }
328
+ ),
329
+ /* @__PURE__ */ jsx(
330
+ Button,
331
+ {
332
+ variant: "soft",
333
+ color: "critical",
334
+ size: "icon-sm",
335
+ "aria-label": "Excluir",
336
+ onClick: () => onDelete?.(row),
337
+ children: /* @__PURE__ */ jsx(Trash2, {})
338
+ }
339
+ )
340
+ ] }),
341
+ footer: /* @__PURE__ */ jsxs(Fragment, { children: [
342
+ /* @__PURE__ */ jsx(Button, { variant: "outline", color: "secondary", size: "sm", onClick: onClose, children: "Cancelar" }),
343
+ /* @__PURE__ */ jsx(
344
+ Button,
345
+ {
346
+ variant: "filled",
347
+ color: "primary",
348
+ size: "sm",
349
+ onClick: () => onSave?.(row),
350
+ children: "Salvar alterações"
351
+ }
352
+ )
353
+ ] }),
354
+ children: [
355
+ /* @__PURE__ */ jsxs(
356
+ DetailSection,
357
+ {
358
+ id: "contact",
359
+ title: "Contato",
360
+ open: openSections.has("contact"),
361
+ onToggle: toggle,
362
+ s,
363
+ children: [
364
+ /* @__PURE__ */ jsx(
365
+ DetailField,
366
+ {
367
+ label: "Email",
368
+ value: /* @__PURE__ */ jsx(
369
+ "a",
370
+ {
371
+ href: `mailto:${row.email}`,
372
+ className: "text-fg-brand hover:underline",
373
+ children: row.email
374
+ }
375
+ ),
376
+ s
377
+ }
378
+ ),
379
+ /* @__PURE__ */ jsx(
380
+ DetailField,
381
+ {
382
+ label: "Telefone",
383
+ value: /* @__PURE__ */ jsx(
384
+ "a",
385
+ {
386
+ href: `tel:${row.phone.replace(/\D/g, "")}`,
387
+ className: "text-fg-brand hover:underline",
388
+ children: row.phone
389
+ }
390
+ ),
391
+ s
392
+ }
393
+ ),
394
+ /* @__PURE__ */ jsx(DetailField, { label: "Localização", value: row.location, s })
395
+ ]
396
+ }
397
+ ),
398
+ /* @__PURE__ */ jsxs(
399
+ DetailSection,
400
+ {
401
+ id: "meta",
402
+ title: "Atendimento",
403
+ open: openSections.has("meta"),
404
+ onToggle: toggle,
405
+ s,
406
+ children: [
407
+ /* @__PURE__ */ jsx(DetailField, { label: "ID", value: row.id, s }),
408
+ /* @__PURE__ */ jsx(
409
+ DetailField,
410
+ {
411
+ label: "Categoria",
412
+ value: cat ? /* @__PURE__ */ jsx(
413
+ Chip,
414
+ {
415
+ color: CATEGORY_KIND[row.categoryId] ?? "info",
416
+ variant: "soft",
417
+ size: "sm",
418
+ shape: "pill",
419
+ children: cat.label
420
+ }
421
+ ) : "—",
422
+ s
423
+ }
424
+ ),
425
+ /* @__PURE__ */ jsx(
426
+ DetailField,
427
+ {
428
+ label: "Atribuído a",
429
+ value: agent ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-gp-sm", children: [
430
+ /* @__PURE__ */ jsx(
431
+ Avatar,
432
+ {
433
+ className: "size-[22px]",
434
+ style: { background: agent.color },
435
+ children: /* @__PURE__ */ jsx(AvatarFallback, { className: "bg-transparent text-white text-[10px] font-bold", children: agentInitials })
436
+ }
437
+ ),
438
+ agent.name
439
+ ] }) : "—",
440
+ s
441
+ }
442
+ ),
443
+ /* @__PURE__ */ jsx(DetailField, { label: "Valor", value: formatBRL(row.value), s }),
444
+ /* @__PURE__ */ jsx(DetailField, { label: "Criado em", value: formatLongDate(row.createdAt), s }),
445
+ /* @__PURE__ */ jsx(
446
+ DetailField,
447
+ {
448
+ label: "Último contato",
449
+ value: formatShortDate(row.lastContact),
450
+ s
451
+ }
452
+ )
453
+ ]
454
+ }
455
+ ),
456
+ /* @__PURE__ */ jsx(
457
+ DetailSection,
458
+ {
459
+ id: "notes",
460
+ title: "Anotações",
461
+ open: openSections.has("notes"),
462
+ onToggle: toggle,
463
+ s,
464
+ children: /* @__PURE__ */ jsx("p", { className: "text-[12.5px] text-fg-muted", children: "Sem anotações." })
465
+ }
466
+ )
467
+ ]
468
+ }
469
+ );
470
+ }
471
+ function buildColumns(handlers) {
472
+ return [
473
+ { field: "id", headerName: "ID", type: "text", width: 130 },
474
+ {
475
+ field: "name",
476
+ headerName: "Nome",
477
+ type: "user",
478
+ sortable: true,
479
+ width: 220,
480
+ typeOptions: {
481
+ users: Object.fromEntries(
482
+ CLIENTS_87.map((c) => [
483
+ c.name,
484
+ {
485
+ name: c.name,
486
+ initials: c.initials,
487
+ color: c.avatarColor
488
+ }
489
+ ])
490
+ )
491
+ },
492
+ valueGetter: (row) => row.name
493
+ },
494
+ {
495
+ field: "email",
496
+ headerName: "Email",
497
+ type: "email",
498
+ enableColumnFilter: true,
499
+ filterType: "text"
500
+ },
501
+ {
502
+ field: "phone",
503
+ headerName: "Telefone",
504
+ type: "phone"
505
+ },
506
+ {
507
+ field: "statusId",
508
+ headerName: "Status",
509
+ type: "status",
510
+ enableColumnFilter: true,
511
+ filterType: "multiSelect",
512
+ filterOptions: STATUS_OPTIONS
513
+ },
514
+ {
515
+ field: "categoryId",
516
+ headerName: "Categoria",
517
+ type: "badge",
518
+ enableColumnFilter: true,
519
+ filterType: "multiSelect",
520
+ filterOptions: CATEGORY_OPTIONS
521
+ },
522
+ {
523
+ field: "agentId",
524
+ headerName: "Atribuído",
525
+ type: "user",
526
+ enableColumnFilter: true,
527
+ filterType: "select",
528
+ filterOptions: AGENT_OPTIONS,
529
+ typeOptions: { users: AGENTS_LOOKUP }
530
+ },
531
+ {
532
+ field: "value",
533
+ headerName: "Valor",
534
+ type: "currency",
535
+ sortable: true,
536
+ enableColumnFilter: true,
537
+ filterType: "number",
538
+ aggregate: "sum",
539
+ aggregateFormatter: (v) => new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(v)
540
+ },
541
+ {
542
+ field: "createdAt",
543
+ headerName: "Criado em",
544
+ type: "date",
545
+ sortable: true,
546
+ enableColumnFilter: true,
547
+ filterType: "date",
548
+ width: 130
549
+ },
550
+ {
551
+ field: "lastContact",
552
+ headerName: "Último contato",
553
+ type: "date",
554
+ sortable: true,
555
+ width: 150
556
+ },
557
+ {
558
+ field: "location",
559
+ headerName: "Localização",
560
+ type: "text",
561
+ minWidth: 150
562
+ },
563
+ {
564
+ field: "_actions",
565
+ headerName: "",
566
+ type: "actions",
567
+ width: 64,
568
+ pinned: "right",
569
+ getActions: ({ row }) => [
570
+ {
571
+ id: "edit",
572
+ label: "Editar",
573
+ icon: /* @__PURE__ */ jsx(Pencil, {}),
574
+ showInMenu: true,
575
+ onClick: () => console.log("Editar", row.id)
576
+ },
577
+ {
578
+ id: "whatsapp",
579
+ label: "Abrir atendimento (WhatsApp)",
580
+ icon: /* @__PURE__ */ jsx(MessageSquare, {}),
581
+ showInMenu: true,
582
+ onClick: () => console.log("Atendimento", row.id)
583
+ },
584
+ {
585
+ id: "archive",
586
+ label: "Arquivar",
587
+ icon: /* @__PURE__ */ jsx(Archive, {}),
588
+ showInMenu: true,
589
+ onClick: () => console.log("Arquivar", row.id)
590
+ },
591
+ {
592
+ id: "delete",
593
+ label: "Excluir cliente",
594
+ icon: /* @__PURE__ */ jsx(Trash2, {}),
595
+ showInMenu: true,
596
+ destructive: true,
597
+ onClick: () => handlers.onAskDelete(row)
598
+ }
599
+ ]
600
+ }
601
+ ];
602
+ }
603
+ const DEFAULT_VIEWS = [
604
+ presetView({
605
+ id: "preset:meus",
606
+ name: "Meus",
607
+ filters: [{ field: "agentId", value: "you" }]
608
+ }),
609
+ presetView({
610
+ id: "preset:ativos",
611
+ name: "Ativos",
612
+ filters: [{ field: "statusId", value: "active" }]
613
+ }),
614
+ presetView({
615
+ id: "preset:royals",
616
+ name: "Royals",
617
+ filters: [{ field: "categoryId", value: "royal" }]
618
+ }),
619
+ presetView({
620
+ id: "preset:ultimos-7-dias",
621
+ name: "Últimos 7 dias",
622
+ sort: [{ field: "createdAt", direction: "desc" }]
623
+ })
624
+ ];
625
+ const INITIAL_FILTERS = {
626
+ items: [
627
+ { id: "filter-status-ativo", field: "statusId", operator: "equals", value: "active" },
628
+ { id: "filter-categoria-royal", field: "categoryId", operator: "equals", value: "royal" }
629
+ ],
630
+ logicOperator: "AND"
631
+ };
632
+ const KANBAN_CONFIG = {
633
+ groupByField: "statusId",
634
+ columns: KANBAN_COLUMNS,
635
+ renderCard: ({ row }) => {
636
+ const cat = CATEGORIES[row.categoryId];
637
+ const agent = AGENTS[row.agentId];
638
+ const agentInitials = agent?.name.split(" ").map((s) => s[0]).join("").slice(0, 2) ?? "?";
639
+ return {
640
+ title: row.name,
641
+ subtitle: row.id,
642
+ avatar: /* @__PURE__ */ jsx(Avatar, { className: "size-[28px]", style: { background: row.avatarColor }, children: /* @__PURE__ */ jsx(AvatarFallback, { className: "bg-transparent text-white text-[11px] font-bold", children: row.initials }) }),
643
+ chip: cat ? /* @__PURE__ */ jsx(
644
+ Chip,
645
+ {
646
+ color: CATEGORY_KIND[row.categoryId] ?? "info",
647
+ variant: "soft",
648
+ size: "sm",
649
+ shape: "pill",
650
+ children: cat.label
651
+ }
652
+ ) : null,
653
+ value: formatBRL(row.value),
654
+ footerLeft: agent ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-gp-sm min-w-0 flex-1", children: [
655
+ /* @__PURE__ */ jsx(Avatar, { className: "size-[22px]", style: { background: agent.color }, children: /* @__PURE__ */ jsx(AvatarFallback, { className: "bg-transparent text-white text-[10px] font-bold", children: agentInitials }) }),
656
+ /* @__PURE__ */ jsx("span", { className: "text-[12px] text-fg-muted whitespace-nowrap overflow-hidden text-ellipsis", children: agent.name })
657
+ ] }) : null,
658
+ footerRight: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-[4px] text-[11.5px] text-fg-muted [font-variant-numeric:tabular-nums] shrink-0", children: [
659
+ /* @__PURE__ */ jsx(Clock, { size: 11, strokeWidth: 1.8, "aria-hidden": true }),
660
+ formatShortDate(row.lastContact)
661
+ ] })
662
+ };
663
+ }
664
+ };
665
+ function ClientesShowcase() {
666
+ const { theme, setTheme } = useTheme();
667
+ const [rows, setRows] = useState(() => CLIENTS_87);
668
+ const [layout, setLayout] = useState("fluid");
669
+ const [filterModel, setFilterModel] = useState(INITIAL_FILTERS);
670
+ const [viewMode, setViewMode] = useState("table");
671
+ const [novoClienteOpen, setNovoClienteOpen] = useState(false);
672
+ const [detailRowId, setDetailRowId] = useState(null);
673
+ const [confirmDelete, setConfirmDelete] = useState(null);
674
+ const detailRow = detailRowId ? rows.find((r) => r.id === detailRowId) ?? null : null;
675
+ const tableRef = useRef(null);
676
+ const askDelete = useCallback(
677
+ (row) => setConfirmDelete({ ids: [row.id], label: row.name }),
678
+ []
679
+ );
680
+ const askBulkDelete = useCallback(
681
+ (ids, onAfter) => setConfirmDelete({
682
+ ids,
683
+ label: `${ids.length} cliente${ids.length === 1 ? "" : "s"}`,
684
+ onAfter
685
+ }),
686
+ []
687
+ );
688
+ const handleConfirmDelete = useCallback(() => {
689
+ if (!confirmDelete) return;
690
+ const ids = new Set(confirmDelete.ids);
691
+ setRows((prev) => prev.filter((r) => !ids.has(r.id)));
692
+ if (detailRowId && ids.has(detailRowId)) setDetailRowId(null);
693
+ confirmDelete.onAfter?.();
694
+ setConfirmDelete(null);
695
+ }, [confirmDelete, detailRowId]);
696
+ const columns = useMemo(
697
+ () => buildColumns({ onAskDelete: askDelete }),
698
+ [askDelete]
699
+ );
700
+ return /* @__PURE__ */ jsxs(
701
+ AppShell,
702
+ {
703
+ contexts: APP_SHELL_CONTEXTS,
704
+ defaultActiveContextId: "inbox",
705
+ defaultActiveItemHref: "#atendimentos",
706
+ breadcrumb: [{ label: "Atendimentos" }],
707
+ commandGroups: APP_SHELL_COMMANDS,
708
+ notifications: {
709
+ items: APP_SHELL_NOTIFICATIONS,
710
+ onMarkAllRead: () => alert("Marcar todas como lidas"),
711
+ onMoreActions: () => alert("Mais ações"),
712
+ onViewAll: () => alert("Ver todas")
713
+ },
714
+ messages: {
715
+ items: APP_SHELL_MESSAGES,
716
+ onNewMessage: () => alert("Nova mensagem"),
717
+ onExpand: () => alert("Expandir"),
718
+ onViewAll: () => alert("Ver todas")
719
+ },
720
+ theme,
721
+ onThemeChange: (id) => setTheme(id),
722
+ themeOptions: APP_SHELL_THEME_OPTIONS,
723
+ user: APP_SHELL_USER,
724
+ layout,
725
+ onLayoutChange: setLayout,
726
+ layoutOptions: APP_SHELL_LAYOUT_OPTIONS,
727
+ onSettings: () => alert("Abrir Configurações"),
728
+ onLogout: () => alert("Sair (mock)"),
729
+ children: [
730
+ /* @__PURE__ */ jsx(
731
+ PageHeader,
732
+ {
733
+ title: "Clientes",
734
+ description: "Gerencie sua base de clientes, acompanhe status de cadastro e abra atendimentos diretos pelo WhatsApp.",
735
+ badge: /* @__PURE__ */ jsxs(Chip, { color: "primary", variant: "soft", size: "sm", shape: "rounded", children: [
736
+ rows.length.toLocaleString("pt-BR"),
737
+ " registros"
738
+ ] }),
739
+ actions: /* @__PURE__ */ jsxs(Fragment, { children: [
740
+ /* @__PURE__ */ jsx(
741
+ Button,
742
+ {
743
+ variant: "outline",
744
+ color: "secondary",
745
+ size: "icon-md",
746
+ "aria-label": "Mais ações",
747
+ onClick: () => alert("Mais ações"),
748
+ children: /* @__PURE__ */ jsx(MoreHorizontal, {})
749
+ }
750
+ ),
751
+ /* @__PURE__ */ jsx(
752
+ Button,
753
+ {
754
+ variant: "filled",
755
+ color: "primary",
756
+ size: "md",
757
+ iconLeft: /* @__PURE__ */ jsx(Plus, {}),
758
+ onClick: () => setNovoClienteOpen(true),
759
+ children: "Novo cliente"
760
+ }
761
+ )
762
+ ] })
763
+ }
764
+ ),
765
+ /* @__PURE__ */ jsx(
766
+ DataTable,
767
+ {
768
+ ref: tableRef,
769
+ rows,
770
+ columns,
771
+ getRowId: (r) => r.id,
772
+ persistId: "showcase-clientes-crud",
773
+ defaultViews: DEFAULT_VIEWS,
774
+ filterModel,
775
+ onFilterModelChange: setFilterModel,
776
+ viewMode,
777
+ onViewModeChange: setViewMode,
778
+ kanbanConfig: KANBAN_CONFIG,
779
+ toolbar: {
780
+ enableSearch: true,
781
+ enableFilters: true,
782
+ enableColumns: true,
783
+ enableDensity: true,
784
+ enableExport: true,
785
+ moreMenu: {
786
+ items: [
787
+ {
788
+ id: "fullscreen",
789
+ label: "Tela cheia",
790
+ icon: /* @__PURE__ */ jsx(Maximize2, {}),
791
+ onSelect: () => alert("Tela cheia")
792
+ },
793
+ {
794
+ id: "duplicate",
795
+ label: "Duplicar visualização",
796
+ icon: /* @__PURE__ */ jsx(Copy, {}),
797
+ onSelect: () => alert("Duplicar visualização")
798
+ },
799
+ {
800
+ id: "import",
801
+ label: "Importar CSV",
802
+ icon: /* @__PURE__ */ jsx(Upload, {}),
803
+ onSelect: () => alert("Importar CSV")
804
+ },
805
+ {
806
+ id: "reset",
807
+ label: "Resetar visualização",
808
+ icon: /* @__PURE__ */ jsx(RotateCcw, {}),
809
+ destructive: true,
810
+ onSelect: () => tableRef.current?.resetPersistedState()
811
+ }
812
+ ]
813
+ }
814
+ },
815
+ paginationConfig: {
816
+ enabled: true,
817
+ initialPageSize: 10,
818
+ pageSizeOptions: [10, 25, 50, 100]
819
+ },
820
+ selectionConfig: {
821
+ enabled: true,
822
+ enableGlobal: true,
823
+ actions: (selectedIds, clearSelection) => /* @__PURE__ */ jsxs(Fragment, { children: [
824
+ /* @__PURE__ */ jsx(
825
+ BulkActionButton,
826
+ {
827
+ icon: /* @__PURE__ */ jsx(Download, {}),
828
+ onClick: () => tableRef.current?.exportCsv("selected"),
829
+ children: "Exportar"
830
+ }
831
+ ),
832
+ /* @__PURE__ */ jsx(
833
+ BulkActionButton,
834
+ {
835
+ icon: /* @__PURE__ */ jsx(Trash2, {}),
836
+ variant: "danger",
837
+ onClick: () => askBulkDelete(selectedIds.map(String), clearSelection),
838
+ children: "Excluir"
839
+ }
840
+ )
841
+ ] })
842
+ },
843
+ onCellEditCommit: async ({ id, field, value }) => {
844
+ await new Promise((res) => setTimeout(res, 400));
845
+ setRows(
846
+ (prev) => prev.map((r) => r.id === id ? { ...r, [field]: value } : r)
847
+ );
848
+ },
849
+ onRowClick: (row) => setDetailRowId(row.id),
850
+ className: "flex-1 min-h-0"
851
+ }
852
+ ),
853
+ /* @__PURE__ */ jsx(
854
+ NovoClienteDrawer,
855
+ {
856
+ open: novoClienteOpen,
857
+ onOpenChange: setNovoClienteOpen,
858
+ onSubmit: (data) => {
859
+ console.log("Novo cliente:", data);
860
+ alert(`Cliente "${data.name}" criado (mock)`);
861
+ }
862
+ }
863
+ ),
864
+ /* @__PURE__ */ jsx(
865
+ DetailDrawer,
866
+ {
867
+ row: detailRow,
868
+ onClose: () => setDetailRowId(null),
869
+ onEdit: (r) => console.log("Editar", r.id),
870
+ onDelete: (r) => askDelete(r),
871
+ onSave: (r) => alert(`Salvar alterações em ${r.name} (mock)`)
872
+ }
873
+ ),
874
+ /* @__PURE__ */ jsx(
875
+ AlertModal,
876
+ {
877
+ open: confirmDelete !== null,
878
+ onOpenChange: (open) => {
879
+ if (!open) setConfirmDelete(null);
880
+ },
881
+ tone: "danger",
882
+ title: confirmDelete && confirmDelete.ids.length > 1 ? `Excluir ${confirmDelete.label}?` : "Excluir cliente?",
883
+ description: confirmDelete ? confirmDelete.ids.length > 1 ? `Esta ação não pode ser desfeita. ${confirmDelete.label} serão removidos permanentemente.` : `Esta ação não pode ser desfeita. "${confirmDelete.label}" será removido permanentemente.` : null,
884
+ confirmLabel: "Excluir",
885
+ cancelLabel: "Cancelar",
886
+ onConfirm: handleConfirmDelete
887
+ }
888
+ )
889
+ ]
890
+ }
891
+ );
892
+ }
893
+ export {
894
+ ClientesShowcase,
895
+ ClientesShowcase as default
896
+ };
897
+ //# sourceMappingURL=clientes.mjs.map