@fayz-ai/plugin-support 0.0.0-stage → 0.2.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 (59) hide show
  1. package/LICENSE +21 -0
  2. package/dist/HelpdeskConsole-7W5IAQIU.js +355 -0
  3. package/dist/HelpdeskConsole-7W5IAQIU.js.map +1 -0
  4. package/dist/SupportCenter-Z2HEPJGD.js +1090 -0
  5. package/dist/SupportCenter-Z2HEPJGD.js.map +1 -0
  6. package/dist/chunk-5K7VA5VP.js +106 -0
  7. package/dist/chunk-5K7VA5VP.js.map +1 -0
  8. package/dist/chunk-7NVBUXTX.js +300 -0
  9. package/dist/chunk-7NVBUXTX.js.map +1 -0
  10. package/dist/chunk-JJPB2T3Z.js +131 -0
  11. package/dist/chunk-JJPB2T3Z.js.map +1 -0
  12. package/dist/components/HelpdeskStatusPanel.d.ts +12 -0
  13. package/dist/components/HelpdeskStatusPanel.d.ts.map +1 -0
  14. package/dist/data/api.d.ts +15 -0
  15. package/dist/data/api.d.ts.map +1 -0
  16. package/dist/data/console.d.ts +37 -0
  17. package/dist/data/console.d.ts.map +1 -0
  18. package/dist/index.d.ts +19 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +901 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/lib/content.d.ts +24 -0
  23. package/dist/lib/content.d.ts.map +1 -0
  24. package/dist/lib/fix-prompt.d.ts +30 -0
  25. package/dist/lib/fix-prompt.d.ts.map +1 -0
  26. package/dist/lib/report-tool.d.ts +25 -0
  27. package/dist/lib/report-tool.d.ts.map +1 -0
  28. package/dist/lib/vocabulary.d.ts +34 -0
  29. package/dist/lib/vocabulary.d.ts.map +1 -0
  30. package/dist/locales/en.d.ts +2 -0
  31. package/dist/locales/en.d.ts.map +1 -0
  32. package/dist/locales/index.d.ts +2 -0
  33. package/dist/locales/index.d.ts.map +1 -0
  34. package/dist/locales/pt-BR.d.ts +2 -0
  35. package/dist/locales/pt-BR.d.ts.map +1 -0
  36. package/dist/migrations/index.d.ts +9 -0
  37. package/dist/migrations/index.d.ts.map +1 -0
  38. package/dist/store.d.ts +27 -0
  39. package/dist/store.d.ts.map +1 -0
  40. package/dist/types.d.ts +80 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/dist/views/HelpdeskConsole.d.ts +10 -0
  43. package/dist/views/HelpdeskConsole.d.ts.map +1 -0
  44. package/dist/views/ScreenCaptureEditor.d.ts +12 -0
  45. package/dist/views/ScreenCaptureEditor.d.ts.map +1 -0
  46. package/dist/views/SupportCenter.d.ts +14 -0
  47. package/dist/views/SupportCenter.d.ts.map +1 -0
  48. package/dist/views/SupportMenu.d.ts +12 -0
  49. package/dist/views/SupportMenu.d.ts.map +1 -0
  50. package/dist/views/SupportRequestDetail.d.ts +6 -0
  51. package/dist/views/SupportRequestDetail.d.ts.map +1 -0
  52. package/dist/views/SupportRequestForm.d.ts +12 -0
  53. package/dist/views/SupportRequestForm.d.ts.map +1 -0
  54. package/dist/views/SupportRequestsPanel.d.ts +11 -0
  55. package/dist/views/SupportRequestsPanel.d.ts.map +1 -0
  56. package/dist/views/TicketDetailPage.d.ts +12 -0
  57. package/dist/views/TicketDetailPage.d.ts.map +1 -0
  58. package/package.json +56 -3
  59. package/README.md +0 -3
