@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.
- package/LICENSE +21 -0
- package/dist/HelpdeskConsole-7W5IAQIU.js +355 -0
- package/dist/HelpdeskConsole-7W5IAQIU.js.map +1 -0
- package/dist/SupportCenter-Z2HEPJGD.js +1090 -0
- package/dist/SupportCenter-Z2HEPJGD.js.map +1 -0
- package/dist/chunk-5K7VA5VP.js +106 -0
- package/dist/chunk-5K7VA5VP.js.map +1 -0
- package/dist/chunk-7NVBUXTX.js +300 -0
- package/dist/chunk-7NVBUXTX.js.map +1 -0
- package/dist/chunk-JJPB2T3Z.js +131 -0
- package/dist/chunk-JJPB2T3Z.js.map +1 -0
- package/dist/components/HelpdeskStatusPanel.d.ts +12 -0
- package/dist/components/HelpdeskStatusPanel.d.ts.map +1 -0
- package/dist/data/api.d.ts +15 -0
- package/dist/data/api.d.ts.map +1 -0
- package/dist/data/console.d.ts +37 -0
- package/dist/data/console.d.ts.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +901 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/content.d.ts +24 -0
- package/dist/lib/content.d.ts.map +1 -0
- package/dist/lib/fix-prompt.d.ts +30 -0
- package/dist/lib/fix-prompt.d.ts.map +1 -0
- package/dist/lib/report-tool.d.ts +25 -0
- package/dist/lib/report-tool.d.ts.map +1 -0
- package/dist/lib/vocabulary.d.ts +34 -0
- package/dist/lib/vocabulary.d.ts.map +1 -0
- package/dist/locales/en.d.ts +2 -0
- package/dist/locales/en.d.ts.map +1 -0
- package/dist/locales/index.d.ts +2 -0
- package/dist/locales/index.d.ts.map +1 -0
- package/dist/locales/pt-BR.d.ts +2 -0
- package/dist/locales/pt-BR.d.ts.map +1 -0
- package/dist/migrations/index.d.ts +9 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/store.d.ts +27 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/types.d.ts +80 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/views/HelpdeskConsole.d.ts +10 -0
- package/dist/views/HelpdeskConsole.d.ts.map +1 -0
- package/dist/views/ScreenCaptureEditor.d.ts +12 -0
- package/dist/views/ScreenCaptureEditor.d.ts.map +1 -0
- package/dist/views/SupportCenter.d.ts +14 -0
- package/dist/views/SupportCenter.d.ts.map +1 -0
- package/dist/views/SupportMenu.d.ts +12 -0
- package/dist/views/SupportMenu.d.ts.map +1 -0
- package/dist/views/SupportRequestDetail.d.ts +6 -0
- package/dist/views/SupportRequestDetail.d.ts.map +1 -0
- package/dist/views/SupportRequestForm.d.ts +12 -0
- package/dist/views/SupportRequestForm.d.ts.map +1 -0
- package/dist/views/SupportRequestsPanel.d.ts +11 -0
- package/dist/views/SupportRequestsPanel.d.ts.map +1 -0
- package/dist/views/TicketDetailPage.d.ts +12 -0
- package/dist/views/TicketDetailPage.d.ts.map +1 -0
- package/package.json +56 -3
- package/README.md +0 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Faya Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import { isOperator, consoleListRequests, consoleDetail, consoleSetStatus, consoleSetPriority, consoleReply } from './chunk-5K7VA5VP.js';
|
|
2
|
+
import { PRIORITY_ORDER, PRIORITY_LABEL, PRIORITY_TONE, STATUS_LABEL, STATUS_TONE, KIND_LABEL, eventLine, signedUrl } from './chunk-7NVBUXTX.js';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { Skeleton, Input, Badge, SubpageHeader, Button, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Textarea, ICON_MAP, ModalTask, Thumbnail, toast } from '@fayz-ai/ui';
|
|
5
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
// src/lib/fix-prompt.ts
|
|
8
|
+
function buildFixPrompt(detail, appName) {
|
|
9
|
+
const lines = [];
|
|
10
|
+
const app = appName?.trim() || "the Fayz app";
|
|
11
|
+
lines.push(`Fix an issue reported by a user of ${app}.`);
|
|
12
|
+
lines.push("");
|
|
13
|
+
lines.push(`Ticket #${String(detail.number).padStart(4, "0")} \xB7 ${KIND_LABEL[detail.kind]} \xB7 status: ${STATUS_LABEL[detail.status]}`);
|
|
14
|
+
if (detail.route) lines.push(`Screen / route: ${detail.route}`);
|
|
15
|
+
if (detail.tenantId) lines.push(`Tenant (store) id: ${detail.tenantId}`);
|
|
16
|
+
if (detail.createdBy) lines.push(`Reported by user id: ${detail.createdBy}`);
|
|
17
|
+
lines.push("");
|
|
18
|
+
lines.push("PROBLEM (in the user's own words):");
|
|
19
|
+
const subject = detail.subject?.trim();
|
|
20
|
+
const description = detail.description.trim();
|
|
21
|
+
if (subject && !description.toLowerCase().startsWith(subject.toLowerCase())) lines.push(subject);
|
|
22
|
+
lines.push(description);
|
|
23
|
+
const activity = detail.screenSnapshot?.activity ?? null;
|
|
24
|
+
if (Array.isArray(activity) && activity.length) {
|
|
25
|
+
lines.push("");
|
|
26
|
+
lines.push("WHAT THE USER DID BEFORE REPORTING (most recent last):");
|
|
27
|
+
for (const e of activity) {
|
|
28
|
+
if (!e?.label) continue;
|
|
29
|
+
lines.push(e.kind === "action" ? `- clicked "${e.label}"` : `- opened ${e.label}${e.path ? ` (${e.path})` : ""}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (detail.attachments.length) {
|
|
33
|
+
lines.push("");
|
|
34
|
+
lines.push(`ATTACHMENTS: ${detail.attachments.map((a) => a.name).join(", ")} (screenshots of the problem).`);
|
|
35
|
+
}
|
|
36
|
+
if (detail.messages.length) {
|
|
37
|
+
lines.push("");
|
|
38
|
+
lines.push("CONVERSATION WITH THE TEAM:");
|
|
39
|
+
for (const m of detail.messages) {
|
|
40
|
+
lines.push(`- ${m.authorKind === "team" ? "Team" : "User"}: ${m.body}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (detail.events.length) {
|
|
44
|
+
lines.push("");
|
|
45
|
+
lines.push("HISTORY:");
|
|
46
|
+
for (const ev of detail.events) lines.push(`- ${eventLine(ev.type, ev.note)}`);
|
|
47
|
+
}
|
|
48
|
+
lines.push("");
|
|
49
|
+
lines.push(
|
|
50
|
+
"Investigate the code path behind this screen in the Fayz SDK (and the app that renders it), find the root cause, and propose a concrete fix. If you need to reproduce it, follow the trail above."
|
|
51
|
+
);
|
|
52
|
+
return lines.join("\n");
|
|
53
|
+
}
|
|
54
|
+
var STATUS_OPTIONS = ["received", "in_service", "waiting_you", "in_development", "resolved_check", "closed", "cancelled"];
|
|
55
|
+
var OPEN_STATUSES = ["received", "in_service", "waiting_you", "in_development", "resolved_check"];
|
|
56
|
+
function go(path) {
|
|
57
|
+
if (typeof window !== "undefined") window.location.hash = path;
|
|
58
|
+
}
|
|
59
|
+
function ticketNo(n) {
|
|
60
|
+
return `#${String(n).padStart(4, "0")}`;
|
|
61
|
+
}
|
|
62
|
+
function useConsoleRoute() {
|
|
63
|
+
const read = () => {
|
|
64
|
+
if (typeof window === "undefined") return null;
|
|
65
|
+
const m = window.location.hash.replace(/^#/, "").match(/^\/support\/console\/([^/?]+)/);
|
|
66
|
+
return m ? decodeURIComponent(m[1]) : null;
|
|
67
|
+
};
|
|
68
|
+
const [id, setId] = React.useState(read);
|
|
69
|
+
React.useEffect(() => {
|
|
70
|
+
const on = () => setId(read());
|
|
71
|
+
window.addEventListener("hashchange", on);
|
|
72
|
+
return () => window.removeEventListener("hashchange", on);
|
|
73
|
+
}, []);
|
|
74
|
+
return id;
|
|
75
|
+
}
|
|
76
|
+
function HelpdeskConsole() {
|
|
77
|
+
const [operator, setOperator] = React.useState(null);
|
|
78
|
+
React.useEffect(() => {
|
|
79
|
+
void isOperator().then(setOperator);
|
|
80
|
+
}, []);
|
|
81
|
+
const ticketId = useConsoleRoute();
|
|
82
|
+
if (operator === false) {
|
|
83
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-xl border bg-card p-10 text-center", children: [
|
|
84
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Acesso restrito" }),
|
|
85
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "A Central de Chamados \xE9 para operadores do suporte." })
|
|
86
|
+
] });
|
|
87
|
+
}
|
|
88
|
+
if (operator === null) return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
89
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-20 w-full" }),
|
|
90
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-20 w-full" })
|
|
91
|
+
] });
|
|
92
|
+
return ticketId ? /* @__PURE__ */ jsx(ConsoleTicketPage, { id: ticketId }) : /* @__PURE__ */ jsx(ConsoleListView, {});
|
|
93
|
+
}
|
|
94
|
+
function ConsoleListView() {
|
|
95
|
+
const [requests, setRequests] = React.useState([]);
|
|
96
|
+
const [loading, setLoading] = React.useState(true);
|
|
97
|
+
const [onlyOpen, setOnlyOpen] = React.useState(true);
|
|
98
|
+
const [search, setSearch] = React.useState("");
|
|
99
|
+
React.useEffect(() => {
|
|
100
|
+
let alive = true;
|
|
101
|
+
setLoading(true);
|
|
102
|
+
consoleListRequests(onlyOpen ? OPEN_STATUSES : void 0, search).then((r) => {
|
|
103
|
+
if (alive) setRequests(r);
|
|
104
|
+
}).catch(() => {
|
|
105
|
+
if (alive) setRequests([]);
|
|
106
|
+
}).finally(() => {
|
|
107
|
+
if (alive) setLoading(false);
|
|
108
|
+
});
|
|
109
|
+
return () => {
|
|
110
|
+
alive = false;
|
|
111
|
+
};
|
|
112
|
+
}, [onlyOpen, search]);
|
|
113
|
+
const grouped = PRIORITY_ORDER.map((p) => ({ priority: p, items: requests.filter((r) => r.priority === p) })).filter((g) => g.items.length > 0);
|
|
114
|
+
return /* @__PURE__ */ jsxs("div", { className: "mx-auto flex max-w-3xl flex-col gap-3", children: [
|
|
115
|
+
/* @__PURE__ */ jsx(Input, { value: search, onChange: (e) => setSearch(e.target.value), placeholder: "Buscar chamado ou loja\u2026" }),
|
|
116
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs", children: [
|
|
117
|
+
/* @__PURE__ */ jsx("button", { onClick: () => setOnlyOpen(true), className: `rounded-full px-3 py-1 ${onlyOpen ? "bg-foreground text-background" : "bg-muted text-muted-foreground"}`, children: "Em aberto" }),
|
|
118
|
+
/* @__PURE__ */ jsx("button", { onClick: () => setOnlyOpen(false), className: `rounded-full px-3 py-1 ${!onlyOpen ? "bg-foreground text-background" : "bg-muted text-muted-foreground"}`, children: "Todos" }),
|
|
119
|
+
/* @__PURE__ */ jsxs("span", { className: "ml-auto text-muted-foreground", children: [
|
|
120
|
+
requests.length,
|
|
121
|
+
" chamado(s)"
|
|
122
|
+
] })
|
|
123
|
+
] }),
|
|
124
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children: loading ? [0, 1, 2].map((i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-16 w-full" }, i)) : requests.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-xl border bg-card p-8 text-center text-sm text-muted-foreground", children: "Nenhum chamado por aqui." }) : grouped.map((g) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
125
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-1", children: [
|
|
126
|
+
/* @__PURE__ */ jsx(Badge, { variant: PRIORITY_TONE[g.priority], children: PRIORITY_LABEL[g.priority] }),
|
|
127
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground", children: g.items.length })
|
|
128
|
+
] }),
|
|
129
|
+
g.items.map((r) => /* @__PURE__ */ jsx(TicketRow, { req: r, onClick: () => go(`/support/console/${r.id}`) }, r.id))
|
|
130
|
+
] }, g.priority)) })
|
|
131
|
+
] });
|
|
132
|
+
}
|
|
133
|
+
function ConsoleTicketPage({ id }) {
|
|
134
|
+
const [detail, setDetail] = React.useState(null);
|
|
135
|
+
const [loading, setLoading] = React.useState(true);
|
|
136
|
+
React.useEffect(() => {
|
|
137
|
+
let alive = true;
|
|
138
|
+
setLoading(true);
|
|
139
|
+
consoleDetail(id).then((d) => {
|
|
140
|
+
if (alive) setDetail(d);
|
|
141
|
+
}).finally(() => {
|
|
142
|
+
if (alive) setLoading(false);
|
|
143
|
+
});
|
|
144
|
+
return () => {
|
|
145
|
+
alive = false;
|
|
146
|
+
};
|
|
147
|
+
}, [id]);
|
|
148
|
+
const ready = detail && detail.id === id;
|
|
149
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
150
|
+
/* @__PURE__ */ jsx(
|
|
151
|
+
SubpageHeader,
|
|
152
|
+
{
|
|
153
|
+
parentLabel: "Central de Chamados",
|
|
154
|
+
onBack: () => go("/support/console"),
|
|
155
|
+
title: ready ? `Ticket ${ticketNo(detail.number)}` : "Ticket",
|
|
156
|
+
subtitle: ready ? detail.tenantName ?? void 0 : void 0,
|
|
157
|
+
titleTrailing: ready ? /* @__PURE__ */ jsx(Badge, { variant: STATUS_TONE[detail.status], children: STATUS_LABEL[detail.status] }) : void 0
|
|
158
|
+
}
|
|
159
|
+
),
|
|
160
|
+
loading && !ready ? /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
161
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-28 w-full" }),
|
|
162
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-40 w-full" })
|
|
163
|
+
] }) : ready ? /* @__PURE__ */ jsx(OperatorDetail, { detail, onApplied: (d) => d && setDetail(d) }) : /* @__PURE__ */ jsxs("div", { className: "rounded-xl border bg-card p-10 text-center", children: [
|
|
164
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Chamado n\xE3o encontrado" }),
|
|
165
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => go("/support/console"), children: "Voltar" }) })
|
|
166
|
+
] })
|
|
167
|
+
] });
|
|
168
|
+
}
|
|
169
|
+
function TicketRow({ req, onClick }) {
|
|
170
|
+
return /* @__PURE__ */ jsxs(
|
|
171
|
+
"button",
|
|
172
|
+
{
|
|
173
|
+
onClick,
|
|
174
|
+
className: "flex w-full flex-col gap-1 rounded-lg border bg-card p-3 text-left transition-colors hover:border-primary/40 hover:bg-accent",
|
|
175
|
+
children: [
|
|
176
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 text-[11px] text-muted-foreground", children: [
|
|
177
|
+
/* @__PURE__ */ jsx("span", { className: "truncate font-medium text-foreground", children: req.tenantName ?? "Loja" }),
|
|
178
|
+
/* @__PURE__ */ jsx("span", { children: ticketNo(req.number) })
|
|
179
|
+
] }),
|
|
180
|
+
/* @__PURE__ */ jsx("div", { className: "truncate text-sm", children: req.subject || KIND_LABEL[req.kind] }),
|
|
181
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
182
|
+
/* @__PURE__ */ jsx(Badge, { variant: STATUS_TONE[req.status], children: STATUS_LABEL[req.status] }),
|
|
183
|
+
req.createdByName && /* @__PURE__ */ jsxs("span", { className: "truncate text-[11px] text-muted-foreground", children: [
|
|
184
|
+
"por ",
|
|
185
|
+
req.createdByName
|
|
186
|
+
] }),
|
|
187
|
+
req.messageCount > 0 && /* @__PURE__ */ jsxs("span", { className: "ml-auto text-[11px] text-muted-foreground", children: [
|
|
188
|
+
req.messageCount,
|
|
189
|
+
" msg"
|
|
190
|
+
] })
|
|
191
|
+
] })
|
|
192
|
+
]
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
function OperatorDetail({ detail, onApplied }) {
|
|
197
|
+
const [busy, setBusy] = React.useState(false);
|
|
198
|
+
const [reply, setReply] = React.useState("");
|
|
199
|
+
React.useEffect(() => {
|
|
200
|
+
setReply("");
|
|
201
|
+
}, [detail.id]);
|
|
202
|
+
async function run(fn, okMsg) {
|
|
203
|
+
setBusy(true);
|
|
204
|
+
try {
|
|
205
|
+
onApplied(await fn());
|
|
206
|
+
toast.success(okMsg);
|
|
207
|
+
} catch (e) {
|
|
208
|
+
toast.error(e?.message ?? "N\xE3o consegui aplicar.");
|
|
209
|
+
} finally {
|
|
210
|
+
setBusy(false);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const activity = detail.screenSnapshot?.activity ?? null;
|
|
214
|
+
return (
|
|
215
|
+
// Two columns, like the CRM deal card: the ticket and its controls on the
|
|
216
|
+
// left, the conversation and the activity feed on the right.
|
|
217
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-5 lg:grid-cols-2 lg:items-start", children: [
|
|
218
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
219
|
+
/* @__PURE__ */ jsxs("section", { className: "rounded-xl border bg-card p-5", children: [
|
|
220
|
+
/* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold leading-snug", children: detail.subject || KIND_LABEL[detail.kind] }),
|
|
221
|
+
/* @__PURE__ */ jsxs("p", { className: "mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground", children: [
|
|
222
|
+
/* @__PURE__ */ jsx("span", { children: KIND_LABEL[detail.kind] }),
|
|
223
|
+
/* @__PURE__ */ jsx(Badge, { variant: PRIORITY_TONE[detail.priority], children: PRIORITY_LABEL[detail.priority] }),
|
|
224
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
225
|
+
"\xB7 aberto por ",
|
|
226
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: detail.createdByName ?? "\u2014" })
|
|
227
|
+
] })
|
|
228
|
+
] }),
|
|
229
|
+
/* @__PURE__ */ jsx("p", { className: "mt-3 whitespace-pre-wrap text-sm leading-relaxed", children: detail.description }),
|
|
230
|
+
detail.route && /* @__PURE__ */ jsxs("p", { className: "mt-2 text-xs text-muted-foreground", children: [
|
|
231
|
+
"Tela: ",
|
|
232
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono", children: detail.route })
|
|
233
|
+
] }),
|
|
234
|
+
detail.attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-3 flex flex-wrap gap-2", children: detail.attachments.map((a) => /* @__PURE__ */ jsx(AttachmentCard, { att: a }, a.id)) }),
|
|
235
|
+
Array.isArray(activity) && activity.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-3 border-t pt-3 text-xs", children: [
|
|
236
|
+
/* @__PURE__ */ jsx("div", { className: "mb-1 text-muted-foreground", children: "Trilha at\xE9 o relato" }),
|
|
237
|
+
/* @__PURE__ */ jsx("ol", { className: "space-y-0.5", children: activity.map((e, i) => /* @__PURE__ */ jsx("li", { children: e.kind === "action" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
238
|
+
"clicou ",
|
|
239
|
+
/* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
|
|
240
|
+
'"',
|
|
241
|
+
e.label,
|
|
242
|
+
'"'
|
|
243
|
+
] })
|
|
244
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
245
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: e.label }),
|
|
246
|
+
" ",
|
|
247
|
+
e.path && /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px] text-muted-foreground", children: e.path })
|
|
248
|
+
] }) }, i)) })
|
|
249
|
+
] })
|
|
250
|
+
] }),
|
|
251
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border bg-card p-4", children: [
|
|
252
|
+
/* @__PURE__ */ jsx("h2", { className: "mb-2 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Andamento" }),
|
|
253
|
+
/* @__PURE__ */ jsx("label", { className: "mb-1 block text-xs text-muted-foreground", children: "Status" }),
|
|
254
|
+
/* @__PURE__ */ jsxs(Select, { value: detail.status, onValueChange: (v) => run(() => consoleSetStatus(detail.id, v), "Status atualizado"), disabled: busy, children: [
|
|
255
|
+
/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
256
|
+
/* @__PURE__ */ jsx(SelectContent, { children: STATUS_OPTIONS.map((s) => /* @__PURE__ */ jsx(SelectItem, { value: s, children: STATUS_LABEL[s] }, s)) })
|
|
257
|
+
] }),
|
|
258
|
+
/* @__PURE__ */ jsx("label", { className: "mb-1 mt-3 block text-xs text-muted-foreground", children: "Prioridade" }),
|
|
259
|
+
/* @__PURE__ */ jsxs(Select, { value: detail.priority, onValueChange: (v) => run(() => consoleSetPriority(detail.id, v), "Prioridade atualizada"), disabled: busy, children: [
|
|
260
|
+
/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
261
|
+
/* @__PURE__ */ jsx(SelectContent, { children: PRIORITY_ORDER.map((p) => /* @__PURE__ */ jsx(SelectItem, { value: p, children: PRIORITY_LABEL[p] }, p)) })
|
|
262
|
+
] })
|
|
263
|
+
] }),
|
|
264
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border bg-card p-4", children: [
|
|
265
|
+
/* @__PURE__ */ jsx("h2", { className: "mb-2 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Cliente" }),
|
|
266
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: detail.tenantName ?? "Loja" }),
|
|
267
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Loja que abriu o chamado \u2014 vinculada automaticamente." }),
|
|
268
|
+
/* @__PURE__ */ jsx(FixWithClaudeConsole, { detail })
|
|
269
|
+
] })
|
|
270
|
+
] }),
|
|
271
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
272
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border bg-card p-4", children: [
|
|
273
|
+
/* @__PURE__ */ jsx("h2", { className: "text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Conversa com o cliente" }),
|
|
274
|
+
detail.messages.length === 0 ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Sem mensagens ainda." }) : /* @__PURE__ */ jsx("div", { className: "mt-3 space-y-2", children: detail.messages.map((m) => /* @__PURE__ */ jsx("div", { className: m.authorKind === "team" ? "flex justify-end" : "flex justify-start", children: /* @__PURE__ */ jsxs("div", { className: `max-w-[85%] rounded-lg px-3 py-2 text-sm ${m.authorKind === "team" ? "bg-primary/10" : "bg-muted"}`, children: [
|
|
275
|
+
/* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap", children: m.body }),
|
|
276
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1 text-right text-[10px] text-muted-foreground", children: fmtWhen(m.createdAt) })
|
|
277
|
+
] }) }, m.id)) }),
|
|
278
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-3 flex items-end gap-2", children: [
|
|
279
|
+
/* @__PURE__ */ jsx(Textarea, { rows: 2, value: reply, onChange: (e) => setReply(e.target.value), placeholder: "Responder ao cliente\u2026", className: "flex-1" }),
|
|
280
|
+
/* @__PURE__ */ jsx(Button, { disabled: busy || !reply.trim(), onClick: () => run(async () => {
|
|
281
|
+
const d = await consoleReply(detail.id, reply);
|
|
282
|
+
setReply("");
|
|
283
|
+
return d;
|
|
284
|
+
}, "Resposta enviada"), children: "Responder" })
|
|
285
|
+
] })
|
|
286
|
+
] }),
|
|
287
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border bg-card p-4", children: [
|
|
288
|
+
/* @__PURE__ */ jsx("h2", { className: "text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Atividades" }),
|
|
289
|
+
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: [
|
|
290
|
+
/* @__PURE__ */ jsx("span", { className: "mt-1 h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/40" }),
|
|
291
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
292
|
+
/* @__PURE__ */ jsx("div", { children: eventLine(e.type, e.note) }),
|
|
293
|
+
/* @__PURE__ */ jsx("div", { className: "text-muted-foreground", children: fmtWhen(e.createdAt) })
|
|
294
|
+
] })
|
|
295
|
+
] }, e.id)) })
|
|
296
|
+
] })
|
|
297
|
+
] })
|
|
298
|
+
] })
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
function fmtWhen(iso) {
|
|
302
|
+
try {
|
|
303
|
+
return new Date(iso).toLocaleString("pt-BR", { day: "2-digit", month: "2-digit", hour: "2-digit", minute: "2-digit" });
|
|
304
|
+
} catch {
|
|
305
|
+
return iso;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
function FixWithClaudeConsole({ detail }) {
|
|
309
|
+
const [open, setOpen] = React.useState(false);
|
|
310
|
+
const prompt = React.useMemo(() => open ? buildFixPrompt(detail, detail.tenantName ?? void 0) : "", [open, detail]);
|
|
311
|
+
async function copy() {
|
|
312
|
+
try {
|
|
313
|
+
await navigator.clipboard.writeText(prompt);
|
|
314
|
+
toast.success("Prompt copiado");
|
|
315
|
+
} catch {
|
|
316
|
+
toast.error("N\xE3o consegui copiar.");
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const Spark = ICON_MAP.Sparkles;
|
|
320
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
321
|
+
/* @__PURE__ */ jsxs(Button, { className: "mt-3 w-full justify-center gap-2", onClick: () => setOpen(true), children: [
|
|
322
|
+
Spark && /* @__PURE__ */ jsx(Spark, { className: "h-4 w-4" }),
|
|
323
|
+
" Corrigir com Claude"
|
|
324
|
+
] }),
|
|
325
|
+
/* @__PURE__ */ jsx(ModalTask, { open, title: "Corrigir com Claude", width: "min(42rem, 94vw)", onClose: () => setOpen(false), children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 p-4", children: [
|
|
326
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Copie e cole no Claude para investigar e corrigir." }),
|
|
327
|
+
/* @__PURE__ */ jsx(Textarea, { value: prompt, readOnly: true, rows: 14, className: "font-mono text-xs", onFocus: (e) => e.currentTarget.select() }),
|
|
328
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
|
|
329
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => setOpen(false), children: "Fechar" }),
|
|
330
|
+
/* @__PURE__ */ jsx(Button, { onClick: copy, children: "Copiar prompt" })
|
|
331
|
+
] })
|
|
332
|
+
] }) })
|
|
333
|
+
] });
|
|
334
|
+
}
|
|
335
|
+
function AttachmentCard({ att }) {
|
|
336
|
+
const [url, setUrl] = React.useState(null);
|
|
337
|
+
React.useEffect(() => {
|
|
338
|
+
let alive = true;
|
|
339
|
+
if ((att.contentType ?? "").startsWith("image/")) void signedUrl(att.storagePath).then((u) => {
|
|
340
|
+
if (alive) setUrl(u);
|
|
341
|
+
});
|
|
342
|
+
return () => {
|
|
343
|
+
alive = false;
|
|
344
|
+
};
|
|
345
|
+
}, [att.storagePath, att.contentType]);
|
|
346
|
+
return /* @__PURE__ */ jsxs("a", { href: url ?? void 0, target: "_blank", rel: "noreferrer", className: "flex items-center gap-2 rounded-lg border bg-card p-2 hover:bg-muted", children: [
|
|
347
|
+
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" }),
|
|
348
|
+
/* @__PURE__ */ jsx("span", { className: "max-w-[10rem] truncate text-xs", children: att.name })
|
|
349
|
+
] });
|
|
350
|
+
}
|
|
351
|
+
var HelpdeskConsole_default = HelpdeskConsole;
|
|
352
|
+
|
|
353
|
+
export { HelpdeskConsole, HelpdeskConsole_default as default };
|
|
354
|
+
//# sourceMappingURL=HelpdeskConsole-7W5IAQIU.js.map
|
|
355
|
+
//# sourceMappingURL=HelpdeskConsole-7W5IAQIU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/fix-prompt.ts","../src/views/HelpdeskConsole.tsx"],"names":[],"mappings":";;;;;;;AA+BO,SAAS,cAAA,CAAe,QAAwB,OAAA,EAA0B;AAC/E,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,MAAM,GAAA,GAAM,OAAA,EAAS,IAAA,EAAK,IAAK,cAAA;AAC/B,EAAA,KAAA,CAAM,IAAA,CAAK,CAAA,mCAAA,EAAsC,GAAG,CAAA,CAAA,CAAG,CAAA;AACvD,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,KAAA,CAAM,IAAA,CAAK,WAAW,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAC,SAAM,UAAA,CAAW,MAAA,CAAO,IAAI,CAAC,CAAA,cAAA,EAAc,aAAa,MAAA,CAAO,MAAM,CAAC,CAAA,CAAE,CAAA;AACpI,EAAA,IAAI,OAAO,KAAA,EAAO,KAAA,CAAM,KAAK,CAAA,gBAAA,EAAmB,MAAA,CAAO,KAAK,CAAA,CAAE,CAAA;AAG9D,EAAA,IAAI,OAAO,QAAA,EAAU,KAAA,CAAM,KAAK,CAAA,mBAAA,EAAsB,MAAA,CAAO,QAAQ,CAAA,CAAE,CAAA;AACvE,EAAA,IAAI,OAAO,SAAA,EAAW,KAAA,CAAM,KAAK,CAAA,qBAAA,EAAwB,MAAA,CAAO,SAAS,CAAA,CAAE,CAAA;AAC3E,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,KAAA,CAAM,KAAK,oCAAqC,CAAA;AAGhD,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,OAAA,EAAS,IAAA,EAAK;AACrC,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,WAAA,CAAY,IAAA,EAAK;AAC5C,EAAA,IAAI,OAAA,IAAW,CAAC,WAAA,CAAY,WAAA,EAAY,CAAE,UAAA,CAAW,OAAA,CAAQ,WAAA,EAAa,CAAA,EAAG,KAAA,CAAM,IAAA,CAAK,OAAO,CAAA;AAC/F,EAAA,KAAA,CAAM,KAAK,WAAW,CAAA;AAEtB,EAAA,MAAM,QAAA,GAAY,MAAA,CAAO,cAAA,EAAgB,QAAA,IAAY,IAAA;AACrD,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,QAAQ,CAAA,IAAK,SAAS,MAAA,EAAQ;AAC9C,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,IAAA,KAAA,CAAM,KAAK,wDAAwD,CAAA;AACnE,IAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACxB,MAAA,IAAI,CAAC,GAAG,KAAA,EAAO;AACf,MAAA,KAAA,CAAM,KAAK,CAAA,CAAE,IAAA,KAAS,WAAW,CAAA,WAAA,EAAc,CAAA,CAAE,KAAK,CAAA,CAAA,CAAA,GAAM,CAAA,SAAA,EAAY,EAAE,KAAK,CAAA,EAAG,EAAE,IAAA,GAAO,CAAA,EAAA,EAAK,EAAE,IAAI,CAAA,CAAA,CAAA,GAAM,EAAE,CAAA,CAAE,CAAA;AAAA,IAClH;AAAA,EACF;AAEA,EAAA,IAAI,MAAA,CAAO,YAAY,MAAA,EAAQ;AAC7B,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,aAAA,EAAgB,MAAA,CAAO,WAAA,CAAY,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,8BAAA,CAAgC,CAAA;AAAA,EAC7G;AAEA,EAAA,IAAI,MAAA,CAAO,SAAS,MAAA,EAAQ;AAC1B,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,IAAA,KAAA,CAAM,KAAK,6BAA6B,CAAA;AACxC,IAAA,KAAA,MAAW,CAAA,IAAK,OAAO,QAAA,EAAU;AAC/B,MAAA,KAAA,CAAM,IAAA,CAAK,CAAA,EAAA,EAAK,CAAA,CAAE,UAAA,KAAe,MAAA,GAAS,SAAS,MAAM,CAAA,EAAA,EAAK,CAAA,CAAE,IAAI,CAAA,CAAE,CAAA;AAAA,IACxE;AAAA,EACF;AAEA,EAAA,IAAI,MAAA,CAAO,OAAO,MAAA,EAAQ;AACxB,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,IAAA,KAAA,CAAM,KAAK,UAAU,CAAA;AACrB,IAAA,KAAA,MAAW,EAAA,IAAM,MAAA,CAAO,MAAA,EAAQ,KAAA,CAAM,IAAA,CAAK,CAAA,EAAA,EAAK,SAAA,CAAU,EAAA,CAAG,IAAA,EAAM,EAAA,CAAG,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,EAC/E;AAEA,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,KAAA,CAAM,IAAA;AAAA,IACJ;AAAA,GAEF;AACA,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;ACrEA,IAAM,cAAA,GAAkC,CAAC,UAAA,EAAY,YAAA,EAAc,eAAe,gBAAA,EAAkB,gBAAA,EAAkB,UAAU,WAAW,CAAA;AAC3I,IAAM,gBAAiC,CAAC,UAAA,EAAY,YAAA,EAAc,aAAA,EAAe,kBAAkB,gBAAgB,CAAA;AAGnH,SAAS,GAAG,IAAA,EAAc;AAAE,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,MAAA,CAAO,SAAS,IAAA,GAAO,IAAA;AAAK;AAE3F,SAAS,SAAS,CAAA,EAAmB;AAAE,EAAA,OAAO,IAAI,MAAA,CAAO,CAAC,EAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA;AAAG;AAG/E,SAAS,eAAA,GAAiC;AACxC,EAAA,MAAM,OAAO,MAAM;AACjB,IAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,IAAA;AAC1C,IAAA,MAAM,CAAA,GAAI,OAAO,QAAA,CAAS,IAAA,CAAK,QAAQ,IAAA,EAAM,EAAE,CAAA,CAAE,KAAA,CAAM,+BAA+B,CAAA;AACtF,IAAA,OAAO,CAAA,GAAI,kBAAA,CAAmB,CAAA,CAAE,CAAC,CAAE,CAAA,GAAI,IAAA;AAAA,EACzC,CAAA;AACA,EAAA,MAAM,CAAC,EAAA,EAAI,KAAK,CAAA,GAAI,KAAA,CAAM,SAAwB,IAAI,CAAA;AACtD,EAAA,KAAA,CAAM,UAAU,MAAM;AACpB,IAAA,MAAM,EAAA,GAAK,MAAM,KAAA,CAAM,IAAA,EAAM,CAAA;AAC7B,IAAA,MAAA,CAAO,gBAAA,CAAiB,cAAc,EAAE,CAAA;AACxC,IAAA,OAAO,MAAM,MAAA,CAAO,mBAAA,CAAoB,YAAA,EAAc,EAAE,CAAA;AAAA,EAC1D,CAAA,EAAG,EAAE,CAAA;AACL,EAAA,OAAO,EAAA;AACT;AAQO,SAAS,eAAA,GAAkB;AAChC,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,KAAA,CAAM,SAAyB,IAAI,CAAA;AACnE,EAAA,KAAA,CAAM,UAAU,MAAM;AAAE,IAAA,KAAK,UAAA,EAAW,CAAE,IAAA,CAAK,WAAW,CAAA;AAAA,EAAE,CAAA,EAAG,EAAE,CAAA;AACjE,EAAA,MAAM,WAAW,eAAA,EAAgB;AAEjC,EAAA,IAAI,aAAa,KAAA,EAAO;AACtB,IAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4CAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,qBAAA,EAAsB,QAAA,EAAA,iBAAA,EAAe,CAAA;AAAA,sBAClD,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,oCAAA,EAAqC,QAAA,EAAA,wDAAA,EAAmD;AAAA,KAAA,EACvG,CAAA;AAAA,EAEJ;AACA,EAAA,IAAI,aAAa,IAAA,EAAM,uBAAO,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,WAAA,EAAY,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,QAAA,EAAA,EAAS,WAAU,aAAA,EAAc,CAAA;AAAA,oBAAE,GAAA,CAAC,QAAA,EAAA,EAAS,SAAA,EAAU,aAAA,EAAc;AAAA,GAAA,EAAE,CAAA;AACjI,EAAA,OAAO,2BAAW,GAAA,CAAC,iBAAA,EAAA,EAAkB,IAAI,QAAA,EAAU,CAAA,uBAAM,eAAA,EAAA,EAAgB,CAAA;AAC3E;AAEA,SAAS,eAAA,GAAkB;AACzB,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,IAAI,KAAA,CAAM,QAAA,CAA2B,EAAE,CAAA;AACnE,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,KAAA,CAAM,SAAS,IAAI,CAAA;AACjD,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,KAAA,CAAM,SAAS,IAAI,CAAA;AACnD,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,KAAA,CAAM,SAAS,EAAE,CAAA;AAE7C,EAAA,KAAA,CAAM,UAAU,MAAM;AACpB,IAAA,IAAI,KAAA,GAAQ,IAAA;AACZ,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,mBAAA,CAAoB,WAAW,aAAA,GAAgB,MAAA,EAAW,MAAM,CAAA,CAC7D,IAAA,CAAK,CAAC,CAAA,KAAM;AAAE,MAAA,IAAI,KAAA,cAAmB,CAAC,CAAA;AAAA,IAAE,CAAC,CAAA,CACzC,KAAA,CAAM,MAAM;AAAE,MAAA,IAAI,KAAA,EAAO,WAAA,CAAY,EAAE,CAAA;AAAA,IAAE,CAAC,CAAA,CAC1C,OAAA,CAAQ,MAAM;AAAE,MAAA,IAAI,KAAA,aAAkB,KAAK,CAAA;AAAA,IAAE,CAAC,CAAA;AACjD,IAAA,OAAO,MAAM;AAAE,MAAA,KAAA,GAAQ,KAAA;AAAA,IAAM,CAAA;AAAA,EAC/B,CAAA,EAAG,CAAC,QAAA,EAAU,MAAM,CAAC,CAAA;AAErB,EAAA,MAAM,OAAA,GAAU,cAAA,CACb,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,QAAA,EAAU,CAAA,EAAG,KAAA,EAAO,QAAA,CAAS,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,QAAA,KAAa,CAAC,CAAA,EAAE,CAAE,CAAA,CAC7E,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,KAAA,CAAM,MAAA,GAAS,CAAC,CAAA;AAEnC,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uCAAA,EACb,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,KAAA,EAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,QAAA,EAAU,CAAC,CAAA,KAAM,SAAA,CAAU,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA,EAAG,WAAA,EAAY,8BAAA,EAA0B,CAAA;AAAA,oBACxG,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iCAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,QAAA,EAAA,EAAO,OAAA,EAAS,MAAM,WAAA,CAAY,IAAI,CAAA,EAAG,SAAA,EAAW,CAAA,uBAAA,EAA0B,QAAA,GAAW,+BAAA,GAAkC,gCAAgC,CAAA,CAAA,EAAI,QAAA,EAAA,WAAA,EAAS,CAAA;AAAA,sBACzK,GAAA,CAAC,QAAA,EAAA,EAAO,OAAA,EAAS,MAAM,YAAY,KAAK,CAAA,EAAG,SAAA,EAAW,CAAA,uBAAA,EAA0B,CAAC,QAAA,GAAW,+BAAA,GAAkC,gCAAgC,IAAI,QAAA,EAAA,OAAA,EAAK,CAAA;AAAA,sBACvK,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,+BAAA,EAAiC,QAAA,EAAA;AAAA,QAAA,QAAA,CAAS,MAAA;AAAA,QAAO;AAAA,OAAA,EAAW;AAAA,KAAA,EAC9E,CAAA;AAAA,wBAEC,KAAA,EAAA,EAAI,SAAA,EAAU,qBAAA,EACZ,QAAA,EAAA,OAAA,GACC,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,CAAE,IAAI,CAAC,CAAA,qBAAM,GAAA,CAAC,QAAA,EAAA,EAAiB,WAAU,aAAA,EAAA,EAAb,CAA2B,CAAE,CAAA,GAC/D,SAAS,MAAA,KAAW,CAAA,mBACtB,GAAA,CAAC,KAAA,EAAA,EAAI,WAAU,yEAAA,EAA0E,QAAA,EAAA,0BAAA,EAAwB,CAAA,GAEjH,OAAA,CAAQ,IAAI,CAAC,CAAA,qBACX,IAAA,CAAC,KAAA,EAAA,EAAqB,WAAU,uBAAA,EAC9B,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,8BAAA,EACb,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,KAAA,EAAA,EAAM,SAAS,aAAA,CAAc,CAAA,CAAE,QAAQ,CAAA,EAAI,QAAA,EAAA,cAAA,CAAe,CAAA,CAAE,QAAQ,CAAA,EAAE,CAAA;AAAA,4BACtE,MAAA,EAAA,EAAK,SAAA,EAAU,mCAAA,EAAqC,QAAA,EAAA,CAAA,CAAE,MAAM,MAAA,EAAO;AAAA,OAAA,EACtE,CAAA;AAAA,MACC,EAAE,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,qBACZ,GAAA,CAAC,aAAqB,GAAA,EAAK,CAAA,EAAG,SAAS,MAAM,EAAA,CAAG,oBAAoB,CAAA,CAAE,EAAE,EAAE,CAAA,EAAA,EAA1D,CAAA,CAAE,EAA2D,CAC9E;AAAA,KAAA,EAAA,EAPO,CAAA,CAAE,QAQZ,CACD,CAAA,EAEL;AAAA,GAAA,EACF,CAAA;AAEJ;AAGA,SAAS,iBAAA,CAAkB,EAAE,EAAA,EAAG,EAAmB;AACjD,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,KAAA,CAAM,SAA+B,IAAI,CAAA;AACrE,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,KAAA,CAAM,SAAS,IAAI,CAAA;AAEjD,EAAA,KAAA,CAAM,UAAU,MAAM;AACpB,IAAA,IAAI,KAAA,GAAQ,IAAA;AACZ,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,aAAA,CAAc,EAAE,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,KAAM;AAAE,MAAA,IAAI,KAAA,YAAiB,CAAC,CAAA;AAAA,IAAE,CAAC,CAAA,CAAE,OAAA,CAAQ,MAAM;AAAE,MAAA,IAAI,KAAA,aAAkB,KAAK,CAAA;AAAA,IAAE,CAAC,CAAA;AACzG,IAAA,OAAO,MAAM;AAAE,MAAA,KAAA,GAAQ,KAAA;AAAA,IAAM,CAAA;AAAA,EAC/B,CAAA,EAAG,CAAC,EAAE,CAAC,CAAA;AAEP,EAAA,MAAM,KAAA,GAAQ,MAAA,IAAU,MAAA,CAAO,EAAA,KAAO,EAAA;AAEtC,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,qBAAA,EACb,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,aAAA;AAAA,MAAA;AAAA,QACC,WAAA,EAAY,qBAAA;AAAA,QACZ,MAAA,EAAQ,MAAM,EAAA,CAAG,kBAAkB,CAAA;AAAA,QACnC,OAAO,KAAA,GAAQ,CAAA,OAAA,EAAU,SAAS,MAAA,CAAO,MAAM,CAAC,CAAA,CAAA,GAAK,QAAA;AAAA,QACrD,QAAA,EAAU,KAAA,GAAS,MAAA,CAAO,UAAA,IAAc,MAAA,GAAa,MAAA;AAAA,QACrD,aAAA,EAAe,KAAA,mBAAQ,GAAA,CAAC,KAAA,EAAA,EAAM,OAAA,EAAS,WAAA,CAAY,MAAA,CAAO,MAAM,CAAA,EAAI,QAAA,EAAA,YAAA,CAAa,MAAA,CAAO,MAAM,GAAE,CAAA,GAAW;AAAA;AAAA,KAC7G;AAAA,IACC,WAAW,CAAC,KAAA,mBACX,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,WAAA,EAAY,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,QAAA,EAAA,EAAS,WAAU,aAAA,EAAc,CAAA;AAAA,sBAAE,GAAA,CAAC,QAAA,EAAA,EAAS,SAAA,EAAU,aAAA,EAAc;AAAA,KAAA,EAAE,IACjG,KAAA,mBACF,GAAA,CAAC,cAAA,EAAA,EAAe,MAAA,EAAgB,WAAW,CAAC,CAAA,KAAM,CAAA,IAAK,SAAA,CAAU,CAAC,CAAA,EAAG,CAAA,mBAErE,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,4CAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,qBAAA,EAAsB,QAAA,EAAA,2BAAA,EAAsB,CAAA;AAAA,sBACzD,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,MAAA,EAAO,8BAAC,MAAA,EAAA,EAAO,OAAA,EAAQ,SAAA,EAAU,OAAA,EAAS,MAAM,EAAA,CAAG,kBAAkB,CAAA,EAAG,oBAAM,CAAA,EAAS;AAAA,KAAA,EACxG;AAAA,GAAA,EAEJ,CAAA;AAEJ;AAEA,SAAS,SAAA,CAAU,EAAE,GAAA,EAAK,OAAA,EAAQ,EAAiD;AACjF,EAAA,uBACE,IAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,OAAA;AAAA,MACA,SAAA,EAAU,8HAAA;AAAA,MAEV,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,2EAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,sCAAA,EAAwC,QAAA,EAAA,GAAA,CAAI,cAAc,MAAA,EAAO,CAAA;AAAA,0BACjF,GAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,QAAA,CAAS,GAAA,CAAI,MAAM,CAAA,EAAE;AAAA,SAAA,EAC9B,CAAA;AAAA,wBACA,GAAA,CAAC,SAAI,SAAA,EAAU,kBAAA,EAAoB,cAAI,OAAA,IAAW,UAAA,CAAW,GAAA,CAAI,IAAI,CAAA,EAAE,CAAA;AAAA,wBACvE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2BAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,KAAA,EAAA,EAAM,SAAS,WAAA,CAAY,GAAA,CAAI,MAAM,CAAA,EAAI,QAAA,EAAA,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA,EAAE,CAAA;AAAA,UAClE,GAAA,CAAI,aAAA,oBAAiB,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,4CAAA,EAA6C,QAAA,EAAA;AAAA,YAAA,MAAA;AAAA,YAAK,GAAA,CAAI;AAAA,WAAA,EAAc,CAAA;AAAA,UACzG,IAAI,YAAA,GAAe,CAAA,oBAAK,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,2CAAA,EAA6C,QAAA,EAAA;AAAA,YAAA,GAAA,CAAI,YAAA;AAAA,YAAa;AAAA,WAAA,EAAI;AAAA,SAAA,EAC7G;AAAA;AAAA;AAAA,GACF;AAEJ;AAEA,SAAS,cAAA,CAAe,EAAE,MAAA,EAAQ,SAAA,EAAU,EAA4E;AACtH,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,KAAA,CAAM,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,KAAA,CAAM,SAAS,EAAE,CAAA;AAE3C,EAAA,KAAA,CAAM,UAAU,MAAM;AAAE,IAAA,QAAA,CAAS,EAAE,CAAA;AAAA,EAAE,CAAA,EAAG,CAAC,MAAA,CAAO,EAAE,CAAC,CAAA;AAEnD,EAAA,eAAe,GAAA,CAAI,IAAyC,KAAA,EAAe;AACzE,IAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,IAAA,IAAI;AAAE,MAAA,SAAA,CAAU,MAAM,IAAI,CAAA;AAAG,MAAA,KAAA,CAAM,QAAQ,KAAK,CAAA;AAAA,IAAE,SAC3C,CAAA,EAAG;AAAE,MAAA,KAAA,CAAM,KAAA,CAAO,CAAA,EAAa,OAAA,IAAW,0BAAuB,CAAA;AAAA,IAAE,CAAA,SAC1E;AAAU,MAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,IAAE;AAAA,EAC3B;AAEA,EAAA,MAAM,QAAA,GAAY,MAAA,CAAO,cAAA,EAAgB,QAAA,IAAY,IAAA;AAErD,EAAA;AAAA;AAAA;AAAA,oBAGE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0CAAA,EAEb,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,qBAAA,EACb,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,SAAA,EAAA,EAAQ,WAAU,+BAAA,EACjB,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,IAAA,EAAA,EAAG,WAAU,oCAAA,EAAsC,QAAA,EAAA,MAAA,CAAO,WAAW,UAAA,CAAW,MAAA,CAAO,IAAI,CAAA,EAAE,CAAA;AAAA,0BAC9F,IAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,gFAAA,EACX,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,UAAA,CAAW,MAAA,CAAO,IAAI,CAAA,EAAE,CAAA;AAAA,4BAC/B,GAAA,CAAC,KAAA,EAAA,EAAM,OAAA,EAAS,aAAA,CAAc,MAAA,CAAO,QAAQ,CAAA,EAAI,QAAA,EAAA,cAAA,CAAe,MAAA,CAAO,QAAQ,CAAA,EAAE,CAAA;AAAA,iCAChF,MAAA,EAAA,EAAK,QAAA,EAAA;AAAA,cAAA,kBAAA;AAAA,kCAAc,MAAA,EAAA,EAAK,SAAA,EAAU,6BAAA,EAA+B,QAAA,EAAA,MAAA,CAAO,iBAAiB,QAAA,EAAI;AAAA,aAAA,EAAO;AAAA,WAAA,EACvG,CAAA;AAAA,0BACA,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,kDAAA,EAAoD,iBAAO,WAAA,EAAY,CAAA;AAAA,UACnF,MAAA,CAAO,KAAA,oBAAS,IAAA,CAAC,GAAA,EAAA,EAAE,WAAU,oCAAA,EAAqC,QAAA,EAAA;AAAA,YAAA,QAAA;AAAA,4BAAM,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,WAAA,EAAa,iBAAO,KAAA,EAAM;AAAA,WAAA,EAAO,CAAA;AAAA,UACzH,MAAA,CAAO,YAAY,MAAA,GAAS,CAAA,wBAC1B,KAAA,EAAA,EAAI,SAAA,EAAU,6BACZ,QAAA,EAAA,MAAA,CAAO,WAAA,CAAY,IAAI,CAAC,CAAA,yBAAO,cAAA,EAAA,EAA0B,GAAA,EAAK,KAAX,CAAA,CAAE,EAAY,CAAE,CAAA,EACtE,CAAA;AAAA,UAED,KAAA,CAAM,OAAA,CAAQ,QAAQ,CAAA,IAAK,QAAA,CAAS,SAAS,CAAA,oBAC5C,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4BAAA,EACb,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4BAAA,EAA6B,QAAA,EAAA,wBAAA,EAAmB,CAAA;AAAA,4BAC/D,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,aAAA,EACX,mBAAS,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,qBAChB,GAAA,CAAC,IAAA,EAAA,EAAY,QAAA,EAAA,CAAA,CAAE,IAAA,KAAS,2BAAW,IAAA,CAAA,QAAA,EAAA,EAAE,QAAA,EAAA;AAAA,cAAA,SAAA;AAAA,8BAAO,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,aAAA,EAAc,QAAA,EAAA;AAAA,gBAAA,GAAA;AAAA,gBAAE,CAAA,CAAE,KAAA;AAAA,gBAAM;AAAA,eAAA,EAAC;AAAA,aAAA,EAAO,oBAAM,IAAA,CAAA,QAAA,EAAA,EAAE,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,aAAA,EAAe,QAAA,EAAA,CAAA,CAAE,KAAA,EAAM,CAAA;AAAA,cAAO,GAAA;AAAA,cAAE,EAAE,IAAA,oBAAQ,GAAA,CAAC,UAAK,SAAA,EAAU,6CAAA,EAA+C,YAAE,IAAA,EAAK;AAAA,aAAA,EAAQ,CAAA,EAAA,EAAnO,CAAuO,CACjP,CAAA,EACH;AAAA,WAAA,EACF;AAAA,SAAA,EAEJ,CAAA;AAAA,wBAEA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,+BAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,+EAAA,EAAgF,QAAA,EAAA,WAAA,EAAS,CAAA;AAAA,0BACvG,GAAA,CAAC,OAAA,EAAA,EAAM,SAAA,EAAU,0CAAA,EAA2C,QAAA,EAAA,QAAA,EAAM,CAAA;AAAA,+BACjE,MAAA,EAAA,EAAO,KAAA,EAAO,OAAO,MAAA,EAAQ,aAAA,EAAe,CAAC,CAAA,KAAM,GAAA,CAAI,MAAM,gBAAA,CAAiB,OAAO,EAAA,EAAI,CAAkB,GAAG,mBAAmB,CAAA,EAAG,UAAU,IAAA,EAC7I,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,aAAA,EAAA,EAAc,QAAA,kBAAA,GAAA,CAAC,WAAA,EAAA,EAAY,CAAA,EAAE,CAAA;AAAA,4BAC9B,GAAA,CAAC,aAAA,EAAA,EACE,QAAA,EAAA,cAAA,CAAe,GAAA,CAAI,CAAC,CAAA,qBAAM,GAAA,CAAC,UAAA,EAAA,EAAmB,KAAA,EAAO,GAAI,QAAA,EAAA,YAAA,CAAa,CAAC,CAAA,EAAA,EAA5B,CAA8B,CAAa,CAAA,EACzF;AAAA,WAAA,EACF,CAAA;AAAA,0BACA,GAAA,CAAC,OAAA,EAAA,EAAM,SAAA,EAAU,+CAAA,EAAgD,QAAA,EAAA,YAAA,EAAU,CAAA;AAAA,+BAC1E,MAAA,EAAA,EAAO,KAAA,EAAO,OAAO,QAAA,EAAU,aAAA,EAAe,CAAC,CAAA,KAAM,GAAA,CAAI,MAAM,kBAAA,CAAmB,OAAO,EAAA,EAAI,CAAoB,GAAG,uBAAuB,CAAA,EAAG,UAAU,IAAA,EACvJ,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,aAAA,EAAA,EAAc,QAAA,kBAAA,GAAA,CAAC,WAAA,EAAA,EAAY,CAAA,EAAE,CAAA;AAAA,4BAC9B,GAAA,CAAC,aAAA,EAAA,EACE,QAAA,EAAA,cAAA,CAAe,GAAA,CAAI,CAAC,CAAA,qBAAM,GAAA,CAAC,UAAA,EAAA,EAAmB,KAAA,EAAO,GAAI,QAAA,EAAA,cAAA,CAAe,CAAC,CAAA,EAAA,EAA9B,CAAgC,CAAa,CAAA,EAC3F;AAAA,WAAA,EACF;AAAA,SAAA,EACF,CAAA;AAAA,wBAEA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,+BAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,+EAAA,EAAgF,QAAA,EAAA,SAAA,EAAO,CAAA;AAAA,8BAGpG,GAAA,EAAA,EAAE,SAAA,EAAU,qBAAA,EAAuB,QAAA,EAAA,MAAA,CAAO,cAAc,MAAA,EAAO,CAAA;AAAA,0BAChE,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,+BAAA,EAAgC,QAAA,EAAA,4DAAA,EAAqD,CAAA;AAAA,0BAClG,GAAA,CAAC,wBAAqB,MAAA,EAAgB;AAAA,SAAA,EACxC;AAAA,OAAA,EACF,CAAA;AAAA,sBAGA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,qBAAA,EACb,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,+BAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,0EAAA,EAA2E,QAAA,EAAA,wBAAA,EAAsB,CAAA;AAAA,UAC9G,OAAO,QAAA,CAAS,MAAA,KAAW,CAAA,mBAC1B,GAAA,CAAC,OAAE,SAAA,EAAU,oCAAA,EAAqC,QAAA,EAAA,sBAAA,EAAoB,CAAA,uBAErE,KAAA,EAAA,EAAI,SAAA,EAAU,gBAAA,EACZ,QAAA,EAAA,MAAA,CAAO,SAAS,GAAA,CAAI,CAAC,CAAA,qBACpB,GAAA,CAAC,SAAe,SAAA,EAAW,CAAA,CAAE,UAAA,KAAe,MAAA,GAAS,qBAAqB,oBAAA,EACxE,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,4CAA4C,CAAA,CAAE,UAAA,KAAe,MAAA,GAAS,eAAA,GAAkB,UAAU,CAAA,CAAA,EAChH,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,qBAAA,EAAuB,QAAA,EAAA,CAAA,CAAE,IAAA,EAAK,CAAA;AAAA,gCAC5C,KAAA,EAAA,EAAI,SAAA,EAAU,qDAAqD,QAAA,EAAA,OAAA,CAAQ,CAAA,CAAE,SAAS,CAAA,EAAE;AAAA,WAAA,EAC3F,CAAA,EAAA,EAJQ,CAAA,CAAE,EAKZ,CACD,CAAA,EACH,CAAA;AAAA,0BAEF,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2BAAA,EACb,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,YAAS,IAAA,EAAM,CAAA,EAAG,KAAA,EAAO,KAAA,EAAO,UAAU,CAAC,CAAA,KAAM,QAAA,CAAS,CAAA,CAAE,OAAO,KAAK,CAAA,EAAG,WAAA,EAAY,4BAAA,EAAwB,WAAU,QAAA,EAAS,CAAA;AAAA,4BACnI,GAAA,CAAC,MAAA,EAAA,EAAO,QAAA,EAAU,IAAA,IAAQ,CAAC,KAAA,CAAM,IAAA,EAAK,EAAG,OAAA,EAAS,MAAM,GAAA,CAAI,YAAY;AAAE,cAAA,MAAM,CAAA,GAAI,MAAM,YAAA,CAAa,MAAA,CAAO,IAAI,KAAK,CAAA;AAAG,cAAA,QAAA,CAAS,EAAE,CAAA;AAAG,cAAA,OAAO,CAAA;AAAA,YAAE,CAAA,EAAG,kBAAkB,CAAA,EAAG,QAAA,EAAA,WAAA,EAAS;AAAA,WAAA,EACpL;AAAA,SAAA,EACF,CAAA;AAAA,wBAEA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,+BAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,0EAAA,EAA2E,QAAA,EAAA,YAAA,EAAU,CAAA;AAAA,UAClG,MAAA,CAAO,OAAO,MAAA,KAAW,CAAA,uBACvB,GAAA,EAAA,EAAE,SAAA,EAAU,oCAAA,EAAqC,QAAA,EAAA,iBAAA,EAAe,CAAA,mBAEjE,GAAA,CAAC,QAAG,SAAA,EAAU,kBAAA,EACX,iBAAO,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,qBAClB,IAAA,CAAC,IAAA,EAAA,EAAc,SAAA,EAAU,oBAAA,EACvB,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,WAAU,+DAAA,EAAgE,CAAA;AAAA,4BAChF,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,SAAA,EACb,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,SAAK,QAAA,EAAA,SAAA,CAAU,CAAA,CAAE,IAAA,EAAM,CAAA,CAAE,IAAI,CAAA,EAAE,CAAA;AAAA,kCAC/B,KAAA,EAAA,EAAI,SAAA,EAAU,yBAAyB,QAAA,EAAA,OAAA,CAAQ,CAAA,CAAE,SAAS,CAAA,EAAE;AAAA,aAAA,EAC/D;AAAA,WAAA,EAAA,EALO,CAAA,CAAE,EAMX,CACD,CAAA,EACH;AAAA,SAAA,EAEJ;AAAA,OAAA,EACF;AAAA,KAAA,EACF;AAAA;AAEJ;AAEA,SAAS,QAAQ,GAAA,EAAqB;AACpC,EAAA,IAAI;AACF,IAAA,OAAO,IAAI,IAAA,CAAK,GAAG,CAAA,CAAE,eAAe,OAAA,EAAS,EAAE,GAAA,EAAK,SAAA,EAAW,OAAO,SAAA,EAAW,IAAA,EAAM,SAAA,EAAW,MAAA,EAAQ,WAAW,CAAA;AAAA,EACvH,CAAA,CAAA,MAAQ;AAAE,IAAA,OAAO,GAAA;AAAA,EAAI;AACvB;AAEA,SAAS,oBAAA,CAAqB,EAAE,MAAA,EAAO,EAA8B;AACnE,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,KAAA,CAAM,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,OAAA,CAAQ,MAAO,OAAO,cAAA,CAAe,MAAA,EAAQ,MAAA,CAAO,UAAA,IAAc,MAAS,CAAA,GAAI,EAAA,EAAK,CAAC,IAAA,EAAM,MAAM,CAAC,CAAA;AACvH,EAAA,eAAe,IAAA,GAAO;AACpB,IAAA,IAAI;AAAE,MAAA,MAAM,SAAA,CAAU,SAAA,CAAU,SAAA,CAAU,MAAM,CAAA;AAAG,MAAA,KAAA,CAAM,QAAQ,gBAAgB,CAAA;AAAA,IAAE,CAAA,CAAA,MAC7E;AAAE,MAAA,KAAA,CAAM,MAAM,yBAAsB,CAAA;AAAA,IAAE;AAAA,EAC9C;AACA,EAAA,MAAM,QAAS,QAAA,CAAyE,QAAA;AACxF,EAAA,uBACE,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,UAAO,SAAA,EAAU,kCAAA,EAAmC,SAAS,MAAM,OAAA,CAAQ,IAAI,CAAA,EAC7E,QAAA,EAAA;AAAA,MAAA,KAAA,oBAAS,GAAA,CAAC,KAAA,EAAA,EAAM,SAAA,EAAU,SAAA,EAAU,CAAA;AAAA,MAAG;AAAA,KAAA,EAC1C,CAAA;AAAA,oBACA,GAAA,CAAC,SAAA,EAAA,EAAU,IAAA,EAAY,KAAA,EAAM,uBAAsB,KAAA,EAAM,kBAAA,EAAmB,OAAA,EAAS,MAAM,QAAQ,KAAK,CAAA,EACtG,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,yBAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,+BAAA,EAAgC,QAAA,EAAA,oDAAA,EAAkD,CAAA;AAAA,0BAC9F,QAAA,EAAA,EAAS,KAAA,EAAO,MAAA,EAAQ,QAAA,EAAQ,MAAC,IAAA,EAAM,EAAA,EAAI,SAAA,EAAU,mBAAA,EAAoB,SAAS,CAAC,CAAA,KAAM,CAAA,CAAE,aAAA,CAAc,QAAO,EAAG,CAAA;AAAA,sBACpH,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wBAAA,EACb,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,MAAA,EAAA,EAAO,SAAQ,SAAA,EAAU,OAAA,EAAS,MAAM,OAAA,CAAQ,KAAK,GAAG,QAAA,EAAA,QAAA,EAAM,CAAA;AAAA,wBAC/D,GAAA,CAAC,MAAA,EAAA,EAAO,OAAA,EAAS,IAAA,EAAM,QAAA,EAAA,eAAA,EAAa;AAAA,OAAA,EACtC;AAAA,KAAA,EACF,CAAA,EACF;AAAA,GAAA,EACF,CAAA;AAEJ;AAEA,SAAS,cAAA,CAAe,EAAE,GAAA,EAAI,EAA+B;AAC3D,EAAA,MAAM,CAAC,GAAA,EAAK,MAAM,CAAA,GAAI,KAAA,CAAM,SAAwB,IAAI,CAAA;AACxD,EAAA,KAAA,CAAM,UAAU,MAAM;AACpB,IAAA,IAAI,KAAA,GAAQ,IAAA;AACZ,IAAA,IAAA,CAAK,GAAA,CAAI,WAAA,IAAe,EAAA,EAAI,UAAA,CAAW,QAAQ,CAAA,EAAG,KAAK,SAAA,CAAU,GAAA,CAAI,WAAW,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,KAAM;AAAE,MAAA,IAAI,KAAA,SAAc,CAAC,CAAA;AAAA,IAAE,CAAC,CAAA;AACtH,IAAA,OAAO,MAAM;AAAE,MAAA,KAAA,GAAQ,KAAA;AAAA,IAAM,CAAA;AAAA,EAC/B,GAAG,CAAC,GAAA,CAAI,WAAA,EAAa,GAAA,CAAI,WAAW,CAAC,CAAA;AACrC,EAAA,uBACE,IAAA,CAAC,GAAA,EAAA,EAAE,IAAA,EAAM,GAAA,IAAO,MAAA,EAAW,QAAO,QAAA,EAAS,GAAA,EAAI,YAAA,EAAa,SAAA,EAAU,sEAAA,EACnE,QAAA,EAAA;AAAA,IAAA,GAAA,mBAAM,GAAA,CAAC,SAAA,EAAA,EAAU,GAAA,EAAK,GAAA,EAAK,KAAK,GAAA,CAAI,IAAA,EAAM,SAAA,EAAU,gCAAA,EAAiC,CAAA,mBAAK,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iGAAgG,QAAA,EAAA,OAAA,EAAK,CAAA;AAAA,oBAC/M,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,gCAAA,EAAkC,cAAI,IAAA,EAAK;AAAA,GAAA,EAC7D,CAAA;AAEJ;AAEA,IAAO,uBAAA,GAAQ","file":"HelpdeskConsole-7W5IAQIU.js","sourcesContent":["import type { SupportKind, SupportStatus, SupportMessage, SupportEvent, SupportAttachment } from '../types'\nimport { KIND_LABEL, STATUS_LABEL, eventLine } from './vocabulary'\n\n/** The fields the prompt needs — satisfied by both the requester's\n * SupportRequestDetail and the operator's ConsoleDetail. */\nexport interface FixPromptInput {\n number: number\n kind: SupportKind\n status: SupportStatus\n subject: string | null\n description: string\n route: string | null\n screenSnapshot: Record<string, unknown>\n messages: SupportMessage[]\n events: SupportEvent[]\n attachments: SupportAttachment[]\n /** The store (tenant) the ticket is from, and the user who reported it — so a\n * coding agent can resolve the exact account and reproduce against it. */\n tenantId?: string\n createdBy?: string\n}\n\n/**\n * The prompt an operator copies into Claude to go fix a reported issue.\n *\n * It carries everything Claude needs to find the cause without a second\n * round-trip: which app and screen, the user's own words, the trail of routes\n * and buttons that led to it, and the conversation so far. English scaffolding\n * (it is read by a coding agent) around the user's pt-BR text (left verbatim —\n * the exact words are the bug report).\n */\nexport function buildFixPrompt(detail: FixPromptInput, appName?: string): string {\n const lines: string[] = []\n const app = appName?.trim() || 'the Fayz app'\n lines.push(`Fix an issue reported by a user of ${app}.`)\n lines.push('')\n lines.push(`Ticket #${String(detail.number).padStart(4, '0')} · ${KIND_LABEL[detail.kind]} · status: ${STATUS_LABEL[detail.status]}`)\n if (detail.route) lines.push(`Screen / route: ${detail.route}`)\n // Ids so a coding agent can resolve the exact account and reproduce/test\n // against it (the store's tenant, and the user who reported it).\n if (detail.tenantId) lines.push(`Tenant (store) id: ${detail.tenantId}`)\n if (detail.createdBy) lines.push(`Reported by user id: ${detail.createdBy}`)\n lines.push('')\n lines.push('PROBLEM (in the user\\'s own words):')\n // Skip the subject when it just repeats the description (the assistant often\n // derives one from the other).\n const subject = detail.subject?.trim()\n const description = detail.description.trim()\n if (subject && !description.toLowerCase().startsWith(subject.toLowerCase())) lines.push(subject)\n lines.push(description)\n\n const activity = (detail.screenSnapshot?.activity ?? null) as Array<{ kind?: string; label?: string; path?: string }> | null\n if (Array.isArray(activity) && activity.length) {\n lines.push('')\n lines.push('WHAT THE USER DID BEFORE REPORTING (most recent last):')\n for (const e of activity) {\n if (!e?.label) continue\n lines.push(e.kind === 'action' ? `- clicked \"${e.label}\"` : `- opened ${e.label}${e.path ? ` (${e.path})` : ''}`)\n }\n }\n\n if (detail.attachments.length) {\n lines.push('')\n lines.push(`ATTACHMENTS: ${detail.attachments.map((a) => a.name).join(', ')} (screenshots of the problem).`)\n }\n\n if (detail.messages.length) {\n lines.push('')\n lines.push('CONVERSATION WITH THE TEAM:')\n for (const m of detail.messages) {\n lines.push(`- ${m.authorKind === 'team' ? 'Team' : 'User'}: ${m.body}`)\n }\n }\n\n if (detail.events.length) {\n lines.push('')\n lines.push('HISTORY:')\n for (const ev of detail.events) lines.push(`- ${eventLine(ev.type, ev.note)}`)\n }\n\n lines.push('')\n lines.push(\n 'Investigate the code path behind this screen in the Fayz SDK (and the app that renders it), ' +\n 'find the root cause, and propose a concrete fix. If you need to reproduce it, follow the trail above.',\n )\n return lines.join('\\n')\n}\n","import React from 'react'\nimport {\n Button, Badge, Input, Textarea, Skeleton, Thumbnail, ModalTask, toast,\n Select, SelectTrigger, SelectValue, SelectContent, SelectItem, ICON_MAP, SubpageHeader,\n} from '@fayz-ai/ui'\nimport {\n consoleListRequests, consoleDetail, consoleSetStatus, consoleSetPriority,\n consoleReply, isOperator,\n type ConsoleRequest, type ConsoleDetail,\n} from '../data/console'\nimport { signedUrl } from '../data/api'\nimport {\n KIND_LABEL, STATUS_LABEL, STATUS_TONE, PRIORITY_LABEL, PRIORITY_TONE, PRIORITY_ORDER, eventLine,\n} from '../lib/vocabulary'\nimport { buildFixPrompt } from '../lib/fix-prompt'\nimport type { SupportStatus, SupportPriority, SupportAttachment } from '../types'\n\nconst STATUS_OPTIONS: SupportStatus[] = ['received', 'in_service', 'waiting_you', 'in_development', 'resolved_check', 'closed', 'cancelled']\nconst OPEN_STATUSES: SupportStatus[] = ['received', 'in_service', 'waiting_you', 'in_development', 'resolved_check']\n\n/** Hash navigation, without reaching into the shell's private routing. */\nfunction go(path: string) { if (typeof window !== 'undefined') window.location.hash = path }\n\nfunction ticketNo(n: number): string { return `#${String(n).padStart(4, '0')}` }\n\n/** The ticket id when the route is #/support/console/<id>, else null. */\nfunction useConsoleRoute(): string | null {\n const read = () => {\n if (typeof window === 'undefined') return null\n const m = window.location.hash.replace(/^#/, '').match(/^\\/support\\/console\\/([^/?]+)/)\n return m ? decodeURIComponent(m[1]!) : null\n }\n const [id, setId] = React.useState<string | null>(read)\n React.useEffect(() => {\n const on = () => setId(read())\n window.addEventListener('hashchange', on)\n return () => window.removeEventListener('hashchange', on)\n }, [])\n return id\n}\n\n/**\n * The GoControl helpdesk console (Zendesk/Intercom-style). An operator reads and\n * acts on the support requests of EVERY tenant through the support_console_* RPCs.\n * The triage list lives at #/support/console; clicking a card opens the ticket as\n * its own nested page (#/support/console/<id>) with a \"← Voltar\" header.\n */\nexport function HelpdeskConsole() {\n const [operator, setOperator] = React.useState<boolean | null>(null)\n React.useEffect(() => { void isOperator().then(setOperator) }, [])\n const ticketId = useConsoleRoute()\n\n if (operator === false) {\n return (\n <div className=\"rounded-xl border bg-card p-10 text-center\">\n <p className=\"text-sm font-medium\">Acesso restrito</p>\n <p className=\"mt-1 text-sm text-muted-foreground\">A Central de Chamados é para operadores do suporte.</p>\n </div>\n )\n }\n if (operator === null) return <div className=\"space-y-3\"><Skeleton className=\"h-20 w-full\" /><Skeleton className=\"h-20 w-full\" /></div>\n return ticketId ? <ConsoleTicketPage id={ticketId} /> : <ConsoleListView />\n}\n\nfunction ConsoleListView() {\n const [requests, setRequests] = React.useState<ConsoleRequest[]>([])\n const [loading, setLoading] = React.useState(true)\n const [onlyOpen, setOnlyOpen] = React.useState(true)\n const [search, setSearch] = React.useState('')\n\n React.useEffect(() => {\n let alive = true\n setLoading(true)\n consoleListRequests(onlyOpen ? OPEN_STATUSES : undefined, search)\n .then((r) => { if (alive) setRequests(r) })\n .catch(() => { if (alive) setRequests([]) })\n .finally(() => { if (alive) setLoading(false) })\n return () => { alive = false }\n }, [onlyOpen, search])\n\n const grouped = PRIORITY_ORDER\n .map((p) => ({ priority: p, items: requests.filter((r) => r.priority === p) }))\n .filter((g) => g.items.length > 0)\n\n return (\n <div className=\"mx-auto flex max-w-3xl flex-col gap-3\">\n <Input value={search} onChange={(e) => setSearch(e.target.value)} placeholder=\"Buscar chamado ou loja…\" />\n <div className=\"flex items-center gap-2 text-xs\">\n <button onClick={() => setOnlyOpen(true)} className={`rounded-full px-3 py-1 ${onlyOpen ? 'bg-foreground text-background' : 'bg-muted text-muted-foreground'}`}>Em aberto</button>\n <button onClick={() => setOnlyOpen(false)} className={`rounded-full px-3 py-1 ${!onlyOpen ? 'bg-foreground text-background' : 'bg-muted text-muted-foreground'}`}>Todos</button>\n <span className=\"ml-auto text-muted-foreground\">{requests.length} chamado(s)</span>\n </div>\n\n <div className=\"flex flex-col gap-4\">\n {loading ? (\n [0, 1, 2].map((i) => <Skeleton key={i} className=\"h-16 w-full\" />)\n ) : requests.length === 0 ? (\n <div className=\"rounded-xl border bg-card p-8 text-center text-sm text-muted-foreground\">Nenhum chamado por aqui.</div>\n ) : (\n grouped.map((g) => (\n <div key={g.priority} className=\"flex flex-col gap-1.5\">\n <div className=\"flex items-center gap-2 px-1\">\n <Badge variant={PRIORITY_TONE[g.priority]}>{PRIORITY_LABEL[g.priority]}</Badge>\n <span className=\"text-[11px] text-muted-foreground\">{g.items.length}</span>\n </div>\n {g.items.map((r) => (\n <TicketRow key={r.id} req={r} onClick={() => go(`/support/console/${r.id}`)} />\n ))}\n </div>\n ))\n )}\n </div>\n </div>\n )\n}\n\n/** The ticket as its own nested page: \"← Voltar\" + full detail and actions. */\nfunction ConsoleTicketPage({ id }: { id: string }) {\n const [detail, setDetail] = React.useState<ConsoleDetail | null>(null)\n const [loading, setLoading] = React.useState(true)\n\n React.useEffect(() => {\n let alive = true\n setLoading(true)\n consoleDetail(id).then((d) => { if (alive) setDetail(d) }).finally(() => { if (alive) setLoading(false) })\n return () => { alive = false }\n }, [id])\n\n const ready = detail && detail.id === id\n\n return (\n <div className=\"flex flex-col gap-4\">\n <SubpageHeader\n parentLabel=\"Central de Chamados\"\n onBack={() => go('/support/console')}\n title={ready ? `Ticket ${ticketNo(detail.number)}` : 'Ticket'}\n subtitle={ready ? (detail.tenantName ?? undefined) : undefined}\n titleTrailing={ready ? <Badge variant={STATUS_TONE[detail.status]}>{STATUS_LABEL[detail.status]}</Badge> : undefined}\n />\n {loading && !ready ? (\n <div className=\"space-y-3\"><Skeleton className=\"h-28 w-full\" /><Skeleton className=\"h-40 w-full\" /></div>\n ) : ready ? (\n <OperatorDetail detail={detail} onApplied={(d) => d && setDetail(d)} />\n ) : (\n <div className=\"rounded-xl border bg-card p-10 text-center\">\n <p className=\"text-sm font-medium\">Chamado não encontrado</p>\n <div className=\"mt-4\"><Button variant=\"outline\" onClick={() => go('/support/console')}>Voltar</Button></div>\n </div>\n )}\n </div>\n )\n}\n\nfunction TicketRow({ req, onClick }: { req: ConsoleRequest; onClick: () => void }) {\n return (\n <button\n onClick={onClick}\n className=\"flex w-full flex-col gap-1 rounded-lg border bg-card p-3 text-left transition-colors hover:border-primary/40 hover:bg-accent\"\n >\n <div className=\"flex items-center justify-between gap-2 text-[11px] text-muted-foreground\">\n <span className=\"truncate font-medium text-foreground\">{req.tenantName ?? 'Loja'}</span>\n <span>{ticketNo(req.number)}</span>\n </div>\n <div className=\"truncate text-sm\">{req.subject || KIND_LABEL[req.kind]}</div>\n <div className=\"flex items-center gap-1.5\">\n <Badge variant={STATUS_TONE[req.status]}>{STATUS_LABEL[req.status]}</Badge>\n {req.createdByName && <span className=\"truncate text-[11px] text-muted-foreground\">por {req.createdByName}</span>}\n {req.messageCount > 0 && <span className=\"ml-auto text-[11px] text-muted-foreground\">{req.messageCount} msg</span>}\n </div>\n </button>\n )\n}\n\nfunction OperatorDetail({ detail, onApplied }: { detail: ConsoleDetail; onApplied: (d: ConsoleDetail | null) => void }) {\n const [busy, setBusy] = React.useState(false)\n const [reply, setReply] = React.useState('')\n\n React.useEffect(() => { setReply('') }, [detail.id])\n\n async function run(fn: () => Promise<ConsoleDetail | null>, okMsg: string) {\n setBusy(true)\n try { onApplied(await fn()); toast.success(okMsg) }\n catch (e) { toast.error((e as Error)?.message ?? 'Não consegui aplicar.') }\n finally { setBusy(false) }\n }\n\n const activity = (detail.screenSnapshot?.activity ?? null) as Array<{ kind?: string; label?: string; path?: string }> | null\n\n return (\n // Two columns, like the CRM deal card: the ticket and its controls on the\n // left, the conversation and the activity feed on the right.\n <div className=\"grid gap-5 lg:grid-cols-2 lg:items-start\">\n {/* ── LEFT: the ticket + operator controls ───────────────────────── */}\n <div className=\"flex flex-col gap-4\">\n <section className=\"rounded-xl border bg-card p-5\">\n <h1 className=\"text-lg font-semibold leading-snug\">{detail.subject || KIND_LABEL[detail.kind]}</h1>\n <p className=\"mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground\">\n <span>{KIND_LABEL[detail.kind]}</span>\n <Badge variant={PRIORITY_TONE[detail.priority]}>{PRIORITY_LABEL[detail.priority]}</Badge>\n <span>· aberto por <span className=\"font-medium text-foreground\">{detail.createdByName ?? '—'}</span></span>\n </p>\n <p className=\"mt-3 whitespace-pre-wrap text-sm leading-relaxed\">{detail.description}</p>\n {detail.route && <p className=\"mt-2 text-xs text-muted-foreground\">Tela: <span className=\"font-mono\">{detail.route}</span></p>}\n {detail.attachments.length > 0 && (\n <div className=\"mt-3 flex flex-wrap gap-2\">\n {detail.attachments.map((a) => <AttachmentCard key={a.id} att={a} />)}\n </div>\n )}\n {Array.isArray(activity) && activity.length > 0 && (\n <div className=\"mt-3 border-t pt-3 text-xs\">\n <div className=\"mb-1 text-muted-foreground\">Trilha até o relato</div>\n <ol className=\"space-y-0.5\">\n {activity.map((e, i) => (\n <li key={i}>{e.kind === 'action' ? <>clicou <span className=\"font-medium\">\"{e.label}\"</span></> : <><span className=\"font-medium\">{e.label}</span> {e.path && <span className=\"font-mono text-[10px] text-muted-foreground\">{e.path}</span>}</>}</li>\n ))}\n </ol>\n </div>\n )}\n </section>\n\n <div className=\"rounded-xl border bg-card p-4\">\n <h2 className=\"mb-2 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground\">Andamento</h2>\n <label className=\"mb-1 block text-xs text-muted-foreground\">Status</label>\n <Select value={detail.status} onValueChange={(v) => run(() => consoleSetStatus(detail.id, v as SupportStatus), 'Status atualizado')} disabled={busy}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {STATUS_OPTIONS.map((s) => <SelectItem key={s} value={s}>{STATUS_LABEL[s]}</SelectItem>)}\n </SelectContent>\n </Select>\n <label className=\"mb-1 mt-3 block text-xs text-muted-foreground\">Prioridade</label>\n <Select value={detail.priority} onValueChange={(v) => run(() => consoleSetPriority(detail.id, v as SupportPriority), 'Prioridade atualizada')} disabled={busy}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {PRIORITY_ORDER.map((p) => <SelectItem key={p} value={p}>{PRIORITY_LABEL[p]}</SelectItem>)}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"rounded-xl border bg-card p-4\">\n <h2 className=\"mb-2 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground\">Cliente</h2>\n {/* The client is the store that opened the chamado — already connected\n by the ticket's tenant_id, shown automatically, not linked by hand. */}\n <p className=\"text-sm font-medium\">{detail.tenantName ?? 'Loja'}</p>\n <p className=\"text-xs text-muted-foreground\">Loja que abriu o chamado — vinculada automaticamente.</p>\n <FixWithClaudeConsole detail={detail} />\n </div>\n </div>\n\n {/* ── RIGHT: conversation + activity feed ─────────────────────────── */}\n <div className=\"flex flex-col gap-4\">\n <div className=\"rounded-xl border bg-card p-4\">\n <h2 className=\"text-[11px] font-semibold uppercase tracking-wider text-muted-foreground\">Conversa com o cliente</h2>\n {detail.messages.length === 0 ? (\n <p className=\"mt-2 text-sm text-muted-foreground\">Sem mensagens ainda.</p>\n ) : (\n <div className=\"mt-3 space-y-2\">\n {detail.messages.map((m) => (\n <div key={m.id} className={m.authorKind === 'team' ? 'flex justify-end' : 'flex justify-start'}>\n <div className={`max-w-[85%] rounded-lg px-3 py-2 text-sm ${m.authorKind === 'team' ? 'bg-primary/10' : 'bg-muted'}`}>\n <div className=\"whitespace-pre-wrap\">{m.body}</div>\n <div className=\"mt-1 text-right text-[10px] text-muted-foreground\">{fmtWhen(m.createdAt)}</div>\n </div>\n </div>\n ))}\n </div>\n )}\n <div className=\"mt-3 flex items-end gap-2\">\n <Textarea rows={2} value={reply} onChange={(e) => setReply(e.target.value)} placeholder=\"Responder ao cliente…\" className=\"flex-1\" />\n <Button disabled={busy || !reply.trim()} onClick={() => run(async () => { const d = await consoleReply(detail.id, reply); setReply(''); return d }, 'Resposta enviada')}>Responder</Button>\n </div>\n </div>\n\n <div className=\"rounded-xl border bg-card p-4\">\n <h2 className=\"text-[11px] font-semibold uppercase tracking-wider text-muted-foreground\">Atividades</h2>\n {detail.events.length === 0 ? (\n <p className=\"mt-2 text-sm text-muted-foreground\">Sem atividades.</p>\n ) : (\n <ol className=\"mt-3 space-y-2.5\">\n {detail.events.map((e) => (\n <li key={e.id} className=\"flex gap-2 text-xs\">\n <span className=\"mt-1 h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/40\" />\n <div className=\"min-w-0\">\n <div>{eventLine(e.type, e.note)}</div>\n <div className=\"text-muted-foreground\">{fmtWhen(e.createdAt)}</div>\n </div>\n </li>\n ))}\n </ol>\n )}\n </div>\n </div>\n </div>\n )\n}\n\nfunction fmtWhen(iso: string): string {\n try {\n return new Date(iso).toLocaleString('pt-BR', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' })\n } catch { return iso }\n}\n\nfunction FixWithClaudeConsole({ detail }: { detail: ConsoleDetail }) {\n const [open, setOpen] = React.useState(false)\n const prompt = React.useMemo(() => (open ? buildFixPrompt(detail, detail.tenantName ?? undefined) : ''), [open, detail])\n async function copy() {\n try { await navigator.clipboard.writeText(prompt); toast.success('Prompt copiado') }\n catch { toast.error('Não consegui copiar.') }\n }\n const Spark = (ICON_MAP as Record<string, React.ComponentType<{ className?: string }>>).Sparkles\n return (\n <>\n <Button className=\"mt-3 w-full justify-center gap-2\" onClick={() => setOpen(true)}>\n {Spark && <Spark className=\"h-4 w-4\" />} Corrigir com Claude\n </Button>\n <ModalTask open={open} title=\"Corrigir com Claude\" width=\"min(42rem, 94vw)\" onClose={() => setOpen(false)}>\n <div className=\"flex flex-col gap-3 p-4\">\n <p className=\"text-sm text-muted-foreground\">Copie e cole no Claude para investigar e corrigir.</p>\n <Textarea value={prompt} readOnly rows={14} className=\"font-mono text-xs\" onFocus={(e) => e.currentTarget.select()} />\n <div className=\"flex justify-end gap-2\">\n <Button variant=\"outline\" onClick={() => setOpen(false)}>Fechar</Button>\n <Button onClick={copy}>Copiar prompt</Button>\n </div>\n </div>\n </ModalTask>\n </>\n )\n}\n\nfunction AttachmentCard({ att }: { att: SupportAttachment }) {\n const [url, setUrl] = React.useState<string | null>(null)\n React.useEffect(() => {\n let alive = true\n if ((att.contentType ?? '').startsWith('image/')) void signedUrl(att.storagePath).then((u) => { if (alive) setUrl(u) })\n return () => { alive = false }\n }, [att.storagePath, att.contentType])\n return (\n <a href={url ?? undefined} target=\"_blank\" rel=\"noreferrer\" className=\"flex items-center gap-2 rounded-lg border bg-card p-2 hover:bg-muted\">\n {url ? <Thumbnail src={url} alt={att.name} className=\"h-12 w-12 rounded object-cover\" /> : <div className=\"flex h-12 w-12 items-center justify-center rounded bg-muted text-[10px] text-muted-foreground\">anexo</div>}\n <span className=\"max-w-[10rem] truncate text-xs\">{att.name}</span>\n </a>\n )\n}\n\nexport default HelpdeskConsole\n"]}
|