@adatechnology/conversations-ui 0.1.0-rc.26 → 0.1.0-rc.28
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/chunk-DXPSPUWF.js +110 -0
- package/dist/{chunk-TV4OQRGH.js → chunk-UZJBYD5O.js} +123 -45
- package/dist/{chunk-2AYDBWNE.js → chunk-WCBDXZ3X.js} +13 -3
- package/dist/flows/index.d.ts +75 -2
- package/dist/flows/index.js +176 -95
- package/dist/index.d.ts +37 -10
- package/dist/index.js +694 -297
- package/dist/preview/index.js +3 -3
- package/dist/styles.css +119 -6
- package/package.json +2 -2
- package/src/AudioPlayer.tsx +8 -0
- package/src/AudioRecorderButton.test.tsx +3 -3
- package/src/AudioRecorderButton.tsx +3 -3
- package/src/AudioTranscription.tsx +4 -1
- package/src/Avatar.tsx +1 -1
- package/src/ConversationContextPanel.tsx +2 -2
- package/src/ConversationDocumentsPanel.tsx +11 -6
- package/src/ConversationHeader.test.tsx +66 -0
- package/src/ConversationHeader.tsx +147 -47
- package/src/ConversationListItem.tsx +3 -2
- package/src/ConversationRow.tsx +31 -7
- package/src/DocumentsLibrary.tsx +9 -4
- package/src/EmojiPicker.tsx +2 -1
- package/src/InteractiveMessage.tsx +3 -0
- package/src/Lightbox.tsx +1 -1
- package/src/MediaRenderer.tsx +2 -0
- package/src/MessageBubble.test.tsx +41 -0
- package/src/MessageBubble.tsx +27 -8
- package/src/MessageComposer.tsx +11 -8
- package/src/RichMessageComposer.test.tsx +42 -12
- package/src/RichMessageComposer.tsx +216 -45
- package/src/SimpleEmojiPicker.tsx +5 -3
- package/src/StatusTicks.tsx +1 -1
- package/src/Toast.tsx +4 -0
- package/src/Tooltip.test.ts +42 -0
- package/src/Tooltip.tsx +164 -0
- package/src/WhatsAppMessageEditor.tsx +4 -4
- package/src/WindowExpiredNotice.tsx +12 -4
- package/src/buildOutput.test.ts +79 -0
- package/src/composer.constant.ts +33 -0
- package/src/conversationWindow.ts +7 -5
- package/src/documents/DocumentsWorkspace.tsx +10 -6
- package/src/flows/FlowGroupHeader.tsx +2 -2
- package/src/flows/FlowMapNode.tsx +2 -1
- package/src/flows/FlowNodeCard.tsx +3 -3
- package/src/flows/FlowNodePanel.tsx +6 -5
- package/src/flows/FlowPalette.tsx +7 -1
- package/src/flows/FlowPortalNode.tsx +1 -1
- package/src/flows/FlowsWorkspace.tsx +69 -102
- package/src/flows/flowEditorOps.test.ts +241 -0
- package/src/flows/flowEditorOps.ts +177 -0
- package/src/flows/flowGraph.ts +1 -1
- package/src/flows/index.ts +16 -0
- package/src/flows/labels.ts +4 -0
- package/src/flows/workspaceContract.test.ts +95 -0
- package/src/hooks/useContainerWidth.ts +35 -0
- package/src/hooks/useConversationRealtime.ts +10 -8
- package/src/icon.constant.ts +12 -0
- package/src/index.ts +1 -0
- package/src/lib/composer-formatting.test.ts +78 -0
- package/src/lib/composer-formatting.ts +145 -0
- package/src/lib/whatsapp-formatting.test.tsx +37 -0
- package/src/lib/whatsapp-formatting.tsx +28 -3
- package/src/listing/index.tsx +5 -1
- package/src/pagination.constant.ts +10 -0
- package/src/preview/ConversationSimulatorPanel.tsx +1 -1
- package/src/providers/ConversationsProvider.tsx +8 -6
- package/src/settings/MessagesWorkspace.tsx +3 -0
- package/src/settings/TopicsForm.tsx +2 -0
- package/src/settings/TranscriptionSettingsForm.test.tsx +1 -1
- package/src/settings/TranscriptionSettingsForm.tsx +1 -0
- package/src/settings/WelcomeFarewellForm.tsx +1 -0
- package/src/settings/WhatsAppCreateTemplateForm.tsx +1 -0
- package/src/settings/WhatsAppTemplateSettingsForm.tsx +5 -2
- package/src/settings/WhatsAppTemplatesSettings.tsx +2 -0
- package/src/styles.css +100 -4
- package/src/workspace/BulkTemplateModal.tsx +4 -2
- package/src/workspace/ConversationPane.tsx +49 -19
- package/src/workspace/ConversationsInboxList.tsx +17 -8
- package/src/workspace/ConversationsWorkspace.tsx +24 -16
- package/src/workspace/useConversationsInbox.ts +5 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TOOLTIP_ATTRIBUTE,
|
|
3
|
+
TooltipLayer
|
|
4
|
+
} from "./chunk-DXPSPUWF.js";
|
|
1
5
|
import {
|
|
2
6
|
AudioPlayer,
|
|
3
7
|
AudioRecorderButton,
|
|
4
8
|
AudioTranscription,
|
|
9
|
+
COMPOSER_BAR_CLASS,
|
|
10
|
+
COMPOSER_COMPACT_WIDTH,
|
|
11
|
+
COMPOSER_MONOSPACE_CLASS,
|
|
12
|
+
COMPOSER_TOOL_BUTTON_ACTIVE_CLASS,
|
|
13
|
+
COMPOSER_TOOL_BUTTON_CLASS,
|
|
14
|
+
COMPOSER_TOOL_BUTTON_IDLE_CLASS,
|
|
5
15
|
ConversationDocumentsPanel,
|
|
6
16
|
ConversationLocalesProvider,
|
|
7
17
|
ConversationWallpaper,
|
|
@@ -26,6 +36,8 @@ import {
|
|
|
26
36
|
MediaRenderer,
|
|
27
37
|
MessageBubble,
|
|
28
38
|
MessageComposer,
|
|
39
|
+
PAGINATION_LABELS,
|
|
40
|
+
QUICK_REPLY_PILL_CLASS,
|
|
29
41
|
StatusTicks,
|
|
30
42
|
applyQuickReplyVariables,
|
|
31
43
|
cn,
|
|
@@ -45,22 +57,123 @@ import {
|
|
|
45
57
|
useConversationDocuments,
|
|
46
58
|
useConversationLocales,
|
|
47
59
|
useConversations
|
|
48
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-UZJBYD5O.js";
|
|
49
61
|
import {
|
|
62
|
+
ZERO_WIDTH_SPACE,
|
|
50
63
|
htmlToWA,
|
|
51
64
|
parseWhatsAppFormatting,
|
|
52
65
|
useDarkMode,
|
|
53
66
|
useIsDarkTheme,
|
|
54
67
|
waToHTML,
|
|
55
68
|
waToHTMLInline
|
|
56
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-WCBDXZ3X.js";
|
|
57
70
|
|
|
58
71
|
// src/RichMessageComposer.tsx
|
|
59
|
-
import { forwardRef, useCallback, useEffect as
|
|
60
|
-
import { Bold, Italic, Strikethrough, Code, Paperclip, SendHorizonal, Braces } from "lucide-react";
|
|
72
|
+
import { forwardRef, useCallback, useEffect as useEffect3, useImperativeHandle, useRef as useRef2, useState as useState3 } from "react";
|
|
73
|
+
import { Bold, Italic, Strikethrough, Code, Paperclip, SendHorizonal, Braces, Type } from "lucide-react";
|
|
74
|
+
|
|
75
|
+
// src/hooks/useContainerWidth.ts
|
|
76
|
+
import { useEffect, useState } from "react";
|
|
77
|
+
function useContainerWidth(ref) {
|
|
78
|
+
const [width, setWidth] = useState(void 0);
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
const element = ref.current;
|
|
81
|
+
if (!element || typeof ResizeObserver === "undefined") return;
|
|
82
|
+
const measure = () => setWidth(element.getBoundingClientRect().width);
|
|
83
|
+
measure();
|
|
84
|
+
const observer = new ResizeObserver(measure);
|
|
85
|
+
observer.observe(element);
|
|
86
|
+
return () => observer.disconnect();
|
|
87
|
+
}, [ref]);
|
|
88
|
+
return width;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/lib/composer-formatting.ts
|
|
92
|
+
var FORMATTING_ACTION = {
|
|
93
|
+
BOLD: "bold",
|
|
94
|
+
ITALIC: "italic",
|
|
95
|
+
STRIKETHROUGH: "strikethrough",
|
|
96
|
+
MONOSPACE: "monospace"
|
|
97
|
+
};
|
|
98
|
+
var EXEC_COMMAND_BY_ACTION = {
|
|
99
|
+
[FORMATTING_ACTION.BOLD]: "bold",
|
|
100
|
+
[FORMATTING_ACTION.ITALIC]: "italic",
|
|
101
|
+
[FORMATTING_ACTION.STRIKETHROUGH]: "strikeThrough"
|
|
102
|
+
};
|
|
103
|
+
var FORMATTING_SEPARATOR = "|";
|
|
104
|
+
function codeAncestorOf({ node, editor }) {
|
|
105
|
+
let current = node;
|
|
106
|
+
while (current && current !== editor) {
|
|
107
|
+
if (current instanceof HTMLElement && current.tagName === "CODE") return current;
|
|
108
|
+
current = current.parentNode;
|
|
109
|
+
}
|
|
110
|
+
return void 0;
|
|
111
|
+
}
|
|
112
|
+
function canQueryCommandState() {
|
|
113
|
+
return typeof document !== "undefined" && typeof document.queryCommandState === "function";
|
|
114
|
+
}
|
|
115
|
+
function canExecuteFormattingCommand() {
|
|
116
|
+
return typeof document !== "undefined" && typeof document.execCommand === "function";
|
|
117
|
+
}
|
|
118
|
+
function isCommandActive(command) {
|
|
119
|
+
if (!canQueryCommandState()) return false;
|
|
120
|
+
try {
|
|
121
|
+
return document.queryCommandState(command);
|
|
122
|
+
} catch {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function activeFormattingIn(editor) {
|
|
127
|
+
const selection = typeof window !== "undefined" ? window.getSelection() : null;
|
|
128
|
+
const anchor = selection?.anchorNode;
|
|
129
|
+
if (!anchor || !editor.contains(anchor)) return "";
|
|
130
|
+
const active = [];
|
|
131
|
+
for (const [action, command] of Object.entries(EXEC_COMMAND_BY_ACTION)) {
|
|
132
|
+
if (isCommandActive(command)) active.push(action);
|
|
133
|
+
}
|
|
134
|
+
if (codeAncestorOf({ node: anchor, editor })) active.push(FORMATTING_ACTION.MONOSPACE);
|
|
135
|
+
return active.join(FORMATTING_SEPARATOR);
|
|
136
|
+
}
|
|
137
|
+
function isFormattingActive({ active, action }) {
|
|
138
|
+
return active.split(FORMATTING_SEPARATOR).includes(action);
|
|
139
|
+
}
|
|
140
|
+
function startMonospaceAt(range) {
|
|
141
|
+
const code = document.createElement("code");
|
|
142
|
+
code.className = COMPOSER_MONOSPACE_CLASS;
|
|
143
|
+
code.textContent = ZERO_WIDTH_SPACE;
|
|
144
|
+
range.deleteContents();
|
|
145
|
+
range.insertNode(code);
|
|
146
|
+
placeCaretAfter(code.firstChild, ZERO_WIDTH_SPACE.length);
|
|
147
|
+
}
|
|
148
|
+
function exitMonospaceAfter(code) {
|
|
149
|
+
const anchor = document.createTextNode(ZERO_WIDTH_SPACE);
|
|
150
|
+
code.after(anchor);
|
|
151
|
+
placeCaretAfter(anchor, ZERO_WIDTH_SPACE.length);
|
|
152
|
+
}
|
|
153
|
+
function unwrapMonospace(code) {
|
|
154
|
+
code.replaceWith(document.createTextNode(code.textContent?.replace(ZERO_WIDTH_SPACE, "") ?? ""));
|
|
155
|
+
}
|
|
156
|
+
function placeCaretAfter(node, offset) {
|
|
157
|
+
const caret = document.createRange();
|
|
158
|
+
caret.setStart(node, offset);
|
|
159
|
+
caret.collapse(true);
|
|
160
|
+
const selection = window.getSelection();
|
|
161
|
+
selection?.removeAllRanges();
|
|
162
|
+
selection?.addRange(caret);
|
|
163
|
+
}
|
|
164
|
+
function toggleFormattingCommand(action) {
|
|
165
|
+
const command = EXEC_COMMAND_BY_ACTION[action];
|
|
166
|
+
if (!command || !canExecuteFormattingCommand()) return false;
|
|
167
|
+
try {
|
|
168
|
+
document.execCommand("styleWithCSS", false, "false");
|
|
169
|
+
return document.execCommand(command);
|
|
170
|
+
} catch {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
61
174
|
|
|
62
175
|
// src/SimpleEmojiPicker.tsx
|
|
63
|
-
import { useEffect, useRef, useState } from "react";
|
|
176
|
+
import { useEffect as useEffect2, useRef, useState as useState2 } from "react";
|
|
64
177
|
import { Smile } from "lucide-react";
|
|
65
178
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
66
179
|
var EMOJIS = [
|
|
@@ -146,9 +259,9 @@ var EMOJIS = [
|
|
|
146
259
|
"\u{1F6E1}\uFE0F"
|
|
147
260
|
];
|
|
148
261
|
function SimpleEmojiPicker({ onSelect, label = "Emojis", pickerWidth = "280px", pickerMaxHeight = "220px" }) {
|
|
149
|
-
const [open, setOpen] =
|
|
262
|
+
const [open, setOpen] = useState2(false);
|
|
150
263
|
const containerRef = useRef(null);
|
|
151
|
-
|
|
264
|
+
useEffect2(() => {
|
|
152
265
|
if (!open) return;
|
|
153
266
|
const handleClickOutside = (e) => {
|
|
154
267
|
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
@@ -164,9 +277,10 @@ function SimpleEmojiPicker({ onSelect, label = "Emojis", pickerWidth = "280px",
|
|
|
164
277
|
{
|
|
165
278
|
type: "button",
|
|
166
279
|
onClick: () => setOpen((v) => !v),
|
|
167
|
-
className: "w-
|
|
168
|
-
|
|
169
|
-
|
|
280
|
+
className: "w-9 h-9 flex items-center justify-center rounded-full text-gray-400 dark:text-gray-500 hover:text-teal-600 dark:hover:text-teal-400 hover:bg-teal-50 dark:hover:bg-teal-900/30 transition-colors",
|
|
281
|
+
"data-cv-tooltip": label,
|
|
282
|
+
"aria-label": label,
|
|
283
|
+
children: /* @__PURE__ */ jsx(Smile, { size: 18 })
|
|
170
284
|
}
|
|
171
285
|
),
|
|
172
286
|
open && /* @__PURE__ */ jsx("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-xl shadow-xl p-2 z-50", children: /* @__PURE__ */ jsx(
|
|
@@ -177,6 +291,8 @@ function SimpleEmojiPicker({ onSelect, label = "Emojis", pickerWidth = "280px",
|
|
|
177
291
|
children: EMOJIS.map((emoji) => /* @__PURE__ */ jsx(
|
|
178
292
|
"button",
|
|
179
293
|
{
|
|
294
|
+
"data-cv-tooltip": emoji,
|
|
295
|
+
"aria-label": emoji,
|
|
180
296
|
type: "button",
|
|
181
297
|
onClick: () => {
|
|
182
298
|
onSelect(emoji);
|
|
@@ -211,7 +327,8 @@ var DEFAULT_RICH_COMPOSER_TOOLTIPS = {
|
|
|
211
327
|
emoji: "Emojis",
|
|
212
328
|
attach: "Anexar arquivo",
|
|
213
329
|
send: "Enviar",
|
|
214
|
-
variables: "Vari\xE1veis dispon\xEDveis"
|
|
330
|
+
variables: "Vari\xE1veis dispon\xEDveis",
|
|
331
|
+
formatting: "Formata\xE7\xE3o"
|
|
215
332
|
};
|
|
216
333
|
var FORMATTING_ELEMENT = {
|
|
217
334
|
bold: "strong",
|
|
@@ -219,7 +336,6 @@ var FORMATTING_ELEMENT = {
|
|
|
219
336
|
strikethrough: "del",
|
|
220
337
|
monospace: "code"
|
|
221
338
|
};
|
|
222
|
-
var MONOSPACE_CLASS = "bg-black/5 dark:bg-white/10 rounded px-0.5 font-mono text-sm";
|
|
223
339
|
var RichMessageComposer = forwardRef(function RichMessageComposer2({
|
|
224
340
|
value,
|
|
225
341
|
onChange,
|
|
@@ -234,14 +350,41 @@ var RichMessageComposer = forwardRef(function RichMessageComposer2({
|
|
|
234
350
|
isSending = false,
|
|
235
351
|
idleAction,
|
|
236
352
|
attachmentsPreview,
|
|
353
|
+
hasQueuedAttachments = false,
|
|
237
354
|
acceptedFileTypes = DEFAULT_ACCEPTED_FILE_TYPES,
|
|
238
355
|
className
|
|
239
356
|
}, ref) {
|
|
240
357
|
const editorRef = useRef2(null);
|
|
241
358
|
const fileInputRef = useRef2(null);
|
|
242
359
|
const variablesRef = useRef2(null);
|
|
243
|
-
const
|
|
244
|
-
|
|
360
|
+
const formattingRef = useRef2(null);
|
|
361
|
+
const barRef = useRef2(null);
|
|
362
|
+
const [isVariablesOpen, setIsVariablesOpen] = useState3(false);
|
|
363
|
+
const [isFormattingOpen, setIsFormattingOpen] = useState3(false);
|
|
364
|
+
const [activeFormatting, setActiveFormatting] = useState3("");
|
|
365
|
+
const barWidth = useContainerWidth(barRef);
|
|
366
|
+
const isCompact = barWidth !== void 0 && barWidth < COMPOSER_COMPACT_WIDTH;
|
|
367
|
+
const lastEmittedRef = useRef2("");
|
|
368
|
+
const emitChange = useCallback((html) => {
|
|
369
|
+
const text = htmlToWA(html);
|
|
370
|
+
lastEmittedRef.current = text;
|
|
371
|
+
onChange(text);
|
|
372
|
+
}, [onChange]);
|
|
373
|
+
useEffect3(() => {
|
|
374
|
+
const editor = editorRef.current;
|
|
375
|
+
if (!editor || value === lastEmittedRef.current) return;
|
|
376
|
+
lastEmittedRef.current = value;
|
|
377
|
+
editor.innerHTML = waToHTML(value);
|
|
378
|
+
}, [value]);
|
|
379
|
+
const refreshActiveFormatting = useCallback(() => {
|
|
380
|
+
const editor = editorRef.current;
|
|
381
|
+
if (editor) setActiveFormatting(activeFormattingIn(editor));
|
|
382
|
+
}, []);
|
|
383
|
+
useEffect3(() => {
|
|
384
|
+
document.addEventListener("selectionchange", refreshActiveFormatting);
|
|
385
|
+
return () => document.removeEventListener("selectionchange", refreshActiveFormatting);
|
|
386
|
+
}, [refreshActiveFormatting]);
|
|
387
|
+
useEffect3(() => {
|
|
245
388
|
if (!isVariablesOpen) return;
|
|
246
389
|
const closeOnOutsideClick = (event) => {
|
|
247
390
|
if (!variablesRef.current?.contains(event.target)) setIsVariablesOpen(false);
|
|
@@ -249,25 +392,36 @@ var RichMessageComposer = forwardRef(function RichMessageComposer2({
|
|
|
249
392
|
document.addEventListener("mousedown", closeOnOutsideClick);
|
|
250
393
|
return () => document.removeEventListener("mousedown", closeOnOutsideClick);
|
|
251
394
|
}, [isVariablesOpen]);
|
|
395
|
+
useEffect3(() => {
|
|
396
|
+
if (!isFormattingOpen) return;
|
|
397
|
+
const closeOnOutsideClick = (event) => {
|
|
398
|
+
if (!formattingRef.current?.contains(event.target)) setIsFormattingOpen(false);
|
|
399
|
+
};
|
|
400
|
+
document.addEventListener("mousedown", closeOnOutsideClick);
|
|
401
|
+
return () => document.removeEventListener("mousedown", closeOnOutsideClick);
|
|
402
|
+
}, [isFormattingOpen]);
|
|
403
|
+
useEffect3(() => {
|
|
404
|
+
if (!isCompact) setIsFormattingOpen(false);
|
|
405
|
+
}, [isCompact]);
|
|
252
406
|
const tooltipOf = (action) => tooltips?.[action] ?? DEFAULT_RICH_COMPOSER_TOOLTIPS[action];
|
|
253
407
|
const shows = (action) => toolbar?.[action] !== false;
|
|
254
408
|
const replaceContent = useCallback((text) => {
|
|
255
409
|
const editor = editorRef.current;
|
|
256
410
|
if (!editor) return;
|
|
257
411
|
editor.innerHTML = waToHTML(text);
|
|
258
|
-
|
|
412
|
+
emitChange(editor.innerHTML);
|
|
259
413
|
editor.focus();
|
|
260
|
-
}, [
|
|
414
|
+
}, [emitChange]);
|
|
261
415
|
useImperativeHandle(ref, () => ({
|
|
262
416
|
setContent: replaceContent,
|
|
263
417
|
clear: () => {
|
|
264
418
|
const editor = editorRef.current;
|
|
265
419
|
if (!editor) return;
|
|
266
420
|
editor.innerHTML = "";
|
|
267
|
-
|
|
421
|
+
emitChange("");
|
|
268
422
|
},
|
|
269
423
|
focus: () => editorRef.current?.focus()
|
|
270
|
-
}), [
|
|
424
|
+
}), [emitChange, replaceContent]);
|
|
271
425
|
const currentRange = useCallback(() => {
|
|
272
426
|
const editor = editorRef.current;
|
|
273
427
|
if (!editor) return void 0;
|
|
@@ -282,8 +436,8 @@ var RichMessageComposer = forwardRef(function RichMessageComposer2({
|
|
|
282
436
|
range.collapse(true);
|
|
283
437
|
selection?.removeAllRanges();
|
|
284
438
|
selection?.addRange(range);
|
|
285
|
-
|
|
286
|
-
}, [
|
|
439
|
+
emitChange(editorRef.current?.innerHTML ?? "");
|
|
440
|
+
}, [emitChange]);
|
|
287
441
|
const insertAtCursor = useCallback((fragment) => {
|
|
288
442
|
const range = currentRange();
|
|
289
443
|
if (!range) return;
|
|
@@ -298,26 +452,74 @@ var RichMessageComposer = forwardRef(function RichMessageComposer2({
|
|
|
298
452
|
if (!range || !selectedText) return;
|
|
299
453
|
range.deleteContents();
|
|
300
454
|
const wrapper = document.createElement(FORMATTING_ELEMENT[action]);
|
|
301
|
-
if (action === "monospace") wrapper.className =
|
|
455
|
+
if (action === "monospace") wrapper.className = COMPOSER_MONOSPACE_CLASS;
|
|
302
456
|
wrapper.textContent = selectedText;
|
|
303
457
|
range.insertNode(wrapper);
|
|
304
458
|
commitRange(range, wrapper);
|
|
305
459
|
}, [commitRange, currentRange]);
|
|
460
|
+
const applyFormatting = useCallback((action) => {
|
|
461
|
+
const editor = editorRef.current;
|
|
462
|
+
const range = currentRange();
|
|
463
|
+
if (!editor || !range) return;
|
|
464
|
+
if (action === FORMATTING_ACTION.MONOSPACE) {
|
|
465
|
+
const code = codeAncestorOf({ node: range.startContainer, editor });
|
|
466
|
+
if (range.collapsed) {
|
|
467
|
+
if (code) exitMonospaceAfter(code);
|
|
468
|
+
else startMonospaceAt(range);
|
|
469
|
+
} else if (code) {
|
|
470
|
+
unwrapMonospace(code);
|
|
471
|
+
} else {
|
|
472
|
+
wrapSelection(action);
|
|
473
|
+
}
|
|
474
|
+
emitChange(editor.innerHTML);
|
|
475
|
+
refreshActiveFormatting();
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
if (toggleFormattingCommand(action)) emitChange(editor.innerHTML);
|
|
479
|
+
else wrapSelection(action);
|
|
480
|
+
refreshActiveFormatting();
|
|
481
|
+
}, [currentRange, emitChange, refreshActiveFormatting, wrapSelection]);
|
|
306
482
|
const handleInput = useCallback((event) => {
|
|
307
|
-
|
|
308
|
-
|
|
483
|
+
emitChange(event.currentTarget.innerHTML);
|
|
484
|
+
refreshActiveFormatting();
|
|
485
|
+
}, [emitChange, refreshActiveFormatting]);
|
|
309
486
|
const handleKeyDown = useCallback((event) => {
|
|
310
487
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
311
488
|
event.preventDefault();
|
|
312
|
-
if (!disabled) onSend();
|
|
489
|
+
if (!disabled && !isSending) onSend();
|
|
313
490
|
}
|
|
314
|
-
}, [disabled, onSend]);
|
|
491
|
+
}, [disabled, isSending, onSend]);
|
|
315
492
|
const handleFileChange = useCallback((event) => {
|
|
316
493
|
if (event.target.files?.length) onAttachFiles?.(event.target.files);
|
|
317
494
|
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
318
495
|
}, [onAttachFiles]);
|
|
319
|
-
const canSend = value.trim().length > 0;
|
|
320
|
-
|
|
496
|
+
const canSend = value.trim().length > 0 || hasQueuedAttachments;
|
|
497
|
+
const formattingButtons = [
|
|
498
|
+
[RICH_COMPOSER_ACTION.BOLD, Bold],
|
|
499
|
+
[RICH_COMPOSER_ACTION.ITALIC, Italic],
|
|
500
|
+
[RICH_COMPOSER_ACTION.STRIKETHROUGH, Strikethrough],
|
|
501
|
+
[RICH_COMPOSER_ACTION.MONOSPACE, Code]
|
|
502
|
+
].filter(([action]) => shows(action)).map(([action, Icon]) => {
|
|
503
|
+
const isActive = isFormattingActive({ active: activeFormatting, action });
|
|
504
|
+
return /* @__PURE__ */ jsx2(
|
|
505
|
+
"button",
|
|
506
|
+
{
|
|
507
|
+
type: "button",
|
|
508
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
509
|
+
onClick: () => applyFormatting(action),
|
|
510
|
+
"data-cv-tooltip": tooltipOf(action),
|
|
511
|
+
"aria-label": tooltipOf(action),
|
|
512
|
+
"aria-pressed": isActive,
|
|
513
|
+
className: cn(
|
|
514
|
+
COMPOSER_TOOL_BUTTON_CLASS,
|
|
515
|
+
isActive ? COMPOSER_TOOL_BUTTON_ACTIVE_CLASS : COMPOSER_TOOL_BUTTON_IDLE_CLASS
|
|
516
|
+
),
|
|
517
|
+
children: /* @__PURE__ */ jsx2(Icon, { size: 18 })
|
|
518
|
+
},
|
|
519
|
+
action
|
|
520
|
+
);
|
|
521
|
+
});
|
|
522
|
+
return /* @__PURE__ */ jsxs2("div", { className: cn(COMPOSER_BAR_CLASS, "flex flex-col", className), children: [
|
|
321
523
|
attachmentsPreview,
|
|
322
524
|
quickReplies?.length ? (
|
|
323
525
|
/* Uma linha só, rolando na horizontal. Deixar quebrar em várias linhas faz a barra crescer
|
|
@@ -327,32 +529,35 @@ var RichMessageComposer = forwardRef(function RichMessageComposer2({
|
|
|
327
529
|
"button",
|
|
328
530
|
{
|
|
329
531
|
type: "button",
|
|
330
|
-
|
|
532
|
+
"data-cv-tooltip": quickReply.tooltip,
|
|
533
|
+
"aria-label": quickReply.tooltip,
|
|
331
534
|
onClick: () => replaceContent(quickReply.text),
|
|
332
|
-
className: "flex-shrink-0
|
|
535
|
+
className: cn(QUICK_REPLY_PILL_CLASS, "flex-shrink-0"),
|
|
333
536
|
children: quickReply.label
|
|
334
537
|
},
|
|
335
538
|
quickReply.id
|
|
336
539
|
)) })
|
|
337
540
|
) : null,
|
|
338
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex flex-
|
|
339
|
-
/* @__PURE__ */
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
541
|
+
/* @__PURE__ */ jsxs2("div", { ref: barRef, className: "flex flex-nowrap items-end gap-1", children: [
|
|
542
|
+
formattingButtons.length > 0 ? isCompact ? /* @__PURE__ */ jsxs2("div", { ref: formattingRef, className: "relative hidden flex-shrink-0 sm:block", children: [
|
|
543
|
+
/* @__PURE__ */ jsx2(
|
|
544
|
+
"button",
|
|
545
|
+
{
|
|
546
|
+
type: "button",
|
|
547
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
548
|
+
onClick: () => setIsFormattingOpen((open) => !open),
|
|
549
|
+
"data-cv-tooltip": tooltipOf("formatting"),
|
|
550
|
+
"aria-label": tooltipOf("formatting"),
|
|
551
|
+
"aria-expanded": isFormattingOpen,
|
|
552
|
+
className: cn(
|
|
553
|
+
COMPOSER_TOOL_BUTTON_CLASS,
|
|
554
|
+
activeFormatting || isFormattingOpen ? COMPOSER_TOOL_BUTTON_ACTIVE_CLASS : COMPOSER_TOOL_BUTTON_IDLE_CLASS
|
|
555
|
+
),
|
|
556
|
+
children: /* @__PURE__ */ jsx2(Type, { size: 18 })
|
|
557
|
+
}
|
|
558
|
+
),
|
|
559
|
+
isFormattingOpen ? /* @__PURE__ */ jsx2("div", { className: "absolute bottom-full left-0 z-20 mb-2 flex items-center gap-1 rounded-full border border-gray-200 bg-white px-1 py-1 shadow-lg dark:border-gray-700 dark:bg-gray-800", children: formattingButtons }) : null
|
|
560
|
+
] }) : /* @__PURE__ */ jsx2("div", { className: "hidden flex-shrink-0 items-center gap-1 sm:flex", children: formattingButtons }) : null,
|
|
356
561
|
shows(RICH_COMPOSER_ACTION.EMOJI) ? /* @__PURE__ */ jsx2(SimpleEmojiPicker, { onSelect: insertAtCursor, label: tooltipOf("emoji") }) : null,
|
|
357
562
|
variables?.length && shows(RICH_COMPOSER_ACTION.VARIABLES) ? /* @__PURE__ */ jsxs2("div", { ref: variablesRef, className: "relative", children: [
|
|
358
563
|
/* @__PURE__ */ jsx2(
|
|
@@ -360,10 +565,10 @@ var RichMessageComposer = forwardRef(function RichMessageComposer2({
|
|
|
360
565
|
{
|
|
361
566
|
type: "button",
|
|
362
567
|
onClick: () => setIsVariablesOpen((open) => !open),
|
|
363
|
-
|
|
568
|
+
"data-cv-tooltip": tooltipOf("variables"),
|
|
364
569
|
"aria-label": tooltipOf("variables"),
|
|
365
570
|
"aria-expanded": isVariablesOpen,
|
|
366
|
-
className:
|
|
571
|
+
className: cn(COMPOSER_TOOL_BUTTON_CLASS, COMPOSER_TOOL_BUTTON_IDLE_CLASS),
|
|
367
572
|
children: /* @__PURE__ */ jsx2(Braces, { size: 18 })
|
|
368
573
|
}
|
|
369
574
|
),
|
|
@@ -371,7 +576,8 @@ var RichMessageComposer = forwardRef(function RichMessageComposer2({
|
|
|
371
576
|
"button",
|
|
372
577
|
{
|
|
373
578
|
type: "button",
|
|
374
|
-
|
|
579
|
+
"data-cv-tooltip": variable.tooltip ?? variable.value,
|
|
580
|
+
"aria-label": variable.tooltip ?? variable.value,
|
|
375
581
|
onClick: () => {
|
|
376
582
|
insertAtCursor(variable.value);
|
|
377
583
|
setIsVariablesOpen(false);
|
|
@@ -402,9 +608,9 @@ var RichMessageComposer = forwardRef(function RichMessageComposer2({
|
|
|
402
608
|
{
|
|
403
609
|
type: "button",
|
|
404
610
|
onClick: () => fileInputRef.current?.click(),
|
|
405
|
-
|
|
611
|
+
"data-cv-tooltip": tooltipOf("attach"),
|
|
406
612
|
"aria-label": tooltipOf("attach"),
|
|
407
|
-
className:
|
|
613
|
+
className: cn(COMPOSER_TOOL_BUTTON_CLASS, COMPOSER_TOOL_BUTTON_IDLE_CLASS),
|
|
408
614
|
children: /* @__PURE__ */ jsx2(Paperclip, { size: 18 })
|
|
409
615
|
}
|
|
410
616
|
)
|
|
@@ -422,7 +628,7 @@ var RichMessageComposer = forwardRef(function RichMessageComposer2({
|
|
|
422
628
|
onInput: handleInput,
|
|
423
629
|
onKeyDown: handleKeyDown,
|
|
424
630
|
style: { minHeight: "36px", maxHeight: "120px" },
|
|
425
|
-
className: "
|
|
631
|
+
className: "ml-1 min-w-0 flex-1 overflow-y-auto rounded-2xl border border-transparent bg-white px-4 py-2 text-sm text-gray-800 transition-all focus:border-transparent focus:outline-none focus:ring-2 focus:ring-teal-300 dark:border-gray-700 dark:bg-gray-700 dark:text-gray-100 empty:before:content-[attr(data-placeholder)] empty:before:text-gray-400 dark:empty:before:text-gray-500 before:pointer-events-none [&_strong]:font-semibold [&_b]:font-semibold [&_em]:italic [&_i]:italic [&_del]:line-through [&_s]:line-through [&_strike]:line-through [&_code]:rounded [&_code]:bg-black/5 [&_code]:px-0.5 [&_code]:font-mono [&_code]:text-sm dark:[&_code]:bg-white/10"
|
|
426
632
|
}
|
|
427
633
|
),
|
|
428
634
|
!canSend && idleAction ? /* @__PURE__ */ jsx2("div", { className: "flex-shrink-0", children: idleAction }) : /* @__PURE__ */ jsx2(
|
|
@@ -431,7 +637,7 @@ var RichMessageComposer = forwardRef(function RichMessageComposer2({
|
|
|
431
637
|
type: "button",
|
|
432
638
|
onClick: onSend,
|
|
433
639
|
disabled: disabled || isSending || !canSend,
|
|
434
|
-
|
|
640
|
+
"data-cv-tooltip": tooltipOf("send"),
|
|
435
641
|
"aria-label": tooltipOf("send"),
|
|
436
642
|
className: "flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-full bg-teal-600 text-white transition-colors hover:bg-teal-700 disabled:cursor-not-allowed disabled:opacity-40",
|
|
437
643
|
children: isSending ? /* @__PURE__ */ jsx2("span", { className: "text-xs", children: "\u23F3" }) : /* @__PURE__ */ jsx2(SendHorizonal, { size: 16 })
|
|
@@ -523,9 +729,9 @@ function WhatsAppMessageEditor({
|
|
|
523
729
|
const toolbarButtonClass = "inline-flex items-center justify-center h-8 w-8 rounded-lg border border-gray-200 dark:border-gray-600 text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors";
|
|
524
730
|
return /* @__PURE__ */ jsxs3("div", { children: [
|
|
525
731
|
/* @__PURE__ */ jsxs3("div", { className: "flex flex-wrap items-center gap-1.5 mb-2", children: [
|
|
526
|
-
/* @__PURE__ */ jsx3("button", { type: "button", onClick: () => wrapSelection("*"), className: toolbarButtonClass,
|
|
527
|
-
/* @__PURE__ */ jsx3("button", { type: "button", onClick: () => wrapSelection("_"), className: toolbarButtonClass,
|
|
528
|
-
/* @__PURE__ */ jsx3("button", { type: "button", onClick: () => wrapSelection("~"), className: toolbarButtonClass,
|
|
732
|
+
/* @__PURE__ */ jsx3("button", { type: "button", onClick: () => wrapSelection("*"), className: toolbarButtonClass, "data-cv-tooltip": editorLabels.boldHint, "aria-label": editorLabels.bold, children: /* @__PURE__ */ jsx3(Bold2, { size: 15 }) }),
|
|
733
|
+
/* @__PURE__ */ jsx3("button", { type: "button", onClick: () => wrapSelection("_"), className: toolbarButtonClass, "data-cv-tooltip": editorLabels.italicHint, "aria-label": editorLabels.italic, children: /* @__PURE__ */ jsx3(Italic2, { size: 15 }) }),
|
|
734
|
+
/* @__PURE__ */ jsx3("button", { type: "button", onClick: () => wrapSelection("~"), className: toolbarButtonClass, "data-cv-tooltip": editorLabels.strikethroughHint, "aria-label": editorLabels.strikethrough, children: /* @__PURE__ */ jsx3(Strikethrough2, { size: 15 }) }),
|
|
529
735
|
placeholders.length > 0 && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
530
736
|
/* @__PURE__ */ jsx3("span", { className: "mx-1 h-5 w-px bg-gray-200 dark:bg-gray-600" }),
|
|
531
737
|
placeholders.map((token) => /* @__PURE__ */ jsx3(
|
|
@@ -534,7 +740,8 @@ function WhatsAppMessageEditor({
|
|
|
534
740
|
type: "button",
|
|
535
741
|
onClick: () => insertAtCursor(token),
|
|
536
742
|
className: "inline-flex items-center h-8 px-2 rounded-lg border border-gray-200 dark:border-gray-600 text-xs text-blue-600 dark:text-blue-300 hover:bg-blue-50 dark:hover:bg-blue-900/40 transition-colors",
|
|
537
|
-
|
|
743
|
+
"data-cv-tooltip": editorLabels.insertPlaceholder(token),
|
|
744
|
+
"aria-label": editorLabels.insertPlaceholder(token),
|
|
538
745
|
children: token
|
|
539
746
|
},
|
|
540
747
|
token
|
|
@@ -618,7 +825,7 @@ function Avatar({ name, avatarUrl, size = "md", className = "", labels }) {
|
|
|
618
825
|
"div",
|
|
619
826
|
{
|
|
620
827
|
className: `${sizeClass} ${bgColor} rounded-full flex items-center justify-center text-white font-semibold flex-shrink-0 ${className}`,
|
|
621
|
-
|
|
828
|
+
"data-cv-tooltip": name,
|
|
622
829
|
children: getInitials(name)
|
|
623
830
|
}
|
|
624
831
|
);
|
|
@@ -793,6 +1000,8 @@ var ConversationListItem = ({
|
|
|
793
1000
|
return /* @__PURE__ */ jsxs4(
|
|
794
1001
|
"button",
|
|
795
1002
|
{
|
|
1003
|
+
"data-cv-tooltip": name,
|
|
1004
|
+
"aria-label": name,
|
|
796
1005
|
onClick: handleClick,
|
|
797
1006
|
className: `w-full flex items-center gap-3 px-3 py-2.5 text-left transition-colors ${highlightActive ? "hover:bg-[#f0f2f5]" : ""} ${showDivider ? "border-b border-[#e9edef]" : ""}`,
|
|
798
1007
|
style: {
|
|
@@ -808,8 +1017,8 @@ var ConversationListItem = ({
|
|
|
808
1017
|
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-1.5 min-w-0", children: [
|
|
809
1018
|
!conversation.clientName && flag ? /* @__PURE__ */ jsx5("span", { "aria-hidden": true, children: flag }) : null,
|
|
810
1019
|
/* @__PURE__ */ jsx5("span", { className: "text-[16px] text-[#111b21] truncate", children: name }),
|
|
811
|
-
windowStatus && windowStatus.label === "expired" && /* @__PURE__ */ jsx5("span", { className: "w-2 h-2 rounded-full bg-red-500 flex-shrink-0",
|
|
812
|
-
windowStatus && windowStatus.label === "warning" && /* @__PURE__ */ jsx5("span", { className: "w-2 h-2 rounded-full bg-orange-500 flex-shrink-0",
|
|
1020
|
+
windowStatus && windowStatus.label === "expired" && /* @__PURE__ */ jsx5("span", { className: "w-2 h-2 rounded-full bg-red-500 flex-shrink-0", "data-cv-tooltip": expiredWindowLabel }),
|
|
1021
|
+
windowStatus && windowStatus.label === "warning" && /* @__PURE__ */ jsx5("span", { className: "w-2 h-2 rounded-full bg-orange-500 flex-shrink-0", "data-cv-tooltip": warningWindowLabel })
|
|
813
1022
|
] }),
|
|
814
1023
|
timestamp && /* @__PURE__ */ jsx5("span", { className: "text-xs text-[#667781] flex-shrink-0", children: timestamp })
|
|
815
1024
|
] }),
|
|
@@ -835,7 +1044,7 @@ var ConversationListItem = ({
|
|
|
835
1044
|
};
|
|
836
1045
|
|
|
837
1046
|
// src/Toast.tsx
|
|
838
|
-
import { createContext, useContext, useState as
|
|
1047
|
+
import { createContext, useContext, useState as useState4, useCallback as useCallback2, useEffect as useEffect4 } from "react";
|
|
839
1048
|
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
840
1049
|
var ToastContext = createContext(null);
|
|
841
1050
|
var nextId = 0;
|
|
@@ -847,6 +1056,7 @@ var toast = {
|
|
|
847
1056
|
}
|
|
848
1057
|
}
|
|
849
1058
|
};
|
|
1059
|
+
var TOAST_CLOSE_LABEL = "Fechar aviso";
|
|
850
1060
|
var typeStyles = {
|
|
851
1061
|
success: "bg-green-600",
|
|
852
1062
|
error: "bg-red-600",
|
|
@@ -865,8 +1075,8 @@ var typeIcons = {
|
|
|
865
1075
|
] })
|
|
866
1076
|
};
|
|
867
1077
|
function ToastItemComponent({ item, onRemove }) {
|
|
868
|
-
const [exiting, setExiting] =
|
|
869
|
-
|
|
1078
|
+
const [exiting, setExiting] = useState4(false);
|
|
1079
|
+
useEffect4(() => {
|
|
870
1080
|
const timer = setTimeout(() => {
|
|
871
1081
|
setExiting(true);
|
|
872
1082
|
setTimeout(() => onRemove(item.id), 300);
|
|
@@ -887,6 +1097,8 @@ function ToastItemComponent({ item, onRemove }) {
|
|
|
887
1097
|
setExiting(true);
|
|
888
1098
|
setTimeout(() => onRemove(item.id), 300);
|
|
889
1099
|
},
|
|
1100
|
+
"data-cv-tooltip": TOAST_CLOSE_LABEL,
|
|
1101
|
+
"aria-label": TOAST_CLOSE_LABEL,
|
|
890
1102
|
className: "flex-shrink-0 opacity-70 hover:opacity-100 transition-opacity",
|
|
891
1103
|
children: /* @__PURE__ */ jsxs5("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
892
1104
|
/* @__PURE__ */ jsx6("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
@@ -899,7 +1111,7 @@ function ToastItemComponent({ item, onRemove }) {
|
|
|
899
1111
|
);
|
|
900
1112
|
}
|
|
901
1113
|
function ToastProvider({ children }) {
|
|
902
|
-
const [items, setItems] =
|
|
1114
|
+
const [items, setItems] = useState4([]);
|
|
903
1115
|
const show = useCallback2((type, message) => {
|
|
904
1116
|
const id = ++nextId;
|
|
905
1117
|
setItems((prev) => [...prev, { id, type, message }]);
|
|
@@ -907,7 +1119,7 @@ function ToastProvider({ children }) {
|
|
|
907
1119
|
const remove = useCallback2((id) => {
|
|
908
1120
|
setItems((prev) => prev.filter((item) => item.id !== id));
|
|
909
1121
|
}, []);
|
|
910
|
-
|
|
1122
|
+
useEffect4(() => {
|
|
911
1123
|
singletonShow = show;
|
|
912
1124
|
return () => {
|
|
913
1125
|
singletonShow = null;
|
|
@@ -939,10 +1151,10 @@ function useToast() {
|
|
|
939
1151
|
}
|
|
940
1152
|
|
|
941
1153
|
// src/MessageText.tsx
|
|
942
|
-
import { useCallback as useCallback3, useState as
|
|
1154
|
+
import { useCallback as useCallback3, useState as useState5 } from "react";
|
|
943
1155
|
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
944
1156
|
function MessageText({ message }) {
|
|
945
|
-
const [copied, setCopied] =
|
|
1157
|
+
const [copied, setCopied] = useState5(false);
|
|
946
1158
|
const handleCopy = useCallback3(async () => {
|
|
947
1159
|
if (!message.content) return;
|
|
948
1160
|
try {
|
|
@@ -996,11 +1208,11 @@ var CONVERSATION_WINDOW = {
|
|
|
996
1208
|
EXPIRED: "expired"
|
|
997
1209
|
};
|
|
998
1210
|
var WINDOW_FILTERS = [
|
|
999
|
-
{ value: CONVERSATION_WINDOW.ALL, label: "Todas",
|
|
1000
|
-
{ value: CONVERSATION_WINDOW.FRESH, label: "<12h",
|
|
1001
|
-
{ value: CONVERSATION_WINDOW.WARNING, label: "12-21h",
|
|
1002
|
-
{ value: CONVERSATION_WINDOW.CRITICAL, label: "21-24h",
|
|
1003
|
-
{ value: CONVERSATION_WINDOW.EXPIRED, label: ">24h",
|
|
1211
|
+
{ value: CONVERSATION_WINDOW.ALL, label: "Todas", tone: "" },
|
|
1212
|
+
{ value: CONVERSATION_WINDOW.FRESH, label: "<12h", tone: "fresh" },
|
|
1213
|
+
{ value: CONVERSATION_WINDOW.WARNING, label: "12-21h", tone: "warning" },
|
|
1214
|
+
{ value: CONVERSATION_WINDOW.CRITICAL, label: "21-24h", tone: "critical" },
|
|
1215
|
+
{ value: CONVERSATION_WINDOW.EXPIRED, label: ">24h", tone: "expired" }
|
|
1004
1216
|
];
|
|
1005
1217
|
var WARNING_RATIO = 0.5;
|
|
1006
1218
|
var CRITICAL_RATIO = 0.875;
|
|
@@ -1025,6 +1237,14 @@ function formatStalledFor(lastAt, now) {
|
|
|
1025
1237
|
return `${minutes}m`;
|
|
1026
1238
|
}
|
|
1027
1239
|
|
|
1240
|
+
// src/ConversationRow.tsx
|
|
1241
|
+
import { AlarmClock, Bot, Hourglass, Play, UserRound } from "lucide-react";
|
|
1242
|
+
|
|
1243
|
+
// src/icon.constant.ts
|
|
1244
|
+
var ICON_SIZE_PILL = 12;
|
|
1245
|
+
var ICON_SIZE_INLINE = 14;
|
|
1246
|
+
var ICON_SIZE_ACTION = 16;
|
|
1247
|
+
|
|
1028
1248
|
// src/ChannelIcon.tsx
|
|
1029
1249
|
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1030
1250
|
var CHANNEL_BRAND_COLOR = {
|
|
@@ -1093,6 +1313,7 @@ var WINDOW_TITLE = {
|
|
|
1093
1313
|
[CONVERSATION_WINDOW.EXPIRED]: "Janela de 24h expirada \u2014 s\xF3 template"
|
|
1094
1314
|
};
|
|
1095
1315
|
var STALLED_THRESHOLD_MS = 60 * 60 * 1e3;
|
|
1316
|
+
var TAKEOVER_LABEL = "Continuar Atendimento";
|
|
1096
1317
|
var WINDOW_BAR_CLASS = {
|
|
1097
1318
|
[CONVERSATION_WINDOW.ALL]: "bg-transparent",
|
|
1098
1319
|
[CONVERSATION_WINDOW.FRESH]: "bg-green-500",
|
|
@@ -1122,7 +1343,7 @@ function ConversationRow({
|
|
|
1122
1343
|
"span",
|
|
1123
1344
|
{
|
|
1124
1345
|
className: cn("w-1 shrink-0", WINDOW_BAR_CLASS[window2], classNames?.windowBar),
|
|
1125
|
-
|
|
1346
|
+
"data-cv-tooltip": WINDOW_TITLE[window2],
|
|
1126
1347
|
"aria-label": WINDOW_TITLE[window2]
|
|
1127
1348
|
}
|
|
1128
1349
|
),
|
|
@@ -1155,25 +1376,56 @@ function ConversationRow({
|
|
|
1155
1376
|
" ",
|
|
1156
1377
|
capabilities.label
|
|
1157
1378
|
] }),
|
|
1158
|
-
conversation.mode === "human" ? /* @__PURE__ */
|
|
1159
|
-
|
|
1160
|
-
|
|
1379
|
+
conversation.mode === "human" ? /* @__PURE__ */ jsxs9("span", { className: "cv-pill cv-pill--success", children: [
|
|
1380
|
+
/* @__PURE__ */ jsx11(UserRound, { size: ICON_SIZE_PILL, "aria-hidden": "true" }),
|
|
1381
|
+
" em atendimento"
|
|
1382
|
+
] }) : null,
|
|
1383
|
+
isWaiting ? /* @__PURE__ */ jsxs9("span", { className: "cv-pill cv-pill--warning", children: [
|
|
1384
|
+
/* @__PURE__ */ jsx11(Hourglass, { size: ICON_SIZE_PILL, "aria-hidden": "true" }),
|
|
1385
|
+
" aguardando atendimento"
|
|
1386
|
+
] }) : null,
|
|
1387
|
+
!isWaiting && conversation.mode === "bot" ? /* @__PURE__ */ jsxs9("span", { className: "cv-pill", children: [
|
|
1388
|
+
/* @__PURE__ */ jsx11(Bot, { size: ICON_SIZE_PILL, "aria-hidden": "true" }),
|
|
1389
|
+
" bot ativo"
|
|
1390
|
+
] }) : null,
|
|
1161
1391
|
isStalled ? /* @__PURE__ */ jsxs9("span", { className: "cv-pill cv-pill--danger", children: [
|
|
1162
|
-
|
|
1392
|
+
/* @__PURE__ */ jsx11(AlarmClock, { size: ICON_SIZE_PILL, "aria-hidden": "true" }),
|
|
1393
|
+
" parada h\xE1",
|
|
1394
|
+
" ",
|
|
1163
1395
|
formatStalledFor(conversation.lastAt, now)
|
|
1164
1396
|
] }) : null,
|
|
1165
|
-
isWaiting ? /* @__PURE__ */
|
|
1397
|
+
isWaiting ? /* @__PURE__ */ jsxs9(
|
|
1398
|
+
"button",
|
|
1399
|
+
{
|
|
1400
|
+
type: "button",
|
|
1401
|
+
onClick: onTakeover,
|
|
1402
|
+
disabled: busy,
|
|
1403
|
+
"data-cv-tooltip": TAKEOVER_LABEL,
|
|
1404
|
+
"aria-label": TAKEOVER_LABEL,
|
|
1405
|
+
className: "cv-header-action",
|
|
1406
|
+
children: [
|
|
1407
|
+
/* @__PURE__ */ jsx11(Play, { size: ICON_SIZE_ACTION, "aria-hidden": "true" }),
|
|
1408
|
+
" ",
|
|
1409
|
+
TAKEOVER_LABEL
|
|
1410
|
+
]
|
|
1411
|
+
}
|
|
1412
|
+
) : null
|
|
1166
1413
|
] })
|
|
1167
1414
|
] })
|
|
1168
1415
|
] });
|
|
1169
1416
|
}
|
|
1170
1417
|
|
|
1171
1418
|
// src/ConversationHeader.tsx
|
|
1172
|
-
import { useState as
|
|
1419
|
+
import { useRef as useRef4, useState as useState6 } from "react";
|
|
1420
|
+
import { ArrowLeft, Bot as Bot2, Download, FileText, Headset, MoreVertical, UserRound as UserRound2, X } from "lucide-react";
|
|
1173
1421
|
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1422
|
+
var HEADER_UTILITIES_MIN_WIDTH = 720;
|
|
1423
|
+
var HEADER_ACTIONS_MIN_WIDTH = 600;
|
|
1174
1424
|
var DEFAULT_CONVERSATION_HEADER_LABELS = {
|
|
1175
|
-
|
|
1176
|
-
|
|
1425
|
+
// Sem emoji no rótulo: quem desenha o modo é o ícone ao lado, e o emoji embutido no texto voltava
|
|
1426
|
+
// a aparecer no tooltip e no leitor de tela como um caractere sem nome.
|
|
1427
|
+
botMode: "atendimento autom\xE1tico",
|
|
1428
|
+
humanMode: "atendimento humano",
|
|
1177
1429
|
returnToBot: "Devolver ao bot",
|
|
1178
1430
|
finish: "Finalizar",
|
|
1179
1431
|
takeover: "Assumir atendimento",
|
|
@@ -1203,31 +1455,71 @@ function ConversationHeader({
|
|
|
1203
1455
|
const displayHandle = formatContactHandle({ handle, channel: conversation.channel });
|
|
1204
1456
|
const flag = contactFlag({ handle, channel: conversation.channel });
|
|
1205
1457
|
const capabilities = capabilitiesOf(conversation.channel);
|
|
1206
|
-
const [menuOpen, setMenuOpen] =
|
|
1207
|
-
const
|
|
1208
|
-
|
|
1209
|
-
|
|
1458
|
+
const [menuOpen, setMenuOpen] = useState6(false);
|
|
1459
|
+
const headerRef = useRef4(null);
|
|
1460
|
+
const headerWidth = useContainerWidth(headerRef);
|
|
1461
|
+
const showsUtilitiesInline = headerWidth === void 0 || headerWidth >= HEADER_UTILITIES_MIN_WIDTH;
|
|
1462
|
+
const showsActionsInline = headerWidth === void 0 || headerWidth >= HEADER_ACTIONS_MIN_WIDTH;
|
|
1463
|
+
const utilityCandidates = [
|
|
1464
|
+
onOpenDocuments ? {
|
|
1465
|
+
key: "documents",
|
|
1466
|
+
icon: /* @__PURE__ */ jsx12(FileText, { size: ICON_SIZE_ACTION }),
|
|
1467
|
+
label: labels.documents,
|
|
1468
|
+
run: onOpenDocuments,
|
|
1469
|
+
active: documentsOpen
|
|
1470
|
+
} : void 0,
|
|
1471
|
+
onDownload ? {
|
|
1472
|
+
key: "download",
|
|
1473
|
+
icon: /* @__PURE__ */ jsx12(Download, { size: ICON_SIZE_ACTION }),
|
|
1474
|
+
label: labels.download,
|
|
1475
|
+
run: onDownload,
|
|
1476
|
+
active: false
|
|
1477
|
+
} : void 0,
|
|
1210
1478
|
...(extraUtilities ?? []).map((utility) => ({ ...utility, active: utility.active ?? false }))
|
|
1211
|
-
]
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1479
|
+
];
|
|
1480
|
+
const utilities = utilityCandidates.filter((utility) => Boolean(utility));
|
|
1481
|
+
const actionCandidates = [
|
|
1482
|
+
!isHuman && onTakeover ? {
|
|
1483
|
+
key: "takeover",
|
|
1484
|
+
icon: /* @__PURE__ */ jsx12(Headset, { size: ICON_SIZE_ACTION }),
|
|
1485
|
+
label: labels.takeover,
|
|
1486
|
+
hint: labels.takeover,
|
|
1487
|
+
run: onTakeover,
|
|
1488
|
+
className: "cv-header-action--primary"
|
|
1489
|
+
} : void 0,
|
|
1490
|
+
isHuman && onReturnToBot ? {
|
|
1491
|
+
key: "release",
|
|
1492
|
+
icon: /* @__PURE__ */ jsx12(Bot2, { size: ICON_SIZE_ACTION }),
|
|
1493
|
+
label: labels.returnToBot,
|
|
1494
|
+
hint: labels.returnToBot,
|
|
1495
|
+
run: onReturnToBot,
|
|
1496
|
+
className: ""
|
|
1497
|
+
} : void 0,
|
|
1498
|
+
isHuman && onFinish ? {
|
|
1499
|
+
key: "finish",
|
|
1500
|
+
icon: /* @__PURE__ */ jsx12(X, { size: ICON_SIZE_ACTION }),
|
|
1501
|
+
label: labels.finish,
|
|
1502
|
+
hint: labels.finish,
|
|
1503
|
+
run: onFinish,
|
|
1504
|
+
className: "cv-header-action--danger"
|
|
1505
|
+
} : void 0
|
|
1506
|
+
];
|
|
1507
|
+
const actions = actionCandidates.filter((action) => Boolean(action));
|
|
1219
1508
|
const menuItems = [
|
|
1220
|
-
...utilities.map((utility) => ({
|
|
1509
|
+
...showsUtilitiesInline ? [] : utilities.map((utility) => ({
|
|
1221
1510
|
key: utility.key,
|
|
1222
|
-
|
|
1511
|
+
icon: utility.icon,
|
|
1512
|
+
label: utility.label,
|
|
1513
|
+
hint: utility.label,
|
|
1223
1514
|
run: utility.run,
|
|
1224
1515
|
className: ""
|
|
1225
1516
|
})),
|
|
1226
|
-
...actions
|
|
1517
|
+
...showsActionsInline ? [] : actions
|
|
1227
1518
|
];
|
|
1228
1519
|
return /* @__PURE__ */ jsxs10(
|
|
1229
1520
|
"header",
|
|
1230
1521
|
{
|
|
1522
|
+
ref: headerRef,
|
|
1231
1523
|
className: cn(
|
|
1232
1524
|
"flex flex-nowrap items-center justify-between gap-3 border-b px-4 py-3",
|
|
1233
1525
|
classNames?.root,
|
|
@@ -1235,51 +1527,67 @@ function ConversationHeader({
|
|
|
1235
1527
|
),
|
|
1236
1528
|
children: [
|
|
1237
1529
|
/* @__PURE__ */ jsxs10("div", { className: cn("flex min-w-0 flex-1 items-center gap-3", classNames?.identity), children: [
|
|
1238
|
-
onBack ? /* @__PURE__ */ jsx12("button", { type: "button", onClick: onBack, className: "cv-back cv-touch", "aria-label": labels.back,
|
|
1530
|
+
onBack ? /* @__PURE__ */ jsx12("button", { type: "button", onClick: onBack, className: "cv-back cv-touch", "aria-label": labels.back, "data-cv-tooltip": labels.back, children: /* @__PURE__ */ jsx12(ArrowLeft, { size: ICON_SIZE_ACTION, "aria-hidden": "true" }) }) : null,
|
|
1239
1531
|
/* @__PURE__ */ jsx12(Avatar, { name: conversation.clientName, size: "md" }),
|
|
1240
1532
|
/* @__PURE__ */ jsxs10("div", { className: "min-w-0", children: [
|
|
1241
1533
|
/* @__PURE__ */ jsx12("p", { className: cn("truncate font-medium", classNames?.name), children: conversation.clientName ?? displayHandle }),
|
|
1242
|
-
/* @__PURE__ */ jsxs10("p", { className: cn("
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1534
|
+
/* @__PURE__ */ jsxs10("p", { className: cn("flex min-w-0 flex-nowrap items-center gap-2 overflow-hidden text-xs text-gray-500", classNames?.meta), children: [
|
|
1535
|
+
/* @__PURE__ */ jsxs10("span", { className: "truncate", children: [
|
|
1536
|
+
flag ? `${flag} ` : "",
|
|
1537
|
+
displayHandle
|
|
1538
|
+
] }),
|
|
1539
|
+
/* @__PURE__ */ jsxs10("span", { className: "inline-flex flex-shrink-0 items-center gap-1", children: [
|
|
1246
1540
|
/* @__PURE__ */ jsx12(ChannelIcon, { channel: conversation.channel }),
|
|
1247
|
-
/* @__PURE__ */ jsx12("span", {
|
|
1541
|
+
showsUtilitiesInline ? /* @__PURE__ */ jsx12("span", { children: capabilities.label }) : null
|
|
1248
1542
|
] }),
|
|
1249
|
-
/* @__PURE__ */
|
|
1250
|
-
|
|
1543
|
+
/* @__PURE__ */ jsxs10(
|
|
1544
|
+
"span",
|
|
1545
|
+
{
|
|
1546
|
+
className: "inline-flex flex-shrink-0 items-center gap-1",
|
|
1547
|
+
...showsUtilitiesInline ? {} : { role: "img", "aria-label": isHuman ? labels.humanMode : labels.botMode, "data-cv-tooltip": isHuman ? labels.humanMode : labels.botMode },
|
|
1548
|
+
children: [
|
|
1549
|
+
isHuman ? /* @__PURE__ */ jsx12(UserRound2, { size: ICON_SIZE_INLINE, "aria-hidden": "true" }) : /* @__PURE__ */ jsx12(Bot2, { size: ICON_SIZE_INLINE, "aria-hidden": "true" }),
|
|
1550
|
+
showsUtilitiesInline ? /* @__PURE__ */ jsx12("span", { children: isHuman ? labels.humanMode : labels.botMode }) : null
|
|
1551
|
+
]
|
|
1552
|
+
}
|
|
1553
|
+
)
|
|
1251
1554
|
] })
|
|
1252
1555
|
] })
|
|
1253
1556
|
] }),
|
|
1254
1557
|
/* @__PURE__ */ jsxs10("div", { className: cn("flex shrink-0 items-center gap-2", classNames?.actions), children: [
|
|
1255
|
-
/* @__PURE__ */ jsxs10("div", { className: cn("
|
|
1256
|
-
utilities.map((utility) => /* @__PURE__ */ jsx12(
|
|
1558
|
+
/* @__PURE__ */ jsxs10("div", { className: cn("flex items-center gap-2", classNames?.desktopActions), children: [
|
|
1559
|
+
(showsUtilitiesInline ? utilities : []).map((utility) => /* @__PURE__ */ jsx12(
|
|
1257
1560
|
"button",
|
|
1258
1561
|
{
|
|
1259
1562
|
type: "button",
|
|
1260
1563
|
onClick: utility.run,
|
|
1261
1564
|
disabled: busy,
|
|
1262
1565
|
"aria-pressed": utility.active,
|
|
1263
|
-
|
|
1566
|
+
"data-cv-tooltip": utility.label,
|
|
1264
1567
|
"aria-label": utility.label,
|
|
1265
1568
|
className: `cv-header-icon ${utility.active ? "cv-header-icon--active" : ""}`,
|
|
1266
1569
|
children: utility.icon
|
|
1267
1570
|
},
|
|
1268
1571
|
utility.key
|
|
1269
1572
|
)),
|
|
1270
|
-
actions.map((action) => /* @__PURE__ */
|
|
1573
|
+
(showsActionsInline ? actions : []).map((action) => /* @__PURE__ */ jsxs10(
|
|
1271
1574
|
"button",
|
|
1272
1575
|
{
|
|
1273
1576
|
type: "button",
|
|
1274
1577
|
onClick: action.run,
|
|
1275
1578
|
disabled: busy,
|
|
1579
|
+
"data-cv-tooltip": action.hint,
|
|
1580
|
+
"aria-label": action.hint,
|
|
1276
1581
|
className: `cv-header-action ${action.className}`,
|
|
1277
|
-
children:
|
|
1582
|
+
children: [
|
|
1583
|
+
action.icon,
|
|
1584
|
+
action.label
|
|
1585
|
+
]
|
|
1278
1586
|
},
|
|
1279
1587
|
action.key
|
|
1280
1588
|
))
|
|
1281
1589
|
] }),
|
|
1282
|
-
menuItems.length > 0 ? /* @__PURE__ */ jsxs10("div", { className: cn("cv-menu
|
|
1590
|
+
menuItems.length > 0 ? /* @__PURE__ */ jsxs10("div", { className: cn("cv-menu", classNames?.mobileMenu), children: [
|
|
1283
1591
|
/* @__PURE__ */ jsx12(
|
|
1284
1592
|
"button",
|
|
1285
1593
|
{
|
|
@@ -1287,12 +1595,12 @@ function ConversationHeader({
|
|
|
1287
1595
|
onClick: () => setMenuOpen(!menuOpen),
|
|
1288
1596
|
"aria-expanded": menuOpen,
|
|
1289
1597
|
"aria-label": labels.moreActions,
|
|
1290
|
-
|
|
1598
|
+
"data-cv-tooltip": labels.moreActions,
|
|
1291
1599
|
className: "cv-header-icon cv-touch",
|
|
1292
|
-
children: "
|
|
1600
|
+
children: /* @__PURE__ */ jsx12(MoreVertical, { size: ICON_SIZE_ACTION, "aria-hidden": "true" })
|
|
1293
1601
|
}
|
|
1294
1602
|
),
|
|
1295
|
-
menuOpen ? /* @__PURE__ */ jsx12("div", { className: "cv-menu-panel", role: "menu", children: menuItems.map((item) => /* @__PURE__ */
|
|
1603
|
+
menuOpen ? /* @__PURE__ */ jsx12("div", { className: "cv-menu-panel", role: "menu", children: menuItems.map((item) => /* @__PURE__ */ jsxs10(
|
|
1296
1604
|
"button",
|
|
1297
1605
|
{
|
|
1298
1606
|
type: "button",
|
|
@@ -1302,8 +1610,13 @@ function ConversationHeader({
|
|
|
1302
1610
|
item.run();
|
|
1303
1611
|
},
|
|
1304
1612
|
disabled: busy,
|
|
1613
|
+
"data-cv-tooltip": item.hint,
|
|
1614
|
+
"aria-label": item.hint,
|
|
1305
1615
|
className: `cv-header-action cv-touch ${item.className}`,
|
|
1306
|
-
children:
|
|
1616
|
+
children: [
|
|
1617
|
+
item.icon,
|
|
1618
|
+
item.label
|
|
1619
|
+
]
|
|
1307
1620
|
},
|
|
1308
1621
|
item.key
|
|
1309
1622
|
)) }) : null
|
|
@@ -1315,17 +1628,17 @@ function ConversationHeader({
|
|
|
1315
1628
|
}
|
|
1316
1629
|
|
|
1317
1630
|
// src/ConversationContextPanel.tsx
|
|
1318
|
-
import { useState as
|
|
1631
|
+
import { useState as useState8 } from "react";
|
|
1319
1632
|
import { Check, ChevronDown, ChevronUp, Clock, Pencil } from "lucide-react";
|
|
1320
1633
|
|
|
1321
1634
|
// src/useIsNarrow.ts
|
|
1322
|
-
import { useEffect as
|
|
1635
|
+
import { useEffect as useEffect5, useState as useState7 } from "react";
|
|
1323
1636
|
var NARROW_MAX_WIDTH_PX = 1023;
|
|
1324
1637
|
function useIsNarrow() {
|
|
1325
|
-
const [isNarrow, setIsNarrow] =
|
|
1638
|
+
const [isNarrow, setIsNarrow] = useState7(
|
|
1326
1639
|
() => typeof window !== "undefined" && window.matchMedia(`(max-width: ${NARROW_MAX_WIDTH_PX}px)`).matches
|
|
1327
1640
|
);
|
|
1328
|
-
|
|
1641
|
+
useEffect5(() => {
|
|
1329
1642
|
const query = window.matchMedia(`(max-width: ${NARROW_MAX_WIDTH_PX}px)`);
|
|
1330
1643
|
const handleChange = (event) => setIsNarrow(event.matches);
|
|
1331
1644
|
query.addEventListener("change", handleChange);
|
|
@@ -1387,7 +1700,7 @@ function ConversationContextPanel({
|
|
|
1387
1700
|
const counts = { completed: 0, pending: 0, editing: 0 };
|
|
1388
1701
|
for (const entry of entries) counts[statusOf(entry)] += 1;
|
|
1389
1702
|
const isNarrow = useIsNarrow();
|
|
1390
|
-
const [manualOpen, setManualOpen] =
|
|
1703
|
+
const [manualOpen, setManualOpen] = useState8(void 0);
|
|
1391
1704
|
const open = manualOpen ?? defaultOpen ?? (!isNarrow && counts.completed > 0);
|
|
1392
1705
|
return (
|
|
1393
1706
|
// Faixa azul clara com separador, como o wrapper do financiamento: sem ela o card encostava
|
|
@@ -1406,7 +1719,8 @@ function ConversationContextPanel({
|
|
|
1406
1719
|
type: "button",
|
|
1407
1720
|
onClick: () => setManualOpen(!open),
|
|
1408
1721
|
"aria-expanded": open,
|
|
1409
|
-
|
|
1722
|
+
"data-cv-tooltip": open ? labels.collapse : labels.expand,
|
|
1723
|
+
"aria-label": open ? labels.collapse : labels.expand,
|
|
1410
1724
|
className: cn(
|
|
1411
1725
|
"flex w-full cursor-pointer items-center justify-between gap-2 px-4 py-2.5 text-left transition-colors hover:bg-blue-100/40 dark:hover:bg-blue-900/20",
|
|
1412
1726
|
classNames?.toggle
|
|
@@ -1504,7 +1818,7 @@ function ConversationContextPanel({
|
|
|
1504
1818
|
"truncate text-center text-xs font-semibold",
|
|
1505
1819
|
entry.value ? "text-gray-900 dark:text-gray-100" : "italic font-normal text-gray-400 dark:text-gray-500"
|
|
1506
1820
|
),
|
|
1507
|
-
|
|
1821
|
+
"data-cv-tooltip": entry.value ?? labels.notCollected,
|
|
1508
1822
|
children: entry.value ?? labels.notCollected
|
|
1509
1823
|
}
|
|
1510
1824
|
)
|
|
@@ -1524,11 +1838,12 @@ function ConversationContextPanel({
|
|
|
1524
1838
|
}
|
|
1525
1839
|
|
|
1526
1840
|
// src/WindowExpiredNotice.tsx
|
|
1841
|
+
import { AlarmClock as AlarmClock2, Send } from "lucide-react";
|
|
1527
1842
|
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1528
1843
|
var DEFAULT_WINDOW_EXPIRED_LABELS = {
|
|
1529
|
-
title: "
|
|
1844
|
+
title: "Janela de 24h expirada \u2014 o WhatsApp n\xE3o aceita mensagens livres.",
|
|
1530
1845
|
description: "Envie uma mensagem de template para reabrir a conversa com o cliente.",
|
|
1531
|
-
sendTemplate: "
|
|
1846
|
+
sendTemplate: "Enviar Template (HSM)"
|
|
1532
1847
|
};
|
|
1533
1848
|
function WindowExpiredNotice({
|
|
1534
1849
|
onSendTemplate,
|
|
@@ -1538,9 +1853,15 @@ function WindowExpiredNotice({
|
|
|
1538
1853
|
}) {
|
|
1539
1854
|
const labels = { ...DEFAULT_WINDOW_EXPIRED_LABELS, ...labelsOverride };
|
|
1540
1855
|
return /* @__PURE__ */ jsxs12("div", { role: "status", className: cn("border-t bg-yellow-50 px-4 py-3 text-sm dark:bg-yellow-950", className), children: [
|
|
1541
|
-
/* @__PURE__ */
|
|
1856
|
+
/* @__PURE__ */ jsxs12("p", { className: "flex items-center gap-2 font-medium text-yellow-900 dark:text-yellow-200", children: [
|
|
1857
|
+
/* @__PURE__ */ jsx14(AlarmClock2, { size: ICON_SIZE_INLINE, "aria-hidden": "true", className: "shrink-0" }),
|
|
1858
|
+
labels.title
|
|
1859
|
+
] }),
|
|
1542
1860
|
/* @__PURE__ */ jsx14("p", { className: "text-yellow-800 dark:text-yellow-300", children: labels.description }),
|
|
1543
|
-
onSendTemplate ? /* @__PURE__ */
|
|
1861
|
+
onSendTemplate ? /* @__PURE__ */ jsxs12("button", { "data-cv-tooltip": labels.sendTemplate, "aria-label": labels.sendTemplate, type: "button", onClick: onSendTemplate, disabled, className: "cv-header-action mt-2", children: [
|
|
1862
|
+
/* @__PURE__ */ jsx14(Send, { size: ICON_SIZE_ACTION, "aria-hidden": "true" }),
|
|
1863
|
+
labels.sendTemplate
|
|
1864
|
+
] }) : null
|
|
1544
1865
|
] });
|
|
1545
1866
|
}
|
|
1546
1867
|
function isWindowBlocking(window2) {
|
|
@@ -1548,12 +1869,12 @@ function isWindowBlocking(window2) {
|
|
|
1548
1869
|
}
|
|
1549
1870
|
|
|
1550
1871
|
// src/documents/DocumentsWorkspace.tsx
|
|
1551
|
-
import { useEffect as
|
|
1552
|
-
import { Download, Eye, MessageSquare, Trash2, X as
|
|
1872
|
+
import { useEffect as useEffect7, useMemo as useMemo2, useState as useState11 } from "react";
|
|
1873
|
+
import { Download as Download2, Eye, MessageSquare, Trash2, X as X3 } from "lucide-react";
|
|
1553
1874
|
|
|
1554
1875
|
// src/listing/index.tsx
|
|
1555
|
-
import { useState as
|
|
1556
|
-
import { ArrowDown, ArrowUp, ArrowUpDown, ChevronDown as ChevronDown2, X } from "lucide-react";
|
|
1876
|
+
import { useState as useState9 } from "react";
|
|
1877
|
+
import { ArrowDown, ArrowUp, ArrowUpDown, ChevronDown as ChevronDown2, X as X2 } from "lucide-react";
|
|
1557
1878
|
import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1558
1879
|
function SortableHead({ label, field, activeField, direction, onSort, className }) {
|
|
1559
1880
|
const isActive = activeField === field;
|
|
@@ -1561,6 +1882,7 @@ function SortableHead({ label, field, activeField, direction, onSort, className
|
|
|
1561
1882
|
return /* @__PURE__ */ jsx15("th", { scope: "col", className: cn("px-3 py-2 text-left text-xs font-medium", className), children: /* @__PURE__ */ jsxs13(
|
|
1562
1883
|
"button",
|
|
1563
1884
|
{
|
|
1885
|
+
"data-cv-tooltip": label,
|
|
1564
1886
|
type: "button",
|
|
1565
1887
|
onClick: () => onSort(field),
|
|
1566
1888
|
"aria-label": label,
|
|
@@ -1573,7 +1895,7 @@ function SortableHead({ label, field, activeField, direction, onSort, className
|
|
|
1573
1895
|
) });
|
|
1574
1896
|
}
|
|
1575
1897
|
function MultiSelectFilter({ label, options, selected, onChange, className }) {
|
|
1576
|
-
const [open, setOpen] =
|
|
1898
|
+
const [open, setOpen] = useState9(false);
|
|
1577
1899
|
function toggle(value) {
|
|
1578
1900
|
onChange(selected.includes(value) ? selected.filter((item) => item !== value) : [...selected, value]);
|
|
1579
1901
|
}
|
|
@@ -1581,6 +1903,8 @@ function MultiSelectFilter({ label, options, selected, onChange, className }) {
|
|
|
1581
1903
|
/* @__PURE__ */ jsxs13(
|
|
1582
1904
|
"button",
|
|
1583
1905
|
{
|
|
1906
|
+
"data-cv-tooltip": label,
|
|
1907
|
+
"aria-label": label,
|
|
1584
1908
|
type: "button",
|
|
1585
1909
|
onClick: () => setOpen((current) => !current),
|
|
1586
1910
|
className: "cv-header-action inline-flex items-center gap-1",
|
|
@@ -1613,8 +1937,8 @@ function BulkActionBar({ selectedCount, selectedLabel, clearLabel, onClear, chil
|
|
|
1613
1937
|
return /* @__PURE__ */ jsxs13("div", { className: "cv-bulk-bar", role: "toolbar", "aria-label": selectedLabel(selectedCount), children: [
|
|
1614
1938
|
/* @__PURE__ */ jsx15("span", { className: "text-xs font-medium", children: selectedLabel(selectedCount) }),
|
|
1615
1939
|
children,
|
|
1616
|
-
/* @__PURE__ */ jsxs13("button", { type: "button", onClick: onClear, className: "cv-header-action ml-auto inline-flex items-center gap-1", children: [
|
|
1617
|
-
/* @__PURE__ */ jsx15(
|
|
1940
|
+
/* @__PURE__ */ jsxs13("button", { "data-cv-tooltip": clearLabel, "aria-label": clearLabel, type: "button", onClick: onClear, className: "cv-header-action ml-auto inline-flex items-center gap-1", children: [
|
|
1941
|
+
/* @__PURE__ */ jsx15(X2, { size: 12, "aria-hidden": "true" }),
|
|
1618
1942
|
clearLabel
|
|
1619
1943
|
] })
|
|
1620
1944
|
] });
|
|
@@ -1651,6 +1975,7 @@ function ListingPagination({
|
|
|
1651
1975
|
/* @__PURE__ */ jsx15(
|
|
1652
1976
|
"button",
|
|
1653
1977
|
{
|
|
1978
|
+
"data-cv-tooltip": labels.previous,
|
|
1654
1979
|
type: "button",
|
|
1655
1980
|
onClick: () => onPageChange(page - 1),
|
|
1656
1981
|
disabled: page <= 1,
|
|
@@ -1663,6 +1988,7 @@ function ListingPagination({
|
|
|
1663
1988
|
/* @__PURE__ */ jsx15(
|
|
1664
1989
|
"button",
|
|
1665
1990
|
{
|
|
1991
|
+
"data-cv-tooltip": labels.next,
|
|
1666
1992
|
type: "button",
|
|
1667
1993
|
onClick: () => onPageChange(page + 1),
|
|
1668
1994
|
disabled: page >= lastPage,
|
|
@@ -1676,7 +2002,7 @@ function ListingPagination({
|
|
|
1676
2002
|
}
|
|
1677
2003
|
|
|
1678
2004
|
// src/hooks/useUrlFilterState.ts
|
|
1679
|
-
import { useCallback as useCallback4, useEffect as
|
|
2005
|
+
import { useCallback as useCallback4, useEffect as useEffect6, useState as useState10 } from "react";
|
|
1680
2006
|
var LIST_SEPARATOR = ",";
|
|
1681
2007
|
function readParams() {
|
|
1682
2008
|
if (typeof window === "undefined") return new URLSearchParams();
|
|
@@ -1691,7 +2017,7 @@ function writeParam(key, value) {
|
|
|
1691
2017
|
window.history.replaceState(null, "", query ? `${window.location.pathname}?${query}` : window.location.pathname);
|
|
1692
2018
|
}
|
|
1693
2019
|
function useUrlStringState(key, initial, { enabled = true } = {}) {
|
|
1694
|
-
const [value, setValue] =
|
|
2020
|
+
const [value, setValue] = useState10(() => enabled ? readParams().get(key) ?? initial : initial);
|
|
1695
2021
|
const update = useCallback4(
|
|
1696
2022
|
(next) => {
|
|
1697
2023
|
setValue(next);
|
|
@@ -1702,7 +2028,7 @@ function useUrlStringState(key, initial, { enabled = true } = {}) {
|
|
|
1702
2028
|
return [value, update];
|
|
1703
2029
|
}
|
|
1704
2030
|
function useUrlNumberState(key, initial, { enabled = true } = {}) {
|
|
1705
|
-
const [value, setValue] =
|
|
2031
|
+
const [value, setValue] = useState10(() => {
|
|
1706
2032
|
if (!enabled) return initial;
|
|
1707
2033
|
const raw = Number(readParams().get(key));
|
|
1708
2034
|
return Number.isFinite(raw) && raw > 0 ? raw : initial;
|
|
@@ -1717,7 +2043,7 @@ function useUrlNumberState(key, initial, { enabled = true } = {}) {
|
|
|
1717
2043
|
return [value, update];
|
|
1718
2044
|
}
|
|
1719
2045
|
function useUrlArrayState(key, { enabled = true } = {}) {
|
|
1720
|
-
const [value, setValue] =
|
|
2046
|
+
const [value, setValue] = useState10(() => {
|
|
1721
2047
|
if (!enabled) return [];
|
|
1722
2048
|
const raw = readParams().get(key);
|
|
1723
2049
|
return raw ? raw.split(LIST_SEPARATOR).filter(Boolean) : [];
|
|
@@ -1732,8 +2058,8 @@ function useUrlArrayState(key, { enabled = true } = {}) {
|
|
|
1732
2058
|
return [value, update];
|
|
1733
2059
|
}
|
|
1734
2060
|
function useDebouncedValue(value, delayMs = 300) {
|
|
1735
|
-
const [debounced, setDebounced] =
|
|
1736
|
-
|
|
2061
|
+
const [debounced, setDebounced] = useState10(value);
|
|
2062
|
+
useEffect6(() => {
|
|
1737
2063
|
const timer = setTimeout(() => setDebounced(value), delayMs);
|
|
1738
2064
|
return () => clearTimeout(timer);
|
|
1739
2065
|
}, [value, delayMs]);
|
|
@@ -1813,14 +2139,14 @@ function DocumentsWorkspace({
|
|
|
1813
2139
|
const [sortDirection, setSortDirection] = useUrlStringState("sortDirection", "desc", urlOptions);
|
|
1814
2140
|
const [page, setPage] = useUrlNumberState("page", 1, urlOptions);
|
|
1815
2141
|
const [perPage, setPerPage] = useUrlNumberState("limit", initialPerPage, urlOptions);
|
|
1816
|
-
const [extra, setExtra] =
|
|
1817
|
-
const [documents, setDocuments] =
|
|
1818
|
-
const [total, setTotal] =
|
|
1819
|
-
const [loading, setLoading] =
|
|
1820
|
-
const [failed, setFailed] =
|
|
1821
|
-
const [selectedIds, setSelectedIds] =
|
|
1822
|
-
const [reloadToken, setReloadToken] =
|
|
1823
|
-
const [busy, setBusy] =
|
|
2142
|
+
const [extra, setExtra] = useState11({});
|
|
2143
|
+
const [documents, setDocuments] = useState11([]);
|
|
2144
|
+
const [total, setTotal] = useState11(0);
|
|
2145
|
+
const [loading, setLoading] = useState11(false);
|
|
2146
|
+
const [failed, setFailed] = useState11(false);
|
|
2147
|
+
const [selectedIds, setSelectedIds] = useState11(/* @__PURE__ */ new Set());
|
|
2148
|
+
const [reloadToken, setReloadToken] = useState11(0);
|
|
2149
|
+
const [busy, setBusy] = useState11(false);
|
|
1824
2150
|
const debouncedSearch = useDebouncedValue(search);
|
|
1825
2151
|
const fetchAll = context?.api.getAllDocuments;
|
|
1826
2152
|
const removeDocument = context?.api.deleteDocument;
|
|
@@ -1835,7 +2161,7 @@ function DocumentsWorkspace({
|
|
|
1835
2161
|
[categories, labels.categoryLabels]
|
|
1836
2162
|
);
|
|
1837
2163
|
const hasFilters = debouncedSearch !== "" || source.length > 0 || category.length > 0 || startDate !== "" || endDate !== "" || Object.keys(extra).length > 0;
|
|
1838
|
-
|
|
2164
|
+
useEffect7(() => {
|
|
1839
2165
|
if (!fetchAll) return;
|
|
1840
2166
|
let active = true;
|
|
1841
2167
|
setLoading(true);
|
|
@@ -1864,7 +2190,7 @@ function DocumentsWorkspace({
|
|
|
1864
2190
|
active = false;
|
|
1865
2191
|
};
|
|
1866
2192
|
}, [fetchAll, debouncedSearch, source, category, startDate, endDate, sortField, sortDirection, page, perPage, extraKey, reloadToken]);
|
|
1867
|
-
|
|
2193
|
+
useEffect7(() => {
|
|
1868
2194
|
setPage(1);
|
|
1869
2195
|
setSelectedIds(/* @__PURE__ */ new Set());
|
|
1870
2196
|
}, [debouncedSearch, source, category, startDate, endDate, perPage, extraKey]);
|
|
@@ -1928,6 +2254,7 @@ function DocumentsWorkspace({
|
|
|
1928
2254
|
const direction = sortDirection === "asc" ? "asc" : "desc";
|
|
1929
2255
|
const canSelect = Boolean(removeDocument ?? downloadArchive);
|
|
1930
2256
|
return /* @__PURE__ */ jsxs14("div", { className: cn("space-y-4", classNames?.root, className), children: [
|
|
2257
|
+
/* @__PURE__ */ jsx16(TooltipLayer, {}),
|
|
1931
2258
|
/* @__PURE__ */ jsxs14("header", { className: cn("space-y-0.5", classNames?.header), children: [
|
|
1932
2259
|
/* @__PURE__ */ jsx16("h2", { className: "text-lg font-semibold", children: labels.title }),
|
|
1933
2260
|
/* @__PURE__ */ jsx16("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: labels.subtitle(total) })
|
|
@@ -1977,8 +2304,8 @@ function DocumentsWorkspace({
|
|
|
1977
2304
|
)
|
|
1978
2305
|
] }) : null,
|
|
1979
2306
|
renderFilters?.({ extra, setExtra }),
|
|
1980
|
-
hasFilters ? /* @__PURE__ */ jsxs14("button", { type: "button", onClick: clearFilters, className: "cv-header-action inline-flex items-center gap-1", children: [
|
|
1981
|
-
/* @__PURE__ */ jsx16(
|
|
2307
|
+
hasFilters ? /* @__PURE__ */ jsxs14("button", { "data-cv-tooltip": labels.clearFilters, "aria-label": labels.clearFilters, type: "button", onClick: clearFilters, className: "cv-header-action inline-flex items-center gap-1", children: [
|
|
2308
|
+
/* @__PURE__ */ jsx16(X3, { size: 12, "aria-hidden": "true" }),
|
|
1982
2309
|
labels.clearFilters
|
|
1983
2310
|
] }) : null
|
|
1984
2311
|
] }),
|
|
@@ -1993,12 +2320,14 @@ function DocumentsWorkspace({
|
|
|
1993
2320
|
downloadArchive ? /* @__PURE__ */ jsxs14(
|
|
1994
2321
|
"button",
|
|
1995
2322
|
{
|
|
2323
|
+
"data-cv-tooltip": labels.bulkDownloadZip,
|
|
2324
|
+
"aria-label": labels.bulkDownloadZip,
|
|
1996
2325
|
type: "button",
|
|
1997
2326
|
onClick: () => void handleDownloadArchive(),
|
|
1998
2327
|
disabled: busy,
|
|
1999
2328
|
className: "cv-header-action inline-flex items-center gap-1 disabled:opacity-40",
|
|
2000
2329
|
children: [
|
|
2001
|
-
/* @__PURE__ */ jsx16(
|
|
2330
|
+
/* @__PURE__ */ jsx16(Download2, { size: 12, "aria-hidden": "true" }),
|
|
2002
2331
|
labels.bulkDownloadZip
|
|
2003
2332
|
]
|
|
2004
2333
|
}
|
|
@@ -2006,6 +2335,8 @@ function DocumentsWorkspace({
|
|
|
2006
2335
|
removeDocument ? /* @__PURE__ */ jsxs14(
|
|
2007
2336
|
"button",
|
|
2008
2337
|
{
|
|
2338
|
+
"data-cv-tooltip": labels.bulkRemove(selectedIds.size),
|
|
2339
|
+
"aria-label": labels.bulkRemove(selectedIds.size),
|
|
2009
2340
|
type: "button",
|
|
2010
2341
|
onClick: () => {
|
|
2011
2342
|
if (window.confirm(labels.bulkRemoveConfirm(selectedIds.size))) void handleRemove(Array.from(selectedIds));
|
|
@@ -2057,14 +2388,15 @@ function DocumentsWorkspace({
|
|
|
2057
2388
|
) }) : null,
|
|
2058
2389
|
/* @__PURE__ */ jsx16("td", { className: "max-w-xs px-3 py-2", children: /* @__PURE__ */ jsxs14("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
2059
2390
|
/* @__PURE__ */ jsx16(FileIcon, { filename: document2.filename, mimeType: document2.mimeType }),
|
|
2060
|
-
/* @__PURE__ */ jsx16("span", { className: "truncate font-medium",
|
|
2391
|
+
/* @__PURE__ */ jsx16("span", { className: "truncate font-medium", "data-cv-tooltip": document2.filename, children: document2.filename })
|
|
2061
2392
|
] }) }),
|
|
2062
2393
|
/* @__PURE__ */ jsx16("td", { className: "hidden px-3 py-2 sm:table-cell", children: onOpenConversation ? /* @__PURE__ */ jsxs14(
|
|
2063
2394
|
"button",
|
|
2064
2395
|
{
|
|
2065
2396
|
type: "button",
|
|
2066
2397
|
onClick: () => onOpenConversation(document2.conversationId),
|
|
2067
|
-
|
|
2398
|
+
"data-cv-tooltip": labels.openConversation,
|
|
2399
|
+
"aria-label": labels.openConversation,
|
|
2068
2400
|
className: "cv-header-action inline-flex items-center gap-1",
|
|
2069
2401
|
children: [
|
|
2070
2402
|
/* @__PURE__ */ jsx16(MessageSquare, { size: 12, "aria-hidden": "true" }),
|
|
@@ -2082,7 +2414,7 @@ function DocumentsWorkspace({
|
|
|
2082
2414
|
{
|
|
2083
2415
|
type: "button",
|
|
2084
2416
|
onClick: () => void handleOpen(document2.id, "inline"),
|
|
2085
|
-
|
|
2417
|
+
"data-cv-tooltip": labels.view,
|
|
2086
2418
|
"aria-label": `${labels.view}: ${document2.filename}`,
|
|
2087
2419
|
className: "cv-header-icon",
|
|
2088
2420
|
children: /* @__PURE__ */ jsx16(Eye, { size: 14 })
|
|
@@ -2093,10 +2425,10 @@ function DocumentsWorkspace({
|
|
|
2093
2425
|
{
|
|
2094
2426
|
type: "button",
|
|
2095
2427
|
onClick: () => void handleOpen(document2.id, "attachment"),
|
|
2096
|
-
|
|
2428
|
+
"data-cv-tooltip": labels.download,
|
|
2097
2429
|
"aria-label": `${labels.download}: ${document2.filename}`,
|
|
2098
2430
|
className: "cv-header-icon",
|
|
2099
|
-
children: /* @__PURE__ */ jsx16(
|
|
2431
|
+
children: /* @__PURE__ */ jsx16(Download2, { size: 14 })
|
|
2100
2432
|
}
|
|
2101
2433
|
),
|
|
2102
2434
|
removeDocument ? /* @__PURE__ */ jsx16(
|
|
@@ -2107,7 +2439,7 @@ function DocumentsWorkspace({
|
|
|
2107
2439
|
if (window.confirm(labels.removeConfirm(document2.filename))) void handleRemove([document2.id]);
|
|
2108
2440
|
},
|
|
2109
2441
|
disabled: busy,
|
|
2110
|
-
|
|
2442
|
+
"data-cv-tooltip": labels.remove,
|
|
2111
2443
|
"aria-label": `${labels.remove}: ${document2.filename}`,
|
|
2112
2444
|
className: "cv-header-icon disabled:opacity-40",
|
|
2113
2445
|
children: /* @__PURE__ */ jsx16(Trash2, { size: 14, className: "text-red-500" })
|
|
@@ -2184,7 +2516,7 @@ function downloadTextFile(filename, content) {
|
|
|
2184
2516
|
}
|
|
2185
2517
|
|
|
2186
2518
|
// src/useWaitingNotifications.ts
|
|
2187
|
-
import { useState as
|
|
2519
|
+
import { useState as useState12, useEffect as useEffect8, useRef as useRef5, useCallback as useCallback5 } from "react";
|
|
2188
2520
|
var DEFAULT_POLL_INTERVAL_MS = 1e4;
|
|
2189
2521
|
var DEFAULT_LIMIT = 50;
|
|
2190
2522
|
var DEFAULT_LABELS = {
|
|
@@ -2193,10 +2525,10 @@ var DEFAULT_LABELS = {
|
|
|
2193
2525
|
};
|
|
2194
2526
|
function useWaitingNotifications(params) {
|
|
2195
2527
|
const conversationsContext = useConversations();
|
|
2196
|
-
const [conversations, setConversations] =
|
|
2197
|
-
const previousUnreadMap =
|
|
2198
|
-
const notifiedIds =
|
|
2199
|
-
const isPollingRef =
|
|
2528
|
+
const [conversations, setConversations] = useState12([]);
|
|
2529
|
+
const previousUnreadMap = useRef5(/* @__PURE__ */ new Map());
|
|
2530
|
+
const notifiedIds = useRef5(/* @__PURE__ */ new Set());
|
|
2531
|
+
const isPollingRef = useRef5(false);
|
|
2200
2532
|
const isEnabled = params?.enabled ?? true;
|
|
2201
2533
|
const intervalMs = params?.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
2202
2534
|
const icon = params?.icon;
|
|
@@ -2228,7 +2560,7 @@ function useWaitingNotifications(params) {
|
|
|
2228
2560
|
isPollingRef.current = false;
|
|
2229
2561
|
}
|
|
2230
2562
|
}, [conversationsContext, listParams, icon, labelTitle, labelBody]);
|
|
2231
|
-
|
|
2563
|
+
useEffect8(() => {
|
|
2232
2564
|
if (!isEnabled) return;
|
|
2233
2565
|
if (typeof window !== "undefined" && "Notification" in window && Notification.permission === "default") {
|
|
2234
2566
|
Notification.requestPermission();
|
|
@@ -2314,6 +2646,8 @@ function WhatsAppTemplateSettingsForm({
|
|
|
2314
2646
|
/* @__PURE__ */ jsxs15(
|
|
2315
2647
|
"button",
|
|
2316
2648
|
{
|
|
2649
|
+
"data-cv-tooltip": labels.refreshList,
|
|
2650
|
+
"aria-label": labels.refreshList,
|
|
2317
2651
|
type: "button",
|
|
2318
2652
|
onClick: onRefreshTemplates,
|
|
2319
2653
|
disabled: loadingTemplates,
|
|
@@ -2363,6 +2697,8 @@ function WhatsAppTemplateSettingsForm({
|
|
|
2363
2697
|
/* @__PURE__ */ jsxs15(
|
|
2364
2698
|
"button",
|
|
2365
2699
|
{
|
|
2700
|
+
"data-cv-tooltip": labels.addVariable,
|
|
2701
|
+
"aria-label": labels.addVariable,
|
|
2366
2702
|
type: "button",
|
|
2367
2703
|
onClick: () => onVariablesChange([...variables, ""]),
|
|
2368
2704
|
className: "flex items-center gap-1 text-xs text-blue-600 dark:text-blue-400 hover:underline",
|
|
@@ -2380,7 +2716,8 @@ function WhatsAppTemplateSettingsForm({
|
|
|
2380
2716
|
{
|
|
2381
2717
|
type: "button",
|
|
2382
2718
|
onClick: () => insertVariable(available.token),
|
|
2383
|
-
|
|
2719
|
+
"data-cv-tooltip": `Inserir ${available.token}`,
|
|
2720
|
+
"aria-label": `Inserir ${available.token}`,
|
|
2384
2721
|
className: "inline-flex items-center gap-1 rounded-md border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-800 px-2 py-1 text-xs hover:border-blue-400 dark:hover:border-blue-500 transition-colors",
|
|
2385
2722
|
children: [
|
|
2386
2723
|
/* @__PURE__ */ jsx17("code", { className: "text-blue-600 dark:text-blue-300", children: available.token }),
|
|
@@ -2414,7 +2751,8 @@ function WhatsAppTemplateSettingsForm({
|
|
|
2414
2751
|
type: "button",
|
|
2415
2752
|
onClick: () => removeVariable(index),
|
|
2416
2753
|
className: "text-gray-400 hover:text-red-500 dark:hover:text-red-400 transition-colors flex-shrink-0",
|
|
2417
|
-
|
|
2754
|
+
"data-cv-tooltip": labels.removeVariable,
|
|
2755
|
+
"aria-label": labels.removeVariable,
|
|
2418
2756
|
children: /* @__PURE__ */ jsx17(Trash22, { size: 14 })
|
|
2419
2757
|
}
|
|
2420
2758
|
)
|
|
@@ -2424,6 +2762,8 @@ function WhatsAppTemplateSettingsForm({
|
|
|
2424
2762
|
/* @__PURE__ */ jsx17("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs15(
|
|
2425
2763
|
"button",
|
|
2426
2764
|
{
|
|
2765
|
+
"data-cv-tooltip": saving ? labels.saving : labels.save,
|
|
2766
|
+
"aria-label": saving ? labels.saving : labels.save,
|
|
2427
2767
|
type: "submit",
|
|
2428
2768
|
disabled: saving || !selectedTemplateName.trim(),
|
|
2429
2769
|
className: "flex items-center gap-2 bg-blue-600 hover:bg-blue-700 disabled:bg-blue-400 text-white font-semibold px-5 py-2.5 rounded-xl transition-colors text-sm",
|
|
@@ -2661,6 +3001,8 @@ function WhatsAppCreateTemplateForm({
|
|
|
2661
3001
|
/* @__PURE__ */ jsx18("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs16(
|
|
2662
3002
|
"button",
|
|
2663
3003
|
{
|
|
3004
|
+
"data-cv-tooltip": submitting ? labels.sending : labels.sendForApproval,
|
|
3005
|
+
"aria-label": submitting ? labels.sending : labels.sendForApproval,
|
|
2664
3006
|
type: "submit",
|
|
2665
3007
|
disabled: submitting || !value.name || !value.bodyText,
|
|
2666
3008
|
className: "flex items-center gap-2 bg-emerald-600 hover:bg-emerald-700 disabled:bg-emerald-400 text-white font-semibold px-5 py-2.5 rounded-xl transition-colors text-sm",
|
|
@@ -2743,6 +3085,8 @@ function WelcomeFarewellForm({
|
|
|
2743
3085
|
/* @__PURE__ */ jsx19("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs17(
|
|
2744
3086
|
"button",
|
|
2745
3087
|
{
|
|
3088
|
+
"data-cv-tooltip": saving ? labels.saving : labels.save,
|
|
3089
|
+
"aria-label": saving ? labels.saving : labels.save,
|
|
2746
3090
|
type: "submit",
|
|
2747
3091
|
disabled: saving,
|
|
2748
3092
|
className: "flex items-center gap-2 bg-blue-600 hover:bg-blue-700 disabled:bg-blue-400 text-white font-semibold px-5 py-2.5 rounded-xl transition-colors text-sm",
|
|
@@ -2835,6 +3179,8 @@ function TranscriptionSettingsForm({
|
|
|
2835
3179
|
/* @__PURE__ */ jsx20("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs18(
|
|
2836
3180
|
"button",
|
|
2837
3181
|
{
|
|
3182
|
+
"data-cv-tooltip": saving ? labels.saving : labels.save,
|
|
3183
|
+
"aria-label": saving ? labels.saving : labels.save,
|
|
2838
3184
|
type: "submit",
|
|
2839
3185
|
disabled: saving || !isAvailable,
|
|
2840
3186
|
className: "flex items-center gap-2 bg-blue-600 hover:bg-blue-700 disabled:bg-blue-400 text-white font-semibold px-5 py-2.5 rounded-xl transition-colors text-sm",
|
|
@@ -2881,7 +3227,7 @@ function ModeOption({
|
|
|
2881
3227
|
}
|
|
2882
3228
|
|
|
2883
3229
|
// src/settings/WhatsAppTemplatesSettings.tsx
|
|
2884
|
-
import { useState as
|
|
3230
|
+
import { useState as useState13 } from "react";
|
|
2885
3231
|
import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2886
3232
|
var TEMPLATE_SETTINGS_TAB = {
|
|
2887
3233
|
SELECT: "select",
|
|
@@ -2898,12 +3244,14 @@ function WhatsAppTemplatesSettings({
|
|
|
2898
3244
|
...settingsProps
|
|
2899
3245
|
}) {
|
|
2900
3246
|
const labels = { ...DEFAULT_TEMPLATES_SETTINGS_LABELS, ...labelsOverride };
|
|
2901
|
-
const [tab, setTab] =
|
|
3247
|
+
const [tab, setTab] = useState13(TEMPLATE_SETTINGS_TAB.SELECT);
|
|
2902
3248
|
return /* @__PURE__ */ jsxs19("div", { className: "space-y-4", children: [
|
|
2903
3249
|
/* @__PURE__ */ jsxs19("nav", { className: "flex gap-1 border-b", role: "tablist", children: [
|
|
2904
3250
|
/* @__PURE__ */ jsx21(
|
|
2905
3251
|
"button",
|
|
2906
3252
|
{
|
|
3253
|
+
"data-cv-tooltip": labels.selectTab,
|
|
3254
|
+
"aria-label": labels.selectTab,
|
|
2907
3255
|
type: "button",
|
|
2908
3256
|
role: "tab",
|
|
2909
3257
|
"aria-selected": tab === TEMPLATE_SETTINGS_TAB.SELECT,
|
|
@@ -2915,6 +3263,8 @@ function WhatsAppTemplatesSettings({
|
|
|
2915
3263
|
create ? /* @__PURE__ */ jsx21(
|
|
2916
3264
|
"button",
|
|
2917
3265
|
{
|
|
3266
|
+
"data-cv-tooltip": labels.createTab,
|
|
3267
|
+
"aria-label": labels.createTab,
|
|
2918
3268
|
type: "button",
|
|
2919
3269
|
role: "tab",
|
|
2920
3270
|
"aria-selected": tab === TEMPLATE_SETTINGS_TAB.CREATE,
|
|
@@ -2963,6 +3313,8 @@ function TopicsForm({
|
|
|
2963
3313
|
/* @__PURE__ */ jsx22(
|
|
2964
3314
|
"button",
|
|
2965
3315
|
{
|
|
3316
|
+
"data-cv-tooltip": topic.label,
|
|
3317
|
+
"aria-label": topic.label,
|
|
2966
3318
|
type: "button",
|
|
2967
3319
|
onClick: () => onToggle(topic.key),
|
|
2968
3320
|
className: `relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none ${topic.enabled ? "bg-blue-600 dark:bg-blue-500" : "bg-gray-200 dark:bg-gray-700"}`,
|
|
@@ -2993,6 +3345,8 @@ function TopicsForm({
|
|
|
2993
3345
|
/* @__PURE__ */ jsxs20(
|
|
2994
3346
|
"button",
|
|
2995
3347
|
{
|
|
3348
|
+
"data-cv-tooltip": labels.saveButton,
|
|
3349
|
+
"aria-label": labels.saveButton,
|
|
2996
3350
|
type: "submit",
|
|
2997
3351
|
disabled: saving,
|
|
2998
3352
|
className: "inline-flex items-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700 disabled:opacity-50",
|
|
@@ -3009,7 +3363,7 @@ function TopicsForm({
|
|
|
3009
3363
|
}
|
|
3010
3364
|
|
|
3011
3365
|
// src/settings/MessagesWorkspace.tsx
|
|
3012
|
-
import { useCallback as useCallback6, useEffect as
|
|
3366
|
+
import { useCallback as useCallback6, useEffect as useEffect9, useState as useState14 } from "react";
|
|
3013
3367
|
import { jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
3014
3368
|
var DEFAULT_LABELS7 = {
|
|
3015
3369
|
title: "Mensagens",
|
|
@@ -3065,26 +3419,26 @@ function MessagesWorkspace({
|
|
|
3065
3419
|
const hasTopics = Boolean(api.getTopics && api.saveTopics);
|
|
3066
3420
|
const hasTemplates = Boolean(api.getTemplateSettings && api.saveTemplateSettings);
|
|
3067
3421
|
const hasTranscription = Boolean(api.getTranscription && api.saveTranscription);
|
|
3068
|
-
const [tab, setTab] =
|
|
3069
|
-
const [loadState, setLoadState] =
|
|
3070
|
-
const [messages, setMessages] =
|
|
3071
|
-
const [savingMessages, setSavingMessages] =
|
|
3072
|
-
const [messagesSaved, setMessagesSaved] =
|
|
3073
|
-
const [topics, setTopics] =
|
|
3074
|
-
const [savingTopics, setSavingTopics] =
|
|
3075
|
-
const [topicsSaved, setTopicsSaved] =
|
|
3076
|
-
const [templateSettings, setTemplateSettings] =
|
|
3077
|
-
const [templates, setTemplates] =
|
|
3078
|
-
const [loadingTemplates, setLoadingTemplates] =
|
|
3079
|
-
const [templatesError, setTemplatesError] =
|
|
3080
|
-
const [savingTemplate, setSavingTemplate] =
|
|
3081
|
-
const [templateSaved, setTemplateSaved] =
|
|
3082
|
-
const [createTemplate, setCreateTemplate] =
|
|
3083
|
-
const [creatingTemplate, setCreatingTemplate] =
|
|
3084
|
-
const [createResult, setCreateResult] =
|
|
3085
|
-
const [transcription, setTranscription] =
|
|
3086
|
-
const [savingTranscription, setSavingTranscription] =
|
|
3087
|
-
const [transcriptionSaved, setTranscriptionSaved] =
|
|
3422
|
+
const [tab, setTab] = useState14(MESSAGES_TAB.BOT);
|
|
3423
|
+
const [loadState, setLoadState] = useState14("loading");
|
|
3424
|
+
const [messages, setMessages] = useState14(EMPTY_MESSAGES);
|
|
3425
|
+
const [savingMessages, setSavingMessages] = useState14(false);
|
|
3426
|
+
const [messagesSaved, setMessagesSaved] = useState14(false);
|
|
3427
|
+
const [topics, setTopics] = useState14([]);
|
|
3428
|
+
const [savingTopics, setSavingTopics] = useState14(false);
|
|
3429
|
+
const [topicsSaved, setTopicsSaved] = useState14(false);
|
|
3430
|
+
const [templateSettings, setTemplateSettings] = useState14(EMPTY_TEMPLATE_SETTINGS);
|
|
3431
|
+
const [templates, setTemplates] = useState14([]);
|
|
3432
|
+
const [loadingTemplates, setLoadingTemplates] = useState14(false);
|
|
3433
|
+
const [templatesError, setTemplatesError] = useState14(false);
|
|
3434
|
+
const [savingTemplate, setSavingTemplate] = useState14(false);
|
|
3435
|
+
const [templateSaved, setTemplateSaved] = useState14(false);
|
|
3436
|
+
const [createTemplate, setCreateTemplate] = useState14(EMPTY_CREATE_TEMPLATE);
|
|
3437
|
+
const [creatingTemplate, setCreatingTemplate] = useState14(false);
|
|
3438
|
+
const [createResult, setCreateResult] = useState14(null);
|
|
3439
|
+
const [transcription, setTranscription] = useState14(UNDECIDED_TRANSCRIPTION);
|
|
3440
|
+
const [savingTranscription, setSavingTranscription] = useState14(false);
|
|
3441
|
+
const [transcriptionSaved, setTranscriptionSaved] = useState14(false);
|
|
3088
3442
|
const reloadTemplates = useCallback6(async () => {
|
|
3089
3443
|
if (!api.listTemplates) return;
|
|
3090
3444
|
setLoadingTemplates(true);
|
|
@@ -3097,7 +3451,7 @@ function MessagesWorkspace({
|
|
|
3097
3451
|
setLoadingTemplates(false);
|
|
3098
3452
|
}
|
|
3099
3453
|
}, [api]);
|
|
3100
|
-
|
|
3454
|
+
useEffect9(() => {
|
|
3101
3455
|
let active = true;
|
|
3102
3456
|
async function load() {
|
|
3103
3457
|
try {
|
|
@@ -3122,7 +3476,7 @@ function MessagesWorkspace({
|
|
|
3122
3476
|
active = false;
|
|
3123
3477
|
};
|
|
3124
3478
|
}, [api]);
|
|
3125
|
-
|
|
3479
|
+
useEffect9(() => {
|
|
3126
3480
|
void reloadTemplates();
|
|
3127
3481
|
}, [reloadTemplates]);
|
|
3128
3482
|
function flash(setter) {
|
|
@@ -3213,6 +3567,7 @@ function MessagesWorkspace({
|
|
|
3213
3567
|
...hasTranscription ? [{ id: MESSAGES_TAB.TRANSCRIPTION, label: labels.tabTranscription }] : []
|
|
3214
3568
|
];
|
|
3215
3569
|
return /* @__PURE__ */ jsxs21("div", { className: `space-y-6 p-4 lg:p-0 ${className ?? ""}`, children: [
|
|
3570
|
+
/* @__PURE__ */ jsx23(TooltipLayer, {}),
|
|
3216
3571
|
/* @__PURE__ */ jsxs21("header", { children: [
|
|
3217
3572
|
/* @__PURE__ */ jsx23("h1", { className: "text-xl font-semibold text-gray-900 dark:text-gray-100", children: labels.title }),
|
|
3218
3573
|
/* @__PURE__ */ jsx23("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: labels.subtitle })
|
|
@@ -3220,6 +3575,8 @@ function MessagesWorkspace({
|
|
|
3220
3575
|
tabs.length > 1 ? /* @__PURE__ */ jsx23("nav", { className: "flex gap-1 border-b border-gray-200 dark:border-gray-700", role: "tablist", children: tabs.map((item) => /* @__PURE__ */ jsx23(
|
|
3221
3576
|
"button",
|
|
3222
3577
|
{
|
|
3578
|
+
"data-cv-tooltip": item.label,
|
|
3579
|
+
"aria-label": item.label,
|
|
3223
3580
|
type: "button",
|
|
3224
3581
|
role: "tab",
|
|
3225
3582
|
"aria-selected": tab === item.id,
|
|
@@ -3351,16 +3708,16 @@ function useConversationMessages(conversationId, params) {
|
|
|
3351
3708
|
}
|
|
3352
3709
|
|
|
3353
3710
|
// src/hooks/useScrollToLatestMessage.ts
|
|
3354
|
-
import { useCallback as useCallback8, useLayoutEffect, useRef as
|
|
3711
|
+
import { useCallback as useCallback8, useLayoutEffect, useRef as useRef6, useState as useState15 } from "react";
|
|
3355
3712
|
var NEAR_BOTTOM_THRESHOLD_PX = 120;
|
|
3356
3713
|
var SCROLL_BEHAVIOR = "auto";
|
|
3357
3714
|
function useScrollToLatestMessage({
|
|
3358
3715
|
conversationId,
|
|
3359
3716
|
messageCount
|
|
3360
3717
|
}) {
|
|
3361
|
-
const containerRef =
|
|
3362
|
-
const [isAwayFromBottom, setIsAwayFromBottom] =
|
|
3363
|
-
const isAwayFromBottomRef =
|
|
3718
|
+
const containerRef = useRef6(null);
|
|
3719
|
+
const [isAwayFromBottom, setIsAwayFromBottom] = useState15(false);
|
|
3720
|
+
const isAwayFromBottomRef = useRef6(false);
|
|
3364
3721
|
const scrollToBottom = useCallback8((behavior = SCROLL_BEHAVIOR) => {
|
|
3365
3722
|
const container = containerRef.current;
|
|
3366
3723
|
if (!container) return;
|
|
@@ -3373,7 +3730,7 @@ function useScrollToLatestMessage({
|
|
|
3373
3730
|
isAwayFromBottomRef.current = away;
|
|
3374
3731
|
setIsAwayFromBottom((current) => current === away ? current : away);
|
|
3375
3732
|
}, []);
|
|
3376
|
-
const jumpedForConversationRef =
|
|
3733
|
+
const jumpedForConversationRef = useRef6(void 0);
|
|
3377
3734
|
useLayoutEffect(() => {
|
|
3378
3735
|
const isNewConversation = jumpedForConversationRef.current !== conversationId;
|
|
3379
3736
|
if (isNewConversation) {
|
|
@@ -3420,36 +3777,36 @@ function useConversationContext(conversationId) {
|
|
|
3420
3777
|
}
|
|
3421
3778
|
|
|
3422
3779
|
// src/hooks/useConversationRealtime.ts
|
|
3423
|
-
import { useEffect as
|
|
3780
|
+
import { useEffect as useEffect10, useRef as useRef7 } from "react";
|
|
3424
3781
|
function useConversationRealtime(conversationId, onEvent) {
|
|
3425
|
-
const
|
|
3426
|
-
const onEventRef =
|
|
3782
|
+
const sse = useConversations()?.sse;
|
|
3783
|
+
const onEventRef = useRef7(onEvent);
|
|
3427
3784
|
onEventRef.current = onEvent;
|
|
3428
|
-
|
|
3429
|
-
if (!
|
|
3430
|
-
const source =
|
|
3785
|
+
useEffect10(() => {
|
|
3786
|
+
if (!sse || !conversationId) return;
|
|
3787
|
+
const source = sse.connectConversationStream(conversationId);
|
|
3431
3788
|
const handler = (event) => onEventRef.current(event);
|
|
3432
3789
|
source.addEventListener("message", handler);
|
|
3433
3790
|
return () => {
|
|
3434
3791
|
source.removeEventListener("message", handler);
|
|
3435
3792
|
source.close();
|
|
3436
3793
|
};
|
|
3437
|
-
}, [
|
|
3794
|
+
}, [sse, conversationId]);
|
|
3438
3795
|
}
|
|
3439
3796
|
function useGlobalRealtime(onEvent) {
|
|
3440
|
-
const
|
|
3441
|
-
const onEventRef =
|
|
3797
|
+
const sse = useConversations()?.sse;
|
|
3798
|
+
const onEventRef = useRef7(onEvent);
|
|
3442
3799
|
onEventRef.current = onEvent;
|
|
3443
|
-
|
|
3444
|
-
if (!
|
|
3445
|
-
const source =
|
|
3800
|
+
useEffect10(() => {
|
|
3801
|
+
if (!sse) return;
|
|
3802
|
+
const source = sse.connectGlobalStream();
|
|
3446
3803
|
const handler = (event) => onEventRef.current(event);
|
|
3447
3804
|
source.addEventListener("message", handler);
|
|
3448
3805
|
return () => {
|
|
3449
3806
|
source.removeEventListener("message", handler);
|
|
3450
3807
|
source.close();
|
|
3451
3808
|
};
|
|
3452
|
-
}, [
|
|
3809
|
+
}, [sse]);
|
|
3453
3810
|
}
|
|
3454
3811
|
|
|
3455
3812
|
// src/hooks/useConversationActions.ts
|
|
@@ -3485,10 +3842,11 @@ function useInboxActions() {
|
|
|
3485
3842
|
}
|
|
3486
3843
|
|
|
3487
3844
|
// src/workspace/ConversationsWorkspace.tsx
|
|
3488
|
-
import { useEffect as
|
|
3845
|
+
import { useEffect as useEffect14, useMemo as useMemo6, useState as useState19 } from "react";
|
|
3846
|
+
import { Check as Check2, CheckCheck, FlaskConical, Hourglass as Hourglass2, Mail as Mail2, MessagesSquare } from "lucide-react";
|
|
3489
3847
|
|
|
3490
3848
|
// src/workspace/BulkTemplateModal.tsx
|
|
3491
|
-
import { useEffect as
|
|
3849
|
+
import { useEffect as useEffect11, useMemo as useMemo4, useState as useState16 } from "react";
|
|
3492
3850
|
import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
3493
3851
|
function BulkTemplateModal({
|
|
3494
3852
|
labels,
|
|
@@ -3502,10 +3860,10 @@ function BulkTemplateModal({
|
|
|
3502
3860
|
throw new Error("BulkTemplateModal requires an ancestor <ConversationsProvider>");
|
|
3503
3861
|
}
|
|
3504
3862
|
const { api } = context;
|
|
3505
|
-
const [templates, setTemplates] =
|
|
3506
|
-
const [search, setSearch] =
|
|
3507
|
-
const [selected, setSelected] =
|
|
3508
|
-
|
|
3863
|
+
const [templates, setTemplates] = useState16([]);
|
|
3864
|
+
const [search, setSearch] = useState16("");
|
|
3865
|
+
const [selected, setSelected] = useState16("");
|
|
3866
|
+
useEffect11(() => {
|
|
3509
3867
|
let active = true;
|
|
3510
3868
|
void api.listTemplates?.().then((loaded) => {
|
|
3511
3869
|
if (active) setTemplates(loaded);
|
|
@@ -3526,7 +3884,7 @@ function BulkTemplateModal({
|
|
|
3526
3884
|
/* @__PURE__ */ jsx24("h3", { children: labels.templateModalTitle }),
|
|
3527
3885
|
/* @__PURE__ */ jsx24("p", { children: labels.templateModalAvailable(templates.length) })
|
|
3528
3886
|
] }),
|
|
3529
|
-
/* @__PURE__ */ jsx24("button", { type: "button", onClick: onClose, "aria-label": labels.templateModalCancel, children: "\u2715" })
|
|
3887
|
+
/* @__PURE__ */ jsx24("button", { "data-cv-tooltip": labels.templateModalCancel, type: "button", onClick: onClose, "aria-label": labels.templateModalCancel, children: "\u2715" })
|
|
3530
3888
|
] }),
|
|
3531
3889
|
/* @__PURE__ */ jsx24("div", { className: "cv-workspace-modal__search", children: /* @__PURE__ */ jsx24(
|
|
3532
3890
|
"input",
|
|
@@ -3543,6 +3901,8 @@ function BulkTemplateModal({
|
|
|
3543
3901
|
filtered.map((template) => /* @__PURE__ */ jsxs22(
|
|
3544
3902
|
"button",
|
|
3545
3903
|
{
|
|
3904
|
+
"data-cv-tooltip": template.name,
|
|
3905
|
+
"aria-label": template.name,
|
|
3546
3906
|
type: "button",
|
|
3547
3907
|
onClick: () => setSelected(template.name === selected ? "" : template.name),
|
|
3548
3908
|
"aria-pressed": template.name === selected,
|
|
@@ -3560,10 +3920,12 @@ function BulkTemplateModal({
|
|
|
3560
3920
|
] }),
|
|
3561
3921
|
expiredCount === 0 ? /* @__PURE__ */ jsx24("p", { className: "cv-workspace-modal__warning", children: labels.templateModalNoneExpired }) : null,
|
|
3562
3922
|
/* @__PURE__ */ jsxs22("footer", { className: "cv-workspace-modal__footer", children: [
|
|
3563
|
-
/* @__PURE__ */ jsx24("button", { type: "button", onClick: onClose, children: labels.templateModalCancel }),
|
|
3923
|
+
/* @__PURE__ */ jsx24("button", { "data-cv-tooltip": labels.templateModalCancel, "aria-label": labels.templateModalCancel, type: "button", onClick: onClose, children: labels.templateModalCancel }),
|
|
3564
3924
|
/* @__PURE__ */ jsx24(
|
|
3565
3925
|
"button",
|
|
3566
3926
|
{
|
|
3927
|
+
"data-cv-tooltip": sending ? labels.templateModalSending : labels.templateModalSend(expiredCount),
|
|
3928
|
+
"aria-label": sending ? labels.templateModalSending : labels.templateModalSend(expiredCount),
|
|
3567
3929
|
type: "button",
|
|
3568
3930
|
disabled: sending || expiredCount === 0,
|
|
3569
3931
|
onClick: () => onSend(selected || void 0),
|
|
@@ -3575,7 +3937,7 @@ function BulkTemplateModal({
|
|
|
3575
3937
|
}
|
|
3576
3938
|
|
|
3577
3939
|
// src/workspace/ConversationPane.tsx
|
|
3578
|
-
import { useEffect as
|
|
3940
|
+
import { useEffect as useEffect12, useRef as useRef8, useState as useState17 } from "react";
|
|
3579
3941
|
import { jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
3580
3942
|
function ConversationPane({
|
|
3581
3943
|
conversation,
|
|
@@ -3609,12 +3971,14 @@ function ConversationPane({
|
|
|
3609
3971
|
const { api } = context;
|
|
3610
3972
|
const { messages, refetch } = useConversationMessages(conversation.id);
|
|
3611
3973
|
const { context: conversationContext } = useConversationContext(conversation.id);
|
|
3612
|
-
const [documentsOpen, setDocumentsOpen] =
|
|
3613
|
-
const [sendFailure, setSendFailure] =
|
|
3614
|
-
const [selectedMessageIds, setSelectedMessageIds] =
|
|
3615
|
-
const [draft, setDraft] =
|
|
3616
|
-
const [queuedFiles, setQueuedFiles] =
|
|
3617
|
-
|
|
3974
|
+
const [documentsOpen, setDocumentsOpen] = useState17(false);
|
|
3975
|
+
const [sendFailure, setSendFailure] = useState17(void 0);
|
|
3976
|
+
const [selectedMessageIds, setSelectedMessageIds] = useState17(/* @__PURE__ */ new Set());
|
|
3977
|
+
const [draft, setDraft] = useState17(initialComposerText ?? "");
|
|
3978
|
+
const [queuedFiles, setQueuedFiles] = useState17([]);
|
|
3979
|
+
const [isSendingDraft, setIsSendingDraft] = useState17(false);
|
|
3980
|
+
const sendInFlightRef = useRef8(false);
|
|
3981
|
+
useEffect12(() => {
|
|
3618
3982
|
setSelectedMessageIds(/* @__PURE__ */ new Set());
|
|
3619
3983
|
setDraft(initialComposerText ?? "");
|
|
3620
3984
|
setQueuedFiles([]);
|
|
@@ -3646,25 +4010,40 @@ function ConversationPane({
|
|
|
3646
4010
|
try {
|
|
3647
4011
|
await action();
|
|
3648
4012
|
await refetch();
|
|
4013
|
+
return true;
|
|
3649
4014
|
} catch (error) {
|
|
3650
4015
|
setSendFailure(error instanceof Error ? error.message : fallback);
|
|
4016
|
+
return false;
|
|
3651
4017
|
}
|
|
3652
4018
|
}
|
|
3653
4019
|
async function handleSend(text) {
|
|
3654
|
-
|
|
4020
|
+
return runSend(() => api.sendMessage(conversation.id, text), labels.sendFailure);
|
|
4021
|
+
}
|
|
4022
|
+
async function handleSendTemplate() {
|
|
4023
|
+
if (conversation.mode !== "human" && onTakeover) await onTakeover();
|
|
4024
|
+
await runSend(() => api.sendTemplate(conversation.id, {}), labels.sendFailure);
|
|
3655
4025
|
}
|
|
3656
4026
|
async function handleRichSend() {
|
|
3657
|
-
if (
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
4027
|
+
if (sendInFlightRef.current) return;
|
|
4028
|
+
sendInFlightRef.current = true;
|
|
4029
|
+
setIsSendingDraft(true);
|
|
4030
|
+
try {
|
|
4031
|
+
if (onSendAttachments && queuedFiles.length > 0) {
|
|
4032
|
+
const files = queuedFiles;
|
|
4033
|
+
const caption = draft;
|
|
4034
|
+
const didSend = await runSend(() => onSendAttachments(files, caption), labels.attachFailure);
|
|
4035
|
+
if (didSend) {
|
|
4036
|
+
setQueuedFiles([]);
|
|
4037
|
+
setDraft("");
|
|
4038
|
+
}
|
|
4039
|
+
return;
|
|
4040
|
+
}
|
|
4041
|
+
if (!draft.trim()) return;
|
|
4042
|
+
if (await handleSend(draft)) setDraft("");
|
|
4043
|
+
} finally {
|
|
4044
|
+
sendInFlightRef.current = false;
|
|
4045
|
+
setIsSendingDraft(false);
|
|
3664
4046
|
}
|
|
3665
|
-
if (!draft.trim()) return;
|
|
3666
|
-
await handleSend(draft);
|
|
3667
|
-
setDraft("");
|
|
3668
4047
|
}
|
|
3669
4048
|
async function handleAttach(file) {
|
|
3670
4049
|
if (!onAttach) return;
|
|
@@ -3738,8 +4117,8 @@ function ConversationPane({
|
|
|
3738
4117
|
messageSelection && selectedMessageIds.size > 0 ? /* @__PURE__ */ jsxs23("div", { className: "cv-workspace-selection", children: [
|
|
3739
4118
|
/* @__PURE__ */ jsx25("span", { children: labels.messagesSelected(selectedMessageIds.size) }),
|
|
3740
4119
|
/* @__PURE__ */ jsxs23("div", { className: "cv-workspace-selection__actions", children: [
|
|
3741
|
-
/* @__PURE__ */ jsx25("button", { type: "button", onClick: () => setSelectedMessageIds(/* @__PURE__ */ new Set()), children: labels.bulkClear }),
|
|
3742
|
-
/* @__PURE__ */ jsx25("button", { type: "button", onClick: copySelectedMessages, children: labels.copySelected })
|
|
4120
|
+
/* @__PURE__ */ jsx25("button", { "data-cv-tooltip": labels.bulkClear, "aria-label": labels.bulkClear, type: "button", onClick: () => setSelectedMessageIds(/* @__PURE__ */ new Set()), children: labels.bulkClear }),
|
|
4121
|
+
/* @__PURE__ */ jsx25("button", { "data-cv-tooltip": labels.copySelected, "aria-label": labels.copySelected, type: "button", onClick: copySelectedMessages, children: labels.copySelected })
|
|
3743
4122
|
] })
|
|
3744
4123
|
] }) : null,
|
|
3745
4124
|
sendFailure ? /* @__PURE__ */ jsx25("p", { role: "alert", className: "cv-workspace-alert", children: sendFailure }) : null,
|
|
@@ -3747,7 +4126,7 @@ function ConversationPane({
|
|
|
3747
4126
|
WindowExpiredNotice,
|
|
3748
4127
|
{
|
|
3749
4128
|
disabled: busy,
|
|
3750
|
-
onSendTemplate: () => void
|
|
4129
|
+
onSendTemplate: () => void handleSendTemplate()
|
|
3751
4130
|
}
|
|
3752
4131
|
) : botOwnsConversation ? (
|
|
3753
4132
|
// Responder com a conversa no bot atropelaria o fluxo automático no meio de uma pergunta.
|
|
@@ -3764,7 +4143,8 @@ function ConversationPane({
|
|
|
3764
4143
|
}
|
|
3765
4144
|
} : {},
|
|
3766
4145
|
placeholder: labels.composerPlaceholder,
|
|
3767
|
-
isSending: busy,
|
|
4146
|
+
isSending: busy || isSendingDraft,
|
|
4147
|
+
hasQueuedAttachments: queuedFiles.length > 0,
|
|
3768
4148
|
...onRecordAudio ? {
|
|
3769
4149
|
idleAction: /* @__PURE__ */ jsx25(
|
|
3770
4150
|
AudioRecorderButton,
|
|
@@ -3780,6 +4160,7 @@ function ConversationPane({
|
|
|
3780
4160
|
/* @__PURE__ */ jsx25(
|
|
3781
4161
|
"button",
|
|
3782
4162
|
{
|
|
4163
|
+
"data-cv-tooltip": labels.attachmentRemove,
|
|
3783
4164
|
type: "button",
|
|
3784
4165
|
"aria-label": labels.attachmentRemove,
|
|
3785
4166
|
onClick: () => setQueuedFiles((current) => current.filter((_, position) => position !== index)),
|
|
@@ -3822,11 +4203,13 @@ function ConversationsInboxList({
|
|
|
3822
4203
|
hasSelection ? /* @__PURE__ */ jsxs24("div", { className: "cv-workspace-bulk", children: [
|
|
3823
4204
|
/* @__PURE__ */ jsx26("span", { className: "cv-workspace-bulk__count", children: labels.bulkSelected(inbox.selectedIds.size) }),
|
|
3824
4205
|
/* @__PURE__ */ jsxs24("div", { className: "cv-workspace-bulk__actions", children: [
|
|
3825
|
-
/* @__PURE__ */ jsx26("button", { type: "button", onClick: inbox.clearBulkSelection, children: labels.bulkClear }),
|
|
3826
|
-
onSendTemplateToSelected ? /* @__PURE__ */ jsx26("button", { type: "button", onClick: onSendTemplateToSelected, disabled: inbox.busy, children: labels.bulkTemplate }) : null,
|
|
4206
|
+
/* @__PURE__ */ jsx26("button", { "data-cv-tooltip": labels.bulkClear, "aria-label": labels.bulkClear, type: "button", onClick: inbox.clearBulkSelection, children: labels.bulkClear }),
|
|
4207
|
+
onSendTemplateToSelected ? /* @__PURE__ */ jsx26("button", { "data-cv-tooltip": labels.bulkTemplate, "aria-label": labels.bulkTemplate, type: "button", onClick: onSendTemplateToSelected, disabled: inbox.busy, children: labels.bulkTemplate }) : null,
|
|
3827
4208
|
inbox.canFinalize ? /* @__PURE__ */ jsx26(
|
|
3828
4209
|
"button",
|
|
3829
4210
|
{
|
|
4211
|
+
"data-cv-tooltip": labels.bulkFinalize,
|
|
4212
|
+
"aria-label": labels.bulkFinalize,
|
|
3830
4213
|
type: "button",
|
|
3831
4214
|
disabled: inbox.busy,
|
|
3832
4215
|
onClick: () => {
|
|
@@ -3853,17 +4236,20 @@ function ConversationsInboxList({
|
|
|
3853
4236
|
),
|
|
3854
4237
|
/* @__PURE__ */ jsxs24("div", { className: "cv-workspace-chips", children: [
|
|
3855
4238
|
/* @__PURE__ */ jsx26("span", { className: "cv-workspace-chips__legend", children: labels.windowLegend }),
|
|
3856
|
-
WINDOW_FILTERS.map((filter) => /* @__PURE__ */
|
|
4239
|
+
WINDOW_FILTERS.map((filter) => /* @__PURE__ */ jsx26(
|
|
3857
4240
|
"button",
|
|
3858
4241
|
{
|
|
3859
4242
|
type: "button",
|
|
3860
4243
|
onClick: () => inbox.setWindowFilter(filter.value),
|
|
3861
4244
|
"aria-pressed": inbox.windowFilter === filter.value,
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
4245
|
+
"data-cv-tooltip": filter.label,
|
|
4246
|
+
"aria-label": filter.label,
|
|
4247
|
+
className: [
|
|
4248
|
+
"cv-workspace-chip",
|
|
4249
|
+
filter.tone ? `cv-workspace-chip--${filter.tone}` : "",
|
|
4250
|
+
inbox.windowFilter === filter.value ? "cv-workspace-chip--on" : ""
|
|
4251
|
+
].filter(Boolean).join(" "),
|
|
4252
|
+
children: filter.label
|
|
3867
4253
|
},
|
|
3868
4254
|
filter.value
|
|
3869
4255
|
))
|
|
@@ -3873,6 +4259,8 @@ function ConversationsInboxList({
|
|
|
3873
4259
|
inbox.channelFilters.map((filter) => /* @__PURE__ */ jsxs24(
|
|
3874
4260
|
"button",
|
|
3875
4261
|
{
|
|
4262
|
+
"data-cv-tooltip": filter.label,
|
|
4263
|
+
"aria-label": filter.label,
|
|
3876
4264
|
type: "button",
|
|
3877
4265
|
onClick: () => inbox.setChannelFilter(filter.value),
|
|
3878
4266
|
"aria-pressed": inbox.channelFilter === filter.value,
|
|
@@ -3913,14 +4301,15 @@ function ConversationsInboxList({
|
|
|
3913
4301
|
/* @__PURE__ */ jsxs24("div", { className: "cv-workspace-pager", children: [
|
|
3914
4302
|
/* @__PURE__ */ jsx26("span", { children: labels.rangeOf(inbox.firstOnPage, inbox.lastOnPage, inbox.filteredCount) }),
|
|
3915
4303
|
/* @__PURE__ */ jsxs24("div", { className: "cv-workspace-pager__buttons", children: [
|
|
3916
|
-
/* @__PURE__ */ jsx26("button", { type: "button", onClick: () => inbox.goToPage(1), disabled: inbox.page === 1, "aria-label": "
|
|
4304
|
+
/* @__PURE__ */ jsx26("button", { type: "button", onClick: () => inbox.goToPage(1), disabled: inbox.page === 1, "aria-label": PAGINATION_LABELS.first, "data-cv-tooltip": PAGINATION_LABELS.first, children: "\xAB" }),
|
|
3917
4305
|
/* @__PURE__ */ jsx26(
|
|
3918
4306
|
"button",
|
|
3919
4307
|
{
|
|
3920
4308
|
type: "button",
|
|
3921
4309
|
onClick: () => inbox.goToPage(inbox.page - 1),
|
|
3922
4310
|
disabled: inbox.page === 1,
|
|
3923
|
-
"aria-label":
|
|
4311
|
+
"aria-label": PAGINATION_LABELS.previous,
|
|
4312
|
+
"data-cv-tooltip": PAGINATION_LABELS.previous,
|
|
3924
4313
|
children: "\u2039"
|
|
3925
4314
|
}
|
|
3926
4315
|
),
|
|
@@ -3931,7 +4320,8 @@ function ConversationsInboxList({
|
|
|
3931
4320
|
type: "button",
|
|
3932
4321
|
onClick: () => inbox.goToPage(inbox.page + 1),
|
|
3933
4322
|
disabled: inbox.page === inbox.pageCount,
|
|
3934
|
-
"aria-label":
|
|
4323
|
+
"aria-label": PAGINATION_LABELS.next,
|
|
4324
|
+
"data-cv-tooltip": PAGINATION_LABELS.next,
|
|
3935
4325
|
children: "\u203A"
|
|
3936
4326
|
}
|
|
3937
4327
|
),
|
|
@@ -3941,7 +4331,8 @@ function ConversationsInboxList({
|
|
|
3941
4331
|
type: "button",
|
|
3942
4332
|
onClick: () => inbox.goToPage(inbox.pageCount),
|
|
3943
4333
|
disabled: inbox.page === inbox.pageCount,
|
|
3944
|
-
"aria-label":
|
|
4334
|
+
"aria-label": PAGINATION_LABELS.last,
|
|
4335
|
+
"data-cv-tooltip": PAGINATION_LABELS.last,
|
|
3945
4336
|
children: "\xBB"
|
|
3946
4337
|
}
|
|
3947
4338
|
)
|
|
@@ -3992,7 +4383,7 @@ var DEFAULT_CONVERSATIONS_WORKSPACE_LABELS = {
|
|
|
3992
4383
|
};
|
|
3993
4384
|
|
|
3994
4385
|
// src/workspace/useConversationsInbox.ts
|
|
3995
|
-
import { useCallback as useCallback9, useEffect as
|
|
4386
|
+
import { useCallback as useCallback9, useEffect as useEffect13, useMemo as useMemo5, useRef as useRef9, useState as useState18 } from "react";
|
|
3996
4387
|
var CONVERSATIONS_PER_PAGE = 50;
|
|
3997
4388
|
function defaultDescribeFailure(error) {
|
|
3998
4389
|
const status = error.status;
|
|
@@ -4010,14 +4401,14 @@ function useConversationsInbox(params = {}) {
|
|
|
4010
4401
|
const perPage = params.perPage ?? CONVERSATIONS_PER_PAGE;
|
|
4011
4402
|
const markReadOnOpen = params.markReadOnOpen ?? true;
|
|
4012
4403
|
const describeFailure = params.describeFailure ?? defaultDescribeFailure;
|
|
4013
|
-
const [waitingOnly, setWaitingOnly] =
|
|
4014
|
-
const [windowFilter, setWindowFilter] =
|
|
4015
|
-
const [channelFilter, setChannelFilter] =
|
|
4016
|
-
const [search, setSearch] =
|
|
4017
|
-
const [page, setPage] =
|
|
4018
|
-
const [selectedId, setSelectedId] =
|
|
4019
|
-
const [selectedIds, setSelectedIds] =
|
|
4020
|
-
const [busy, setBusy] =
|
|
4404
|
+
const [waitingOnly, setWaitingOnly] = useState18(false);
|
|
4405
|
+
const [windowFilter, setWindowFilter] = useState18(CONVERSATION_WINDOW.ALL);
|
|
4406
|
+
const [channelFilter, setChannelFilter] = useState18(CHANNEL_FILTER_ALL);
|
|
4407
|
+
const [search, setSearch] = useState18("");
|
|
4408
|
+
const [page, setPage] = useState18(1);
|
|
4409
|
+
const [selectedId, setSelectedId] = useState18(void 0);
|
|
4410
|
+
const [selectedIds, setSelectedIds] = useState18(/* @__PURE__ */ new Set());
|
|
4411
|
+
const [busy, setBusy] = useState18(false);
|
|
4021
4412
|
const { conversations, total, loading, error, refetch } = useConversationList({
|
|
4022
4413
|
...waitingOnly ? { waitingHuman: true } : {},
|
|
4023
4414
|
...search ? { search } : {},
|
|
@@ -4042,16 +4433,16 @@ function useConversationsInbox(params = {}) {
|
|
|
4042
4433
|
const pageCount = Math.max(1, Math.ceil(totalForPaging / perPage));
|
|
4043
4434
|
const currentPage = Math.min(page, pageCount);
|
|
4044
4435
|
const pageConversations = params.serverPaginated ? filtered : filtered.slice((currentPage - 1) * perPage, currentPage * perPage);
|
|
4045
|
-
|
|
4436
|
+
useEffect13(() => {
|
|
4046
4437
|
setPage(1);
|
|
4047
4438
|
}, [search, waitingOnly, windowFilter, channelFilter]);
|
|
4048
|
-
|
|
4439
|
+
useEffect13(() => {
|
|
4049
4440
|
if (selectedId && !conversations.some((conversation) => conversation.id === selectedId)) {
|
|
4050
4441
|
setSelectedId(void 0);
|
|
4051
4442
|
}
|
|
4052
4443
|
}, [conversations, selectedId]);
|
|
4053
|
-
const lastMarkReadAttempt =
|
|
4054
|
-
|
|
4444
|
+
const lastMarkReadAttempt = useRef9(void 0);
|
|
4445
|
+
useEffect13(() => {
|
|
4055
4446
|
if (!markReadOnOpen || !selectedId) return;
|
|
4056
4447
|
const opened = conversations.find((conversation) => conversation.id === selectedId);
|
|
4057
4448
|
if (!opened || opened.unread === 0) return;
|
|
@@ -4111,8 +4502,11 @@ function useConversationsInbox(params = {}) {
|
|
|
4111
4502
|
selectedConversation: conversations.find((conversation) => conversation.id === selectedId),
|
|
4112
4503
|
loading,
|
|
4113
4504
|
now,
|
|
4114
|
-
|
|
4115
|
-
|
|
4505
|
+
// Com paginação no servidor `conversations` é só a página, então contar o array mostrava o
|
|
4506
|
+
// tamanho da página no lugar do tamanho da base. Não lidas e aguardando seguem sendo da página:
|
|
4507
|
+
// somar a base inteira exige agregado do servidor, que a listagem não devolve.
|
|
4508
|
+
totalCount: params.serverPaginated ? total : conversations.length,
|
|
4509
|
+
unreadCount: conversations.reduce((sum, conversation) => sum + conversation.unread, 0),
|
|
4116
4510
|
waitingCount: conversations.filter((conversation) => conversation.waitingHuman).length,
|
|
4117
4511
|
filteredCount: totalForPaging,
|
|
4118
4512
|
expiredSelectedCount: conversations.filter(
|
|
@@ -4211,10 +4605,10 @@ function ConversationsWorkspace({
|
|
|
4211
4605
|
...markReadOnOpen === void 0 ? {} : { markReadOnOpen },
|
|
4212
4606
|
...serverPaginated ? { serverPaginated } : {}
|
|
4213
4607
|
});
|
|
4214
|
-
const [simulatorOpen, setSimulatorOpen] =
|
|
4215
|
-
const [templateModalOpen, setTemplateModalOpen] =
|
|
4216
|
-
const [openedFromLink, setOpenedFromLink] =
|
|
4217
|
-
|
|
4608
|
+
const [simulatorOpen, setSimulatorOpen] = useState19(false);
|
|
4609
|
+
const [templateModalOpen, setTemplateModalOpen] = useState19(false);
|
|
4610
|
+
const [openedFromLink, setOpenedFromLink] = useState19(void 0);
|
|
4611
|
+
useEffect14(() => {
|
|
4218
4612
|
const link = initialConversationId ?? initialWhatsappNumber;
|
|
4219
4613
|
if (!link || openedFromLink === link) return;
|
|
4220
4614
|
const target = inbox.conversations.find(
|
|
@@ -4235,7 +4629,7 @@ function ConversationsWorkspace({
|
|
|
4235
4629
|
...fromProduct,
|
|
4236
4630
|
{
|
|
4237
4631
|
key: "simulator",
|
|
4238
|
-
icon: simulator?.icon ??
|
|
4632
|
+
icon: simulator?.icon ?? /* @__PURE__ */ jsx27(FlaskConical, { size: ICON_SIZE_ACTION }),
|
|
4239
4633
|
label: simulator?.label ?? "Simular cliente",
|
|
4240
4634
|
active: simulatorOpen,
|
|
4241
4635
|
run: () => setSimulatorOpen((open) => !open)
|
|
@@ -4243,28 +4637,32 @@ function ConversationsWorkspace({
|
|
|
4243
4637
|
];
|
|
4244
4638
|
}, [selected, extraUtilitiesFor, simulatorEnabled, simulator, simulatorOpen]);
|
|
4245
4639
|
return /* @__PURE__ */ jsxs25("div", { className: `cv-workspace${className ? ` ${className}` : ""}`, children: [
|
|
4640
|
+
/* @__PURE__ */ jsx27(TooltipLayer, {}),
|
|
4246
4641
|
/* @__PURE__ */ jsxs25("header", { className: "cv-workspace-header", children: [
|
|
4247
4642
|
/* @__PURE__ */ jsxs25("div", { className: "cv-workspace-header__titles", children: [
|
|
4248
4643
|
/* @__PURE__ */ jsx27("h1", { children: labels.title }),
|
|
4249
4644
|
/* @__PURE__ */ jsxs25("p", { children: [
|
|
4250
|
-
/* @__PURE__ */ jsxs25("span", {
|
|
4251
|
-
|
|
4645
|
+
/* @__PURE__ */ jsxs25("span", { "data-cv-tooltip": labels.conversations, className: "cv-stat", children: [
|
|
4646
|
+
/* @__PURE__ */ jsx27(MessagesSquare, { size: ICON_SIZE_INLINE, "aria-hidden": "true" }),
|
|
4647
|
+
" ",
|
|
4252
4648
|
inbox.totalCount,
|
|
4253
4649
|
/* @__PURE__ */ jsxs25("span", { className: "cv-only-wide", children: [
|
|
4254
4650
|
" ",
|
|
4255
4651
|
labels.conversations
|
|
4256
4652
|
] })
|
|
4257
4653
|
] }),
|
|
4258
|
-
/* @__PURE__ */ jsxs25("span", {
|
|
4259
|
-
"
|
|
4654
|
+
/* @__PURE__ */ jsxs25("span", { "data-cv-tooltip": labels.waiting, className: "cv-stat cv-workspace-header__waiting", children: [
|
|
4655
|
+
/* @__PURE__ */ jsx27(Hourglass2, { size: ICON_SIZE_INLINE, "aria-hidden": "true" }),
|
|
4656
|
+
" ",
|
|
4260
4657
|
inbox.waitingCount,
|
|
4261
4658
|
/* @__PURE__ */ jsxs25("span", { className: "cv-only-wide", children: [
|
|
4262
4659
|
" ",
|
|
4263
4660
|
labels.waiting
|
|
4264
4661
|
] })
|
|
4265
4662
|
] }),
|
|
4266
|
-
/* @__PURE__ */ jsxs25("span", {
|
|
4267
|
-
"
|
|
4663
|
+
/* @__PURE__ */ jsxs25("span", { "data-cv-tooltip": labels.unread, className: "cv-stat", children: [
|
|
4664
|
+
/* @__PURE__ */ jsx27(Mail2, { size: ICON_SIZE_INLINE, "aria-hidden": "true" }),
|
|
4665
|
+
" ",
|
|
4268
4666
|
inbox.unreadCount,
|
|
4269
4667
|
/* @__PURE__ */ jsxs25("span", { className: "cv-only-wide", children: [
|
|
4270
4668
|
" ",
|
|
@@ -4280,14 +4678,12 @@ function ConversationsWorkspace({
|
|
|
4280
4678
|
type: "button",
|
|
4281
4679
|
onClick: () => inbox.setWaitingOnly(!inbox.waitingOnly),
|
|
4282
4680
|
"aria-pressed": inbox.waitingOnly,
|
|
4283
|
-
|
|
4681
|
+
"data-cv-tooltip": labels.waitingOnly,
|
|
4682
|
+
"aria-label": labels.waitingOnly,
|
|
4284
4683
|
className: inbox.waitingOnly ? "cv-workspace-toggle cv-workspace-toggle--on" : "cv-workspace-toggle",
|
|
4285
4684
|
children: [
|
|
4286
|
-
"
|
|
4287
|
-
/* @__PURE__ */
|
|
4288
|
-
" ",
|
|
4289
|
-
labels.waitingOnly
|
|
4290
|
-
] })
|
|
4685
|
+
/* @__PURE__ */ jsx27(Hourglass2, { size: ICON_SIZE_ACTION, "aria-hidden": "true" }),
|
|
4686
|
+
/* @__PURE__ */ jsx27("span", { className: "cv-only-wide", children: labels.waitingOnly })
|
|
4291
4687
|
]
|
|
4292
4688
|
}
|
|
4293
4689
|
),
|
|
@@ -4297,16 +4693,17 @@ function ConversationsWorkspace({
|
|
|
4297
4693
|
type: "button",
|
|
4298
4694
|
onClick: () => void inbox.markSelectedAsRead(),
|
|
4299
4695
|
disabled: inbox.selectedIds.size === 0 || inbox.busy,
|
|
4300
|
-
|
|
4696
|
+
"data-cv-tooltip": labels.markSelectedAsRead,
|
|
4301
4697
|
"aria-label": labels.markSelectedAsRead,
|
|
4302
4698
|
className: "cv-workspace-toggle",
|
|
4303
4699
|
children: [
|
|
4304
|
-
"
|
|
4305
|
-
/* @__PURE__ */
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4700
|
+
/* @__PURE__ */ jsx27(Check2, { size: ICON_SIZE_ACTION, "aria-hidden": "true" }),
|
|
4701
|
+
/* @__PURE__ */ jsx27("span", { className: "cv-only-wide", children: labels.markSelectedAsRead }),
|
|
4702
|
+
inbox.selectedIds.size > 0 ? /* @__PURE__ */ jsxs25("span", { children: [
|
|
4703
|
+
"(",
|
|
4704
|
+
inbox.selectedIds.size,
|
|
4705
|
+
")"
|
|
4706
|
+
] }) : null
|
|
4310
4707
|
]
|
|
4311
4708
|
}
|
|
4312
4709
|
),
|
|
@@ -4316,14 +4713,12 @@ function ConversationsWorkspace({
|
|
|
4316
4713
|
type: "button",
|
|
4317
4714
|
onClick: () => void inbox.markAllAsRead(),
|
|
4318
4715
|
disabled: inbox.busy,
|
|
4319
|
-
|
|
4716
|
+
"data-cv-tooltip": labels.markAllAsRead,
|
|
4717
|
+
"aria-label": labels.markAllAsRead,
|
|
4320
4718
|
className: "cv-workspace-toggle",
|
|
4321
4719
|
children: [
|
|
4322
|
-
"
|
|
4323
|
-
/* @__PURE__ */
|
|
4324
|
-
" ",
|
|
4325
|
-
labels.markAllAsRead
|
|
4326
|
-
] })
|
|
4720
|
+
/* @__PURE__ */ jsx27(CheckCheck, { size: ICON_SIZE_ACTION, "aria-hidden": "true" }),
|
|
4721
|
+
/* @__PURE__ */ jsx27("span", { className: "cv-only-wide", children: labels.markAllAsRead })
|
|
4327
4722
|
]
|
|
4328
4723
|
}
|
|
4329
4724
|
) : null,
|
|
@@ -4362,7 +4757,7 @@ function ConversationsWorkspace({
|
|
|
4362
4757
|
now: inbox.now,
|
|
4363
4758
|
busy: inbox.busy,
|
|
4364
4759
|
labels,
|
|
4365
|
-
...inbox.canTakeover ? { onTakeover: () =>
|
|
4760
|
+
...inbox.canTakeover ? { onTakeover: () => inbox.takeover(selected.id) } : {},
|
|
4366
4761
|
...inbox.canTakeover ? { onReturnToBot: () => void inbox.releaseToBot(selected.id) } : {},
|
|
4367
4762
|
...inbox.canFinalize ? { onFinish: () => void inbox.finalize(selected.id) } : {},
|
|
4368
4763
|
...flowLabelOf ? { flowLabel: flowLabelOf(selected) } : {},
|
|
@@ -4478,7 +4873,9 @@ export {
|
|
|
4478
4873
|
SortableHead,
|
|
4479
4874
|
StatusTicks,
|
|
4480
4875
|
TEMPLATE_SETTINGS_TAB,
|
|
4876
|
+
TOOLTIP_ATTRIBUTE,
|
|
4481
4877
|
ToastProvider,
|
|
4878
|
+
TooltipLayer,
|
|
4482
4879
|
TopicsForm,
|
|
4483
4880
|
TranscriptionSettingsForm,
|
|
4484
4881
|
WINDOW_FILTERS,
|