@@ -0,0 +1,1090 @@
1
+ import { toEmbedUrl, useSupportStore } from './chunk-JJPB2T3Z.js';
2
+ import { KIND_LABEL, STATUS_LABEL, STATUS_TONE, canValidate, canMessage, canCancel, eventLine, FILTER_LABEL, signedUrl, DOORS, FORM_COPY, MAX_ATTACHMENTS } from './chunk-7NVBUXTX.js';
3
+ import React from 'react';
4
+ import { Input, Button, ModalTask, Badge, SubpageHeader, Textarea, ICON_MAP, SegmentedControl, Skeleton, Thumbnail, Separator, Takeover } from '@fayz-ai/ui';
5
+ import { useChatStore, useTenantOptional, useAuth, useHasPermission } from '@fayz-ai/admin';
6
+ import { useConnectivity } from '@fayz-ai/core';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
+
9
+ function Row({ icon, title, hint, onClick }) {
10
+ const Icon2 = ICON_MAP[icon] ?? ICON_MAP.HelpCircle;
11
+ return /* @__PURE__ */ jsxs(
12
+ "button",
13
+ {
14
+ onClick,
15
+ className: "flex w-full items-center gap-3 rounded-xl border bg-card p-3 text-left transition-colors hover:bg-accent",
16
+ children: [
17
+ /* @__PURE__ */ jsx("span", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-warning-soft text-warning-soft-foreground", children: Icon2 && /* @__PURE__ */ jsx(Icon2, { className: "h-5 w-5" }) }),
18
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
19
+ /* @__PURE__ */ jsx("span", { className: "block text-sm font-semibold", children: title }),
20
+ /* @__PURE__ */ jsx("span", { className: "block truncate text-xs text-muted-foreground", children: hint })
21
+ ] }),
22
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u203A" })
23
+ ]
24
+ }
25
+ );
26
+ }
27
+ function SupportMenu({ onPickKind, onAskDico, onOpenList, unread = 0 }) {
28
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
29
+ /* @__PURE__ */ jsxs("div", { children: [
30
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold", children: "Em que podemos ajudar?" }),
31
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Escolha o tipo de ajuda." })
32
+ ] }),
33
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
34
+ onAskDico && /* @__PURE__ */ jsx(Row, { icon: "HelpCircle", title: "Tirar d\xFAvidas", hint: "Pergunte sobre qualquer parte do sistema", onClick: onAskDico }),
35
+ DOORS.map((d) => /* @__PURE__ */ jsx(Row, { icon: d.icon, title: d.title, hint: d.hint, onClick: () => onPickKind(d.kind) }, d.kind))
36
+ ] }),
37
+ onOpenList && /* @__PURE__ */ jsxs("button", { onClick: onOpenList, className: "flex items-center gap-2 pt-1 text-sm text-muted-foreground hover:text-foreground", children: [
38
+ /* @__PURE__ */ jsx("span", { children: "Minhas solicita\xE7\xF5es" }),
39
+ unread > 0 && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-warning px-1.5 text-[10px] font-semibold text-warning-foreground", children: unread })
40
+ ] })
41
+ ] });
42
+ }
43
+ var PIXEL = 12;
44
+ function ScreenCaptureEditor({ open, onClose, onUse, initialFile, autoStart }) {
45
+ const canvasRef = React.useRef(null);
46
+ const baseRef = React.useRef(null);
47
+ const [hasImage, setHasImage] = React.useState(false);
48
+ const [rects, setRects] = React.useState([]);
49
+ const [drag, setDrag] = React.useState(null);
50
+ const [error, setError] = React.useState(null);
51
+ const [busy, setBusy] = React.useState(false);
52
+ const reset = React.useCallback(() => {
53
+ setHasImage(false);
54
+ setRects([]);
55
+ setDrag(null);
56
+ setError(null);
57
+ baseRef.current = null;
58
+ }, []);
59
+ React.useEffect(() => {
60
+ if (!open) {
61
+ reset();
62
+ return;
63
+ }
64
+ if (initialFile) void loadFromBlob(initialFile);
65
+ else if (autoStart) void capture(autoStart === "tab");
66
+ }, [open, initialFile, autoStart]);
67
+ async function loadFromBlob(blob) {
68
+ try {
69
+ const bitmap = await createImageBitmap(blob);
70
+ const base = document.createElement("canvas");
71
+ base.width = bitmap.width;
72
+ base.height = bitmap.height;
73
+ base.getContext("2d").drawImage(bitmap, 0, 0);
74
+ baseRef.current = base;
75
+ setRects([]);
76
+ setHasImage(true);
77
+ setError(null);
78
+ requestAnimationFrame(redraw);
79
+ } catch {
80
+ setError("N\xE3o consegui abrir esta imagem.");
81
+ }
82
+ }
83
+ async function capture(preferCurrentTab) {
84
+ setError(null);
85
+ setBusy(true);
86
+ try {
87
+ const md = navigator.mediaDevices;
88
+ if (!md?.getDisplayMedia) {
89
+ setError('Seu navegador n\xE3o permite capturar a tela aqui. Use "Arquivo".');
90
+ return;
91
+ }
92
+ const stream = await md.getDisplayMedia(
93
+ preferCurrentTab ? { video: { displaySurface: "browser" }, preferCurrentTab: true } : { video: true }
94
+ );
95
+ const track = stream.getVideoTracks()[0];
96
+ const video = document.createElement("video");
97
+ video.srcObject = stream;
98
+ await video.play();
99
+ await new Promise((r) => setTimeout(r, 180));
100
+ const base = document.createElement("canvas");
101
+ base.width = video.videoWidth;
102
+ base.height = video.videoHeight;
103
+ base.getContext("2d").drawImage(video, 0, 0);
104
+ track.stop();
105
+ baseRef.current = base;
106
+ setRects([]);
107
+ setHasImage(true);
108
+ requestAnimationFrame(redraw);
109
+ } catch (e) {
110
+ if (e?.name !== "NotAllowedError") setError("N\xE3o consegui capturar a tela.");
111
+ } finally {
112
+ setBusy(false);
113
+ }
114
+ }
115
+ function redraw() {
116
+ const base = baseRef.current, canvas = canvasRef.current;
117
+ if (!base || !canvas) return;
118
+ canvas.width = base.width;
119
+ canvas.height = base.height;
120
+ const ctx = canvas.getContext("2d");
121
+ ctx.drawImage(base, 0, 0);
122
+ for (const r of rects) pixelate(ctx, r);
123
+ if (drag) {
124
+ ctx.strokeStyle = "#111";
125
+ ctx.lineWidth = 2;
126
+ ctx.setLineDash([6, 4]);
127
+ ctx.strokeRect(drag.x, drag.y, drag.w, drag.h);
128
+ ctx.setLineDash([]);
129
+ }
130
+ }
131
+ React.useEffect(() => {
132
+ redraw();
133
+ });
134
+ function pixelate(ctx, r) {
135
+ const { x, y, w, h } = normalize(r);
136
+ if (w < 2 || h < 2) return;
137
+ const sw = Math.max(1, Math.floor(w / PIXEL)), sh = Math.max(1, Math.floor(h / PIXEL));
138
+ const tmp = document.createElement("canvas");
139
+ tmp.width = sw;
140
+ tmp.height = sh;
141
+ const tctx = tmp.getContext("2d");
142
+ tctx.drawImage(ctx.canvas, x, y, w, h, 0, 0, sw, sh);
143
+ ctx.imageSmoothingEnabled = false;
144
+ ctx.drawImage(tmp, 0, 0, sw, sh, x, y, w, h);
145
+ ctx.imageSmoothingEnabled = true;
146
+ }
147
+ function normalize(r) {
148
+ return { x: Math.min(r.x, r.x + r.w), y: Math.min(r.y, r.y + r.h), w: Math.abs(r.w), h: Math.abs(r.h) };
149
+ }
150
+ function toCanvasXY(e) {
151
+ const canvas = canvasRef.current;
152
+ const rect = canvas.getBoundingClientRect();
153
+ return { x: (e.clientX - rect.left) * (canvas.width / rect.width), y: (e.clientY - rect.top) * (canvas.height / rect.height) };
154
+ }
155
+ async function finish() {
156
+ const canvas = canvasRef.current;
157
+ if (!canvas) return;
158
+ const blob = await new Promise((res) => canvas.toBlob(res, "image/png"));
159
+ if (!blob) {
160
+ setError("N\xE3o consegui gerar a imagem.");
161
+ return;
162
+ }
163
+ const file = new File([blob], `captura-${Date.now()}.png`, { type: "image/png" });
164
+ onUse(file, URL.createObjectURL(blob));
165
+ onClose();
166
+ }
167
+ return /* @__PURE__ */ jsx(Takeover, { open, onClose, label: "Capturar a tela", closeLabel: "Descartar captura", children: /* @__PURE__ */ jsx("div", { className: "mx-auto flex h-full w-full max-w-5xl flex-col gap-4 p-4", children: !hasImage ? /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-4 text-center", children: [
168
+ /* @__PURE__ */ jsx("p", { className: "max-w-md text-sm text-muted-foreground", children: "Fotografe a tela do sistema para anexar \xE0 solicita\xE7\xE3o. No pr\xF3ximo passo voc\xEA borra nomes, telefones ou valores que n\xE3o precisam ir para o suporte." }),
169
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-center gap-2", children: [
170
+ /* @__PURE__ */ jsx(Button, { onClick: () => capture(true), disabled: busy, children: "Capturar esta tela" }),
171
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => capture(false), disabled: busy, children: "Outra janela" })
172
+ ] }),
173
+ error && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: error })
174
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
175
+ /* @__PURE__ */ jsxs("div", { children: [
176
+ /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold", children: "Esconder informa\xE7\xF5es antes de enviar" }),
177
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Arraste sobre nomes, telefones ou valores que n\xE3o precisam ir para o suporte. Eles saem borrados na imagem." })
178
+ ] }),
179
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto rounded-lg border bg-muted/30 p-2", children: /* @__PURE__ */ jsx(
180
+ "canvas",
181
+ {
182
+ ref: canvasRef,
183
+ className: "mx-auto block max-w-full cursor-crosshair touch-none",
184
+ onPointerDown: (e) => {
185
+ e.target.setPointerCapture(e.pointerId);
186
+ const p = toCanvasXY(e);
187
+ setDrag({ x: p.x, y: p.y, w: 0, h: 0 });
188
+ },
189
+ onPointerMove: (e) => {
190
+ if (!drag) return;
191
+ const p = toCanvasXY(e);
192
+ setDrag({ ...drag, w: p.x - drag.x, h: p.y - drag.y });
193
+ },
194
+ onPointerUp: () => {
195
+ if (drag) {
196
+ setRects((rs) => [...rs, normalize(drag)]);
197
+ setDrag(null);
198
+ }
199
+ }
200
+ }
201
+ ) }),
202
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
203
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
204
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: () => setRects((rs) => rs.slice(0, -1)), disabled: !rects.length, children: "Desfazer" }),
205
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: () => setRects([]), disabled: !rects.length, children: "Limpar" })
206
+ ] }),
207
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
208
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: onClose, children: "Descartar captura" }),
209
+ /* @__PURE__ */ jsx(Button, { onClick: finish, children: "Usar esta imagem" })
210
+ ] })
211
+ ] }),
212
+ error && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: error })
213
+ ] }) }) });
214
+ }
215
+ var MIN_DESCRIPTION = 5;
216
+ function SupportRequestForm({ kind, onDone, onBack }) {
217
+ const copy = FORM_COPY[kind];
218
+ const create = useSupportStore((s) => s.create);
219
+ const [description, setDescription] = React.useState("");
220
+ const [subject, setSubject] = React.useState("");
221
+ const [pending, setPending] = React.useState([]);
222
+ const [submitting, setSubmitting] = React.useState(false);
223
+ const [error, setError] = React.useState(null);
224
+ const [capture, setCapture] = React.useState(null);
225
+ const fileRef = React.useRef(null);
226
+ const canSubmit = description.trim().length >= MIN_DESCRIPTION && !submitting;
227
+ const full = pending.length >= MAX_ATTACHMENTS;
228
+ React.useEffect(() => () => pending.forEach((p) => p.previewUrl && URL.revokeObjectURL(p.previewUrl)), [pending]);
229
+ function addFile(file, previewUrl) {
230
+ setPending((ps) => ps.length >= MAX_ATTACHMENTS ? ps : [...ps, {
231
+ id: crypto.randomUUID(),
232
+ file,
233
+ name: file.name,
234
+ contentType: file.type || "application/octet-stream",
235
+ sizeBytes: file.size,
236
+ previewUrl: previewUrl ?? (file.type.startsWith("image/") ? URL.createObjectURL(file) : void 0)
237
+ }]);
238
+ }
239
+ function onPaste(e) {
240
+ const img = Array.from(e.clipboardData.files).find((f) => f.type.startsWith("image/"));
241
+ if (img) {
242
+ e.preventDefault();
243
+ setCapture({ mode: null, file: img });
244
+ }
245
+ }
246
+ async function submit() {
247
+ setSubmitting(true);
248
+ setError(null);
249
+ try {
250
+ const result = await create(
251
+ {
252
+ kind,
253
+ description,
254
+ subject: subject.trim() || null,
255
+ route: typeof location !== "undefined" ? location.hash || location.pathname : null,
256
+ screenSnapshot: snapshot()
257
+ },
258
+ pending
259
+ );
260
+ onDone(result);
261
+ } catch (e) {
262
+ setError(e?.message ?? "N\xE3o consegui enviar a solicita\xE7\xE3o.");
263
+ } finally {
264
+ setSubmitting(false);
265
+ }
266
+ }
267
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
268
+ /* @__PURE__ */ jsx(SubpageHeader, { title: copy.title, subtitle: copy.intro, onBack, parentLabel: "Suporte" }),
269
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
270
+ /* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Descri\xE7\xE3o" }),
271
+ /* @__PURE__ */ jsx(
272
+ Textarea,
273
+ {
274
+ rows: 5,
275
+ value: description,
276
+ onChange: (e) => setDescription(e.target.value),
277
+ onPaste,
278
+ placeholder: "O que voc\xEA estava fazendo, o que esperava que acontecesse e o que apareceu?"
279
+ }
280
+ ),
281
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
282
+ "Pode falar em vez de escrever, ou colar um print aqui. M\xEDnimo de ",
283
+ MIN_DESCRIPTION,
284
+ " caracteres."
285
+ ] })
286
+ ] }),
287
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
288
+ /* @__PURE__ */ jsxs("label", { className: "text-sm font-medium", children: [
289
+ "Assunto ",
290
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "(opcional)" })
291
+ ] }),
292
+ /* @__PURE__ */ jsx(Input, { value: subject, onChange: (e) => setSubject(e.target.value), placeholder: copy.subjectPlaceholder, maxLength: 200 })
293
+ ] }),
294
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
295
+ /* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Anexos" }),
296
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
297
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", disabled: full, onClick: () => setCapture({ mode: "tab", file: null }), children: "Capturar esta tela" }),
298
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", disabled: full, onClick: () => setCapture({ mode: "window", file: null }), children: "Outra janela" }),
299
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", disabled: full, onClick: () => fileRef.current?.click(), children: "Arquivo" }),
300
+ /* @__PURE__ */ jsx(
301
+ "input",
302
+ {
303
+ ref: fileRef,
304
+ type: "file",
305
+ className: "hidden",
306
+ accept: "image/*,application/pdf,text/plain,text/csv,audio/*,video/mp4,video/webm",
307
+ onChange: (e) => {
308
+ const f = e.target.files?.[0];
309
+ if (f) addFile(f);
310
+ e.target.value = "";
311
+ }
312
+ }
313
+ )
314
+ ] }),
315
+ full && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
316
+ "No m\xE1ximo ",
317
+ MAX_ATTACHMENTS,
318
+ " anexos por solicita\xE7\xE3o."
319
+ ] }),
320
+ pending.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: pending.map((p) => /* @__PURE__ */ jsxs("div", { className: "relative flex items-center gap-2 rounded-lg border bg-card p-2 pr-7", children: [
321
+ p.previewUrl ? /* @__PURE__ */ jsx(Thumbnail, { src: p.previewUrl, alt: p.name, className: "h-10 w-10 rounded object-cover" }) : /* @__PURE__ */ jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded bg-muted text-xs text-muted-foreground", children: "arq" }),
322
+ /* @__PURE__ */ jsx("span", { className: "max-w-[12rem] truncate text-xs", children: p.name }),
323
+ /* @__PURE__ */ jsx(
324
+ "button",
325
+ {
326
+ "aria-label": "Remover anexo",
327
+ className: "absolute right-1 top-1 rounded p-0.5 text-muted-foreground hover:bg-muted",
328
+ onClick: () => setPending((ps) => ps.filter((x) => x.id !== p.id)),
329
+ children: "\xD7"
330
+ }
331
+ )
332
+ ] }, p.id)) })
333
+ ] }),
334
+ error && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: error }),
335
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 pt-2", children: [
336
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: onBack, children: "Voltar" }),
337
+ /* @__PURE__ */ jsx(Button, { onClick: submit, disabled: !canSubmit, children: submitting ? "Enviando\u2026" : "Enviar solicita\xE7\xE3o" })
338
+ ] }),
339
+ /* @__PURE__ */ jsx(
340
+ ScreenCaptureEditor,
341
+ {
342
+ open: !!capture,
343
+ autoStart: capture?.mode ?? null,
344
+ initialFile: capture?.file ?? null,
345
+ onClose: () => setCapture(null),
346
+ onUse: (file, previewUrl) => addFile(file, previewUrl)
347
+ }
348
+ )
349
+ ] });
350
+ }
351
+ function snapshot() {
352
+ if (typeof window === "undefined") return {};
353
+ return {
354
+ url: location.href,
355
+ hash: location.hash,
356
+ title: document.title,
357
+ viewport: { w: window.innerWidth, h: window.innerHeight },
358
+ at: (/* @__PURE__ */ new Date()).toISOString()
359
+ };
360
+ }
361
+ function SupportRequestDetail({ onBack }) {
362
+ const detail = useSupportStore((s) => s.detail);
363
+ const loading = useSupportStore((s) => s.loadingDetail);
364
+ const sendMessage = useSupportStore((s) => s.sendMessage);
365
+ const cancel = useSupportStore((s) => s.cancel);
366
+ const validate = useSupportStore((s) => s.validate);
367
+ const [message, setMessage] = React.useState("");
368
+ const [sending, setSending] = React.useState(false);
369
+ const [confirmingCancel, setConfirmingCancel] = React.useState(false);
370
+ const [reopenReason, setReopenReason] = React.useState("");
371
+ const [reopening, setReopening] = React.useState(false);
372
+ React.useEffect(() => {
373
+ setMessage("");
374
+ setConfirmingCancel(false);
375
+ setReopenReason("");
376
+ setReopening(false);
377
+ }, [detail?.id]);
378
+ if (loading && !detail) {
379
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3 p-4", children: [
380
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-48" }),
381
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-24 w-full" }),
382
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-16 w-full" })
383
+ ] });
384
+ }
385
+ if (!detail) {
386
+ return /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center p-8 text-center text-sm text-muted-foreground", children: "Escolha uma solicita\xE7\xE3o para ver a conversa com a equipe." });
387
+ }
388
+ async function send() {
389
+ if (!message.trim()) return;
390
+ setSending(true);
391
+ try {
392
+ await sendMessage(message);
393
+ setMessage("");
394
+ } finally {
395
+ setSending(false);
396
+ }
397
+ }
398
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col", children: [
399
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3 border-b p-4", children: [
400
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
401
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
402
+ onBack && /* @__PURE__ */ jsx("button", { className: "rounded px-1 hover:bg-muted lg:hidden", onClick: onBack, "aria-label": "Voltar \xE0 lista", children: "\u2190" }),
403
+ /* @__PURE__ */ jsxs("span", { children: [
404
+ "#",
405
+ detail.number,
406
+ " \xB7 ",
407
+ KIND_LABEL[detail.kind],
408
+ " \xB7 aberta em ",
409
+ fmtDate(detail.createdAt)
410
+ ] })
411
+ ] }),
412
+ /* @__PURE__ */ jsx("h2", { className: "mt-1 truncate text-base font-semibold", children: detail.subject || KIND_LABEL[detail.kind] })
413
+ ] }),
414
+ /* @__PURE__ */ jsx(Badge, { variant: STATUS_TONE[detail.status], children: STATUS_LABEL[detail.status] })
415
+ ] }),
416
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto p-4", children: [
417
+ /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-3 text-sm whitespace-pre-wrap", children: detail.description }),
418
+ detail.attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: detail.attachments.map((a) => /* @__PURE__ */ jsx(AttachmentCard, { att: a }, a.id)) }),
419
+ detail.messages.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-2", children: detail.messages.map((m) => /* @__PURE__ */ jsx("div", { className: m.authorKind === "team" ? "flex justify-start" : "flex justify-end", children: /* @__PURE__ */ jsxs("div", { className: `max-w-[85%] rounded-lg px-3 py-2 text-sm ${m.authorKind === "team" ? "bg-muted" : "bg-primary/10"}`, children: [
420
+ /* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap", children: m.body }),
421
+ /* @__PURE__ */ jsx("div", { className: "mt-1 text-right text-[10px] text-muted-foreground", children: fmtDate(m.createdAt) })
422
+ ] }) }, m.id)) }),
423
+ /* @__PURE__ */ jsx(Separator, {}),
424
+ /* @__PURE__ */ jsx("ol", { className: "space-y-1 text-xs text-muted-foreground", children: detail.events.map((e) => /* @__PURE__ */ jsxs("li", { children: [
425
+ "\u2022 ",
426
+ eventLine(e.type, e.note),
427
+ " ",
428
+ /* @__PURE__ */ jsxs("span", { className: "opacity-60", children: [
429
+ "\xB7 ",
430
+ fmtDate(e.createdAt)
431
+ ] })
432
+ ] }, e.id)) })
433
+ ] }),
434
+ /* @__PURE__ */ jsx("div", { className: "border-t p-3", children: canValidate(detail.status) ? reopening ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
435
+ /* @__PURE__ */ jsx(Textarea, { rows: 2, value: reopenReason, onChange: (e) => setReopenReason(e.target.value), placeholder: "Conte o que ainda n\xE3o ficou certo." }),
436
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
437
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => setReopening(false), children: "Voltar" }),
438
+ /* @__PURE__ */ jsx(Button, { size: "sm", disabled: !reopenReason.trim(), onClick: () => void validate(false, reopenReason), children: "Enviar" })
439
+ ] })
440
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
441
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => setReopening(true), children: "Ainda n\xE3o resolveu" }),
442
+ /* @__PURE__ */ jsx(Button, { size: "sm", onClick: () => void validate(true), children: "Ficou bom" })
443
+ ] }) : canMessage(detail.status) ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
444
+ /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2", children: [
445
+ /* @__PURE__ */ jsx(Textarea, { rows: 2, value: message, onChange: (e) => setMessage(e.target.value), placeholder: "Escreva para a equipe\u2026", className: "flex-1" }),
446
+ /* @__PURE__ */ jsx(Button, { size: "sm", disabled: !message.trim() || sending, onClick: send, children: "Enviar" })
447
+ ] }),
448
+ canCancel(detail.status) && (confirmingCancel ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2 text-sm", children: [
449
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Cancelar esta solicita\xE7\xE3o?" }),
450
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => setConfirmingCancel(false), children: "N\xE3o" }),
451
+ /* @__PURE__ */ jsx(Button, { variant: "destructive", size: "sm", onClick: () => {
452
+ setConfirmingCancel(false);
453
+ void cancel();
454
+ }, children: "Cancelar solicita\xE7\xE3o" })
455
+ ] }) : /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => setConfirmingCancel(true), children: "Cancelar solicita\xE7\xE3o" }) }))
456
+ ] }) : /* @__PURE__ */ jsxs("p", { className: "text-center text-xs text-muted-foreground", children: [
457
+ "Esta solicita\xE7\xE3o est\xE1 ",
458
+ STATUS_LABEL[detail.status].toLowerCase(),
459
+ "."
460
+ ] }) })
461
+ ] });
462
+ }
463
+ function AttachmentCard({ att }) {
464
+ const [url, setUrl] = React.useState(null);
465
+ React.useEffect(() => {
466
+ let alive = true;
467
+ if ((att.contentType ?? "").startsWith("image/")) void signedUrl(att.storagePath).then((u) => {
468
+ if (alive) setUrl(u);
469
+ });
470
+ return () => {
471
+ alive = false;
472
+ };
473
+ }, [att.storagePath, att.contentType]);
474
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-lg border bg-card p-2", children: [
475
+ url ? /* @__PURE__ */ jsx(Thumbnail, { src: url, alt: att.name, className: "h-12 w-12 rounded object-cover" }) : /* @__PURE__ */ jsx("div", { className: "flex h-12 w-12 items-center justify-center rounded bg-muted text-[10px] text-muted-foreground", children: "anexo" }),
476
+ /* @__PURE__ */ jsxs("div", { className: "text-xs", children: [
477
+ /* @__PURE__ */ jsx("div", { className: "max-w-[10rem] truncate", children: att.name }),
478
+ att.sizeBytes != null && /* @__PURE__ */ jsx("div", { className: "text-muted-foreground", children: fmtSize(att.sizeBytes) })
479
+ ] })
480
+ ] });
481
+ }
482
+ function fmtDate(iso) {
483
+ try {
484
+ const d = new Date(iso);
485
+ const today = /* @__PURE__ */ new Date();
486
+ const sameDay = d.toDateString() === today.toDateString();
487
+ return sameDay ? d.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" }) : d.toLocaleDateString("pt-BR", { day: "2-digit", month: "2-digit" }) + ", " + d.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" });
488
+ } catch {
489
+ return iso;
490
+ }
491
+ }
492
+ function fmtSize(bytes) {
493
+ if (bytes < 1024) return `${bytes} B`;
494
+ if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
495
+ return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
496
+ }
497
+ var FILTERS = ["waiting", "in_progress", "closed", "all"];
498
+ function SupportRequestsPanel({ onAskDico, startNew, onOpenTicket }) {
499
+ const { requests, loadingList, scope, filter, selectedId } = useSupportStore();
500
+ const setScope = useSupportStore((s) => s.setScope);
501
+ const setFilter = useSupportStore((s) => s.setFilter);
502
+ const loadList = useSupportStore((s) => s.loadList);
503
+ const select = useSupportStore((s) => s.select);
504
+ const refreshUnread = useSupportStore((s) => s.refreshUnread);
505
+ const canSeeAll = useHasPermission("support.all", "read");
506
+ const [view, setView] = React.useState(startNew ? { t: "menu" } : { t: "list" });
507
+ React.useEffect(() => {
508
+ void loadList();
509
+ void refreshUnread();
510
+ }, [loadList, refreshUnread]);
511
+ const openDetail = (id) => {
512
+ if (onOpenTicket) {
513
+ onOpenTicket(id);
514
+ return;
515
+ }
516
+ void select(id);
517
+ setView({ t: "detail", id });
518
+ };
519
+ const backToList = () => {
520
+ void select(null);
521
+ setView({ t: "list" });
522
+ };
523
+ if (view.t === "menu") {
524
+ return /* @__PURE__ */ jsx(Section, { onBack: backToList, children: /* @__PURE__ */ jsx(SupportMenu, { onPickKind: (kind) => setView({ t: "form", kind }), onAskDico }) });
525
+ }
526
+ if (view.t === "form") {
527
+ return /* @__PURE__ */ jsx(
528
+ SupportRequestForm,
529
+ {
530
+ kind: view.kind,
531
+ onBack: () => setView({ t: "menu" }),
532
+ onDone: (res) => {
533
+ setView({ t: "created", number: res.number });
534
+ void refreshUnread();
535
+ }
536
+ }
537
+ );
538
+ }
539
+ if (view.t === "created") {
540
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-3 p-8 text-center", children: [
541
+ /* @__PURE__ */ jsx("div", { className: "flex h-12 w-12 items-center justify-center rounded-full bg-success-soft text-success-soft-foreground text-xl", children: "\u2713" }),
542
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: "Recebemos sua solicita\xE7\xE3o" }),
543
+ /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
544
+ "N\xFAmero ",
545
+ /* @__PURE__ */ jsxs("strong", { children: [
546
+ "#",
547
+ view.number
548
+ ] }),
549
+ ". Voc\xEA acompanha o andamento e conversa com a equipe aqui, e avisamos quando houver resposta."
550
+ ] }),
551
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
552
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: backToList, children: "Ver minhas solicita\xE7\xF5es" }),
553
+ /* @__PURE__ */ jsx(Button, { onClick: () => setView({ t: "menu" }), children: "Abrir outra" })
554
+ ] })
555
+ ] });
556
+ }
557
+ if (view.t === "detail") {
558
+ return /* @__PURE__ */ jsx("div", { className: "h-full min-h-[22rem]", children: /* @__PURE__ */ jsx(SupportRequestDetail, { onBack: backToList }) });
559
+ }
560
+ const filterOptions = FILTERS.map((f) => ({ value: f, label: FILTER_LABEL[f] }));
561
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col gap-3", children: [
562
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
563
+ /* @__PURE__ */ jsx(SegmentedControl, { options: filterOptions, value: filter, onChange: (v) => setFilter(v) }),
564
+ /* @__PURE__ */ jsx(Button, { onClick: () => setView({ t: "menu" }), children: "Nova solicita\xE7\xE3o" })
565
+ ] }),
566
+ canSeeAll && /* @__PURE__ */ jsx(
567
+ SegmentedControl,
568
+ {
569
+ options: [{ value: "mine", label: "Minhas" }, { value: "all", label: "Toda a empresa" }],
570
+ value: scope,
571
+ onChange: (v) => setScope(v)
572
+ }
573
+ ),
574
+ /* @__PURE__ */ jsx("div", { className: "min-h-[18rem] flex-1 overflow-y-auto rounded-xl border bg-card", children: loadingList ? /* @__PURE__ */ jsx("div", { className: "space-y-2 p-3", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-16 w-full" }, i)) }) : requests.length === 0 ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center text-sm text-muted-foreground", children: "Nenhuma solicita\xE7\xE3o por aqui ainda." }) : /* @__PURE__ */ jsx("ul", { className: "divide-y", children: requests.map((r) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(RequestCard, { req: r, active: selectedId === r.id, onClick: () => openDetail(r.id) }) }, r.id)) }) })
575
+ ] });
576
+ }
577
+ function Section({ children, onBack }) {
578
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
579
+ /* @__PURE__ */ jsx("button", { onClick: onBack, className: "self-start text-sm text-muted-foreground hover:text-foreground", children: "\u2190 Voltar" }),
580
+ children
581
+ ] });
582
+ }
583
+ function RequestCard({ req, active, onClick }) {
584
+ return /* @__PURE__ */ jsxs("button", { onClick, className: `block w-full p-3 text-left transition-colors hover:bg-accent ${active ? "bg-accent" : ""}`, children: [
585
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: [
586
+ /* @__PURE__ */ jsxs("span", { children: [
587
+ "#",
588
+ req.number,
589
+ " \xB7 ",
590
+ KIND_LABEL[req.kind]
591
+ ] }),
592
+ /* @__PURE__ */ jsx("span", { children: shortTime(req.createdAt) })
593
+ ] }),
594
+ /* @__PURE__ */ jsx("div", { className: "mt-0.5 truncate text-sm font-medium", children: req.subject || KIND_LABEL[req.kind] }),
595
+ /* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(Badge, { variant: STATUS_TONE[req.status], children: STATUS_LABEL[req.status] }) })
596
+ ] });
597
+ }
598
+ function shortTime(iso) {
599
+ try {
600
+ const d = new Date(iso);
601
+ const sameDay = d.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
602
+ return sameDay ? d.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" }) : d.toLocaleDateString("pt-BR", { day: "2-digit", month: "2-digit" });
603
+ } catch {
604
+ return "";
605
+ }
606
+ }
607
+ function go(path) {
608
+ if (typeof window !== "undefined") window.location.hash = path;
609
+ }
610
+ function ticketNo(n) {
611
+ return `#${String(n).padStart(4, "0")}`;
612
+ }
613
+ function TicketDetailPage({ id }) {
614
+ const detail = useSupportStore((s) => s.detail);
615
+ const loading = useSupportStore((s) => s.loadingDetail);
616
+ const selectedId = useSupportStore((s) => s.selectedId);
617
+ const select = useSupportStore((s) => s.select);
618
+ const sendMessage = useSupportStore((s) => s.sendMessage);
619
+ const cancel = useSupportStore((s) => s.cancel);
620
+ const validate = useSupportStore((s) => s.validate);
621
+ const user = useAuth().user;
622
+ const [message, setMessage] = React.useState("");
623
+ const [sending, setSending] = React.useState(false);
624
+ const [confirmingCancel, setConfirmingCancel] = React.useState(false);
625
+ const [reopening, setReopening] = React.useState(false);
626
+ const [reopenReason, setReopenReason] = React.useState("");
627
+ const [advanced, setAdvanced] = React.useState(false);
628
+ React.useEffect(() => {
629
+ void select(id);
630
+ }, [id, select]);
631
+ React.useEffect(() => {
632
+ setMessage("");
633
+ setConfirmingCancel(false);
634
+ setReopening(false);
635
+ setReopenReason("");
636
+ }, [detail?.id]);
637
+ const ready = detail && detail.id === id;
638
+ const attempted = selectedId === id && !loading;
639
+ async function send() {
640
+ if (!message.trim()) return;
641
+ setSending(true);
642
+ try {
643
+ await sendMessage(message);
644
+ setMessage("");
645
+ } finally {
646
+ setSending(false);
647
+ }
648
+ }
649
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
650
+ /* @__PURE__ */ jsx(
651
+ SubpageHeader,
652
+ {
653
+ title: ready ? `Ticket ${ticketNo(detail.number)}` : "Ticket",
654
+ parentLabel: "Suporte",
655
+ onBack: () => go("/support"),
656
+ titleTrailing: ready ? /* @__PURE__ */ jsx(Badge, { variant: STATUS_TONE[detail.status], children: STATUS_LABEL[detail.status] }) : void 0
657
+ }
658
+ ),
659
+ !ready && !attempted ? /* @__PURE__ */ jsx(TicketSkeleton, {}) : !ready ? /* @__PURE__ */ jsxs("div", { className: "rounded-xl border bg-card p-10 text-center", children: [
660
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Solicita\xE7\xE3o n\xE3o encontrada" }),
661
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Ela pode ter sido removida, ou pertencer a outra conta." }),
662
+ /* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => go("/support"), children: "Voltar para o Suporte" }) })
663
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "grid gap-5 lg:grid-cols-2 lg:items-start", children: [
664
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
665
+ /* @__PURE__ */ jsxs("section", { className: "rounded-xl border bg-card p-5", children: [
666
+ /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold leading-snug", children: detail.subject || KIND_LABEL[detail.kind] }),
667
+ /* @__PURE__ */ jsxs("p", { className: "mt-1 text-xs text-muted-foreground", children: [
668
+ KIND_LABEL[detail.kind],
669
+ " \xB7 aberta em ",
670
+ fmtDateTime(detail.createdAt)
671
+ ] }),
672
+ /* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
673
+ /* @__PURE__ */ jsx("h2", { className: "text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Descri\xE7\xE3o" }),
674
+ /* @__PURE__ */ jsx("p", { className: "mt-1.5 whitespace-pre-wrap text-sm leading-relaxed", children: detail.description })
675
+ ] }),
676
+ detail.attachments.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
677
+ /* @__PURE__ */ jsx("h2", { className: "text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Anexos" }),
678
+ /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2", children: detail.attachments.map((a) => /* @__PURE__ */ jsx(AttachmentCard2, { att: a }, a.id)) })
679
+ ] })
680
+ ] }),
681
+ /* @__PURE__ */ jsxs("div", { className: "rounded-xl border bg-card p-5", children: [
682
+ /* @__PURE__ */ jsx("h2", { className: "text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Informa\xE7\xF5es" }),
683
+ /* @__PURE__ */ jsxs("dl", { className: "mt-3 divide-y divide-border/60 text-sm", children: [
684
+ /* @__PURE__ */ jsx(Row2, { label: "N\xFAmero", children: ticketNo(detail.number) }),
685
+ /* @__PURE__ */ jsx(Row2, { label: "Status", children: /* @__PURE__ */ jsx(Badge, { variant: STATUS_TONE[detail.status], children: STATUS_LABEL[detail.status] }) }),
686
+ /* @__PURE__ */ jsx(Row2, { label: "Tipo", children: KIND_LABEL[detail.kind] }),
687
+ /* @__PURE__ */ jsx(Row2, { label: "Solicitante", children: detail.createdBy === user?.id ? user?.fullName || user?.email || "Voc\xEA" : "\u2014" }),
688
+ /* @__PURE__ */ jsx(Row2, { label: "Respons\xE1vel", children: "Equipe de Suporte" }),
689
+ /* @__PURE__ */ jsx(Row2, { label: "Aberta em", children: fmtDateTime(detail.createdAt) }),
690
+ /* @__PURE__ */ jsx(Row2, { label: "Atualizada", children: fmtDateTime(detail.updatedAt) })
691
+ ] }),
692
+ /* @__PURE__ */ jsxs(
693
+ "button",
694
+ {
695
+ onClick: () => setAdvanced((v) => !v),
696
+ className: "mt-3 flex w-full items-center justify-between rounded-md border-t pt-3 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground",
697
+ "aria-expanded": advanced,
698
+ children: [
699
+ /* @__PURE__ */ jsx("span", { children: "Informa\xE7\xF5es avan\xE7adas" }),
700
+ /* @__PURE__ */ jsx(Chevron, { className: `h-3.5 w-3.5 transition-transform ${advanced ? "rotate-180" : ""}` })
701
+ ]
702
+ }
703
+ ),
704
+ advanced && /* @__PURE__ */ jsxs("div", { className: "mt-2 text-xs", children: [
705
+ /* @__PURE__ */ jsxs("dl", { className: "divide-y divide-border/60", children: [
706
+ detail.route && /* @__PURE__ */ jsx(Row2, { label: "Tela", children: detail.route }),
707
+ /* @__PURE__ */ jsx(Row2, { label: "ID", children: /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px] break-all", children: detail.id }) })
708
+ ] }),
709
+ /* @__PURE__ */ jsx(ActivityTrail, { snapshot: detail.screenSnapshot })
710
+ ] })
711
+ ] })
712
+ ] }),
713
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
714
+ /* @__PURE__ */ jsxs("section", { className: "rounded-xl border bg-card p-5", children: [
715
+ /* @__PURE__ */ jsx("h2", { className: "text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Conversa com a equipe" }),
716
+ detail.messages.length === 0 ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Ainda n\xE3o h\xE1 mensagens. Escreva abaixo para falar com a equipe." }) : /* @__PURE__ */ jsx("div", { className: "mt-3 space-y-2", children: detail.messages.map((m) => /* @__PURE__ */ jsx("div", { className: m.authorKind === "team" ? "flex justify-start" : "flex justify-end", children: /* @__PURE__ */ jsxs("div", { className: `max-w-[85%] rounded-lg px-3 py-2 text-sm ${m.authorKind === "team" ? "bg-muted" : "bg-primary/10"}`, children: [
717
+ /* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap", children: m.body }),
718
+ /* @__PURE__ */ jsx("div", { className: "mt-1 text-right text-[10px] text-muted-foreground", children: fmtDate2(m.createdAt) })
719
+ ] }) }, m.id)) }),
720
+ /* @__PURE__ */ jsx("div", { className: "mt-3", children: canValidate(detail.status) ? reopening ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
721
+ /* @__PURE__ */ jsx(Textarea, { rows: 2, value: reopenReason, onChange: (e) => setReopenReason(e.target.value), placeholder: "Conte o que ainda n\xE3o ficou certo." }),
722
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
723
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => setReopening(false), children: "Voltar" }),
724
+ /* @__PURE__ */ jsx(Button, { size: "sm", disabled: !reopenReason.trim(), onClick: () => void validate(false, reopenReason), children: "Enviar" })
725
+ ] })
726
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
727
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => setReopening(true), children: "Ainda n\xE3o resolveu" }),
728
+ /* @__PURE__ */ jsx(Button, { size: "sm", onClick: () => void validate(true), children: "Ficou bom" })
729
+ ] }) : canMessage(detail.status) ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
730
+ /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2", children: [
731
+ /* @__PURE__ */ jsx(Textarea, { rows: 2, value: message, onChange: (e) => setMessage(e.target.value), placeholder: "Escreva para a equipe\u2026", className: "flex-1" }),
732
+ /* @__PURE__ */ jsx(Button, { size: "sm", disabled: !message.trim() || sending, onClick: send, children: "Enviar" })
733
+ ] }),
734
+ canCancel(detail.status) && (confirmingCancel ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2 text-sm", children: [
735
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Cancelar esta solicita\xE7\xE3o?" }),
736
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => setConfirmingCancel(false), children: "N\xE3o" }),
737
+ /* @__PURE__ */ jsx(Button, { variant: "destructive", size: "sm", onClick: () => {
738
+ setConfirmingCancel(false);
739
+ void cancel();
740
+ }, children: "Cancelar solicita\xE7\xE3o" })
741
+ ] }) : /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => setConfirmingCancel(true), children: "Cancelar solicita\xE7\xE3o" }) }))
742
+ ] }) : /* @__PURE__ */ jsxs("p", { className: "text-center text-xs text-muted-foreground", children: [
743
+ "Esta solicita\xE7\xE3o est\xE1 ",
744
+ STATUS_LABEL[detail.status].toLowerCase(),
745
+ "."
746
+ ] }) })
747
+ ] }),
748
+ /* @__PURE__ */ jsxs("div", { className: "rounded-xl border bg-card p-5", children: [
749
+ /* @__PURE__ */ jsx("h2", { className: "text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Atividades" }),
750
+ detail.events.length === 0 ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Sem atividades." }) : /* @__PURE__ */ jsx("ol", { className: "mt-3 space-y-2.5", children: detail.events.map((e) => /* @__PURE__ */ jsxs("li", { className: "flex gap-2 text-xs", children: [
751
+ /* @__PURE__ */ jsx("span", { className: "mt-1 h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/40" }),
752
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
753
+ /* @__PURE__ */ jsx("div", { children: eventLine(e.type, e.note) }),
754
+ /* @__PURE__ */ jsx("div", { className: "text-muted-foreground", children: fmtDate2(e.createdAt) })
755
+ ] })
756
+ ] }, e.id)) })
757
+ ] })
758
+ ] })
759
+ ] })
760
+ ] });
761
+ }
762
+ function TicketSkeleton() {
763
+ return /* @__PURE__ */ jsxs("div", { className: "grid gap-5 lg:grid-cols-2 lg:items-start", children: [
764
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
765
+ /* @__PURE__ */ jsxs("div", { className: "rounded-xl border bg-card p-5", children: [
766
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-2/3" }),
767
+ /* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-3 w-1/3" }),
768
+ /* @__PURE__ */ jsx(Skeleton, { className: "mt-4 h-16 w-full" })
769
+ ] }),
770
+ /* @__PURE__ */ jsx("div", { className: "rounded-xl border bg-card p-5 space-y-2.5", children: [0, 1, 2, 3].map((i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" }, i)) })
771
+ ] }),
772
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
773
+ /* @__PURE__ */ jsxs("div", { className: "rounded-xl border bg-card p-5", children: [
774
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-28 w-full" }),
775
+ /* @__PURE__ */ jsx(Skeleton, { className: "mt-3 h-10 w-full" })
776
+ ] }),
777
+ /* @__PURE__ */ jsx("div", { className: "rounded-xl border bg-card p-5 space-y-2.5", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-5/6" }, i)) })
778
+ ] })
779
+ ] });
780
+ }
781
+ function Row2({ label, children }) {
782
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3 py-2 first:pt-0 last:pb-0", children: [
783
+ /* @__PURE__ */ jsx("dt", { className: "shrink-0 text-muted-foreground", children: label }),
784
+ /* @__PURE__ */ jsx("dd", { className: "min-w-0 text-right font-medium", children })
785
+ ] });
786
+ }
787
+ function Chevron({ className }) {
788
+ const C = ICON_MAP.ChevronDown;
789
+ return C ? /* @__PURE__ */ jsx(C, { className }) : /* @__PURE__ */ jsx("span", { className, children: "\u25BE" });
790
+ }
791
+ function ActivityTrail({ snapshot: snapshot2 }) {
792
+ const activity = snapshot2?.activity;
793
+ if (Array.isArray(activity) && activity.length) {
794
+ const items = activity.filter((e) => !!e && typeof e === "object" && typeof e.label === "string");
795
+ if (!items.length) return null;
796
+ return /* @__PURE__ */ jsxs("div", { className: "mt-3 border-t pt-3", children: [
797
+ /* @__PURE__ */ jsx("div", { className: "mb-1.5 text-muted-foreground", children: "Trilha at\xE9 o relato" }),
798
+ /* @__PURE__ */ jsx("ol", { className: "space-y-1", children: items.map((e, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-1.5", children: [
799
+ /* @__PURE__ */ jsx("span", { className: "mt-[3px] text-muted-foreground/50", children: e.kind === "action" ? "\u203A" : "\u2022" }),
800
+ /* @__PURE__ */ jsx("span", { className: "min-w-0", children: e.kind === "action" ? /* @__PURE__ */ jsxs(Fragment, { children: [
801
+ "clicou ",
802
+ /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
803
+ '"',
804
+ e.label,
805
+ '"'
806
+ ] })
807
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
808
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: e.label }),
809
+ e.path && /* @__PURE__ */ jsx("span", { className: "ml-1 font-mono text-[10px] text-muted-foreground", children: e.path })
810
+ ] }) })
811
+ ] }, i)) })
812
+ ] });
813
+ }
814
+ const recent = snapshot2?.recentScreens;
815
+ if (!Array.isArray(recent) || recent.length === 0) return null;
816
+ const labels = recent.map((r) => r && typeof r === "object" ? r.label : void 0).filter((l) => !!l);
817
+ if (!labels.length) return null;
818
+ return /* @__PURE__ */ jsxs("div", { className: "mt-3 border-t pt-3", children: [
819
+ /* @__PURE__ */ jsx("div", { className: "mb-1 text-muted-foreground", children: "Telas recentes" }),
820
+ /* @__PURE__ */ jsx("div", { children: labels.join(" \u2192 ") })
821
+ ] });
822
+ }
823
+ function AttachmentCard2({ att }) {
824
+ const [url, setUrl] = React.useState(null);
825
+ React.useEffect(() => {
826
+ let alive = true;
827
+ if ((att.contentType ?? "").startsWith("image/")) void signedUrl(att.storagePath).then((u) => {
828
+ if (alive) setUrl(u);
829
+ });
830
+ return () => {
831
+ alive = false;
832
+ };
833
+ }, [att.storagePath, att.contentType]);
834
+ return /* @__PURE__ */ jsxs(
835
+ "a",
836
+ {
837
+ href: url ?? void 0,
838
+ target: "_blank",
839
+ rel: "noreferrer",
840
+ className: "flex items-center gap-2 rounded-lg border bg-card p-2 transition-colors hover:bg-muted",
841
+ children: [
842
+ url ? /* @__PURE__ */ jsx(Thumbnail, { src: url, alt: att.name, className: "h-12 w-12 rounded object-cover" }) : /* @__PURE__ */ jsx("div", { className: "flex h-12 w-12 items-center justify-center rounded bg-muted text-[10px] text-muted-foreground", children: "anexo" }),
843
+ /* @__PURE__ */ jsxs("div", { className: "text-xs", children: [
844
+ /* @__PURE__ */ jsx("div", { className: "max-w-[10rem] truncate", children: att.name }),
845
+ att.sizeBytes != null && /* @__PURE__ */ jsx("div", { className: "text-muted-foreground", children: fmtSize2(att.sizeBytes) })
846
+ ] })
847
+ ]
848
+ }
849
+ );
850
+ }
851
+ function fmtDate2(iso) {
852
+ try {
853
+ const d = new Date(iso);
854
+ const sameDay = d.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
855
+ return sameDay ? d.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" }) : d.toLocaleDateString("pt-BR", { day: "2-digit", month: "2-digit" }) + ", " + d.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" });
856
+ } catch {
857
+ return iso;
858
+ }
859
+ }
860
+ function fmtDateTime(iso) {
861
+ try {
862
+ return new Date(iso).toLocaleString("pt-BR", { day: "2-digit", month: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit" });
863
+ } catch {
864
+ return iso;
865
+ }
866
+ }
867
+ function fmtSize2(bytes) {
868
+ if (bytes < 1024) return `${bytes} B`;
869
+ if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
870
+ return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
871
+ }
872
+ function go2(path) {
873
+ if (typeof window !== "undefined") window.location.hash = path;
874
+ }
875
+ function useTicketRoute() {
876
+ const read = () => {
877
+ if (typeof window === "undefined") return null;
878
+ const m = window.location.hash.replace(/^#/, "").match(/^\/support\/ticket\/([^/?]+)/);
879
+ return m ? decodeURIComponent(m[1]) : null;
880
+ };
881
+ const [id, setId] = React.useState(read);
882
+ React.useEffect(() => {
883
+ const on = () => setId(read());
884
+ window.addEventListener("hashchange", on);
885
+ return () => window.removeEventListener("hashchange", on);
886
+ }, []);
887
+ return id;
888
+ }
889
+ function SupportCenter({ content }) {
890
+ const ticketId = useTicketRoute();
891
+ return ticketId ? /* @__PURE__ */ jsx(TicketDetailPage, { id: ticketId }) : /* @__PURE__ */ jsx(SupportCenterHome, { content });
892
+ }
893
+ function Icon({ name, className }) {
894
+ const C = ICON_MAP[name];
895
+ return C ? /* @__PURE__ */ jsx(C, { className }) : null;
896
+ }
897
+ function SupportCenterHome({ content }) {
898
+ const [query, setQuery] = React.useState("");
899
+ const [requestsOpen, setRequestsOpen] = React.useState(false);
900
+ const [startNew, setStartNew] = React.useState(false);
901
+ const setChatOpen = useChatStore((s) => s.setOpen);
902
+ const queuePrompt = useChatStore((s) => s.queuePrompt);
903
+ function askDico() {
904
+ setChatOpen(true);
905
+ const q2 = query.trim();
906
+ if (q2) queuePrompt(q2);
907
+ }
908
+ const q = query.trim().toLowerCase();
909
+ const faq = q ? content.faq.filter((f) => [f.question, f.answer, f.category].filter(Boolean).some((s) => s.toLowerCase().includes(q))) : content.faq;
910
+ function openRequests(forNew) {
911
+ setStartNew(forNew);
912
+ setRequestsOpen(true);
913
+ }
914
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
915
+ /* @__PURE__ */ jsxs("div", { className: "rounded-2xl border bg-card p-6", children: [
916
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm font-medium text-muted-foreground", children: [
917
+ /* @__PURE__ */ jsx(Icon, { name: "Sparkles", className: "h-4 w-4" }),
918
+ " Dico \xB7 central de ajuda"
919
+ ] }),
920
+ /* @__PURE__ */ jsx("h1", { className: "mt-1 text-2xl font-semibold tracking-tight", children: "Como podemos ajudar?" }),
921
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Pergunte ao Dico ou busque na central de ajuda." }),
922
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 flex gap-2", children: [
923
+ /* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
924
+ /* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground", children: /* @__PURE__ */ jsx(Icon, { name: "Search", className: "h-4 w-4" }) }),
925
+ /* @__PURE__ */ jsx(
926
+ Input,
927
+ {
928
+ value: query,
929
+ onChange: (e) => setQuery(e.target.value),
930
+ onKeyDown: (e) => {
931
+ if (e.key === "Enter") askDico();
932
+ },
933
+ placeholder: "Pergunte ou busque\u2026 ex.: como recebo pagamentos?",
934
+ className: "pl-9"
935
+ }
936
+ )
937
+ ] }),
938
+ /* @__PURE__ */ jsxs(Button, { onClick: askDico, children: [
939
+ /* @__PURE__ */ jsx(Icon, { name: "Sparkles", className: "mr-1.5 h-4 w-4" }),
940
+ " Perguntar ao Dico"
941
+ ] })
942
+ ] })
943
+ ] }),
944
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-5 lg:grid-cols-[1fr_20rem] lg:items-start", children: [
945
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
946
+ /* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-muted-foreground", children: "Perguntas frequentes e v\xEDdeos" }),
947
+ faq.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-xl border bg-card p-6 text-center text-sm text-muted-foreground", children: [
948
+ 'Nada encontrado para "',
949
+ query,
950
+ '".',
951
+ /* @__PURE__ */ jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: askDico, children: "Perguntar ao Dico" }) })
952
+ ] }) : /* @__PURE__ */ jsx("div", { className: "divide-y rounded-xl border bg-card", children: faq.map((item) => /* @__PURE__ */ jsx(FaqRow, { item }, item.id)) })
953
+ ] }),
954
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
955
+ /* @__PURE__ */ jsx(StatusCard, { components: content.statusComponents }),
956
+ /* @__PURE__ */ jsx(PlanCard, {}),
957
+ /* @__PURE__ */ jsx(WhatsNewCard, { items: content.whatsNew }),
958
+ /* @__PURE__ */ jsx(RequestsCard, { onOpen: () => openRequests(false), onNew: () => openRequests(true) })
959
+ ] })
960
+ ] }),
961
+ /* @__PURE__ */ jsx(ModalTask, { open: requestsOpen, title: "Minhas solicita\xE7\xF5es", width: "min(44rem, 94vw)", onClose: () => setRequestsOpen(false), children: /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx(
962
+ SupportRequestsPanel,
963
+ {
964
+ startNew,
965
+ onAskDico: () => {
966
+ setRequestsOpen(false);
967
+ setChatOpen(true);
968
+ },
969
+ onOpenTicket: (id) => {
970
+ setRequestsOpen(false);
971
+ go2(`/support/ticket/${id}`);
972
+ }
973
+ }
974
+ ) }) })
975
+ ] });
976
+ }
977
+ function FaqRow({ item }) {
978
+ const [open, setOpen] = React.useState(false);
979
+ const [playing, setPlaying] = React.useState(false);
980
+ return /* @__PURE__ */ jsxs("div", { className: "p-4", children: [
981
+ /* @__PURE__ */ jsxs("button", { onClick: () => setOpen((v) => !v), className: "flex w-full items-center gap-3 text-left", children: [
982
+ item.videoUrl ? /* @__PURE__ */ jsx(Icon, { name: "PlayCircle", className: "h-5 w-5 shrink-0 text-muted-foreground" }) : /* @__PURE__ */ jsx(Icon, { name: "HelpCircle", className: "h-5 w-5 shrink-0 text-muted-foreground" }),
983
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm font-medium", children: item.question }),
984
+ /* @__PURE__ */ jsx(Icon, { name: "ChevronDown", className: `h-4 w-4 shrink-0 text-muted-foreground transition-transform ${open ? "rotate-180" : ""}` })
985
+ ] }),
986
+ open && /* @__PURE__ */ jsxs("div", { className: "mt-2 pl-8 text-sm text-muted-foreground", children: [
987
+ /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap", children: item.answer }),
988
+ item.videoUrl && (playing ? /* @__PURE__ */ jsx("div", { className: "mt-3 aspect-video w-full max-w-md overflow-hidden rounded-lg border", children: /\.(mp4|webm)(\?|$)/.test(item.videoUrl) ? /* @__PURE__ */ jsx("video", { src: item.videoUrl, controls: true, autoPlay: true, className: "h-full w-full" }) : /* @__PURE__ */ jsx("iframe", { src: toEmbedUrl(item.videoUrl), className: "h-full w-full", allow: "autoplay; fullscreen", allowFullScreen: true, title: item.question }) }) : /* @__PURE__ */ jsxs("button", { onClick: () => setPlaying(true), className: "mt-3 inline-flex items-center gap-1.5 text-sm font-medium text-primary hover:underline", children: [
989
+ /* @__PURE__ */ jsx(Icon, { name: "PlayCircle", className: "h-4 w-4" }),
990
+ " Assistir ao v\xEDdeo"
991
+ ] }))
992
+ ] })
993
+ ] });
994
+ }
995
+ function Card({ title, icon, action, children }) {
996
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-xl border bg-card p-4", children: [
997
+ /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
998
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm font-semibold", children: [
999
+ /* @__PURE__ */ jsx(Icon, { name: icon, className: "h-4 w-4 text-muted-foreground" }),
1000
+ " ",
1001
+ title
1002
+ ] }),
1003
+ action
1004
+ ] }),
1005
+ children
1006
+ ] });
1007
+ }
1008
+ function StatusCard({ components }) {
1009
+ const conn = useConnectivity();
1010
+ const ok = conn.online;
1011
+ return /* @__PURE__ */ jsxs(Card, { title: "Status", icon: "Activity", children: [
1012
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1013
+ /* @__PURE__ */ jsx("span", { className: `h-2.5 w-2.5 rounded-full ${ok ? "bg-success" : "bg-warning"}` }),
1014
+ /* @__PURE__ */ jsx("span", { className: "text-sm", children: ok ? "Todos os sistemas operacionais" : "Sem conex\xE3o com o servidor" })
1015
+ ] }),
1016
+ /* @__PURE__ */ jsx("ul", { className: "mt-3 space-y-1.5", children: components.map((c) => /* @__PURE__ */ jsxs("li", { className: "flex items-center justify-between text-xs text-muted-foreground", children: [
1017
+ /* @__PURE__ */ jsx("span", { children: c.label }),
1018
+ /* @__PURE__ */ jsxs("span", { className: `inline-flex items-center gap-1 ${ok ? "text-success" : "text-warning"}`, children: [
1019
+ /* @__PURE__ */ jsx("span", { className: `h-1.5 w-1.5 rounded-full ${ok ? "bg-success" : "bg-warning"}` }),
1020
+ ok ? "Operacional" : "Inst\xE1vel"
1021
+ ] })
1022
+ ] }, c.id)) })
1023
+ ] });
1024
+ }
1025
+ function PlanCard() {
1026
+ const org = useTenantOptional()?.org;
1027
+ const plan = org?.plan;
1028
+ const label = plan ? plan.charAt(0).toUpperCase() + plan.slice(1) : null;
1029
+ const paid = !!plan && !/free|trial|gratis|grátis/i.test(plan);
1030
+ return /* @__PURE__ */ jsx(Card, { title: "Seu plano", icon: "CreditCard", action: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => go2("/settings"), children: "Gerenciar" }), children: label ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1031
+ /* @__PURE__ */ jsx(Badge, { variant: paid ? "success" : "secondary", children: label }),
1032
+ org?.name && /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-muted-foreground", children: org.name })
1033
+ ] }) : /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Plano n\xE3o identificado." }) });
1034
+ }
1035
+ function WhatsNewCard({ items }) {
1036
+ if (!items.length) return null;
1037
+ return /* @__PURE__ */ jsx(Card, { title: "Novidades", icon: "Rocket", children: /* @__PURE__ */ jsx("ul", { className: "space-y-2.5", children: items.slice(0, 4).map((n) => /* @__PURE__ */ jsxs("li", { children: [
1038
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-2", children: [
1039
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: n.title }),
1040
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[10px] text-muted-foreground", children: fmtDate3(n.date) })
1041
+ ] }),
1042
+ n.note && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: n.note })
1043
+ ] }, n.id)) }) });
1044
+ }
1045
+ function RequestsCard({ onOpen, onNew }) {
1046
+ const requests = useSupportStore((s) => s.requests);
1047
+ const unread = useSupportStore((s) => s.unread);
1048
+ const loadList = useSupportStore((s) => s.loadList);
1049
+ const refreshUnread = useSupportStore((s) => s.refreshUnread);
1050
+ React.useEffect(() => {
1051
+ void loadList();
1052
+ void refreshUnread();
1053
+ }, [loadList, refreshUnread]);
1054
+ const recent = requests.slice(0, 3);
1055
+ return /* @__PURE__ */ jsxs(
1056
+ Card,
1057
+ {
1058
+ title: "Minhas solicita\xE7\xF5es",
1059
+ icon: "Inbox",
1060
+ action: unread > 0 ? /* @__PURE__ */ jsx("span", { className: "rounded-full bg-warning px-1.5 text-[10px] font-semibold text-warning-foreground", children: unread }) : void 0,
1061
+ children: [
1062
+ recent.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Voc\xEA ainda n\xE3o abriu nenhuma solicita\xE7\xE3o." }) : /* @__PURE__ */ jsx("ul", { className: "mb-3 space-y-1.5", children: recent.map((r) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("button", { onClick: () => go2(`/support/ticket/${r.id}`), className: "flex w-full items-center justify-between gap-2 text-left hover:text-foreground", children: [
1063
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 truncate text-xs", children: [
1064
+ "#",
1065
+ r.number,
1066
+ " ",
1067
+ r.subject || KIND_LABEL[r.kind]
1068
+ ] }),
1069
+ /* @__PURE__ */ jsx(Badge, { variant: STATUS_TONE[r.status], children: STATUS_LABEL[r.status] })
1070
+ ] }) }, r.id)) }),
1071
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
1072
+ /* @__PURE__ */ jsx(Button, { size: "sm", className: "flex-1", onClick: onNew, children: "Nova solicita\xE7\xE3o" }),
1073
+ recent.length > 0 && /* @__PURE__ */ jsx(Button, { size: "sm", variant: "outline", onClick: onOpen, children: "Ver todas" })
1074
+ ] })
1075
+ ]
1076
+ }
1077
+ );
1078
+ }
1079
+ function fmtDate3(iso) {
1080
+ try {
1081
+ return new Date(iso).toLocaleDateString("pt-BR", { day: "2-digit", month: "short" });
1082
+ } catch {
1083
+ return iso;
1084
+ }
1085
+ }
1086
+ var SupportCenter_default = SupportCenter;
1087
+
1088
+ export { SupportCenter, SupportCenter_default as default };
1089
+ //# sourceMappingURL=SupportCenter-Z2HEPJGD.js.map
1090
+ //# sourceMappingURL=SupportCenter-Z2HEPJGD.js.map