@veploy/ploychat 0.1.1 → 0.1.3
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/dist/index.js +672 -565
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -46,7 +46,7 @@ function createPloyClient(config = {}) {
|
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
const live = !!(config.apiBase && config.workspaceId && config.getToken);
|
|
49
|
-
return { apiFetch, supabase, live };
|
|
49
|
+
return { apiFetch, supabase, live, agentName: config.agentName || null };
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
// src/lib/context.jsx
|
|
@@ -56,7 +56,7 @@ function PloyConfigProvider({ config, children }) {
|
|
|
56
56
|
const value = useMemo(() => {
|
|
57
57
|
const client = createPloyClient(config);
|
|
58
58
|
return { config, client };
|
|
59
|
-
}, [config.apiBase, config.workspaceId, config.getToken, config.supabase, config.supabaseUrl, config.supabaseAnonKey]);
|
|
59
|
+
}, [config.apiBase, config.workspaceId, config.getToken, config.supabase, config.supabaseUrl, config.supabaseAnonKey, config.agentName]);
|
|
60
60
|
return /* @__PURE__ */ jsx(PloyContext.Provider, { value, children });
|
|
61
61
|
}
|
|
62
62
|
function usePloy() {
|
|
@@ -100,18 +100,21 @@ function relTime(iso) {
|
|
|
100
100
|
if (h < 24) return `${h}h`;
|
|
101
101
|
return `${Math.floor(h / 24)}d`;
|
|
102
102
|
}
|
|
103
|
-
function
|
|
103
|
+
function nowHHMM2() {
|
|
104
104
|
const d = /* @__PURE__ */ new Date();
|
|
105
105
|
return `${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
|
106
106
|
}
|
|
107
107
|
var STATUS_MAP = { open: "open", pending: "in_progress", resolved: "resolved", snoozed: "waiting" };
|
|
108
108
|
function mapConversation(c) {
|
|
109
109
|
const contact = c.contact || {};
|
|
110
|
-
const
|
|
110
|
+
const isGroup = String(contact.external_id || "").endsWith("@g.us");
|
|
111
|
+
const name = contact.name || (isGroup ? "Grupo" : contact.push_name || contact.phone_e164 || contact.external_id || "Contato");
|
|
111
112
|
return {
|
|
112
113
|
id: c.id,
|
|
113
114
|
name,
|
|
114
|
-
|
|
115
|
+
isGroup,
|
|
116
|
+
phone: isGroup ? "" : contact.phone_e164 || "",
|
|
117
|
+
avatar: contact.profile_pic_url || null,
|
|
115
118
|
avatarColor: colorFor(c.id),
|
|
116
119
|
preview: c.last_message_preview || "",
|
|
117
120
|
waitFor: relTime(c.last_message_at),
|
|
@@ -119,12 +122,17 @@ function mapConversation(c) {
|
|
|
119
122
|
sla: "ok",
|
|
120
123
|
priority: c.priority || "normal",
|
|
121
124
|
status: STATUS_MAP[c.status] || "open",
|
|
122
|
-
ticket
|
|
125
|
+
// só mostra "ticket" quando há REF real de imóvel; senão nada (o #id era ruído)
|
|
126
|
+
ticket: c.property_ref ? `REF ${c.property_ref}` : null,
|
|
123
127
|
starred: false,
|
|
128
|
+
aiSummary: c.ai_summary || "",
|
|
129
|
+
// resumo IA persistido (tarja)
|
|
130
|
+
aiSummaryCount: c.ai_summary_msg_count || 0,
|
|
124
131
|
_raw: c
|
|
125
132
|
};
|
|
126
133
|
}
|
|
127
134
|
function mapMessage(m) {
|
|
135
|
+
var _a, _b;
|
|
128
136
|
const ts = m.sent_at || m.created_at;
|
|
129
137
|
if (m.kind === "note") {
|
|
130
138
|
return { id: m.id, side: "note", kind: "text", text: m.text || "", time: timeOf(ts), day: dayOf(ts), author: m.author_name, _raw: m };
|
|
@@ -144,8 +152,11 @@ function mapMessage(m) {
|
|
|
144
152
|
// 'in' | 'out'
|
|
145
153
|
kind,
|
|
146
154
|
text,
|
|
155
|
+
// em grupos, quem enviou (participante) — vem do pushName no payload bruto
|
|
156
|
+
author: m.direction === "in" ? ((_a = m.raw) == null ? void 0 : _a.pushName) || ((_b = m.raw) == null ? void 0 : _b.push_name) || "" : "",
|
|
147
157
|
caption: m.caption || "",
|
|
148
158
|
meta: m.media_mime || "",
|
|
159
|
+
filename: m.media_filename || "",
|
|
149
160
|
mediaUrl: m.media_url || "",
|
|
150
161
|
time: timeOf(ts),
|
|
151
162
|
day: dayOf(ts),
|
|
@@ -161,14 +172,21 @@ function useInbox() {
|
|
|
161
172
|
const [conversations2, setConversations] = useState([]);
|
|
162
173
|
const [activeId, setActiveId] = useState(null);
|
|
163
174
|
const [messages, setMessages] = useState([]);
|
|
175
|
+
const [messagesLoading, setMessagesLoading] = useState(false);
|
|
164
176
|
const [channels, setChannels] = useState([]);
|
|
177
|
+
const [channelsLoaded, setChannelsLoaded] = useState(false);
|
|
165
178
|
const [agents, setAgents] = useState([]);
|
|
166
179
|
const [me, setMe] = useState(null);
|
|
180
|
+
const [canDelete, setCanDelete] = useState(false);
|
|
181
|
+
const [scope, setScope] = useState("all");
|
|
182
|
+
const [draftConv, setDraftConv] = useState(null);
|
|
167
183
|
const [tenantId, setTenantId] = useState(null);
|
|
184
|
+
const [typingConvId, setTypingConvId] = useState(null);
|
|
168
185
|
const [loading, setLoading] = useState(live);
|
|
169
186
|
const [error, setError] = useState(null);
|
|
170
187
|
const activeIdRef = useRef(null);
|
|
171
188
|
activeIdRef.current = activeId;
|
|
189
|
+
const typingTimerRef = useRef(null);
|
|
172
190
|
const api = client.apiFetch;
|
|
173
191
|
useEffect(() => {
|
|
174
192
|
if (!live) return;
|
|
@@ -176,6 +194,8 @@ function useInbox() {
|
|
|
176
194
|
var _a;
|
|
177
195
|
if ((_a = m == null ? void 0 : m.user) == null ? void 0 : _a.id) setMe(m.user.id);
|
|
178
196
|
if (m == null ? void 0 : m.tenant_id) setTenantId(m.tenant_id);
|
|
197
|
+
setCanDelete(!!(m == null ? void 0 : m.can_delete));
|
|
198
|
+
if (m == null ? void 0 : m.inbox_scope) setScope(m.inbox_scope);
|
|
179
199
|
}).catch(() => {
|
|
180
200
|
});
|
|
181
201
|
}, [live, api]);
|
|
@@ -195,13 +215,28 @@ function useInbox() {
|
|
|
195
215
|
setLoading(false);
|
|
196
216
|
}
|
|
197
217
|
}, [live, api]);
|
|
198
|
-
const
|
|
218
|
+
const msgCacheRef = useRef({});
|
|
219
|
+
const loadMessages = useCallback(async (convId, opts = {}) => {
|
|
199
220
|
if (!live || !convId) return;
|
|
221
|
+
if (!opts.silent) {
|
|
222
|
+
const cached = msgCacheRef.current[convId];
|
|
223
|
+
if (cached) {
|
|
224
|
+
setMessages(cached);
|
|
225
|
+
setMessagesLoading(false);
|
|
226
|
+
} else {
|
|
227
|
+
setMessages([]);
|
|
228
|
+
setMessagesLoading(true);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
200
231
|
try {
|
|
201
232
|
const res = await api(`/v1/conversations/${convId}/messages?limit=50`);
|
|
202
|
-
|
|
233
|
+
const mapped = ((res == null ? void 0 : res.messages) || []).slice().reverse().map(mapMessage);
|
|
234
|
+
msgCacheRef.current[convId] = mapped;
|
|
235
|
+
if (activeIdRef.current === convId) setMessages(mapped);
|
|
203
236
|
} catch (e) {
|
|
204
237
|
setError(e.message);
|
|
238
|
+
} finally {
|
|
239
|
+
if (activeIdRef.current === convId) setMessagesLoading(false);
|
|
205
240
|
}
|
|
206
241
|
}, [live, api]);
|
|
207
242
|
const loadChannels = useCallback(async () => {
|
|
@@ -212,6 +247,8 @@ function useInbox() {
|
|
|
212
247
|
return l;
|
|
213
248
|
} catch {
|
|
214
249
|
return [];
|
|
250
|
+
} finally {
|
|
251
|
+
setChannelsLoaded(true);
|
|
215
252
|
}
|
|
216
253
|
}, [live, api]);
|
|
217
254
|
const loadAgents = useCallback(async () => {
|
|
@@ -232,6 +269,9 @@ function useInbox() {
|
|
|
232
269
|
useEffect(() => {
|
|
233
270
|
loadMessages(activeId);
|
|
234
271
|
}, [activeId, loadMessages]);
|
|
272
|
+
useEffect(() => {
|
|
273
|
+
if (draftConv && conversations2.some((c) => c.id === draftConv.id)) setDraftConv(null);
|
|
274
|
+
}, [conversations2, draftConv]);
|
|
235
275
|
const markRead = useCallback(async (convId) => {
|
|
236
276
|
if (!live || !convId) return;
|
|
237
277
|
setConversations((cs) => cs.map((c) => c.id === convId ? { ...c, unread: 0 } : c));
|
|
@@ -252,12 +292,13 @@ function useInbox() {
|
|
|
252
292
|
const send = useCallback(async (text, isNote = false) => {
|
|
253
293
|
const t = (text || "").trim();
|
|
254
294
|
if (!t || !live || !activeIdRef.current) return;
|
|
255
|
-
const
|
|
256
|
-
|
|
295
|
+
const cid = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : null;
|
|
296
|
+
const tmpId = cid || `tmp${Date.now()}`;
|
|
297
|
+
setMessages((ms) => [...ms, isNote ? { id: tmpId, side: "note", kind: "text", text: t, time: nowHHMM2() } : { id: tmpId, side: "out", kind: "text", text: t, time: nowHHMM2(), status: "pending" }]);
|
|
257
298
|
try {
|
|
258
299
|
const saved = await api(`/v1/conversations/${activeIdRef.current}/messages`, {
|
|
259
300
|
method: "POST",
|
|
260
|
-
body: isNote ? { text: t, note: true } : { text: t }
|
|
301
|
+
body: isNote ? { text: t, note: true, client_id: cid || void 0 } : { text: t, author_name: client.agentName || void 0, client_id: cid || void 0 }
|
|
261
302
|
});
|
|
262
303
|
setMessages((ms) => ms.map((m) => m.id === tmpId ? mapMessage(saved) : m));
|
|
263
304
|
} catch {
|
|
@@ -266,12 +307,13 @@ function useInbox() {
|
|
|
266
307
|
}, [live, api]);
|
|
267
308
|
const sendMedia = useCallback(async ({ data, mime, kind, filename, previewUrl, caption }) => {
|
|
268
309
|
if (!live || !activeIdRef.current || !data) return;
|
|
269
|
-
const
|
|
270
|
-
|
|
310
|
+
const cid = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : null;
|
|
311
|
+
const tmpId = cid || `tmp${Date.now()}`;
|
|
312
|
+
setMessages((ms) => [...ms, { id: tmpId, side: "out", kind, mediaUrl: previewUrl || "", caption: caption || "", filename: filename || "", meta: mime || "", time: nowHHMM2(), status: "pending" }]);
|
|
271
313
|
try {
|
|
272
314
|
const saved = await api(`/v1/conversations/${activeIdRef.current}/messages`, {
|
|
273
315
|
method: "POST",
|
|
274
|
-
body: { media: { data, mime, kind, filename }, caption }
|
|
316
|
+
body: { media: { data, mime, kind, filename }, caption, author_name: client.agentName || void 0, client_id: cid || void 0 }
|
|
275
317
|
});
|
|
276
318
|
const mapped = mapMessage(saved);
|
|
277
319
|
setMessages((ms) => ms.map((m) => m.id === tmpId ? { ...mapped, mediaUrl: mapped.mediaUrl || previewUrl || "" } : m));
|
|
@@ -279,6 +321,43 @@ function useInbox() {
|
|
|
279
321
|
setMessages((ms) => ms.map((m) => m.id === tmpId ? { ...m, status: "failed" } : m));
|
|
280
322
|
}
|
|
281
323
|
}, [live, api]);
|
|
324
|
+
const deleteMessage = useCallback(async (messageId) => {
|
|
325
|
+
if (!live || !messageId || !activeIdRef.current) return;
|
|
326
|
+
const convId = activeIdRef.current;
|
|
327
|
+
setMessages((ms) => ms.filter((m) => m.id !== messageId));
|
|
328
|
+
try {
|
|
329
|
+
await api(`/v1/conversations/${convId}/messages/${messageId}`, { method: "DELETE" });
|
|
330
|
+
} catch (e) {
|
|
331
|
+
setError(e.message);
|
|
332
|
+
loadMessages(convId);
|
|
333
|
+
}
|
|
334
|
+
}, [live, api, loadMessages]);
|
|
335
|
+
const setTyping = useCallback((convId, state) => {
|
|
336
|
+
if (!live || !convId) return;
|
|
337
|
+
api(`/v1/conversations/${convId}/typing`, { method: "POST", body: { state } }).catch(() => {
|
|
338
|
+
});
|
|
339
|
+
}, [live, api]);
|
|
340
|
+
const createConversation = useCallback(async (phone, text) => {
|
|
341
|
+
if (!live) return null;
|
|
342
|
+
const conv = await api("/v1/conversations", {
|
|
343
|
+
method: "POST",
|
|
344
|
+
body: { phone, text: text || void 0, author_name: client.agentName || void 0 }
|
|
345
|
+
});
|
|
346
|
+
const mapped = mapConversation(conv);
|
|
347
|
+
if (conv == null ? void 0 : conv.last_message_at) {
|
|
348
|
+
setDraftConv(null);
|
|
349
|
+
await loadConversations();
|
|
350
|
+
} else {
|
|
351
|
+
setDraftConv(mapped);
|
|
352
|
+
}
|
|
353
|
+
if (mapped == null ? void 0 : mapped.id) setActiveId(mapped.id);
|
|
354
|
+
return conv;
|
|
355
|
+
}, [live, api, loadConversations]);
|
|
356
|
+
const summarize = useCallback(async (convId) => {
|
|
357
|
+
if (!live || !convId) return "";
|
|
358
|
+
const r = await api(`/v1/ai/conversations/${convId}/summary`, { method: "POST" });
|
|
359
|
+
return (r == null ? void 0 : r.summary) || "";
|
|
360
|
+
}, [live, api]);
|
|
282
361
|
const createChannel = useCallback((displayName) => api("/v1/channels", { method: "POST", body: { display_name: displayName } }), [api]);
|
|
283
362
|
const connect = useCallback((id) => api(`/v1/channels/${id}/connect`, { method: "POST" }), [api]);
|
|
284
363
|
const channelStatus = useCallback((id) => api(`/v1/channels/${id}/status`), [api]);
|
|
@@ -287,17 +366,26 @@ function useInbox() {
|
|
|
287
366
|
const sb = client.supabase;
|
|
288
367
|
if (!sb) return;
|
|
289
368
|
const ch = sb.channel(`inbox:${tenantId}`).on("broadcast", { event: "message.created" }, ({ payload }) => {
|
|
290
|
-
if ((payload == null ? void 0 : payload.conversation_id) === activeIdRef.current) {
|
|
291
|
-
setMessages((ms) => ms.some((m) => m.id === payload.id) ? ms : [...ms, mapMessage(payload)]);
|
|
292
|
-
}
|
|
369
|
+
if ((payload == null ? void 0 : payload.conversation_id) === activeIdRef.current) loadMessages(activeIdRef.current, { silent: true });
|
|
293
370
|
loadConversations();
|
|
294
371
|
}).on("broadcast", { event: "message.updated" }, ({ payload }) => {
|
|
295
372
|
setMessages((ms) => ms.map((m) => m.id === (payload == null ? void 0 : payload.id) ? { ...m, status: payload.status || m.status } : m));
|
|
296
|
-
}).on("broadcast", { event: "conversation.updated" }, () => loadConversations()).on("broadcast", { event: "channel.updated" }, () => loadChannels()).
|
|
373
|
+
}).on("broadcast", { event: "conversation.updated" }, () => loadConversations()).on("broadcast", { event: "channel.updated" }, () => loadChannels()).on("broadcast", { event: "message.deleted" }, ({ payload }) => {
|
|
374
|
+
setMessages((ms) => ms.filter((m) => m.id !== (payload == null ? void 0 : payload.id)));
|
|
375
|
+
}).on("broadcast", { event: "presence.update" }, ({ payload }) => {
|
|
376
|
+
if ((payload == null ? void 0 : payload.state) === "composing") {
|
|
377
|
+
setTypingConvId(payload.conversation_id);
|
|
378
|
+
clearTimeout(typingTimerRef.current);
|
|
379
|
+
typingTimerRef.current = setTimeout(() => setTypingConvId(null), 6e3);
|
|
380
|
+
} else {
|
|
381
|
+
setTypingConvId((cur) => cur === (payload == null ? void 0 : payload.conversation_id) ? null : cur);
|
|
382
|
+
}
|
|
383
|
+
}).subscribe();
|
|
297
384
|
return () => {
|
|
298
385
|
sb.removeChannel(ch);
|
|
386
|
+
clearTimeout(typingTimerRef.current);
|
|
299
387
|
};
|
|
300
|
-
}, [live, tenantId, client, loadConversations, loadChannels]);
|
|
388
|
+
}, [live, tenantId, client, loadConversations, loadChannels, loadMessages]);
|
|
301
389
|
return {
|
|
302
390
|
live,
|
|
303
391
|
loading,
|
|
@@ -306,6 +394,9 @@ function useInbox() {
|
|
|
306
394
|
activeId,
|
|
307
395
|
setActiveId,
|
|
308
396
|
messages,
|
|
397
|
+
messagesLoading,
|
|
398
|
+
scope,
|
|
399
|
+
draftConv,
|
|
309
400
|
send,
|
|
310
401
|
sendMedia,
|
|
311
402
|
markRead,
|
|
@@ -314,10 +405,17 @@ function useInbox() {
|
|
|
314
405
|
agents,
|
|
315
406
|
loadAgents,
|
|
316
407
|
channels,
|
|
408
|
+
channelsLoaded,
|
|
317
409
|
loadChannels,
|
|
318
410
|
createChannel,
|
|
411
|
+
createConversation,
|
|
319
412
|
connect,
|
|
320
|
-
channelStatus
|
|
413
|
+
channelStatus,
|
|
414
|
+
setTyping,
|
|
415
|
+
typingConvId,
|
|
416
|
+
deleteMessage,
|
|
417
|
+
canDelete,
|
|
418
|
+
summarize
|
|
321
419
|
};
|
|
322
420
|
}
|
|
323
421
|
|
|
@@ -517,6 +615,7 @@ function TransferModal({ inbox, conversationId, currentAssignee, onClose }) {
|
|
|
517
615
|
|
|
518
616
|
// src/components/App.jsx
|
|
519
617
|
import { Fragment, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
618
|
+
var REGEN_EVERY = 3;
|
|
520
619
|
var Icon = ({ d, className = "w-4 h-4", stroke = 1.8, fill = "none" }) => /* @__PURE__ */ jsx5("svg", { viewBox: "0 0 24 24", className, fill, stroke: "currentColor", strokeWidth: stroke, strokeLinecap: "round", strokeLinejoin: "round", children: d });
|
|
521
620
|
var I = {
|
|
522
621
|
inbox: /* @__PURE__ */ jsx5(Icon, { d: /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
@@ -745,14 +844,29 @@ var I = {
|
|
|
745
844
|
/* @__PURE__ */ jsx5("path", { d: "M14 21h.01" }),
|
|
746
845
|
/* @__PURE__ */ jsx5("path", { d: "M21 21v-3.5" }),
|
|
747
846
|
/* @__PURE__ */ jsx5("path", { d: "M17.5 21h.01" })
|
|
847
|
+
] }) }),
|
|
848
|
+
back: /* @__PURE__ */ jsx5(Icon, { d: /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
849
|
+
/* @__PURE__ */ jsx5("path", { d: "M19 12H5" }),
|
|
850
|
+
/* @__PURE__ */ jsx5("path", { d: "M12 19l-7-7 7-7" })
|
|
851
|
+
] }) }),
|
|
852
|
+
trash: /* @__PURE__ */ jsx5(Icon, { d: /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
853
|
+
/* @__PURE__ */ jsx5("polyline", { points: "3 6 5 6 21 6" }),
|
|
854
|
+
/* @__PURE__ */ jsx5("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
|
|
855
|
+
] }) }),
|
|
856
|
+
sparkle: /* @__PURE__ */ jsx5(Icon, { d: /* @__PURE__ */ jsx5("path", { d: "M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9L12 3Z" }) }),
|
|
857
|
+
warn: /* @__PURE__ */ jsx5(Icon, { d: /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
858
|
+
/* @__PURE__ */ jsx5("path", { d: "M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z" }),
|
|
859
|
+
/* @__PURE__ */ jsx5("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
|
|
860
|
+
/* @__PURE__ */ jsx5("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
|
|
748
861
|
] }) })
|
|
749
862
|
};
|
|
750
|
-
var Avatar = ({ name, size = "md", color = "bg-violet-500", online }) => {
|
|
751
|
-
const sizes = { sm: "w-7 h-7 text-[11px]", md: "w-9 h-9 text-xs", lg: "w-11 h-11 text-sm", xl: "w-14 h-14 text-base" };
|
|
752
|
-
const initials = name.split(" ").map((p) => p[0]).slice(0, 2).join("").toUpperCase();
|
|
863
|
+
var Avatar = ({ name = "", src, size = "md", color = "bg-violet-500", online, dot }) => {
|
|
864
|
+
const sizes = { xs: "w-5 h-5 text-[9px]", sm: "w-7 h-7 text-[11px]", md: "w-9 h-9 text-xs", lg: "w-11 h-11 text-sm", xl: "w-14 h-14 text-base" };
|
|
865
|
+
const initials = (name || "").split(" ").filter(Boolean).map((p) => p[0]).slice(0, 2).join("").toUpperCase() || "?";
|
|
866
|
+
const dotColor = dot || (online ? "bg-emerald-500" : null);
|
|
753
867
|
return /* @__PURE__ */ jsxs3("div", { className: "relative inline-flex", children: [
|
|
754
|
-
/* @__PURE__ */ jsx5("div", { className: `${sizes[size]} ${color} rounded-full text-white font-semibold inline-flex items-center justify-center select-none shrink-0`, children: initials }),
|
|
755
|
-
|
|
868
|
+
src ? /* @__PURE__ */ jsx5("img", { src, alt: name, className: `${sizes[size]} rounded-full object-cover select-none shrink-0` }) : /* @__PURE__ */ jsx5("div", { className: `${sizes[size]} ${color} rounded-full text-white font-semibold inline-flex items-center justify-center select-none shrink-0`, children: initials }),
|
|
869
|
+
dotColor && /* @__PURE__ */ jsx5("span", { className: `absolute bottom-0 right-0 w-2.5 h-2.5 rounded-full ${dotColor} ring-2 ring-white` })
|
|
756
870
|
] });
|
|
757
871
|
};
|
|
758
872
|
var Pill = ({ children, tone = "slate" }) => {
|
|
@@ -878,15 +992,12 @@ var quickReplies = [
|
|
|
878
992
|
{ id: "q3", label: "Agendar visita", text: "Posso j\xE1 agendar a visita pra voc\xEA. Qual o melhor dia e hor\xE1rio essa semana?" },
|
|
879
993
|
{ id: "q4", label: "Documentos", text: "Pra avan\xE7ar com a proposta, vou precisar de RG, CPF, comprovante de renda e resid\xEAncia. Pode me enviar por aqui mesmo." }
|
|
880
994
|
];
|
|
881
|
-
|
|
882
|
-
open: { tone: "sky", label: "Aberto" },
|
|
883
|
-
in_progress: { tone: "amber", label: "Em atendimento" },
|
|
884
|
-
waiting: { tone: "violet", label: "Aguardando cliente" },
|
|
885
|
-
resolved: { tone: "emerald", label: "Resolvido" }
|
|
886
|
-
};
|
|
887
|
-
function App() {
|
|
995
|
+
function App({ onBack, agent, onUnreadChange }) {
|
|
888
996
|
var _a;
|
|
889
997
|
const inbox = useInbox();
|
|
998
|
+
const [available, setAvailable] = useState4(true);
|
|
999
|
+
const typingSentRef = useRef3(0);
|
|
1000
|
+
const typingStopRef = useRef3(null);
|
|
890
1001
|
const live = inbox.live;
|
|
891
1002
|
const [mockActiveId, setMockActiveId] = useState4("c1");
|
|
892
1003
|
const activeId = live ? inbox.activeId : mockActiveId;
|
|
@@ -894,6 +1005,16 @@ function App() {
|
|
|
894
1005
|
const [connectOpen, setConnectOpen] = useState4(false);
|
|
895
1006
|
const [transferOpen, setTransferOpen] = useState4(false);
|
|
896
1007
|
const [emojiOpen, setEmojiOpen] = useState4(false);
|
|
1008
|
+
const emojiRef = useRef3(null);
|
|
1009
|
+
const [mediaPreview, setMediaPreview] = useState4(null);
|
|
1010
|
+
const [selectMode, setSelectMode] = useState4(false);
|
|
1011
|
+
const [selectedMsgs, setSelectedMsgs] = useState4(() => /* @__PURE__ */ new Set());
|
|
1012
|
+
const [confirmDelete, setConfirmDelete] = useState4(false);
|
|
1013
|
+
const [newConv, setNewConv] = useState4(null);
|
|
1014
|
+
const [aiSummary, setAiSummary] = useState4(null);
|
|
1015
|
+
const [convSummary, setConvSummary] = useState4(null);
|
|
1016
|
+
const curConvRef = useRef3(null);
|
|
1017
|
+
const summarizingRef = useRef3(null);
|
|
897
1018
|
const [filterOpen, setFilterOpen] = useState4(false);
|
|
898
1019
|
const [unreadOnly, setUnreadOnly] = useState4(false);
|
|
899
1020
|
const [mineOnly, setMineOnly] = useState4(false);
|
|
@@ -902,7 +1023,7 @@ function App() {
|
|
|
902
1023
|
const [composeMode, setComposeMode] = useState4("reply");
|
|
903
1024
|
const [text, setText] = useState4("");
|
|
904
1025
|
const [filter, setFilter] = useState4("all");
|
|
905
|
-
const [detailsOpen, setDetailsOpen] = useState4(
|
|
1026
|
+
const [detailsOpen, setDetailsOpen] = useState4(false);
|
|
906
1027
|
const [quickOpen, setQuickOpen] = useState4(false);
|
|
907
1028
|
const [searchOpen, setSearchOpen] = useState4(false);
|
|
908
1029
|
const [searchQuery, setSearchQuery] = useState4("");
|
|
@@ -974,27 +1095,91 @@ function App() {
|
|
|
974
1095
|
setEmojiOpen(false);
|
|
975
1096
|
(_a2 = textareaRef.current) == null ? void 0 : _a2.focus();
|
|
976
1097
|
};
|
|
977
|
-
const
|
|
1098
|
+
const enterSelect = (id) => {
|
|
1099
|
+
setSelectMode(true);
|
|
1100
|
+
setSelectedMsgs(/* @__PURE__ */ new Set([id]));
|
|
1101
|
+
};
|
|
1102
|
+
const toggleSelect = (id) => setSelectedMsgs((s) => {
|
|
1103
|
+
const n = new Set(s);
|
|
1104
|
+
n.has(id) ? n.delete(id) : n.add(id);
|
|
1105
|
+
if (n.size === 0) setSelectMode(false);
|
|
1106
|
+
return n;
|
|
1107
|
+
});
|
|
1108
|
+
const exitSelect = () => {
|
|
1109
|
+
setSelectMode(false);
|
|
1110
|
+
setSelectedMsgs(/* @__PURE__ */ new Set());
|
|
1111
|
+
};
|
|
1112
|
+
const doDeleteSelected = async () => {
|
|
1113
|
+
const ids = [...selectedMsgs];
|
|
1114
|
+
setConfirmDelete(false);
|
|
1115
|
+
exitSelect();
|
|
1116
|
+
await Promise.all(ids.map((id) => inbox.deleteMessage(id)));
|
|
1117
|
+
};
|
|
1118
|
+
const handleSummarize = async () => {
|
|
1119
|
+
if (!active) return;
|
|
1120
|
+
setAiSummary({ loading: true });
|
|
1121
|
+
try {
|
|
1122
|
+
const s = await inbox.summarize(active.id);
|
|
1123
|
+
setAiSummary({ text: s });
|
|
1124
|
+
} catch (e) {
|
|
1125
|
+
setAiSummary({ error: e.message || "Falha ao gerar o resumo" });
|
|
1126
|
+
}
|
|
1127
|
+
};
|
|
1128
|
+
const submitNewConv = async () => {
|
|
1129
|
+
const phone = ((newConv == null ? void 0 : newConv.phone) || "").trim();
|
|
1130
|
+
if (!phone) return;
|
|
1131
|
+
setNewConv((c) => ({ ...c, busy: true, error: "" }));
|
|
1132
|
+
try {
|
|
1133
|
+
await inbox.createConversation(phone, newConv.text);
|
|
1134
|
+
setNewConv(null);
|
|
1135
|
+
} catch (e) {
|
|
1136
|
+
setNewConv((c) => ({ ...c, busy: false, error: e.message || "Falha ao iniciar conversa" }));
|
|
1137
|
+
}
|
|
1138
|
+
};
|
|
1139
|
+
useEffect4(() => {
|
|
1140
|
+
if (!emojiOpen) return;
|
|
1141
|
+
const onDoc = (e) => {
|
|
1142
|
+
if (emojiRef.current && !emojiRef.current.contains(e.target)) setEmojiOpen(false);
|
|
1143
|
+
};
|
|
1144
|
+
document.addEventListener("mousedown", onDoc);
|
|
1145
|
+
return () => document.removeEventListener("mousedown", onDoc);
|
|
1146
|
+
}, [emojiOpen]);
|
|
1147
|
+
useEffect4(() => {
|
|
1148
|
+
setSelectMode(false);
|
|
1149
|
+
setSelectedMsgs(/* @__PURE__ */ new Set());
|
|
1150
|
+
}, [activeId]);
|
|
1151
|
+
useEffect4(() => {
|
|
1152
|
+
if (typeof onUnreadChange !== "function") return;
|
|
1153
|
+
onUnreadChange((convList || []).reduce((s, c) => s + (c.unread || 0), 0));
|
|
1154
|
+
}, [convList, onUnreadChange]);
|
|
1155
|
+
const openMediaPreview = (file, kind) => {
|
|
978
1156
|
if (!file) return;
|
|
979
|
-
|
|
980
|
-
|
|
1157
|
+
setMediaPreview({ file, kind, previewUrl: URL.createObjectURL(file), caption: "" });
|
|
1158
|
+
};
|
|
1159
|
+
const confirmMediaSend = async () => {
|
|
1160
|
+
var _a2;
|
|
1161
|
+
const p = mediaPreview;
|
|
1162
|
+
if (!p) return;
|
|
1163
|
+
setMediaPreview(null);
|
|
1164
|
+
const data = await fileToDataUrl(p.file);
|
|
1165
|
+
const caption = ((_a2 = p.caption) == null ? void 0 : _a2.trim()) || void 0;
|
|
981
1166
|
if (live) {
|
|
982
|
-
inbox.sendMedia({ data, mime: file.type, kind, filename: file.name, previewUrl });
|
|
1167
|
+
inbox.sendMedia({ data, mime: p.file.type, kind: p.kind, filename: p.file.name, previewUrl: p.previewUrl, caption });
|
|
983
1168
|
} else {
|
|
984
|
-
setMessages((ms) => [...ms, { id: `m${Date.now()}`, side: "out", kind, mediaUrl: previewUrl,
|
|
1169
|
+
setMessages((ms) => [...ms, { id: `m${Date.now()}`, side: "out", kind: p.kind, mediaUrl: p.previewUrl, filename: p.file.name, caption: caption || "", time: nowHHMM(), status: "sent" }]);
|
|
985
1170
|
}
|
|
986
1171
|
};
|
|
987
|
-
const onPickImage =
|
|
1172
|
+
const onPickImage = (e) => {
|
|
988
1173
|
var _a2;
|
|
989
1174
|
const f = (_a2 = e.target.files) == null ? void 0 : _a2[0];
|
|
990
1175
|
e.target.value = "";
|
|
991
|
-
|
|
1176
|
+
openMediaPreview(f, "image");
|
|
992
1177
|
};
|
|
993
|
-
const onPickFile =
|
|
1178
|
+
const onPickFile = (e) => {
|
|
994
1179
|
var _a2;
|
|
995
1180
|
const f = (_a2 = e.target.files) == null ? void 0 : _a2[0];
|
|
996
1181
|
e.target.value = "";
|
|
997
|
-
|
|
1182
|
+
openMediaPreview(f, "document");
|
|
998
1183
|
};
|
|
999
1184
|
const startRecording = async () => {
|
|
1000
1185
|
try {
|
|
@@ -1113,19 +1298,50 @@ function App() {
|
|
|
1113
1298
|
};
|
|
1114
1299
|
const nextMatch = () => searchMatches.length && setSearchIndex((i) => (i + 1) % searchMatches.length);
|
|
1115
1300
|
const prevMatch = () => searchMatches.length && setSearchIndex((i) => (i - 1 + searchMatches.length) % searchMatches.length);
|
|
1116
|
-
const active = convList.find((c) => c.id === activeId);
|
|
1301
|
+
const active = convList.find((c) => c.id === activeId) || (inbox.draftConv && inbox.draftConv.id === activeId ? inbox.draftConv : null);
|
|
1302
|
+
useEffect4(() => {
|
|
1303
|
+
curConvRef.current = activeId;
|
|
1304
|
+
if (!live || !active || threadMessages.length === 0) {
|
|
1305
|
+
setConvSummary(null);
|
|
1306
|
+
return;
|
|
1307
|
+
}
|
|
1308
|
+
const convId = activeId;
|
|
1309
|
+
const saved = active.aiSummary || "";
|
|
1310
|
+
const savedCount = active.aiSummaryCount || 0;
|
|
1311
|
+
const count = threadMessages.length;
|
|
1312
|
+
setConvSummary({ convId, text: saved });
|
|
1313
|
+
const stale = !saved || count - savedCount >= REGEN_EVERY;
|
|
1314
|
+
if (!stale || summarizingRef.current === convId) return;
|
|
1315
|
+
summarizingRef.current = convId;
|
|
1316
|
+
setConvSummary({ convId, loading: true, text: saved });
|
|
1317
|
+
inbox.summarize(convId).then((text2) => {
|
|
1318
|
+
summarizingRef.current = null;
|
|
1319
|
+
if (curConvRef.current !== convId || !text2) return;
|
|
1320
|
+
setConvSummary({ convId, text: text2 });
|
|
1321
|
+
inbox.loadConversations();
|
|
1322
|
+
}).catch((e) => {
|
|
1323
|
+
summarizingRef.current = null;
|
|
1324
|
+
if (curConvRef.current === convId) setConvSummary({ convId, text: saved, error: e.message });
|
|
1325
|
+
});
|
|
1326
|
+
}, [activeId, threadMessages.length, live, active == null ? void 0 : active.aiSummary, active == null ? void 0 : active.aiSummaryCount]);
|
|
1117
1327
|
useEffect4(() => {
|
|
1118
1328
|
if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
|
|
1119
1329
|
}, [activeId, threadMessages.length]);
|
|
1120
1330
|
const counts = useMemo2(() => ({
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1331
|
+
all: convList.length,
|
|
1332
|
+
unread: convList.filter((c) => c.unread > 0).length,
|
|
1333
|
+
mine: convList.filter((c) => {
|
|
1334
|
+
var _a2;
|
|
1335
|
+
return ((_a2 = c._raw) == null ? void 0 : _a2.assignee_user_id) && c._raw.assignee_user_id === inbox.me;
|
|
1336
|
+
}).length
|
|
1337
|
+
}), [convList, inbox.me]);
|
|
1125
1338
|
const filtered = useMemo2(() => {
|
|
1126
1339
|
let list = convList;
|
|
1127
|
-
if (filter === "
|
|
1128
|
-
else if (filter
|
|
1340
|
+
if (filter === "unread") list = list.filter((c) => c.unread > 0);
|
|
1341
|
+
else if (filter === "mine") list = list.filter((c) => {
|
|
1342
|
+
var _a2;
|
|
1343
|
+
return ((_a2 = c._raw) == null ? void 0 : _a2.assignee_user_id) && c._raw.assignee_user_id === inbox.me;
|
|
1344
|
+
});
|
|
1129
1345
|
if (unreadOnly) list = list.filter((c) => c.unread > 0);
|
|
1130
1346
|
if (mineOnly) list = list.filter((c) => {
|
|
1131
1347
|
var _a2;
|
|
@@ -1133,55 +1349,100 @@ function App() {
|
|
|
1133
1349
|
});
|
|
1134
1350
|
return list;
|
|
1135
1351
|
}, [filter, convList, unreadOnly, mineOnly, inbox.me]);
|
|
1136
|
-
|
|
1137
|
-
|
|
1352
|
+
const channelList = inbox.channels || [];
|
|
1353
|
+
const isConnected = channelList.some((c) => c.status === "connected");
|
|
1354
|
+
const hasChannel = channelList.length > 0;
|
|
1355
|
+
const channelsReady = inbox.channelsLoaded;
|
|
1356
|
+
const needsReconnect = live && channelsReady && hasChannel && !isConnected;
|
|
1357
|
+
const needsConnect = live && channelsReady && !hasChannel;
|
|
1358
|
+
const agentOf = (id) => id ? (inbox.agents || []).find((a) => a.user_id === id) : null;
|
|
1359
|
+
const notifyTyping = () => {
|
|
1360
|
+
if (!live || !activeId || composeMode !== "reply") return;
|
|
1361
|
+
const now = Date.now();
|
|
1362
|
+
if (now - typingSentRef.current > 2500) {
|
|
1363
|
+
typingSentRef.current = now;
|
|
1364
|
+
inbox.setTyping(activeId, "composing");
|
|
1365
|
+
}
|
|
1366
|
+
clearTimeout(typingStopRef.current);
|
|
1367
|
+
typingStopRef.current = setTimeout(() => {
|
|
1368
|
+
inbox.setTyping(activeId, "paused");
|
|
1369
|
+
typingSentRef.current = 0;
|
|
1370
|
+
}, 3e3);
|
|
1371
|
+
};
|
|
1372
|
+
return /* @__PURE__ */ jsxs3("div", { className: "h-full w-full bg-slate-100 flex flex-col text-slate-900", children: [
|
|
1373
|
+
needsReconnect && /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 px-4 py-2 bg-amber-50 border-b border-amber-200 text-amber-800 text-[13px] shrink-0", children: [
|
|
1374
|
+
/* @__PURE__ */ jsx5("span", { className: "shrink-0", children: I.warn }),
|
|
1375
|
+
/* @__PURE__ */ jsx5("span", { className: "min-w-0", children: "WhatsApp desconectado. Reconecte o n\xFAmero para continuar recebendo mensagens." }),
|
|
1376
|
+
/* @__PURE__ */ jsx5(
|
|
1377
|
+
"button",
|
|
1378
|
+
{
|
|
1379
|
+
onClick: () => setConnectOpen(true),
|
|
1380
|
+
className: "ml-auto shrink-0 font-medium bg-amber-500 hover:bg-amber-600 text-white px-3 py-1 rounded-lg",
|
|
1381
|
+
children: "Reconectar"
|
|
1382
|
+
}
|
|
1383
|
+
)
|
|
1384
|
+
] }),
|
|
1385
|
+
needsConnect && /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 px-4 py-2 bg-emerald-50 border-b border-emerald-200 text-emerald-800 text-[13px] shrink-0", children: [
|
|
1386
|
+
/* @__PURE__ */ jsx5("span", { className: "min-w-0", children: "Conecte um n\xFAmero de WhatsApp para come\xE7ar a atender." }),
|
|
1387
|
+
/* @__PURE__ */ jsx5(
|
|
1388
|
+
"button",
|
|
1389
|
+
{
|
|
1390
|
+
onClick: () => setConnectOpen(true),
|
|
1391
|
+
className: "ml-auto shrink-0 font-medium bg-emerald-600 hover:bg-emerald-700 text-white px-3 py-1 rounded-lg",
|
|
1392
|
+
children: "Conectar"
|
|
1393
|
+
}
|
|
1394
|
+
)
|
|
1395
|
+
] }),
|
|
1396
|
+
/* @__PURE__ */ jsxs3("main", { className: "flex-1 flex overflow-hidden min-h-0", children: [
|
|
1138
1397
|
/* @__PURE__ */ jsxs3("section", { style: { width: listWidth }, className: "relative bg-white border-r border-slate-200 flex flex-col shrink-0", children: [
|
|
1139
1398
|
/* @__PURE__ */ jsxs3("header", { className: "px-4 pt-4 pb-3 border-b border-slate-100", children: [
|
|
1140
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between mb-3", children: [
|
|
1141
|
-
/* @__PURE__ */
|
|
1142
|
-
|
|
1143
|
-
live && /* @__PURE__ */ jsx5(
|
|
1399
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between mb-3 gap-2", children: [
|
|
1400
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-1.5 min-w-0", children: [
|
|
1401
|
+
onBack && /* @__PURE__ */ jsx5(
|
|
1144
1402
|
"button",
|
|
1145
1403
|
{
|
|
1146
|
-
onClick:
|
|
1147
|
-
title: "
|
|
1148
|
-
className: "p-1.5 rounded-md hover:bg-
|
|
1149
|
-
children: I.
|
|
1404
|
+
onClick: onBack,
|
|
1405
|
+
title: "Voltar",
|
|
1406
|
+
className: "-ml-1.5 p-1.5 rounded-md text-slate-500 hover:bg-slate-100 shrink-0",
|
|
1407
|
+
children: I.back
|
|
1150
1408
|
}
|
|
1151
1409
|
),
|
|
1152
|
-
/* @__PURE__ */
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1410
|
+
/* @__PURE__ */ jsx5("h1", { className: "font-semibold text-[15px] truncate", children: "Caixa de entrada" }),
|
|
1411
|
+
live && /* @__PURE__ */ jsxs3(
|
|
1412
|
+
"button",
|
|
1413
|
+
{
|
|
1414
|
+
onClick: () => setAvailable((v) => !v),
|
|
1415
|
+
title: `${(agent == null ? void 0 : agent.name) || "Voc\xEA"} \u2014 ${available ? "Dispon\xEDvel (clique para pausar)" : "Pausado (clique para voltar a atender)"}`,
|
|
1416
|
+
className: "shrink-0 inline-flex items-center gap-1.5 pl-0.5 pr-2 py-0.5 rounded-full hover:bg-slate-100 transition-colors",
|
|
1417
|
+
children: [
|
|
1418
|
+
/* @__PURE__ */ jsx5(Avatar, { name: (agent == null ? void 0 : agent.name) || "Voc\xEA", src: agent == null ? void 0 : agent.avatar, size: "xs", dot: available ? "bg-emerald-500" : "bg-slate-400" }),
|
|
1419
|
+
/* @__PURE__ */ jsx5("span", { className: "text-[11.5px] font-medium text-slate-600 truncate max-w-[84px]", children: (agent == null ? void 0 : agent.name) || "Voc\xEA" })
|
|
1420
|
+
]
|
|
1421
|
+
}
|
|
1422
|
+
)
|
|
1423
|
+
] }),
|
|
1424
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-1 shrink-0", children: [
|
|
1425
|
+
live && isConnected && /* @__PURE__ */ jsx5(
|
|
1426
|
+
"button",
|
|
1427
|
+
{
|
|
1428
|
+
onClick: () => setNewConv({ phone: "", text: "", busy: false, error: "" }),
|
|
1429
|
+
title: "Nova conversa",
|
|
1430
|
+
className: "p-1.5 rounded-md text-slate-500 hover:bg-slate-100 hover:text-slate-900",
|
|
1431
|
+
children: I.plus
|
|
1432
|
+
}
|
|
1433
|
+
),
|
|
1434
|
+
live && channelsReady && !isConnected && /* @__PURE__ */ jsxs3(
|
|
1435
|
+
"button",
|
|
1436
|
+
{
|
|
1437
|
+
onClick: () => setConnectOpen(true),
|
|
1438
|
+
title: needsReconnect ? "WhatsApp desconectado \u2014 reconectar" : "Conectar WhatsApp",
|
|
1439
|
+
className: "relative p-1.5 rounded-md hover:bg-emerald-50 text-emerald-600",
|
|
1440
|
+
children: [
|
|
1441
|
+
I.qrcode,
|
|
1442
|
+
needsReconnect && /* @__PURE__ */ jsx5("span", { className: "absolute -top-1 -right-1 w-3.5 h-3.5 rounded-full bg-amber-500 text-white text-[9px] font-bold inline-flex items-center justify-center ring-2 ring-white", children: "!" })
|
|
1443
|
+
]
|
|
1444
|
+
}
|
|
1445
|
+
)
|
|
1185
1446
|
] })
|
|
1186
1447
|
] }),
|
|
1187
1448
|
/* @__PURE__ */ jsxs3("div", { className: "relative", children: [
|
|
@@ -1190,8 +1451,8 @@ function App() {
|
|
|
1190
1451
|
] }),
|
|
1191
1452
|
/* @__PURE__ */ jsx5("div", { className: "flex items-center gap-2 mt-3 text-[12px]", children: [
|
|
1192
1453
|
["all", "Todas", counts.all],
|
|
1193
|
-
["
|
|
1194
|
-
["
|
|
1454
|
+
["unread", "N\xE3o lidas", counts.unread],
|
|
1455
|
+
["mine", "Minhas", counts.mine]
|
|
1195
1456
|
].map(([k, l, n]) => /* @__PURE__ */ jsxs3(
|
|
1196
1457
|
"button",
|
|
1197
1458
|
{
|
|
@@ -1206,17 +1467,22 @@ function App() {
|
|
|
1206
1467
|
k
|
|
1207
1468
|
)) })
|
|
1208
1469
|
] }),
|
|
1209
|
-
/* @__PURE__ */ jsx5("div", { className: "flex-1 overflow-y-auto", children: filtered.map((
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1470
|
+
/* @__PURE__ */ jsx5("div", { className: "flex-1 overflow-y-auto", children: live && inbox.loading && filtered.length === 0 ? [...Array(7)].map((_, i) => /* @__PURE__ */ jsx5(ConversationSkeleton, {}, i)) : filtered.map((c) => {
|
|
1471
|
+
var _a2;
|
|
1472
|
+
return /* @__PURE__ */ jsx5(
|
|
1473
|
+
ConversationItem,
|
|
1474
|
+
{
|
|
1475
|
+
c,
|
|
1476
|
+
active: c.id === activeId,
|
|
1477
|
+
assignee: inbox.scope === "all" ? agentOf((_a2 = c._raw) == null ? void 0 : _a2.assignee_user_id) : null,
|
|
1478
|
+
onClick: () => {
|
|
1479
|
+
setActiveId(c.id);
|
|
1480
|
+
if (live) inbox.markRead(c.id);
|
|
1481
|
+
}
|
|
1482
|
+
},
|
|
1483
|
+
c.id
|
|
1484
|
+
);
|
|
1485
|
+
}) }),
|
|
1220
1486
|
/* @__PURE__ */ jsx5(
|
|
1221
1487
|
"div",
|
|
1222
1488
|
{
|
|
@@ -1226,8 +1492,43 @@ function App() {
|
|
|
1226
1492
|
}
|
|
1227
1493
|
)
|
|
1228
1494
|
] }),
|
|
1229
|
-
/* @__PURE__ */
|
|
1230
|
-
|
|
1495
|
+
/* @__PURE__ */ jsx5("section", { className: "flex-1 flex flex-col bg-slate-50 min-w-0", children: active ? /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
1496
|
+
/* @__PURE__ */ jsx5(ChatHeader, { c: active, onToggleDetails: () => setDetailsOpen((v) => !v), detailsOpen, onOpenSearch: openSearch, onTransfer: () => setTransferOpen(true), typing: live && inbox.typingConvId === (active == null ? void 0 : active.id), onSummarize: live ? handleSummarize : null }),
|
|
1497
|
+
selectMode && /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-3 px-5 py-2.5 bg-slate-900 text-white", children: [
|
|
1498
|
+
/* @__PURE__ */ jsx5("button", { onClick: exitSelect, title: "Cancelar", className: "p-1 rounded hover:bg-white/10", children: I.x }),
|
|
1499
|
+
/* @__PURE__ */ jsxs3("span", { className: "text-[14px] font-medium flex-1", children: [
|
|
1500
|
+
selectedMsgs.size,
|
|
1501
|
+
" selecionada",
|
|
1502
|
+
selectedMsgs.size === 1 ? "" : "s"
|
|
1503
|
+
] }),
|
|
1504
|
+
/* @__PURE__ */ jsx5(
|
|
1505
|
+
"button",
|
|
1506
|
+
{
|
|
1507
|
+
onClick: () => selectedMsgs.size && setConfirmDelete(true),
|
|
1508
|
+
disabled: !selectedMsgs.size,
|
|
1509
|
+
title: "Apagar selecionadas",
|
|
1510
|
+
className: "p-1.5 rounded-md hover:bg-white/10 disabled:opacity-40",
|
|
1511
|
+
children: I.trash
|
|
1512
|
+
}
|
|
1513
|
+
)
|
|
1514
|
+
] }),
|
|
1515
|
+
!selectMode && convSummary && (convSummary.text || convSummary.loading) && /* @__PURE__ */ jsxs3(
|
|
1516
|
+
"button",
|
|
1517
|
+
{
|
|
1518
|
+
onClick: () => convSummary.text && setAiSummary({ text: convSummary.text }),
|
|
1519
|
+
title: "Ver resumo completo",
|
|
1520
|
+
className: "w-full text-left flex items-start gap-2 px-5 py-2 bg-violet-50 border-b border-violet-100 hover:bg-violet-100/70 transition-colors",
|
|
1521
|
+
children: [
|
|
1522
|
+
/* @__PURE__ */ jsx5("span", { className: "text-violet-500 shrink-0 mt-0.5", children: I.sparkle }),
|
|
1523
|
+
convSummary.loading && !convSummary.text ? /* @__PURE__ */ jsx5("span", { className: "text-[12.5px] text-violet-400 animate-pulse", children: "Resumindo a conversa\u2026" }) : /* @__PURE__ */ jsxs3("span", { className: "text-[12.5px] text-violet-900 leading-snug line-clamp-2 flex-1", children: [
|
|
1524
|
+
/* @__PURE__ */ jsx5("strong", { className: "font-semibold text-violet-700", children: "Resumo:" }),
|
|
1525
|
+
" ",
|
|
1526
|
+
convSummary.text
|
|
1527
|
+
] }),
|
|
1528
|
+
convSummary.loading && convSummary.text && /* @__PURE__ */ jsx5("span", { className: "text-[11px] text-violet-400 shrink-0", children: "atualizando\u2026" })
|
|
1529
|
+
]
|
|
1530
|
+
}
|
|
1531
|
+
),
|
|
1231
1532
|
searchOpen && /* @__PURE__ */ jsx5(
|
|
1232
1533
|
SearchBar,
|
|
1233
1534
|
{
|
|
@@ -1240,24 +1541,27 @@ function App() {
|
|
|
1240
1541
|
onClose: closeSearch
|
|
1241
1542
|
}
|
|
1242
1543
|
),
|
|
1243
|
-
/* @__PURE__ */ jsxs3("div", { ref: scrollRef, className: "flex-1 overflow-y-auto px-
|
|
1244
|
-
/* @__PURE__ */ jsx5(
|
|
1544
|
+
/* @__PURE__ */ jsxs3("div", { ref: scrollRef, className: "flex-1 overflow-y-auto px-8 py-6 space-y-1.5", children: [
|
|
1545
|
+
live && inbox.messagesLoading && threadMessages.length === 0 && /* @__PURE__ */ jsx5("div", { className: "space-y-3 py-2", children: [["in", "w-40"], ["in", "w-56"], ["out", "w-48"], ["in", "w-32"], ["out", "w-60"], ["out", "w-36"]].map(([side, w], i) => /* @__PURE__ */ jsx5("div", { className: `flex ${side === "out" ? "justify-end" : "justify-start"}`, children: /* @__PURE__ */ jsx5("div", { className: `h-9 ${w} max-w-[70%] rounded-2xl animate-pulse ${side === "out" ? "bg-emerald-200/70" : "bg-slate-200"}` }) }, i)) }),
|
|
1546
|
+
threadMessages.length > 0 && /* @__PURE__ */ jsx5(DayDivider, { label: "Hoje" }),
|
|
1245
1547
|
threadMessages.map((m, i) => /* @__PURE__ */ jsx5(
|
|
1246
1548
|
Message,
|
|
1247
1549
|
{
|
|
1248
1550
|
m,
|
|
1249
1551
|
prev: threadMessages[i - 1],
|
|
1250
1552
|
searchQuery: searchOpen ? searchQuery : "",
|
|
1251
|
-
isCurrentMatch: m.id === currentMatchId
|
|
1553
|
+
isCurrentMatch: m.id === currentMatchId,
|
|
1554
|
+
isGroup: !!(active == null ? void 0 : active.isGroup),
|
|
1555
|
+
selectable: live && inbox.canDelete,
|
|
1556
|
+
selectMode,
|
|
1557
|
+
selected: selectedMsgs.has(m.id),
|
|
1558
|
+
onEnterSelect: () => enterSelect(m.id),
|
|
1559
|
+
onToggleSelect: () => toggleSelect(m.id)
|
|
1252
1560
|
},
|
|
1253
1561
|
m.id
|
|
1254
|
-
))
|
|
1255
|
-
/* @__PURE__ */ jsx5("div", { className: "text-center mt-4", children: /* @__PURE__ */ jsxs3("span", { className: "text-[11px] text-slate-400 inline-flex items-center gap-1", children: [
|
|
1256
|
-
/* @__PURE__ */ jsx5(Avatar, { name: (active == null ? void 0 : active.name) || "", size: "sm", color: active == null ? void 0 : active.avatarColor }),
|
|
1257
|
-
" Conversa criada por voc\xEA \xB7 agora"
|
|
1258
|
-
] }) })
|
|
1562
|
+
))
|
|
1259
1563
|
] }),
|
|
1260
|
-
/* @__PURE__ */ jsx5("div", { className: "px-
|
|
1564
|
+
/* @__PURE__ */ jsx5("div", { className: "px-8 pb-6", children: /* @__PURE__ */ jsxs3("div", { className: "bg-white border border-slate-200 rounded-2xl shadow-soft", children: [
|
|
1261
1565
|
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-1 px-3 pt-2 text-[12px]", children: [
|
|
1262
1566
|
[
|
|
1263
1567
|
["reply", "Mensagem"],
|
|
@@ -1298,14 +1602,17 @@ function App() {
|
|
|
1298
1602
|
ref: textareaRef,
|
|
1299
1603
|
rows: 3,
|
|
1300
1604
|
value: text,
|
|
1301
|
-
onChange: (e) =>
|
|
1605
|
+
onChange: (e) => {
|
|
1606
|
+
setText(e.target.value);
|
|
1607
|
+
notifyTyping();
|
|
1608
|
+
},
|
|
1302
1609
|
onKeyDown: (e) => {
|
|
1303
1610
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
1304
1611
|
e.preventDefault();
|
|
1305
1612
|
handleSend();
|
|
1306
1613
|
}
|
|
1307
1614
|
},
|
|
1308
|
-
placeholder: composeMode === "note" ? "Adicione uma nota interna \u2014 vis\xEDvel s\xF3 para o time\u2026" : "Digite uma mensagem
|
|
1615
|
+
placeholder: composeMode === "note" ? "Adicione uma nota interna \u2014 vis\xEDvel s\xF3 para o time\u2026" : "Digite uma mensagem\u2026",
|
|
1309
1616
|
className: `w-full text-[14px] resize-none bg-transparent outline-none placeholder:text-slate-400 ${composeMode === "note" ? "text-yellow-900 placeholder:text-yellow-600" : ""}`
|
|
1310
1617
|
}
|
|
1311
1618
|
) }),
|
|
@@ -1321,7 +1628,7 @@ function App() {
|
|
|
1321
1628
|
/* @__PURE__ */ jsx5("span", { className: "opacity-90", children: I.send })
|
|
1322
1629
|
] })
|
|
1323
1630
|
] }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
1324
|
-
/* @__PURE__ */ jsxs3("div", { className: "relative", children: [
|
|
1631
|
+
/* @__PURE__ */ jsxs3("div", { className: "relative", ref: emojiRef, children: [
|
|
1325
1632
|
/* @__PURE__ */ jsx5(
|
|
1326
1633
|
"button",
|
|
1327
1634
|
{
|
|
@@ -1367,21 +1674,125 @@ function App() {
|
|
|
1367
1674
|
/* @__PURE__ */ jsx5("input", { ref: fileInputRef, type: "file", className: "hidden", onChange: onPickFile })
|
|
1368
1675
|
] })
|
|
1369
1676
|
] }) })
|
|
1370
|
-
] }),
|
|
1677
|
+
] }) : /* @__PURE__ */ jsx5(EmptyConversation, {}) }),
|
|
1371
1678
|
detailsOpen && active && /* @__PURE__ */ jsx5(DetailsPanel, { c: active, onClose: () => setDetailsOpen(false) })
|
|
1372
1679
|
] }),
|
|
1373
1680
|
connectOpen && /* @__PURE__ */ jsx5(ConnectChannel, { inbox, onClose: () => setConnectOpen(false) }),
|
|
1374
|
-
transferOpen && active && /* @__PURE__ */ jsx5(TransferModal, { inbox, conversationId: active.id, currentAssignee: (_a = active._raw) == null ? void 0 : _a.assignee_user_id, onClose: () => setTransferOpen(false) })
|
|
1681
|
+
transferOpen && active && /* @__PURE__ */ jsx5(TransferModal, { inbox, conversationId: active.id, currentAssignee: (_a = active._raw) == null ? void 0 : _a.assignee_user_id, onClose: () => setTransferOpen(false) }),
|
|
1682
|
+
mediaPreview && /* @__PURE__ */ jsx5("div", { className: "fixed inset-0 z-50 bg-black/50 flex items-center justify-center p-4", onClick: () => setMediaPreview(null), children: /* @__PURE__ */ jsxs3("div", { className: "bg-white rounded-2xl shadow-xl w-[420px] max-w-full p-4", onClick: (e) => e.stopPropagation(), children: [
|
|
1683
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between mb-3", children: [
|
|
1684
|
+
/* @__PURE__ */ jsxs3("h3", { className: "font-semibold text-[15px]", children: [
|
|
1685
|
+
"Enviar ",
|
|
1686
|
+
mediaPreview.kind === "image" ? "imagem" : "arquivo"
|
|
1687
|
+
] }),
|
|
1688
|
+
/* @__PURE__ */ jsx5("button", { onClick: () => setMediaPreview(null), className: "text-slate-400 hover:text-slate-700 text-xl leading-none", children: "\xD7" })
|
|
1689
|
+
] }),
|
|
1690
|
+
mediaPreview.kind === "image" ? /* @__PURE__ */ jsx5("img", { src: mediaPreview.previewUrl, alt: "", className: "w-full max-h-72 object-contain rounded-lg bg-slate-50" }) : /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-3 bg-slate-50 rounded-lg p-3", children: [
|
|
1691
|
+
/* @__PURE__ */ jsx5("span", { className: "text-slate-500", children: I.file }),
|
|
1692
|
+
/* @__PURE__ */ jsx5("span", { className: "text-[13px] truncate flex-1", children: mediaPreview.file.name })
|
|
1693
|
+
] }),
|
|
1694
|
+
/* @__PURE__ */ jsx5(
|
|
1695
|
+
"input",
|
|
1696
|
+
{
|
|
1697
|
+
autoFocus: true,
|
|
1698
|
+
value: mediaPreview.caption,
|
|
1699
|
+
onChange: (e) => setMediaPreview((p) => ({ ...p, caption: e.target.value })),
|
|
1700
|
+
onKeyDown: (e) => {
|
|
1701
|
+
if (e.key === "Enter") confirmMediaSend();
|
|
1702
|
+
if (e.key === "Escape") setMediaPreview(null);
|
|
1703
|
+
},
|
|
1704
|
+
placeholder: "Legenda (opcional)\u2026",
|
|
1705
|
+
className: "w-full mt-3 px-3 py-2 text-[14px] rounded-lg border border-slate-200 outline-none focus:border-slate-300"
|
|
1706
|
+
}
|
|
1707
|
+
),
|
|
1708
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex justify-end gap-2 mt-3", children: [
|
|
1709
|
+
/* @__PURE__ */ jsx5("button", { onClick: () => setMediaPreview(null), className: "text-[13px] px-3 py-1.5 rounded-lg text-slate-600 hover:bg-slate-100", children: "Cancelar" }),
|
|
1710
|
+
/* @__PURE__ */ jsxs3("button", { onClick: confirmMediaSend, className: "text-[13px] font-medium bg-emerald-600 hover:bg-emerald-700 text-white px-4 py-1.5 rounded-lg inline-flex items-center gap-1.5", children: [
|
|
1711
|
+
"Enviar ",
|
|
1712
|
+
/* @__PURE__ */ jsx5("span", { className: "opacity-90", children: I.send })
|
|
1713
|
+
] })
|
|
1714
|
+
] })
|
|
1715
|
+
] }) }),
|
|
1716
|
+
confirmDelete && /* @__PURE__ */ jsx5("div", { className: "fixed inset-0 z-50 bg-black/50 flex items-center justify-center p-4", onClick: () => setConfirmDelete(false), children: /* @__PURE__ */ jsxs3("div", { className: "bg-white rounded-2xl shadow-xl w-[360px] max-w-full p-5", onClick: (e) => e.stopPropagation(), children: [
|
|
1717
|
+
/* @__PURE__ */ jsxs3("h3", { className: "font-semibold text-[16px] text-slate-900", children: [
|
|
1718
|
+
"Apagar ",
|
|
1719
|
+
selectedMsgs.size,
|
|
1720
|
+
" ",
|
|
1721
|
+
selectedMsgs.size === 1 ? "mensagem" : "mensagens",
|
|
1722
|
+
"?"
|
|
1723
|
+
] }),
|
|
1724
|
+
/* @__PURE__ */ jsx5("p", { className: "text-[13px] text-slate-500 mt-1 mb-4", children: "Ser\xE1 removida para todos no WhatsApp e do seu inbox. N\xE3o d\xE1 pra desfazer." }),
|
|
1725
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex justify-end gap-2", children: [
|
|
1726
|
+
/* @__PURE__ */ jsx5("button", { onClick: () => setConfirmDelete(false), className: "text-[13px] px-3.5 py-2 rounded-lg text-slate-600 hover:bg-slate-100", children: "Cancelar" }),
|
|
1727
|
+
/* @__PURE__ */ jsx5("button", { onClick: doDeleteSelected, className: "text-[13px] font-medium bg-rose-600 hover:bg-rose-700 text-white px-4 py-2 rounded-lg", children: "Apagar" })
|
|
1728
|
+
] })
|
|
1729
|
+
] }) }),
|
|
1730
|
+
newConv && /* @__PURE__ */ jsx5("div", { className: "fixed inset-0 z-50 bg-black/50 flex items-center justify-center p-4", onClick: () => !newConv.busy && setNewConv(null), children: /* @__PURE__ */ jsxs3("div", { className: "bg-white rounded-2xl shadow-xl w-[400px] max-w-full p-5", onClick: (e) => e.stopPropagation(), children: [
|
|
1731
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between mb-3", children: [
|
|
1732
|
+
/* @__PURE__ */ jsx5("h3", { className: "font-semibold text-[15px]", children: "Nova conversa" }),
|
|
1733
|
+
/* @__PURE__ */ jsx5("button", { onClick: () => setNewConv(null), className: "text-slate-400 hover:text-slate-700 text-xl leading-none", children: "\xD7" })
|
|
1734
|
+
] }),
|
|
1735
|
+
newConv.error && /* @__PURE__ */ jsx5("div", { className: "text-[12px] text-rose-600 mb-2 break-words", children: newConv.error }),
|
|
1736
|
+
/* @__PURE__ */ jsx5("label", { className: "block text-[12px] text-slate-500 mb-1", children: "N\xFAmero (DDD + n\xFAmero; o DDI 55 \xE9 adicionado automaticamente)" }),
|
|
1737
|
+
/* @__PURE__ */ jsx5(
|
|
1738
|
+
"input",
|
|
1739
|
+
{
|
|
1740
|
+
autoFocus: true,
|
|
1741
|
+
value: newConv.phone,
|
|
1742
|
+
onChange: (e) => setNewConv((c) => ({ ...c, phone: e.target.value })),
|
|
1743
|
+
placeholder: "11 99999-9999",
|
|
1744
|
+
className: "w-full px-3 py-2 text-[14px] rounded-lg border border-slate-200 outline-none focus:border-slate-300"
|
|
1745
|
+
}
|
|
1746
|
+
),
|
|
1747
|
+
/* @__PURE__ */ jsx5("label", { className: "block text-[12px] text-slate-500 mt-3 mb-1", children: "Primeira mensagem (opcional)" }),
|
|
1748
|
+
/* @__PURE__ */ jsx5(
|
|
1749
|
+
"textarea",
|
|
1750
|
+
{
|
|
1751
|
+
rows: 3,
|
|
1752
|
+
value: newConv.text,
|
|
1753
|
+
onChange: (e) => setNewConv((c) => ({ ...c, text: e.target.value })),
|
|
1754
|
+
placeholder: "Ol\xE1! ...",
|
|
1755
|
+
className: "w-full px-3 py-2 text-[14px] rounded-lg border border-slate-200 outline-none focus:border-slate-300 resize-none"
|
|
1756
|
+
}
|
|
1757
|
+
),
|
|
1758
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex justify-end gap-2 mt-4", children: [
|
|
1759
|
+
/* @__PURE__ */ jsx5("button", { onClick: () => setNewConv(null), disabled: newConv.busy, className: "text-[13px] px-3.5 py-2 rounded-lg text-slate-600 hover:bg-slate-100", children: "Cancelar" }),
|
|
1760
|
+
/* @__PURE__ */ jsx5(
|
|
1761
|
+
"button",
|
|
1762
|
+
{
|
|
1763
|
+
onClick: submitNewConv,
|
|
1764
|
+
disabled: newConv.busy || !newConv.phone.trim(),
|
|
1765
|
+
className: "text-[13px] font-medium bg-emerald-600 hover:bg-emerald-700 disabled:opacity-50 text-white px-4 py-2 rounded-lg",
|
|
1766
|
+
children: newConv.busy ? "Iniciando\u2026" : "Iniciar"
|
|
1767
|
+
}
|
|
1768
|
+
)
|
|
1769
|
+
] })
|
|
1770
|
+
] }) }),
|
|
1771
|
+
aiSummary && /* @__PURE__ */ jsx5("div", { className: "fixed inset-0 z-50 bg-black/50 flex items-center justify-center p-4", onClick: () => setAiSummary(null), children: /* @__PURE__ */ jsxs3("div", { className: "bg-white rounded-2xl shadow-xl w-[440px] max-w-full p-5", onClick: (e) => e.stopPropagation(), children: [
|
|
1772
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between mb-3", children: [
|
|
1773
|
+
/* @__PURE__ */ jsxs3("h3", { className: "font-semibold text-[15px] inline-flex items-center gap-1.5 text-violet-700", children: [
|
|
1774
|
+
I.sparkle,
|
|
1775
|
+
" Resumo da conversa"
|
|
1776
|
+
] }),
|
|
1777
|
+
/* @__PURE__ */ jsx5("button", { onClick: () => setAiSummary(null), className: "text-slate-400 hover:text-slate-700 text-xl leading-none", children: "\xD7" })
|
|
1778
|
+
] }),
|
|
1779
|
+
aiSummary.loading && /* @__PURE__ */ jsx5("div", { className: "py-8 flex items-center justify-center text-violet-300", children: /* @__PURE__ */ jsxs3("svg", { className: "animate-spin w-6 h-6", viewBox: "0 0 24 24", fill: "none", children: [
|
|
1780
|
+
/* @__PURE__ */ jsx5("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "3", opacity: "0.25" }),
|
|
1781
|
+
/* @__PURE__ */ jsx5("path", { d: "M22 12a10 10 0 0 1-10 10", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round" })
|
|
1782
|
+
] }) }),
|
|
1783
|
+
aiSummary.error && /* @__PURE__ */ jsx5("div", { className: "text-[13px] text-rose-600", children: aiSummary.error }),
|
|
1784
|
+
aiSummary.text != null && !aiSummary.loading && /* @__PURE__ */ jsx5("div", { className: "text-[13.5px] text-slate-700 whitespace-pre-wrap leading-relaxed max-h-80 overflow-y-auto", children: aiSummary.text })
|
|
1785
|
+
] }) })
|
|
1375
1786
|
] });
|
|
1376
1787
|
}
|
|
1377
|
-
function ConversationItem({ c, active, onClick }) {
|
|
1788
|
+
function ConversationItem({ c, active, onClick, assignee }) {
|
|
1378
1789
|
return /* @__PURE__ */ jsxs3(
|
|
1379
1790
|
"button",
|
|
1380
1791
|
{
|
|
1381
1792
|
onClick,
|
|
1382
1793
|
className: `w-full text-left px-3 py-3 border-l-2 transition-colors flex gap-3 ${active ? "bg-slate-50 border-emerald-500" : "border-transparent hover:bg-slate-50"}`,
|
|
1383
1794
|
children: [
|
|
1384
|
-
/* @__PURE__ */ jsx5(Avatar, { name: c.name, color: c.avatarColor }),
|
|
1795
|
+
/* @__PURE__ */ jsx5(Avatar, { name: c.name, src: c.avatar, color: c.avatarColor }),
|
|
1385
1796
|
/* @__PURE__ */ jsxs3("div", { className: "flex-1 min-w-0", children: [
|
|
1386
1797
|
/* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between gap-2", children: [
|
|
1387
1798
|
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-1.5 min-w-0", children: [
|
|
@@ -1391,16 +1802,26 @@ function ConversationItem({ c, active, onClick }) {
|
|
|
1391
1802
|
/* @__PURE__ */ jsx5("span", { className: `text-[11px] shrink-0 ${c.unread ? "text-emerald-600 font-semibold" : "text-slate-400"}`, children: c.waitFor })
|
|
1392
1803
|
] }),
|
|
1393
1804
|
/* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between gap-2 mt-0.5", children: [
|
|
1394
|
-
/* @__PURE__ */ jsx5("p", { className: `text-[12.5px] truncate ${c.unread ? "text-slate-700" : "text-slate-500"}`, children: c.preview }),
|
|
1805
|
+
/* @__PURE__ */ jsx5("p", { className: `text-[12.5px] truncate ${c.unread ? "text-slate-700" : "text-slate-500"} ${c.preview ? "" : "italic text-slate-400"}`, children: c.preview || "Sem mensagens" }),
|
|
1395
1806
|
c.unread > 0 && /* @__PURE__ */ jsx5("span", { className: "shrink-0 min-w-[18px] h-[18px] px-1.5 rounded-full bg-emerald-500 text-white text-[10px] font-bold inline-flex items-center justify-center", children: c.unread })
|
|
1396
1807
|
] }),
|
|
1397
|
-
/* @__PURE__ */ jsx5("div", { className: "flex items-center gap-1.5 mt-1.5", children: /* @__PURE__ */ jsx5(Pill, { tone: "slate", children: c.ticket }) })
|
|
1398
|
-
] })
|
|
1808
|
+
c.ticket && /* @__PURE__ */ jsx5("div", { className: "flex items-center gap-1.5 mt-1.5", children: /* @__PURE__ */ jsx5(Pill, { tone: "slate", children: c.ticket }) })
|
|
1809
|
+
] }),
|
|
1810
|
+
assignee && /* @__PURE__ */ jsx5("span", { className: "self-center shrink-0", title: `Respons\xE1vel: ${assignee.name}`, children: /* @__PURE__ */ jsx5(Avatar, { name: assignee.name, src: assignee.avatar, size: "xs" }) })
|
|
1399
1811
|
]
|
|
1400
1812
|
}
|
|
1401
1813
|
);
|
|
1402
1814
|
}
|
|
1403
|
-
function
|
|
1815
|
+
function ConversationSkeleton() {
|
|
1816
|
+
return /* @__PURE__ */ jsxs3("div", { className: "px-3 py-3 flex gap-3 items-center", children: [
|
|
1817
|
+
/* @__PURE__ */ jsx5("div", { className: "w-9 h-9 rounded-full bg-slate-200 animate-pulse shrink-0" }),
|
|
1818
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex-1 min-w-0 space-y-2", children: [
|
|
1819
|
+
/* @__PURE__ */ jsx5("div", { className: "h-3 w-1/3 rounded bg-slate-200 animate-pulse" }),
|
|
1820
|
+
/* @__PURE__ */ jsx5("div", { className: "h-2.5 w-2/3 rounded bg-slate-100 animate-pulse" })
|
|
1821
|
+
] })
|
|
1822
|
+
] });
|
|
1823
|
+
}
|
|
1824
|
+
function ChatHeader({ c, onToggleDetails, detailsOpen, onOpenSearch, onTransfer, typing, onSummarize }) {
|
|
1404
1825
|
const [menuOpen, setMenuOpen] = useState4(false);
|
|
1405
1826
|
const menuRef = useRef3(null);
|
|
1406
1827
|
useEffect4(() => {
|
|
@@ -1412,40 +1833,25 @@ function ChatHeader({ c, onToggleDetails, detailsOpen, onOpenSearch, onTransfer
|
|
|
1412
1833
|
return () => document.removeEventListener("mousedown", onDoc);
|
|
1413
1834
|
}, [menuOpen]);
|
|
1414
1835
|
return /* @__PURE__ */ jsxs3("header", { className: "bg-white border-b border-slate-200 px-5 py-3 flex items-center gap-3 min-w-0", children: [
|
|
1415
|
-
/* @__PURE__ */ jsx5(Avatar, { name: c.name, color: c.avatarColor, size: "lg"
|
|
1836
|
+
/* @__PURE__ */ jsx5(Avatar, { name: c.name, src: c.avatar, color: c.avatarColor, size: "lg" }),
|
|
1416
1837
|
/* @__PURE__ */ jsxs3("div", { className: "flex-1 min-w-0", children: [
|
|
1417
1838
|
/* @__PURE__ */ jsx5("div", { className: "flex items-center gap-2 min-w-0", children: /* @__PURE__ */ jsx5("h2", { className: "font-semibold text-[15px] truncate", children: c.name }) }),
|
|
1418
|
-
/* @__PURE__ */
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
] }),
|
|
1424
|
-
/* @__PURE__ */ jsx5("span", { className: "hidden lg:inline text-slate-300 shrink-0", children: "\xB7" }),
|
|
1425
|
-
/* @__PURE__ */ jsxs3("span", { className: "hidden lg:inline-flex items-center gap-1 shrink-0", children: [
|
|
1426
|
-
I.tag,
|
|
1427
|
-
" ",
|
|
1428
|
-
c.ticket
|
|
1429
|
-
] })
|
|
1430
|
-
] })
|
|
1431
|
-
] }),
|
|
1432
|
-
/* @__PURE__ */ jsxs3("div", { className: "hidden 2xl:flex items-center gap-4 text-[12px] pr-3 border-r border-slate-200 shrink-0", children: [
|
|
1433
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-end leading-tight", children: [
|
|
1434
|
-
/* @__PURE__ */ jsx5("span", { className: "text-[9.5px] uppercase tracking-wide text-slate-400", children: "SLA" }),
|
|
1435
|
-
/* @__PURE__ */ jsx5("span", { className: "font-semibold text-amber-600 tabular-nums", children: "02:14" })
|
|
1436
|
-
] }),
|
|
1437
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-end leading-tight", children: [
|
|
1438
|
-
/* @__PURE__ */ jsx5("span", { className: "text-[9.5px] uppercase tracking-wide text-slate-400", children: "1\xAA resposta" }),
|
|
1439
|
-
/* @__PURE__ */ jsx5("span", { className: "font-semibold text-emerald-600 tabular-nums", children: "00:48" })
|
|
1440
|
-
] })
|
|
1441
|
-
] }),
|
|
1442
|
-
/* @__PURE__ */ jsxs3("button", { className: "shrink-0 text-[12.5px] font-medium bg-emerald-600 hover:bg-emerald-700 text-white px-3 py-1.5 rounded-lg inline-flex items-center gap-1.5", children: [
|
|
1443
|
-
I.check,
|
|
1444
|
-
" ",
|
|
1445
|
-
/* @__PURE__ */ jsx5("span", { className: "hidden lg:inline", children: "Resolver" })
|
|
1839
|
+
/* @__PURE__ */ jsx5("div", { className: "flex items-center gap-2 text-[12px] mt-0.5 min-w-0", children: typing ? /* @__PURE__ */ jsx5("span", { className: "text-emerald-600 font-medium", children: "digitando\u2026" }) : c.phone ? /* @__PURE__ */ jsxs3("span", { className: "inline-flex items-center gap-1 shrink-0 text-slate-500", children: [
|
|
1840
|
+
I.phone,
|
|
1841
|
+
" ",
|
|
1842
|
+
c.phone
|
|
1843
|
+
] }) : null })
|
|
1446
1844
|
] }),
|
|
1447
|
-
/* @__PURE__ */ jsx5("div", { className: "w-px h-6 bg-slate-200 shrink-0" }),
|
|
1448
1845
|
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-0.5 shrink-0", children: [
|
|
1846
|
+
onSummarize && /* @__PURE__ */ jsx5(
|
|
1847
|
+
"button",
|
|
1848
|
+
{
|
|
1849
|
+
onClick: onSummarize,
|
|
1850
|
+
title: "Resumo IA da conversa",
|
|
1851
|
+
className: "p-1.5 rounded-md text-violet-500 hover:bg-violet-50",
|
|
1852
|
+
children: I.sparkle
|
|
1853
|
+
}
|
|
1854
|
+
),
|
|
1449
1855
|
/* @__PURE__ */ jsx5(
|
|
1450
1856
|
"button",
|
|
1451
1857
|
{
|
|
@@ -1466,22 +1872,14 @@ function ChatHeader({ c, onToggleDetails, detailsOpen, onOpenSearch, onTransfer
|
|
|
1466
1872
|
}
|
|
1467
1873
|
),
|
|
1468
1874
|
menuOpen && /* @__PURE__ */ jsxs3("div", { className: "absolute right-0 top-[calc(100%+6px)] z-20 w-56 bg-white border border-slate-200 rounded-xl shadow-lg py-1.5 text-[13px]", children: [
|
|
1469
|
-
/* @__PURE__ */ jsx5(MenuItem, { icon: I.phone, label: "Ligar", onClick: () => setMenuOpen(false) }),
|
|
1470
1875
|
/* @__PURE__ */ jsx5(MenuItem, { icon: I.forward, label: "Transferir", onClick: () => {
|
|
1471
1876
|
setMenuOpen(false);
|
|
1472
1877
|
onTransfer == null ? void 0 : onTransfer();
|
|
1473
1878
|
} }),
|
|
1474
|
-
/* @__PURE__ */ jsx5(MenuItem, { icon: I.userPlus, label: "Adicionar participantes", onClick: () => setMenuOpen(false) }),
|
|
1475
|
-
/* @__PURE__ */ jsx5("div", { className: "my-1 h-px bg-slate-100" }),
|
|
1476
1879
|
/* @__PURE__ */ jsx5(MenuItem, { icon: I.search, label: "Procurar na conversa", onClick: () => {
|
|
1477
1880
|
setMenuOpen(false);
|
|
1478
1881
|
onOpenSearch == null ? void 0 : onOpenSearch();
|
|
1479
|
-
} })
|
|
1480
|
-
/* @__PURE__ */ jsx5(MenuItem, { icon: I.star, label: "Marcar com estrela", onClick: () => setMenuOpen(false) }),
|
|
1481
|
-
/* @__PURE__ */ jsx5(MenuItem, { icon: I.tag, label: "Editar tags", onClick: () => setMenuOpen(false) }),
|
|
1482
|
-
/* @__PURE__ */ jsx5(MenuItem, { icon: I.link, label: "Copiar link da conversa", onClick: () => setMenuOpen(false) }),
|
|
1483
|
-
/* @__PURE__ */ jsx5("div", { className: "my-1 h-px bg-slate-100" }),
|
|
1484
|
-
/* @__PURE__ */ jsx5(MenuItem, { icon: I.x, label: "Encerrar sem resolver", tone: "danger", onClick: () => setMenuOpen(false) })
|
|
1882
|
+
} })
|
|
1485
1883
|
] })
|
|
1486
1884
|
] })
|
|
1487
1885
|
] })
|
|
@@ -1589,13 +1987,31 @@ function highlightText(text, query, isCurrent) {
|
|
|
1589
1987
|
function DayDivider({ label }) {
|
|
1590
1988
|
return /* @__PURE__ */ jsx5("div", { className: "flex items-center justify-center my-3", children: /* @__PURE__ */ jsx5("span", { className: "text-[11px] font-medium text-slate-600 bg-white border border-slate-200 rounded-full px-2.5 py-0.5 shadow-soft", children: label }) });
|
|
1591
1989
|
}
|
|
1990
|
+
function EmptyConversation() {
|
|
1991
|
+
return /* @__PURE__ */ jsxs3("div", { className: "flex-1 flex flex-col items-center justify-center text-center px-8 select-none", children: [
|
|
1992
|
+
/* @__PURE__ */ jsx5("div", { className: "w-20 h-20 rounded-full bg-slate-100 flex items-center justify-center text-slate-300 mb-5", children: /* @__PURE__ */ jsx5(
|
|
1993
|
+
Icon,
|
|
1994
|
+
{
|
|
1995
|
+
d: /* @__PURE__ */ jsx5("path", { d: "M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5Z" }),
|
|
1996
|
+
className: "w-9 h-9"
|
|
1997
|
+
}
|
|
1998
|
+
) }),
|
|
1999
|
+
/* @__PURE__ */ jsx5("h3", { className: "text-[15px] font-semibold text-slate-700", children: "Nenhuma conversa aberta" }),
|
|
2000
|
+
/* @__PURE__ */ jsx5("p", { className: "text-[13px] text-slate-400 mt-1 max-w-xs leading-relaxed", children: "Selecione uma conversa na lista ao lado para ver as mensagens e responder." })
|
|
2001
|
+
] });
|
|
2002
|
+
}
|
|
1592
2003
|
function Ticks({ status }) {
|
|
1593
|
-
if (status === "
|
|
1594
|
-
|
|
1595
|
-
|
|
2004
|
+
if (status === "pending" || !status) return /* @__PURE__ */ jsxs3("svg", { className: "inline w-3 h-3 opacity-70", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2005
|
+
/* @__PURE__ */ jsx5("circle", { cx: "12", cy: "12", r: "9" }),
|
|
2006
|
+
/* @__PURE__ */ jsx5("path", { d: "M12 7.5V12l3 1.5" })
|
|
2007
|
+
] });
|
|
2008
|
+
if (status === "failed") return /* @__PURE__ */ jsx5("span", { className: "text-rose-200 font-bold", title: "Falha ao enviar", children: "!" });
|
|
2009
|
+
if (status === "sent") return /* @__PURE__ */ jsx5("span", { className: "text-emerald-100/80", children: "\u2713" });
|
|
2010
|
+
if (status === "delivered") return /* @__PURE__ */ jsx5("span", { className: "text-emerald-100/80", style: { letterSpacing: "-0.18em" }, children: "\u2713\u2713" });
|
|
2011
|
+
if (status === "read") return /* @__PURE__ */ jsx5("span", { className: "text-sky-300", style: { letterSpacing: "-0.18em" }, children: "\u2713\u2713" });
|
|
1596
2012
|
return null;
|
|
1597
2013
|
}
|
|
1598
|
-
function Message({ m, searchQuery = "", isCurrentMatch = false }) {
|
|
2014
|
+
function Message({ m, searchQuery = "", isCurrentMatch = false, isGroup, selectable, selectMode, selected, onEnterSelect, onToggleSelect }) {
|
|
1599
2015
|
if (m.side === "system") {
|
|
1600
2016
|
return /* @__PURE__ */ jsx5("div", { className: "flex justify-center my-2", children: /* @__PURE__ */ jsxs3("span", { className: "text-[11px] text-slate-500 bg-slate-100 rounded-full px-2.5 py-0.5", children: [
|
|
1601
2017
|
m.text,
|
|
@@ -1617,58 +2033,73 @@ function Message({ m, searchQuery = "", isCurrentMatch = false }) {
|
|
|
1617
2033
|
] }) });
|
|
1618
2034
|
}
|
|
1619
2035
|
const isOut = m.side === "out";
|
|
1620
|
-
return /* @__PURE__ */ jsxs3(
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
2036
|
+
return /* @__PURE__ */ jsxs3(
|
|
2037
|
+
"div",
|
|
2038
|
+
{
|
|
2039
|
+
className: `flex items-center gap-2 group ${selectMode ? "cursor-pointer -mx-2 px-2 py-0.5 rounded-lg" : ""} ${selected ? "bg-emerald-50" : ""}`,
|
|
2040
|
+
onClick: selectMode ? onToggleSelect : void 0,
|
|
2041
|
+
children: [
|
|
2042
|
+
selectMode && /* @__PURE__ */ jsx5("span", { className: `shrink-0 w-5 h-5 rounded-full border-2 flex items-center justify-center ${selected ? "bg-emerald-500 border-emerald-500 text-white" : "border-slate-300 bg-white"}`, children: selected && /* @__PURE__ */ jsx5("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx5("polyline", { points: "20 6 9 17 4 12" }) }) }),
|
|
2043
|
+
/* @__PURE__ */ jsxs3("div", { className: `flex-1 min-w-0 flex ${isOut ? "justify-end" : "justify-start"} items-center`, children: [
|
|
2044
|
+
/* @__PURE__ */ jsx5("div", { className: "max-w-[70%]", children: /* @__PURE__ */ jsxs3("div", { className: `relative px-3.5 py-2.5 rounded-2xl shadow-soft ${isOut ? "bg-emerald-600 text-white rounded-tr-sm" : "bg-white border border-slate-200 text-slate-800 rounded-tl-sm"} ${isCurrentMatch ? "ring-2 ring-amber-400" : ""}`, children: [
|
|
2045
|
+
!isOut && isGroup && m.author && /* @__PURE__ */ jsx5("div", { className: "text-[11.5px] font-semibold text-emerald-700 mb-0.5", children: m.author }),
|
|
2046
|
+
m.kind === "text" && /* @__PURE__ */ jsx5("p", { className: "text-[13.5px] leading-relaxed whitespace-pre-wrap", children: highlightText(m.text, searchQuery, isCurrentMatch) }),
|
|
2047
|
+
m.kind === "image" && /* @__PURE__ */ jsxs3("div", { className: "-mx-1 -mt-1", children: [
|
|
2048
|
+
m.mediaUrl ? /* @__PURE__ */ jsx5("a", { href: m.mediaUrl, target: "_blank", rel: "noreferrer", children: /* @__PURE__ */ jsx5("img", { src: m.mediaUrl, alt: m.caption || "imagem", className: "w-64 max-h-72 object-cover rounded-lg" }) }) : /* @__PURE__ */ jsx5("div", { className: "w-64 h-40 rounded-lg bg-gradient-to-br from-slate-200 to-slate-300 flex items-center justify-center text-slate-500", children: I.image }),
|
|
2049
|
+
m.caption && /* @__PURE__ */ jsx5("p", { className: "text-[13px] mt-2", children: highlightText(m.caption, searchQuery, isCurrentMatch) })
|
|
2050
|
+
] }),
|
|
2051
|
+
m.kind === "video" && /* @__PURE__ */ jsxs3("div", { className: "-mx-1 -mt-1", children: [
|
|
2052
|
+
m.mediaUrl ? /* @__PURE__ */ jsx5("video", { src: m.mediaUrl, controls: true, className: "w-64 rounded-lg" }) : /* @__PURE__ */ jsx5("div", { className: "w-64 h-40 rounded-lg bg-slate-200 flex items-center justify-center text-slate-500", children: "\u{1F3A5}" }),
|
|
2053
|
+
m.caption && /* @__PURE__ */ jsx5("p", { className: "text-[13px] mt-2", children: highlightText(m.caption, searchQuery, isCurrentMatch) })
|
|
2054
|
+
] }),
|
|
2055
|
+
m.kind === "document" && /* @__PURE__ */ jsxs3(
|
|
2056
|
+
"a",
|
|
2057
|
+
{
|
|
2058
|
+
href: m.mediaUrl || "#",
|
|
2059
|
+
target: "_blank",
|
|
2060
|
+
rel: "noreferrer",
|
|
2061
|
+
className: `flex items-center gap-2.5 min-w-[200px] rounded-lg px-2 py-1.5 ${isOut ? "bg-emerald-700/40" : "bg-slate-100"}`,
|
|
2062
|
+
children: [
|
|
2063
|
+
/* @__PURE__ */ jsx5("span", { className: isOut ? "text-emerald-100" : "text-slate-500", children: I.file }),
|
|
2064
|
+
/* @__PURE__ */ jsx5("span", { className: "text-[13px] truncate flex-1", children: m.filename || m.caption || "Documento" })
|
|
2065
|
+
]
|
|
2066
|
+
}
|
|
2067
|
+
),
|
|
2068
|
+
m.kind === "audio" && (m.mediaUrl ? (
|
|
2069
|
+
// player real (quando a mídia estiver armazenada — R2)
|
|
2070
|
+
/* @__PURE__ */ jsx5("audio", { src: m.mediaUrl, controls: true, className: "w-60 max-w-full" })
|
|
2071
|
+
) : (
|
|
2072
|
+
// sem mídia guardada ainda: chip honesto, sem player falso
|
|
2073
|
+
/* @__PURE__ */ jsxs3("div", { className: `flex items-center gap-2 min-w-[140px] ${isOut ? "text-emerald-50" : "text-slate-600"}`, children: [
|
|
2074
|
+
/* @__PURE__ */ jsx5("span", { className: isOut ? "text-emerald-100" : "text-slate-500", children: I.mic }),
|
|
2075
|
+
/* @__PURE__ */ jsxs3("span", { className: "text-[13px]", children: [
|
|
2076
|
+
"\xC1udio",
|
|
2077
|
+
m.caption ? ` \xB7 ${m.caption}` : ""
|
|
2078
|
+
] })
|
|
2079
|
+
] })
|
|
2080
|
+
)),
|
|
2081
|
+
/* @__PURE__ */ jsxs3("div", { className: `flex items-center gap-1 justify-end mt-1 text-[10.5px] ${isOut ? "text-emerald-100" : "text-slate-400"}`, children: [
|
|
2082
|
+
m.author && !isOut === false && /* @__PURE__ */ jsx5("span", { className: "mr-1", children: m.author }),
|
|
2083
|
+
/* @__PURE__ */ jsx5("span", { children: m.time }),
|
|
2084
|
+
isOut && /* @__PURE__ */ jsx5(Ticks, { status: m.status })
|
|
2085
|
+
] })
|
|
2086
|
+
] }) }),
|
|
2087
|
+
!selectMode && selectable && /* @__PURE__ */ jsx5(
|
|
2088
|
+
"button",
|
|
2089
|
+
{
|
|
2090
|
+
onClick: (e) => {
|
|
2091
|
+
e.stopPropagation();
|
|
2092
|
+
onEnterSelect();
|
|
2093
|
+
},
|
|
2094
|
+
title: "Selecionar mensagem",
|
|
2095
|
+
className: "opacity-0 group-hover:opacity-100 transition-opacity self-center mx-1 p-1 rounded-md text-slate-400 hover:text-slate-700 hover:bg-slate-100 shrink-0",
|
|
2096
|
+
children: I.check
|
|
2097
|
+
}
|
|
2098
|
+
)
|
|
1658
2099
|
] })
|
|
1659
|
-
]
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
/* @__PURE__ */ jsx5(HoverBtn, { icon: I.forward }),
|
|
1663
|
-
/* @__PURE__ */ jsx5(HoverBtn, { icon: I.emoji }),
|
|
1664
|
-
/* @__PURE__ */ jsx5(HoverBtn, { icon: I.more })
|
|
1665
|
-
] })
|
|
1666
|
-
] }),
|
|
1667
|
-
isOut && /* @__PURE__ */ jsx5(Avatar, { name: m.author || "Maria Eduarda", color: m.author === "Alissa Mendes" ? "bg-sky-500" : "bg-amber-500", size: "sm" })
|
|
1668
|
-
] });
|
|
1669
|
-
}
|
|
1670
|
-
function HoverBtn({ icon }) {
|
|
1671
|
-
return /* @__PURE__ */ jsx5("button", { className: "p-1 rounded-md text-slate-400 bg-white border border-slate-200 hover:text-slate-700 shadow-soft", children: icon });
|
|
2100
|
+
]
|
|
2101
|
+
}
|
|
2102
|
+
);
|
|
1672
2103
|
}
|
|
1673
2104
|
function fmtSecs(s) {
|
|
1674
2105
|
const m = Math.floor(s / 60);
|
|
@@ -1773,354 +2204,27 @@ function DetailsPanel({ c, onClose }) {
|
|
|
1773
2204
|
] })
|
|
1774
2205
|
] });
|
|
1775
2206
|
}
|
|
1776
|
-
function Section({ title, action, children, defaultOpen = true }) {
|
|
1777
|
-
const [open, setOpen] = useState4(defaultOpen);
|
|
1778
|
-
return /* @__PURE__ */ jsxs3("div", { className: "border-b border-slate-100", children: [
|
|
1779
|
-
/* @__PURE__ */ jsxs3("button", { onClick: () => setOpen((v) => !v), className: "w-full px-4 pt-4 pb-2 flex items-center justify-between", children: [
|
|
1780
|
-
/* @__PURE__ */ jsx5("span", { className: "text-[11px] font-semibold uppercase tracking-wider text-slate-500", children: title }),
|
|
1781
|
-
/* @__PURE__ */ jsx5("span", { className: `text-slate-400 transition-transform ${open ? "" : "-rotate-90"}`, children: I.chevDown })
|
|
1782
|
-
] }),
|
|
1783
|
-
open && /* @__PURE__ */ jsxs3("div", { className: "px-4 pb-4 space-y-2.5", children: [
|
|
1784
|
-
children,
|
|
1785
|
-
action
|
|
1786
|
-
] })
|
|
1787
|
-
] });
|
|
1788
|
-
}
|
|
1789
|
-
function Row({ label, children }) {
|
|
1790
|
-
return /* @__PURE__ */ jsxs3("div", { className: "flex items-start gap-3 text-[12.5px]", children: [
|
|
1791
|
-
/* @__PURE__ */ jsx5("span", { className: "w-28 shrink-0 text-slate-500 pt-0.5", children: label }),
|
|
1792
|
-
/* @__PURE__ */ jsx5("div", { className: "flex-1 min-w-0 text-slate-800", children })
|
|
1793
|
-
] });
|
|
1794
|
-
}
|
|
1795
|
-
var PROPERTY_CATALOG = [
|
|
1796
|
-
{ id: "856235", title: "Apto 80m\xB2 \xB7 Jardins \xB7 2 dorm" },
|
|
1797
|
-
{ id: "856301", title: "Apto 65m\xB2 \xB7 Vila Mariana \xB7 2 dorm" },
|
|
1798
|
-
{ id: "857188", title: "Cobertura 120m\xB2 \xB7 Itaim \xB7 3 dorm" },
|
|
1799
|
-
{ id: "854902", title: "Casa 180m\xB2 \xB7 Alto de Pinheiros \xB7 4 dorm" },
|
|
1800
|
-
{ id: "855417", title: "Studio 35m\xB2 \xB7 Pinheiros \xB7 1 dorm" },
|
|
1801
|
-
{ id: "858033", title: "Apto 95m\xB2 \xB7 Moema \xB7 3 dorm" },
|
|
1802
|
-
{ id: "858720", title: "Apto 110m\xB2 \xB7 Perdizes \xB7 3 dorm" }
|
|
1803
|
-
];
|
|
1804
|
-
function PropertyLinker() {
|
|
1805
|
-
const [linked, setLinked] = useState4([PROPERTY_CATALOG[0], PROPERTY_CATALOG[5]]);
|
|
1806
|
-
const [query, setQuery] = useState4("");
|
|
1807
|
-
const [adding, setAdding] = useState4(false);
|
|
1808
|
-
const inputRef = useRef3(null);
|
|
1809
|
-
const wrapRef = useRef3(null);
|
|
1810
|
-
useEffect4(() => {
|
|
1811
|
-
var _a;
|
|
1812
|
-
if (adding) (_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
1813
|
-
}, [adding]);
|
|
1814
|
-
useEffect4(() => {
|
|
1815
|
-
if (!adding) return;
|
|
1816
|
-
const onDoc = (e) => {
|
|
1817
|
-
if (wrapRef.current && !wrapRef.current.contains(e.target)) closeAdd();
|
|
1818
|
-
};
|
|
1819
|
-
document.addEventListener("mousedown", onDoc);
|
|
1820
|
-
return () => document.removeEventListener("mousedown", onDoc);
|
|
1821
|
-
}, [adding]);
|
|
1822
|
-
const suggestions = useMemo2(() => {
|
|
1823
|
-
const q = query.trim().toLowerCase();
|
|
1824
|
-
const linkedIds = new Set(linked.map((p) => p.id));
|
|
1825
|
-
return PROPERTY_CATALOG.filter(
|
|
1826
|
-
(p) => !linkedIds.has(p.id) && (q === "" || p.id.toLowerCase().includes(q) || p.title.toLowerCase().includes(q))
|
|
1827
|
-
).slice(0, 5);
|
|
1828
|
-
}, [query, linked]);
|
|
1829
|
-
const closeAdd = () => {
|
|
1830
|
-
setAdding(false);
|
|
1831
|
-
setQuery("");
|
|
1832
|
-
};
|
|
1833
|
-
const addProperty = (p) => {
|
|
1834
|
-
setLinked((l) => [...l, p]);
|
|
1835
|
-
closeAdd();
|
|
1836
|
-
};
|
|
1837
|
-
const removeProperty = (id) => setLinked((l) => l.filter((p) => p.id !== id));
|
|
1838
|
-
return /* @__PURE__ */ jsxs3("div", { ref: wrapRef, className: "w-full", children: [
|
|
1839
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1", children: [
|
|
1840
|
-
linked.map((p) => /* @__PURE__ */ jsxs3("div", { className: "group inline-flex items-center gap-0.5 text-[13px] leading-tight", children: [
|
|
1841
|
-
/* @__PURE__ */ jsxs3(
|
|
1842
|
-
"a",
|
|
1843
|
-
{
|
|
1844
|
-
href: "#",
|
|
1845
|
-
title: p.title,
|
|
1846
|
-
className: "text-slate-700 underline underline-offset-2 hover:text-emerald-700 inline-flex items-center gap-1 tabular-nums",
|
|
1847
|
-
children: [
|
|
1848
|
-
p.id,
|
|
1849
|
-
/* @__PURE__ */ jsx5("span", { className: "text-slate-400 group-hover:text-emerald-600", children: I.external })
|
|
1850
|
-
]
|
|
1851
|
-
}
|
|
1852
|
-
),
|
|
1853
|
-
/* @__PURE__ */ jsx5(
|
|
1854
|
-
"button",
|
|
1855
|
-
{
|
|
1856
|
-
onClick: () => removeProperty(p.id),
|
|
1857
|
-
title: "Desvincular",
|
|
1858
|
-
className: "opacity-0 group-hover:opacity-100 p-0.5 text-slate-400 hover:text-rose-500 transition-opacity",
|
|
1859
|
-
children: /* @__PURE__ */ jsxs3("svg", { width: "11", height: "11", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: "2.5", fill: "none", strokeLinecap: "round", children: [
|
|
1860
|
-
/* @__PURE__ */ jsx5("line", { x1: "6", y1: "6", x2: "18", y2: "18" }),
|
|
1861
|
-
/* @__PURE__ */ jsx5("line", { x1: "6", y1: "18", x2: "18", y2: "6" })
|
|
1862
|
-
] })
|
|
1863
|
-
}
|
|
1864
|
-
)
|
|
1865
|
-
] }, p.id)),
|
|
1866
|
-
!adding && /* @__PURE__ */ jsx5(
|
|
1867
|
-
"button",
|
|
1868
|
-
{
|
|
1869
|
-
onClick: () => setAdding(true),
|
|
1870
|
-
title: "Vincular im\xF3vel",
|
|
1871
|
-
className: "text-[11px] text-slate-500 hover:text-slate-800 inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded-full border border-dashed border-slate-300 hover:border-slate-400 hover:bg-slate-50",
|
|
1872
|
-
children: "+ im\xF3vel"
|
|
1873
|
-
}
|
|
1874
|
-
)
|
|
1875
|
-
] }),
|
|
1876
|
-
adding && /* @__PURE__ */ jsxs3("div", { className: "relative mt-2", children: [
|
|
1877
|
-
/* @__PURE__ */ jsx5("span", { className: "absolute left-2 top-1/2 -translate-y-1/2 text-slate-400 pointer-events-none", children: I.search }),
|
|
1878
|
-
/* @__PURE__ */ jsx5(
|
|
1879
|
-
"input",
|
|
1880
|
-
{
|
|
1881
|
-
ref: inputRef,
|
|
1882
|
-
value: query,
|
|
1883
|
-
onChange: (e) => setQuery(e.target.value),
|
|
1884
|
-
onKeyDown: (e) => {
|
|
1885
|
-
if (e.key === "Escape") closeAdd();
|
|
1886
|
-
},
|
|
1887
|
-
placeholder: "C\xF3digo ou bairro\u2026",
|
|
1888
|
-
className: "w-full pl-7 pr-2 py-1.5 text-[12px] rounded-lg bg-white border border-slate-300 outline-none focus:border-slate-400 placeholder:text-slate-400"
|
|
1889
|
-
}
|
|
1890
|
-
),
|
|
1891
|
-
suggestions.length > 0 && /* @__PURE__ */ jsx5("div", { className: "absolute top-full left-0 right-0 mt-1 z-30 bg-white border border-slate-200 rounded-lg shadow-lg overflow-hidden", children: suggestions.map((p) => /* @__PURE__ */ jsxs3(
|
|
1892
|
-
"button",
|
|
1893
|
-
{
|
|
1894
|
-
onClick: () => addProperty(p),
|
|
1895
|
-
className: "w-full text-left px-2.5 py-1.5 hover:bg-slate-50 flex items-center gap-2 border-b border-slate-100 last:border-b-0",
|
|
1896
|
-
children: [
|
|
1897
|
-
/* @__PURE__ */ jsx5("span", { className: "text-[12.5px] font-mono font-semibold text-slate-700 tabular-nums", children: p.id }),
|
|
1898
|
-
/* @__PURE__ */ jsx5("span", { className: "text-slate-300", children: "\xB7" }),
|
|
1899
|
-
/* @__PURE__ */ jsx5("span", { className: "text-[11.5px] text-slate-500 truncate flex-1 min-w-0", children: p.title }),
|
|
1900
|
-
/* @__PURE__ */ jsx5("span", { className: "text-slate-300 shrink-0", children: I.plus })
|
|
1901
|
-
]
|
|
1902
|
-
},
|
|
1903
|
-
p.id
|
|
1904
|
-
)) }),
|
|
1905
|
-
query.trim() && suggestions.length === 0 && /* @__PURE__ */ jsxs3("div", { className: "absolute top-full left-0 right-0 mt-1 z-30 bg-white border border-slate-200 rounded-lg shadow-lg px-3 py-2 text-[12px] text-slate-500", children: [
|
|
1906
|
-
'Nenhum im\xF3vel encontrado para "',
|
|
1907
|
-
query.trim(),
|
|
1908
|
-
'".'
|
|
1909
|
-
] })
|
|
1910
|
-
] })
|
|
1911
|
-
] });
|
|
1912
|
-
}
|
|
1913
|
-
function ActionRow({ icon, label, children, onClick }) {
|
|
1914
|
-
const [open, setOpen] = useState4(false);
|
|
1915
|
-
const hasSubmenu = !!children;
|
|
1916
|
-
const handle = () => hasSubmenu ? setOpen((v) => !v) : onClick == null ? void 0 : onClick();
|
|
1917
|
-
return /* @__PURE__ */ jsxs3("div", { children: [
|
|
1918
|
-
/* @__PURE__ */ jsxs3(
|
|
1919
|
-
"button",
|
|
1920
|
-
{
|
|
1921
|
-
onClick: handle,
|
|
1922
|
-
className: "w-full flex items-center gap-2 text-[13px] text-slate-700 hover:bg-slate-50 -mx-1 px-1 py-1 rounded-md",
|
|
1923
|
-
children: [
|
|
1924
|
-
/* @__PURE__ */ jsx5("span", { className: "text-slate-500", children: icon }),
|
|
1925
|
-
/* @__PURE__ */ jsx5("span", { className: "flex-1 text-left", children: label }),
|
|
1926
|
-
/* @__PURE__ */ jsx5("span", { className: `text-slate-400 transition-transform ${hasSubmenu && open ? "rotate-90" : ""}`, children: hasSubmenu ? I.chevRight : I.plus })
|
|
1927
|
-
]
|
|
1928
|
-
}
|
|
1929
|
-
),
|
|
1930
|
-
hasSubmenu && open && /* @__PURE__ */ jsx5("div", { className: "ml-7 mt-0.5 mb-1 border-l border-slate-200 pl-3 space-y-0.5", children })
|
|
1931
|
-
] });
|
|
1932
|
-
}
|
|
1933
|
-
function SubAction({ label, onClick }) {
|
|
1934
|
-
return /* @__PURE__ */ jsx5(
|
|
1935
|
-
"button",
|
|
1936
|
-
{
|
|
1937
|
-
onClick,
|
|
1938
|
-
className: "w-full text-left text-[12.5px] text-slate-600 hover:text-slate-900 hover:bg-slate-50 -mx-1 px-1.5 py-1 rounded-md",
|
|
1939
|
-
children: label
|
|
1940
|
-
}
|
|
1941
|
-
);
|
|
1942
|
-
}
|
|
1943
2207
|
function DetailsTab({ c }) {
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
{ label: "Zona Sul", tone: "emerald" },
|
|
1950
|
-
{ label: "At\xE9 R$ 900k", tone: "amber" }
|
|
1951
|
-
]);
|
|
1952
|
-
const [expanded, setExpanded] = useState4(false);
|
|
1953
|
-
const [adding, setAdding] = useState4(false);
|
|
1954
|
-
const [newTag, setNewTag] = useState4("");
|
|
1955
|
-
const tagInputRef = useRef3(null);
|
|
1956
|
-
useEffect4(() => {
|
|
1957
|
-
var _a;
|
|
1958
|
-
if (adding) (_a = tagInputRef.current) == null ? void 0 : _a.focus();
|
|
1959
|
-
}, [adding]);
|
|
1960
|
-
const VISIBLE = 3;
|
|
1961
|
-
const shownTags = expanded ? tags : tags.slice(0, VISIBLE);
|
|
1962
|
-
const hiddenCount = Math.max(0, tags.length - VISIBLE);
|
|
1963
|
-
const addTag = () => {
|
|
1964
|
-
const v = newTag.trim();
|
|
1965
|
-
if (v) setTags((t) => [...t, { label: v, tone: palette[t.length % palette.length] }]);
|
|
1966
|
-
setNewTag("");
|
|
1967
|
-
setAdding(false);
|
|
1968
|
-
};
|
|
1969
|
-
const removeTag = (i) => setTags((t) => t.filter((_, idx) => idx !== i));
|
|
1970
|
-
return /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
1971
|
-
/* @__PURE__ */ jsxs3("div", { className: "px-4 pt-4 pb-3 flex items-start gap-3", children: [
|
|
1972
|
-
/* @__PURE__ */ jsx5(Avatar, { name: c.name, color: c.avatarColor, size: "xl", online: true }),
|
|
1973
|
-
/* @__PURE__ */ jsxs3("div", { className: "min-w-0 flex-1", children: [
|
|
1974
|
-
/* @__PURE__ */ jsx5("div", { className: "font-semibold truncate", children: c.name }),
|
|
1975
|
-
/* @__PURE__ */ jsx5("div", { className: "text-[12px] text-slate-500 truncate", children: c.phone }),
|
|
1976
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex flex-wrap gap-1 mt-1.5", children: [
|
|
1977
|
-
shownTags.map((t, i) => /* @__PURE__ */ jsxs3(Pill, { tone: t.tone, children: [
|
|
1978
|
-
t.label,
|
|
1979
|
-
/* @__PURE__ */ jsx5(
|
|
1980
|
-
"button",
|
|
1981
|
-
{
|
|
1982
|
-
onClick: () => removeTag(i),
|
|
1983
|
-
title: "Remover",
|
|
1984
|
-
className: "ml-0.5 -mr-0.5 opacity-60 hover:opacity-100",
|
|
1985
|
-
children: /* @__PURE__ */ jsxs3("svg", { width: "10", height: "10", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: "3", fill: "none", strokeLinecap: "round", children: [
|
|
1986
|
-
/* @__PURE__ */ jsx5("line", { x1: "6", y1: "6", x2: "18", y2: "18" }),
|
|
1987
|
-
/* @__PURE__ */ jsx5("line", { x1: "6", y1: "18", x2: "18", y2: "6" })
|
|
1988
|
-
] })
|
|
1989
|
-
}
|
|
1990
|
-
)
|
|
1991
|
-
] }, `${t.label}-${i}`)),
|
|
1992
|
-
!expanded && hiddenCount > 0 && /* @__PURE__ */ jsxs3(
|
|
1993
|
-
"button",
|
|
1994
|
-
{
|
|
1995
|
-
onClick: () => setExpanded(true),
|
|
1996
|
-
className: "text-[11px] text-slate-500 hover:text-slate-800 px-1.5 py-0.5 rounded-full hover:bg-slate-100 self-center",
|
|
1997
|
-
children: [
|
|
1998
|
-
"+",
|
|
1999
|
-
hiddenCount
|
|
2000
|
-
]
|
|
2001
|
-
}
|
|
2002
|
-
),
|
|
2003
|
-
expanded && tags.length > VISIBLE && /* @__PURE__ */ jsx5(
|
|
2004
|
-
"button",
|
|
2005
|
-
{
|
|
2006
|
-
onClick: () => setExpanded(false),
|
|
2007
|
-
className: "text-[11px] text-slate-500 hover:text-slate-800 px-1.5 py-0.5 rounded-full hover:bg-slate-100 self-center",
|
|
2008
|
-
children: "mostrar menos"
|
|
2009
|
-
}
|
|
2010
|
-
),
|
|
2011
|
-
adding ? /* @__PURE__ */ jsx5(
|
|
2012
|
-
"input",
|
|
2013
|
-
{
|
|
2014
|
-
ref: tagInputRef,
|
|
2015
|
-
value: newTag,
|
|
2016
|
-
onChange: (e) => setNewTag(e.target.value),
|
|
2017
|
-
onBlur: addTag,
|
|
2018
|
-
onKeyDown: (e) => {
|
|
2019
|
-
if (e.key === "Enter") {
|
|
2020
|
-
e.preventDefault();
|
|
2021
|
-
addTag();
|
|
2022
|
-
}
|
|
2023
|
-
if (e.key === "Escape") {
|
|
2024
|
-
setNewTag("");
|
|
2025
|
-
setAdding(false);
|
|
2026
|
-
}
|
|
2027
|
-
},
|
|
2028
|
-
placeholder: "nova tag\u2026",
|
|
2029
|
-
className: "text-[11px] px-2 py-0.5 rounded-full bg-white border border-slate-300 outline-none focus:border-slate-500 w-24"
|
|
2030
|
-
}
|
|
2031
|
-
) : /* @__PURE__ */ jsx5(
|
|
2032
|
-
"button",
|
|
2033
|
-
{
|
|
2034
|
-
onClick: () => {
|
|
2035
|
-
setExpanded(true);
|
|
2036
|
-
setAdding(true);
|
|
2037
|
-
},
|
|
2038
|
-
title: "Adicionar tag",
|
|
2039
|
-
className: "text-[11px] text-slate-500 hover:text-slate-800 inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded-full border border-dashed border-slate-300 hover:border-slate-400 hover:bg-slate-50",
|
|
2040
|
-
children: "+ tag"
|
|
2041
|
-
}
|
|
2042
|
-
)
|
|
2043
|
-
] })
|
|
2044
|
-
] })
|
|
2045
|
-
] }),
|
|
2046
|
-
/* @__PURE__ */ jsxs3(Section, { title: "Atribui\xE7\xE3o", children: [
|
|
2047
|
-
/* @__PURE__ */ jsx5(Row, { label: "Atendente", children: /* @__PURE__ */ jsxs3("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
2048
|
-
/* @__PURE__ */ jsx5(Avatar, { name: "Maria Eduarda", size: "sm", color: "bg-amber-500" }),
|
|
2049
|
-
" Maria Eduarda"
|
|
2050
|
-
] }) }),
|
|
2051
|
-
/* @__PURE__ */ jsx5(Row, { label: "Departamento", children: /* @__PURE__ */ jsxs3("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
2052
|
-
/* @__PURE__ */ jsx5("span", { className: "w-5 h-5 rounded-md bg-rose-500 text-white text-[10px] flex items-center justify-center font-bold", children: "CO" }),
|
|
2053
|
-
"Comercial"
|
|
2054
|
-
] }) }),
|
|
2055
|
-
/* @__PURE__ */ jsx5(Row, { label: "Origem", children: /* @__PURE__ */ jsxs3("span", { className: "inline-flex items-center gap-1.5 text-emerald-700", children: [
|
|
2056
|
-
I.whatsapp,
|
|
2057
|
-
" WhatsApp Business"
|
|
2058
|
-
] }) })
|
|
2059
|
-
] }),
|
|
2060
|
-
/* @__PURE__ */ jsxs3(Section, { title: "Ticket", children: [
|
|
2061
|
-
/* @__PURE__ */ jsx5(Row, { label: "Tipo", children: /* @__PURE__ */ jsx5(Pill, { tone: "rose", children: "\u{1F3E0} Interesse em compra" }) }),
|
|
2062
|
-
/* @__PURE__ */ jsx5(Row, { label: "Status", children: /* @__PURE__ */ jsx5(Pill, { tone: statusInfo[c.status].tone, children: statusInfo[c.status].label }) }),
|
|
2063
|
-
/* @__PURE__ */ jsx5(Row, { label: "Prioridade", children: /* @__PURE__ */ jsx5(Pill, { tone: c.priority === "urgent" ? "rose" : c.priority === "high" ? "amber" : "slate", children: "Alta" }) }),
|
|
2064
|
-
/* @__PURE__ */ jsx5(Row, { label: "Im\xF3veis", children: /* @__PURE__ */ jsx5(PropertyLinker, {}) }),
|
|
2065
|
-
/* @__PURE__ */ jsx5(Row, { label: "Aberto", children: "h\xE1 18 min" })
|
|
2066
|
-
] }),
|
|
2067
|
-
/* @__PURE__ */ jsxs3(Section, { title: "A\xE7\xF5es", children: [
|
|
2068
|
-
/* @__PURE__ */ jsxs3(ActionRow, { icon: I.userPlus, label: "Adicionar cliente", children: [
|
|
2069
|
-
/* @__PURE__ */ jsx5(SubAction, { label: "Propriet\xE1rio" }),
|
|
2070
|
-
/* @__PURE__ */ jsx5(SubAction, { label: "Cliente" })
|
|
2071
|
-
] }),
|
|
2072
|
-
/* @__PURE__ */ jsx5(ActionRow, { icon: I.checkCircle, label: "Criar tarefa" }),
|
|
2073
|
-
/* @__PURE__ */ jsx5(ActionRow, { icon: I.calendar, label: "Agendar visita" }),
|
|
2074
|
-
/* @__PURE__ */ jsx5(ActionRow, { icon: I.file, label: "Enviar documentos" })
|
|
2208
|
+
return /* @__PURE__ */ jsx5(Fragment, { children: /* @__PURE__ */ jsxs3("div", { className: "px-4 pt-4 pb-3 flex items-start gap-3", children: [
|
|
2209
|
+
/* @__PURE__ */ jsx5(Avatar, { name: c.name, src: c.avatar, color: c.avatarColor, size: "xl" }),
|
|
2210
|
+
/* @__PURE__ */ jsxs3("div", { className: "min-w-0 flex-1", children: [
|
|
2211
|
+
/* @__PURE__ */ jsx5("div", { className: "font-semibold truncate", children: c.name }),
|
|
2212
|
+
c.phone && /* @__PURE__ */ jsx5("div", { className: "text-[12px] text-slate-500 truncate", children: c.phone })
|
|
2075
2213
|
] })
|
|
2214
|
+
] }) });
|
|
2215
|
+
}
|
|
2216
|
+
function EmptyTab({ icon, title, hint }) {
|
|
2217
|
+
return /* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-center justify-center text-center px-8 py-16 select-none", children: [
|
|
2218
|
+
/* @__PURE__ */ jsx5("div", { className: "w-12 h-12 rounded-full bg-slate-100 flex items-center justify-center text-slate-300 mb-3", children: icon }),
|
|
2219
|
+
/* @__PURE__ */ jsx5("p", { className: "text-[13px] font-medium text-slate-600", children: title }),
|
|
2220
|
+
hint && /* @__PURE__ */ jsx5("p", { className: "text-[12px] text-slate-400 mt-1 max-w-[220px]", children: hint })
|
|
2076
2221
|
] });
|
|
2077
2222
|
}
|
|
2078
2223
|
function NotesTab() {
|
|
2079
|
-
return /* @__PURE__ */
|
|
2080
|
-
/* @__PURE__ */ jsxs3("div", { className: "bg-yellow-50 border border-yellow-200 rounded-xl p-3", children: [
|
|
2081
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between mb-1.5", children: [
|
|
2082
|
-
/* @__PURE__ */ jsxs3("span", { className: "text-[11.5px] font-semibold text-yellow-800 inline-flex items-center gap-1", children: [
|
|
2083
|
-
I.pin,
|
|
2084
|
-
" Maria Eduarda"
|
|
2085
|
-
] }),
|
|
2086
|
-
/* @__PURE__ */ jsx5("span", { className: "text-[11px] text-yellow-700", children: "h\xE1 11 min" })
|
|
2087
|
-
] }),
|
|
2088
|
-
/* @__PURE__ */ jsx5("p", { className: "text-[13px] text-yellow-900", children: "Cliente Gold \u2014 perfil quente, decis\xE3o r\xE1pida. J\xE1 visitou conosco em fev/26 (ticket #7892), gostou da regi\xE3o mas o im\xF3vel estava acima do or\xE7amento." })
|
|
2089
|
-
] }),
|
|
2090
|
-
/* @__PURE__ */ jsxs3("div", { className: "bg-yellow-50 border border-yellow-200 rounded-xl p-3", children: [
|
|
2091
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between mb-1.5", children: [
|
|
2092
|
-
/* @__PURE__ */ jsxs3("span", { className: "text-[11.5px] font-semibold text-yellow-800 inline-flex items-center gap-1", children: [
|
|
2093
|
-
I.pin,
|
|
2094
|
-
" Alissa Mendes"
|
|
2095
|
-
] }),
|
|
2096
|
-
/* @__PURE__ */ jsx5("span", { className: "text-[11px] text-yellow-700", children: "h\xE1 4 min" })
|
|
2097
|
-
] }),
|
|
2098
|
-
/* @__PURE__ */ jsx5("p", { className: "text-[13px] text-yellow-900", children: "Confirmei com os propriet\xE1rios \u2014 Vila Mariana e Moema liberados pra visita amanh\xE3 das 10h \xE0s 17h." })
|
|
2099
|
-
] }),
|
|
2100
|
-
/* @__PURE__ */ jsxs3("button", { className: "w-full text-[12.5px] py-2 rounded-lg border border-dashed border-slate-300 text-slate-500 hover:bg-slate-50 inline-flex items-center justify-center gap-1", children: [
|
|
2101
|
-
I.plus,
|
|
2102
|
-
" Nova nota"
|
|
2103
|
-
] })
|
|
2104
|
-
] });
|
|
2224
|
+
return /* @__PURE__ */ jsx5(EmptyTab, { icon: I.pin, title: "Nenhuma nota ainda", hint: "Use \u201CNota interna\u201D no compositor do chat para registrar algo vis\xEDvel s\xF3 para o time." });
|
|
2105
2225
|
}
|
|
2106
2226
|
function HistoryTab() {
|
|
2107
|
-
|
|
2108
|
-
{ t: "Ticket #7892 \u2014 Visita apto Itaim", s: "Sem proposta", when: "fev/26", tone: "slate" },
|
|
2109
|
-
{ t: "Ticket #7541 \u2014 Interesse em cobertura", s: "Resolvido", when: "jan/26", tone: "emerald" },
|
|
2110
|
-
{ t: "Ticket #7233 \u2014 Pedido de matr\xEDcula", s: "Resolvido", when: "dez/25", tone: "emerald" },
|
|
2111
|
-
{ t: "Ticket #6890 \u2014 Primeira simula\xE7\xE3o", s: "Resolvido", when: "out/25", tone: "emerald" }
|
|
2112
|
-
];
|
|
2113
|
-
return /* @__PURE__ */ jsx5("div", { className: "p-4 space-y-2", children: items.map((it, i) => /* @__PURE__ */ jsxs3("button", { className: "w-full text-left bg-white border border-slate-200 hover:border-slate-300 rounded-xl p-3 flex items-start gap-3", children: [
|
|
2114
|
-
/* @__PURE__ */ jsx5("span", { className: "w-8 h-8 rounded-lg bg-slate-100 text-slate-500 flex items-center justify-center", children: I.chat }),
|
|
2115
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex-1 min-w-0", children: [
|
|
2116
|
-
/* @__PURE__ */ jsx5("p", { className: "text-[13px] font-medium truncate", children: it.t }),
|
|
2117
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 mt-1", children: [
|
|
2118
|
-
/* @__PURE__ */ jsx5(Pill, { tone: it.tone, children: it.s }),
|
|
2119
|
-
/* @__PURE__ */ jsx5("span", { className: "text-[11.5px] text-slate-500", children: it.when })
|
|
2120
|
-
] })
|
|
2121
|
-
] }),
|
|
2122
|
-
/* @__PURE__ */ jsx5("span", { className: "text-slate-400 mt-1", children: I.chevRight })
|
|
2123
|
-
] }, i)) });
|
|
2227
|
+
return /* @__PURE__ */ jsx5(EmptyTab, { icon: I.chat, title: "Sem hist\xF3rico", hint: "Atendimentos anteriores deste contato aparecer\xE3o aqui." });
|
|
2124
2228
|
}
|
|
2125
2229
|
|
|
2126
2230
|
// src/PloyChat.jsx
|
|
@@ -2132,11 +2236,14 @@ function PloyChat({
|
|
|
2132
2236
|
supabase,
|
|
2133
2237
|
supabaseUrl,
|
|
2134
2238
|
supabaseAnonKey,
|
|
2135
|
-
className
|
|
2239
|
+
className,
|
|
2240
|
+
onBack,
|
|
2241
|
+
agent,
|
|
2242
|
+
onUnreadChange
|
|
2136
2243
|
}) {
|
|
2137
|
-
const config = { apiBase, workspaceId, getToken, supabase, supabaseUrl, supabaseAnonKey };
|
|
2244
|
+
const config = { apiBase, workspaceId, getToken, supabase, supabaseUrl, supabaseAnonKey, agentName: agent == null ? void 0 : agent.name };
|
|
2138
2245
|
const rootClass = ["ploychat-root", className].filter(Boolean).join(" ");
|
|
2139
|
-
return /* @__PURE__ */ jsx6(PloyConfigProvider, { config, children: /* @__PURE__ */ jsx6("div", { className: rootClass, style: { height: "100%", width: "100%" }, children: /* @__PURE__ */ jsx6(App, {}) }) });
|
|
2246
|
+
return /* @__PURE__ */ jsx6(PloyConfigProvider, { config, children: /* @__PURE__ */ jsx6("div", { className: rootClass, style: { height: "100%", width: "100%" }, children: /* @__PURE__ */ jsx6(App, { onBack, agent, onUnreadChange }) }) });
|
|
2140
2247
|
}
|
|
2141
2248
|
var PloyChat_default = PloyChat;
|
|
2142
2249
|
export {
|