@adatechnology/conversations-ui 0.1.1 → 0.2.1
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/{ConversationSimulatorPanel--5fIzXWY.d.ts → ConversationSimulatorPanel-ikgmlciE.d.ts} +103 -1
- package/dist/{chunk-BJNRLLDO.js → chunk-NHQDQJL2.js} +769 -244
- package/dist/index.d.ts +304 -9
- package/dist/index.js +2181 -507
- package/dist/preview/index.d.ts +2 -2
- package/dist/preview/index.js +147 -1
- package/dist/styles.css +135 -0
- package/package.json +1 -1
- package/src/MessageComposer.test.tsx +14 -0
- package/src/MessageComposer.tsx +327 -73
- package/src/RichMessageComposer.test.tsx +22 -4
- package/src/RichMessageComposer.tsx +674 -370
- package/src/index.ts +28 -1
- package/src/preview/createMockConversationsApi.ts +184 -0
- package/src/providers/types.ts +34 -0
- package/src/quickReplies/AttachmentsFormSection.tsx +160 -0
- package/src/quickReplies/QuickRepliesPicker.test.tsx +114 -0
- package/src/quickReplies/QuickRepliesPicker.tsx +188 -0
- package/src/quickReplies/QuickRepliesWorkspace.test.tsx +32 -0
- package/src/quickReplies/QuickRepliesWorkspace.tsx +395 -0
- package/src/quickReplies/createUploadQueue.test.ts +106 -0
- package/src/quickReplies/createUploadQueue.ts +69 -0
- package/src/quickReplies/index.ts +5 -0
- package/src/quickReplies/labels.ts +124 -0
- package/src/quickReplies/quickReply.types.ts +74 -0
- package/src/quickReplies/quickReplyAttachmentUpload.test.ts +76 -0
- package/src/quickReplies/quickReplyAttachmentUpload.ts +81 -0
- package/src/quickReplies/quickReplyAttachments.test.ts +467 -0
- package/src/quickReplies/quickReplyAttachments.ts +328 -0
- package/src/quickReplies/quickReplySearch.test.ts +88 -0
- package/src/quickReplies/quickReplySearch.ts +104 -0
- package/src/quickReplies/quickReplyShortcut.test.ts +38 -0
- package/src/quickReplies/quickReplyShortcut.ts +46 -0
- package/src/quickReplies/resolveConversationVariables.test.ts +63 -0
- package/src/quickReplies/resolveConversationVariables.ts +41 -0
- package/src/quickReplies/useQuickRepliesPicker.test.ts +20 -0
- package/src/quickReplies/useQuickRepliesPicker.ts +121 -0
- package/src/quickReplies/useQuickRepliesWorkspace.test.ts +222 -0
- package/src/quickReplies/useQuickRepliesWorkspace.ts +426 -0
- package/src/quickReplies/useQuickReplyAttachmentUploads.ts +159 -0
- package/src/styles.css +87 -0
- package/src/workspace/ConversationPane.tsx +137 -73
- package/src/workspace/ConversationsWorkspace.tsx +16 -1
- package/src/workspace/QueuedAttachmentsList.test.ts +27 -0
- package/src/workspace/QueuedAttachmentsList.tsx +198 -0
- package/src/workspace/index.ts +1 -0
- package/src/workspace/labels.ts +14 -0
- package/src/workspace/useComposerAttachmentRetry.ts +169 -0
- package/src/workspace/useComposerQueue.ts +229 -0
|
@@ -1298,7 +1298,13 @@ function AudioRecorderButton({
|
|
|
1298
1298
|
}
|
|
1299
1299
|
|
|
1300
1300
|
// src/MessageComposer.tsx
|
|
1301
|
-
import {
|
|
1301
|
+
import {
|
|
1302
|
+
useState as useState9,
|
|
1303
|
+
useRef as useRef5,
|
|
1304
|
+
useCallback as useCallback5,
|
|
1305
|
+
useEffect as useEffect5,
|
|
1306
|
+
useId
|
|
1307
|
+
} from "react";
|
|
1302
1308
|
|
|
1303
1309
|
// src/composer.constant.ts
|
|
1304
1310
|
var COMPOSER_BAR_CLASS = "cv-composer-bar";
|
|
@@ -1309,8 +1315,282 @@ var COMPOSER_MONOSPACE_CLASS = "bg-black/5 dark:bg-white/10 rounded px-0.5 font-
|
|
|
1309
1315
|
var COMPOSER_COMPACT_WIDTH = 480;
|
|
1310
1316
|
var QUICK_REPLY_PILL_CLASS = "whitespace-nowrap rounded-full border border-gray-200 bg-white px-3 py-1.5 text-xs text-gray-600 shadow-sm transition-colors hover:border-teal-200 hover:bg-teal-50 hover:text-teal-700 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:border-teal-800 dark:hover:bg-teal-950/40 dark:hover:text-teal-400";
|
|
1311
1317
|
|
|
1318
|
+
// src/quickReplies/QuickRepliesPicker.tsx
|
|
1319
|
+
import { useEffect as useEffect3, useRef as useRef3 } from "react";
|
|
1320
|
+
import { Paperclip } from "lucide-react";
|
|
1321
|
+
|
|
1322
|
+
// src/quickReplies/labels.ts
|
|
1323
|
+
var DEFAULT_QUICK_REPLIES_PICKER_LABELS = {
|
|
1324
|
+
loading: "Carregando mensagens prontas\u2026",
|
|
1325
|
+
error: "N\xE3o foi poss\xEDvel carregar as mensagens prontas.",
|
|
1326
|
+
empty: "Nenhuma mensagem pronta cadastrada ainda.",
|
|
1327
|
+
noResults: "Nenhuma mensagem encontrada.",
|
|
1328
|
+
attachmentsCount: (count) => `${count} ${count === 1 ? "anexo" : "anexos"}`,
|
|
1329
|
+
attachmentsUnavailable: "Este produto n\xE3o envia os anexos desta mensagem \u2014 s\xF3 o texto entra."
|
|
1330
|
+
};
|
|
1331
|
+
var DEFAULT_QUICK_REPLIES_WORKSPACE_LABELS = {
|
|
1332
|
+
title: "Mensagens prontas",
|
|
1333
|
+
subtitle: (total) => `${total} ${total === 1 ? "mensagem cadastrada" : "mensagens cadastradas"}`,
|
|
1334
|
+
searchPlaceholder: "Buscar por t\xEDtulo, atalho ou texto",
|
|
1335
|
+
loading: "Carregando mensagens prontas\u2026",
|
|
1336
|
+
failure: "N\xE3o foi poss\xEDvel carregar as mensagens prontas.",
|
|
1337
|
+
empty: "Nenhuma mensagem pronta cadastrada ainda.",
|
|
1338
|
+
noResults: "Nenhuma mensagem encontrada para a busca.",
|
|
1339
|
+
create: "Nova mensagem",
|
|
1340
|
+
edit: "Editar",
|
|
1341
|
+
remove: "Excluir",
|
|
1342
|
+
removeConfirm: (title) => `Excluir a mensagem "${title}"?`,
|
|
1343
|
+
save: "Salvar",
|
|
1344
|
+
cancel: "Cancelar",
|
|
1345
|
+
columnTitle: "T\xEDtulo",
|
|
1346
|
+
columnShortcut: "Atalho",
|
|
1347
|
+
columnBody: "Texto",
|
|
1348
|
+
columnActions: "A\xE7\xF5es",
|
|
1349
|
+
fieldTitle: "T\xEDtulo",
|
|
1350
|
+
fieldTitleInvalid: "Digite um t\xEDtulo de at\xE9 40 caracteres.",
|
|
1351
|
+
fieldShortcut: "Atalho",
|
|
1352
|
+
fieldShortcutHint: "Letras min\xFAsculas, n\xFAmeros e h\xEDfen, sem espa\xE7o nem acento.",
|
|
1353
|
+
fieldShortcutInvalid: "Atalho inv\xE1lido \u2014 s\xF3 letras min\xFAsculas, n\xFAmeros e h\xEDfen, at\xE9 20 caracteres.",
|
|
1354
|
+
fieldBody: "Texto",
|
|
1355
|
+
fieldBodyInvalid: "Digite um texto de at\xE9 1000 caracteres.",
|
|
1356
|
+
insertVariable: "Inserir vari\xE1vel",
|
|
1357
|
+
shortcutTaken: "Esse atalho j\xE1 est\xE1 em uso \u2014 escolha outro.",
|
|
1358
|
+
readOnlyNotice: "Voc\xEA s\xF3 pode consultar as mensagens prontas.",
|
|
1359
|
+
saveError: "N\xE3o foi poss\xEDvel salvar a mensagem.",
|
|
1360
|
+
saveUnavailable: "Salvar mensagens prontas n\xE3o est\xE1 dispon\xEDvel.",
|
|
1361
|
+
saving: "Salvando\u2026",
|
|
1362
|
+
deleting: "Excluindo\u2026",
|
|
1363
|
+
attachmentsTitle: "Anexos",
|
|
1364
|
+
attachmentsAdd: "Adicionar anexo",
|
|
1365
|
+
attachmentsEmpty: "Nenhum anexo \u2014 at\xE9 10 arquivos.",
|
|
1366
|
+
attachmentUploading: (percent) => `Enviando\u2026 ${percent}%`,
|
|
1367
|
+
attachmentProcessing: "Processando\u2026",
|
|
1368
|
+
attachmentRetry: "Tentar de novo",
|
|
1369
|
+
attachmentRemove: "Remover anexo",
|
|
1370
|
+
attachmentCancel: "Cancelar envio",
|
|
1371
|
+
attachmentMoveUp: "Mover para cima",
|
|
1372
|
+
attachmentMoveDown: "Mover para baixo",
|
|
1373
|
+
attachmentLimitReached: "Limite de 10 anexos por mensagem.",
|
|
1374
|
+
attachmentTooLarge: (filename) => `${filename}: excede o tamanho m\xE1ximo para o tipo de arquivo.`,
|
|
1375
|
+
saveBlockedUploading: "Aguardando o envio dos anexos\u2026"
|
|
1376
|
+
};
|
|
1377
|
+
|
|
1378
|
+
// src/quickReplies/QuickRepliesPicker.tsx
|
|
1379
|
+
import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1380
|
+
var LOADING_SKELETON_ROWS = 4;
|
|
1381
|
+
function QuickRepliesPicker({
|
|
1382
|
+
id,
|
|
1383
|
+
items,
|
|
1384
|
+
search,
|
|
1385
|
+
highlightedIndex,
|
|
1386
|
+
isLoading,
|
|
1387
|
+
hasError,
|
|
1388
|
+
onHover,
|
|
1389
|
+
onSelect,
|
|
1390
|
+
labels,
|
|
1391
|
+
className,
|
|
1392
|
+
ownSearch,
|
|
1393
|
+
variables,
|
|
1394
|
+
hasAttachmentsCapability
|
|
1395
|
+
}) {
|
|
1396
|
+
const text = { ...DEFAULT_QUICK_REPLIES_PICKER_LABELS, ...labels };
|
|
1397
|
+
const searchInputRef = useRef3(null);
|
|
1398
|
+
useEffect3(() => {
|
|
1399
|
+
if (ownSearch) searchInputRef.current?.focus();
|
|
1400
|
+
}, []);
|
|
1401
|
+
const activeOptionId = items.length > 0 ? `${id}-option-${highlightedIndex}` : void 0;
|
|
1402
|
+
return /* @__PURE__ */ jsxs10("div", { className, children: [
|
|
1403
|
+
ownSearch ? /* @__PURE__ */ jsx14(
|
|
1404
|
+
"input",
|
|
1405
|
+
{
|
|
1406
|
+
ref: searchInputRef,
|
|
1407
|
+
type: "text",
|
|
1408
|
+
role: "combobox",
|
|
1409
|
+
"aria-expanded": "true",
|
|
1410
|
+
"aria-controls": id,
|
|
1411
|
+
"aria-activedescendant": activeOptionId,
|
|
1412
|
+
value: ownSearch.value,
|
|
1413
|
+
onChange: (event) => ownSearch.onChange(event.target.value),
|
|
1414
|
+
onKeyDown: ownSearch.onKeyDown,
|
|
1415
|
+
placeholder: ownSearch.label,
|
|
1416
|
+
"aria-label": ownSearch.label,
|
|
1417
|
+
className: "mb-1 w-72 rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm outline-none focus:border-gray-400 dark:border-gray-700 dark:bg-gray-900"
|
|
1418
|
+
}
|
|
1419
|
+
) : null,
|
|
1420
|
+
/* @__PURE__ */ jsxs10(
|
|
1421
|
+
"ul",
|
|
1422
|
+
{
|
|
1423
|
+
role: "listbox",
|
|
1424
|
+
id,
|
|
1425
|
+
className: "max-h-64 w-72 overflow-y-auto rounded-lg border border-gray-200 bg-white py-1 shadow-lg dark:border-gray-700 dark:bg-gray-900",
|
|
1426
|
+
children: [
|
|
1427
|
+
isLoading ? /* @__PURE__ */ jsxs10("li", { "aria-busy": "true", "aria-live": "polite", children: [
|
|
1428
|
+
/* @__PURE__ */ jsx14("span", { className: "sr-only", children: text.loading }),
|
|
1429
|
+
Array.from({ length: LOADING_SKELETON_ROWS }).map((_, index) => /* @__PURE__ */ jsxs10("span", { className: "flex flex-col gap-1 px-3 py-2", children: [
|
|
1430
|
+
/* @__PURE__ */ jsx14("span", { className: "cv-skeleton-line", style: { width: "60%", height: "0.75rem" } }),
|
|
1431
|
+
/* @__PURE__ */ jsx14("span", { className: "cv-skeleton-line", style: { width: "85%", height: "0.625rem" } })
|
|
1432
|
+
] }, index))
|
|
1433
|
+
] }) : null,
|
|
1434
|
+
!isLoading && hasError ? /* @__PURE__ */ jsx14("li", { role: "alert", className: "px-3 py-2 text-sm text-red-600 dark:text-red-400", children: text.error }) : null,
|
|
1435
|
+
!isLoading && !hasError && items.length === 0 ? /* @__PURE__ */ jsx14("li", { className: "px-3 py-2 text-sm text-gray-500 dark:text-gray-400", children: search.trim() ? text.noResults : text.empty }) : null,
|
|
1436
|
+
!isLoading && !hasError ? items.map((quickReply, index) => {
|
|
1437
|
+
const resolvedBody = applyQuickReplyVariables(quickReply.body, variables);
|
|
1438
|
+
return /* @__PURE__ */ jsxs10(
|
|
1439
|
+
"li",
|
|
1440
|
+
{
|
|
1441
|
+
id: `${id}-option-${index}`,
|
|
1442
|
+
role: "option",
|
|
1443
|
+
"aria-selected": index === highlightedIndex,
|
|
1444
|
+
className: cn(
|
|
1445
|
+
"flex cursor-pointer flex-col gap-0.5 px-3 py-2 text-sm",
|
|
1446
|
+
index === highlightedIndex ? "bg-gray-100 dark:bg-gray-800" : void 0
|
|
1447
|
+
),
|
|
1448
|
+
onMouseEnter: () => onHover(index),
|
|
1449
|
+
onMouseDown: (event) => {
|
|
1450
|
+
event.preventDefault();
|
|
1451
|
+
onSelect(quickReply);
|
|
1452
|
+
},
|
|
1453
|
+
children: [
|
|
1454
|
+
/* @__PURE__ */ jsxs10("span", { className: "flex items-center gap-2", children: [
|
|
1455
|
+
/* @__PURE__ */ jsxs10("span", { className: "font-mono text-xs text-gray-400", children: [
|
|
1456
|
+
"/",
|
|
1457
|
+
quickReply.shortcut
|
|
1458
|
+
] }),
|
|
1459
|
+
/* @__PURE__ */ jsx14("span", { className: "truncate font-medium", children: highlightMatch(quickReply.title, search).map(
|
|
1460
|
+
(segment, segmentIndex) => segment.isMatch ? /* @__PURE__ */ jsx14("mark", { className: "rounded-sm bg-yellow-200 dark:bg-yellow-700/60", children: segment.text }, segmentIndex) : /* @__PURE__ */ jsx14("span", { children: segment.text }, segmentIndex)
|
|
1461
|
+
) }),
|
|
1462
|
+
quickReply.attachments && quickReply.attachments.length > 0 ? /* @__PURE__ */ jsxs10(
|
|
1463
|
+
"span",
|
|
1464
|
+
{
|
|
1465
|
+
className: cn(
|
|
1466
|
+
"flex flex-none items-center gap-0.5 text-xs",
|
|
1467
|
+
hasAttachmentsCapability ? "text-gray-500 dark:text-gray-400" : "text-amber-600 dark:text-amber-400"
|
|
1468
|
+
),
|
|
1469
|
+
title: hasAttachmentsCapability ? void 0 : text.attachmentsUnavailable,
|
|
1470
|
+
children: [
|
|
1471
|
+
/* @__PURE__ */ jsx14(Paperclip, { "aria-hidden": "true", className: "h-3 w-3" }),
|
|
1472
|
+
text.attachmentsCount(quickReply.attachments.length)
|
|
1473
|
+
]
|
|
1474
|
+
}
|
|
1475
|
+
) : null
|
|
1476
|
+
] }),
|
|
1477
|
+
quickReply.attachments && quickReply.attachments.length > 0 && !hasAttachmentsCapability ? /* @__PURE__ */ jsx14("span", { className: "text-xs text-amber-600 dark:text-amber-400", children: text.attachmentsUnavailable }) : null,
|
|
1478
|
+
/* @__PURE__ */ jsx14("span", { className: "truncate text-xs text-gray-500 dark:text-gray-400", children: highlightMatch(resolvedBody, search).map(
|
|
1479
|
+
(segment, segmentIndex) => segment.isMatch ? /* @__PURE__ */ jsx14("mark", { className: "rounded-sm bg-yellow-200 dark:bg-yellow-700/60", children: segment.text }, segmentIndex) : /* @__PURE__ */ jsx14("span", { children: segment.text }, segmentIndex)
|
|
1480
|
+
) })
|
|
1481
|
+
]
|
|
1482
|
+
},
|
|
1483
|
+
quickReply.id
|
|
1484
|
+
);
|
|
1485
|
+
}) : null
|
|
1486
|
+
]
|
|
1487
|
+
}
|
|
1488
|
+
)
|
|
1489
|
+
] });
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
// src/quickReplies/useQuickRepliesPicker.ts
|
|
1493
|
+
import { useCallback as useCallback4, useEffect as useEffect4, useRef as useRef4, useState as useState8 } from "react";
|
|
1494
|
+
function nextHighlightedIndex(current, length, delta) {
|
|
1495
|
+
if (length === 0) return 0;
|
|
1496
|
+
return (current + delta + length) % length;
|
|
1497
|
+
}
|
|
1498
|
+
function useQuickRepliesPicker({
|
|
1499
|
+
isOpen,
|
|
1500
|
+
search,
|
|
1501
|
+
listQuickReplies,
|
|
1502
|
+
quickReplyVariables,
|
|
1503
|
+
onSelect,
|
|
1504
|
+
onClose
|
|
1505
|
+
}) {
|
|
1506
|
+
const cacheRef = useRef4(void 0);
|
|
1507
|
+
const requestIdRef = useRef4(0);
|
|
1508
|
+
const [items, setItems] = useState8([]);
|
|
1509
|
+
const [isLoading, setIsLoading] = useState8(false);
|
|
1510
|
+
const [hasError, setHasError] = useState8(false);
|
|
1511
|
+
const [highlightedIndex, setHighlightedIndex] = useState8(0);
|
|
1512
|
+
const load = useCallback4(() => {
|
|
1513
|
+
if (!listQuickReplies) return;
|
|
1514
|
+
const requestId = ++requestIdRef.current;
|
|
1515
|
+
setIsLoading(true);
|
|
1516
|
+
setHasError(false);
|
|
1517
|
+
listQuickReplies().then((result) => {
|
|
1518
|
+
if (requestIdRef.current !== requestId) return;
|
|
1519
|
+
cacheRef.current = result;
|
|
1520
|
+
setItems(result);
|
|
1521
|
+
setIsLoading(false);
|
|
1522
|
+
}).catch(() => {
|
|
1523
|
+
if (requestIdRef.current !== requestId) return;
|
|
1524
|
+
setHasError(true);
|
|
1525
|
+
setIsLoading(false);
|
|
1526
|
+
});
|
|
1527
|
+
}, [listQuickReplies]);
|
|
1528
|
+
useEffect4(() => {
|
|
1529
|
+
if (!isOpen || !listQuickReplies) return;
|
|
1530
|
+
if (cacheRef.current) {
|
|
1531
|
+
setItems(cacheRef.current);
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
load();
|
|
1535
|
+
}, [isOpen, listQuickReplies, load]);
|
|
1536
|
+
const refetch = useCallback4(() => {
|
|
1537
|
+
cacheRef.current = void 0;
|
|
1538
|
+
load();
|
|
1539
|
+
}, [load]);
|
|
1540
|
+
const filtered = filterQuickReplies({ quickReplies: items, search, variables: quickReplyVariables });
|
|
1541
|
+
useEffect4(() => {
|
|
1542
|
+
setHighlightedIndex(0);
|
|
1543
|
+
}, [search, filtered.length]);
|
|
1544
|
+
const handleKeyDown = useCallback4(
|
|
1545
|
+
(event) => {
|
|
1546
|
+
if (event.key === "ArrowDown") {
|
|
1547
|
+
event.preventDefault();
|
|
1548
|
+
setHighlightedIndex((index) => nextHighlightedIndex(index, filtered.length, 1));
|
|
1549
|
+
return;
|
|
1550
|
+
}
|
|
1551
|
+
if (event.key === "ArrowUp") {
|
|
1552
|
+
event.preventDefault();
|
|
1553
|
+
setHighlightedIndex((index) => nextHighlightedIndex(index, filtered.length, -1));
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1556
|
+
if (event.key === "Enter") {
|
|
1557
|
+
const selected = filtered[highlightedIndex];
|
|
1558
|
+
if (!selected) return;
|
|
1559
|
+
event.preventDefault();
|
|
1560
|
+
onSelect(selected);
|
|
1561
|
+
return;
|
|
1562
|
+
}
|
|
1563
|
+
if (event.key === "Escape") {
|
|
1564
|
+
event.preventDefault();
|
|
1565
|
+
onClose();
|
|
1566
|
+
}
|
|
1567
|
+
},
|
|
1568
|
+
[filtered, highlightedIndex, onSelect, onClose]
|
|
1569
|
+
);
|
|
1570
|
+
return { items: filtered, isLoading, hasError, highlightedIndex, setHighlightedIndex, handleKeyDown, refetch };
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
// src/quickReplies/quickReplyShortcut.ts
|
|
1574
|
+
var QUICK_REPLY_SHORTCUT_PATTERN = /(?:^|\s)\/([a-z0-9-]*)$/i;
|
|
1575
|
+
function detectQuickReplyShortcut(text) {
|
|
1576
|
+
const match = QUICK_REPLY_SHORTCUT_PATTERN.exec(text);
|
|
1577
|
+
if (!match) return void 0;
|
|
1578
|
+
return { start: match.index + (match[0].startsWith("/") ? 0 : 1), term: match[1] ?? "" };
|
|
1579
|
+
}
|
|
1580
|
+
function replaceQuickReplyShortcut({
|
|
1581
|
+
text,
|
|
1582
|
+
start,
|
|
1583
|
+
caret,
|
|
1584
|
+
replacement
|
|
1585
|
+
}) {
|
|
1586
|
+
return {
|
|
1587
|
+
text: text.slice(0, start) + replacement + text.slice(caret),
|
|
1588
|
+
caret: start + replacement.length
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1312
1592
|
// src/MessageComposer.tsx
|
|
1313
|
-
import { Fragment as Fragment3, jsx as
|
|
1593
|
+
import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1314
1594
|
function applyQuickReplyVariables(template, variables = {}) {
|
|
1315
1595
|
return template.replace(/\{\{\s*([\w.]+)\s*\}\}/g, (_, chave) => variables[chave] ?? "");
|
|
1316
1596
|
}
|
|
@@ -1321,7 +1601,8 @@ var DEFAULT_MESSAGE_COMPOSER_LABELS = {
|
|
|
1321
1601
|
emoji: "Emoji",
|
|
1322
1602
|
attach: "Anexar",
|
|
1323
1603
|
send: "Enviar",
|
|
1324
|
-
removeAttachment: "Remover anexo"
|
|
1604
|
+
removeAttachment: "Remover anexo",
|
|
1605
|
+
quickReplies: "Mensagens prontas"
|
|
1325
1606
|
};
|
|
1326
1607
|
var DEFAULT_ACCEPTED_FILE_TYPES = [
|
|
1327
1608
|
"image/jpeg,image/png,image/webp",
|
|
@@ -1340,6 +1621,7 @@ var MessageComposer = ({
|
|
|
1340
1621
|
onChange: externalOnChange,
|
|
1341
1622
|
quickReplies,
|
|
1342
1623
|
quickReplyVariables,
|
|
1624
|
+
savedQuickReplies,
|
|
1343
1625
|
features,
|
|
1344
1626
|
placeholder = "Digite uma mensagem...",
|
|
1345
1627
|
maxLength,
|
|
@@ -1354,23 +1636,124 @@ var MessageComposer = ({
|
|
|
1354
1636
|
const attachLabel = labels?.attach ?? DEFAULT_MESSAGE_COMPOSER_LABELS.attach;
|
|
1355
1637
|
const sendLabel = labels?.send ?? DEFAULT_MESSAGE_COMPOSER_LABELS.send;
|
|
1356
1638
|
const removeAttachmentLabel = labels?.removeAttachment ?? DEFAULT_MESSAGE_COMPOSER_LABELS.removeAttachment;
|
|
1357
|
-
const
|
|
1358
|
-
const [
|
|
1359
|
-
const [
|
|
1360
|
-
const
|
|
1361
|
-
const
|
|
1639
|
+
const quickRepliesLabel = labels?.quickReplies ?? DEFAULT_MESSAGE_COMPOSER_LABELS.quickReplies;
|
|
1640
|
+
const [internalText, setInternalText] = useState9("");
|
|
1641
|
+
const [showEmoji, setShowEmoji] = useState9(false);
|
|
1642
|
+
const [attachments, setAttachments] = useState9([]);
|
|
1643
|
+
const textareaRef = useRef5(null);
|
|
1644
|
+
const fileInputRef = useRef5(null);
|
|
1645
|
+
const quickRepliesListboxId = useId();
|
|
1646
|
+
const [isQuickRepliesOpen, setIsQuickRepliesOpen] = useState9(false);
|
|
1647
|
+
const [quickRepliesTerm, setQuickRepliesTerm] = useState9("");
|
|
1648
|
+
const [shortcutStart, setShortcutStart] = useState9(null);
|
|
1649
|
+
const [quickRepliesMode, setQuickRepliesMode] = useState9("shortcut");
|
|
1650
|
+
const [caretPosition, setCaretPosition] = useState9(0);
|
|
1651
|
+
const quickRepliesPopoverRef = useRef5(null);
|
|
1652
|
+
const quickRepliesTriggerRef = useRef5(null);
|
|
1362
1653
|
const isControlled = externalValue !== void 0;
|
|
1363
1654
|
const text = isControlled ? externalValue : internalText;
|
|
1364
|
-
const setText =
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1655
|
+
const setText = useCallback5(
|
|
1656
|
+
(newText) => {
|
|
1657
|
+
if (isControlled) {
|
|
1658
|
+
externalOnChange?.(newText);
|
|
1659
|
+
} else {
|
|
1660
|
+
setInternalText(newText);
|
|
1661
|
+
}
|
|
1662
|
+
},
|
|
1663
|
+
[isControlled, externalOnChange]
|
|
1664
|
+
);
|
|
1371
1665
|
const showEmojiButton = features?.emoji !== false;
|
|
1372
1666
|
const showAttachButton = features?.documents !== false;
|
|
1373
|
-
const
|
|
1667
|
+
const showQuickRepliesButton = Boolean(savedQuickReplies);
|
|
1668
|
+
useEffect5(() => {
|
|
1669
|
+
if (!showQuickRepliesButton || quickRepliesMode === "button") return;
|
|
1670
|
+
const match = detectQuickReplyShortcut(text.slice(0, caretPosition));
|
|
1671
|
+
setIsQuickRepliesOpen(Boolean(match));
|
|
1672
|
+
setQuickRepliesTerm(match?.term ?? "");
|
|
1673
|
+
setShortcutStart(match?.start ?? null);
|
|
1674
|
+
}, [text, caretPosition, showQuickRepliesButton, quickRepliesMode]);
|
|
1675
|
+
useEffect5(() => {
|
|
1676
|
+
if (!showQuickRepliesButton) setIsQuickRepliesOpen(false);
|
|
1677
|
+
}, [showQuickRepliesButton]);
|
|
1678
|
+
const closeQuickReplies = useCallback5(() => {
|
|
1679
|
+
setIsQuickRepliesOpen(false);
|
|
1680
|
+
setShortcutStart(null);
|
|
1681
|
+
setQuickRepliesTerm("");
|
|
1682
|
+
setQuickRepliesMode("shortcut");
|
|
1683
|
+
}, []);
|
|
1684
|
+
const closeQuickRepliesAndRefocus = useCallback5(() => {
|
|
1685
|
+
closeQuickReplies();
|
|
1686
|
+
textareaRef.current?.focus();
|
|
1687
|
+
}, [closeQuickReplies]);
|
|
1688
|
+
const trackCaret = useCallback5((event) => {
|
|
1689
|
+
setCaretPosition(event.currentTarget.selectionStart);
|
|
1690
|
+
}, []);
|
|
1691
|
+
const insertSavedQuickReply = useCallback5(
|
|
1692
|
+
(quickReply) => {
|
|
1693
|
+
savedQuickReplies?.onSelect?.(quickReply);
|
|
1694
|
+
const ta = textareaRef.current;
|
|
1695
|
+
if (!ta) return;
|
|
1696
|
+
const resolvedBody = applyQuickReplyVariables(quickReply.body, savedQuickReplies?.variables);
|
|
1697
|
+
if (quickRepliesMode === "button") {
|
|
1698
|
+
const start = ta.selectionStart;
|
|
1699
|
+
const end = ta.selectionEnd;
|
|
1700
|
+
const newText2 = text.slice(0, start) + resolvedBody + text.slice(end);
|
|
1701
|
+
setText(newText2);
|
|
1702
|
+
closeQuickReplies();
|
|
1703
|
+
requestAnimationFrame(() => {
|
|
1704
|
+
ta.focus();
|
|
1705
|
+
const caret2 = start + resolvedBody.length;
|
|
1706
|
+
ta.setSelectionRange(caret2, caret2);
|
|
1707
|
+
});
|
|
1708
|
+
return;
|
|
1709
|
+
}
|
|
1710
|
+
if (shortcutStart === null) return;
|
|
1711
|
+
const shortcutEnd = shortcutStart + 1 + quickRepliesTerm.length;
|
|
1712
|
+
const { text: newText, caret } = replaceQuickReplyShortcut({
|
|
1713
|
+
text,
|
|
1714
|
+
start: shortcutStart,
|
|
1715
|
+
caret: shortcutEnd,
|
|
1716
|
+
replacement: resolvedBody
|
|
1717
|
+
});
|
|
1718
|
+
setText(newText);
|
|
1719
|
+
closeQuickReplies();
|
|
1720
|
+
requestAnimationFrame(() => {
|
|
1721
|
+
ta.focus();
|
|
1722
|
+
ta.setSelectionRange(caret, caret);
|
|
1723
|
+
});
|
|
1724
|
+
},
|
|
1725
|
+
[text, setText, shortcutStart, quickRepliesTerm, quickRepliesMode, savedQuickReplies, closeQuickReplies]
|
|
1726
|
+
);
|
|
1727
|
+
const quickRepliesPicker = useQuickRepliesPicker({
|
|
1728
|
+
isOpen: isQuickRepliesOpen,
|
|
1729
|
+
search: quickRepliesTerm,
|
|
1730
|
+
listQuickReplies: savedQuickReplies?.listQuickReplies,
|
|
1731
|
+
quickReplyVariables: savedQuickReplies?.variables,
|
|
1732
|
+
onSelect: insertSavedQuickReply,
|
|
1733
|
+
onClose: closeQuickRepliesAndRefocus
|
|
1734
|
+
});
|
|
1735
|
+
const openQuickRepliesViaButton = useCallback5(() => {
|
|
1736
|
+
if (isQuickRepliesOpen && quickRepliesMode === "button") {
|
|
1737
|
+
closeQuickRepliesAndRefocus();
|
|
1738
|
+
return;
|
|
1739
|
+
}
|
|
1740
|
+
setQuickRepliesMode("button");
|
|
1741
|
+
setQuickRepliesTerm("");
|
|
1742
|
+
setShortcutStart(null);
|
|
1743
|
+
setIsQuickRepliesOpen(true);
|
|
1744
|
+
}, [isQuickRepliesOpen, quickRepliesMode, closeQuickRepliesAndRefocus]);
|
|
1745
|
+
useEffect5(() => {
|
|
1746
|
+
if (!isQuickRepliesOpen || quickRepliesMode !== "button") return;
|
|
1747
|
+
const handleOutsideClick = (event) => {
|
|
1748
|
+
const target = event.target;
|
|
1749
|
+
if (quickRepliesPopoverRef.current?.contains(target)) return;
|
|
1750
|
+
if (quickRepliesTriggerRef.current?.contains(target)) return;
|
|
1751
|
+
closeQuickRepliesAndRefocus();
|
|
1752
|
+
};
|
|
1753
|
+
document.addEventListener("mousedown", handleOutsideClick);
|
|
1754
|
+
return () => document.removeEventListener("mousedown", handleOutsideClick);
|
|
1755
|
+
}, [isQuickRepliesOpen, quickRepliesMode, closeQuickRepliesAndRefocus]);
|
|
1756
|
+
const sendMessage = useCallback5(() => {
|
|
1374
1757
|
const trimmed = text.trim();
|
|
1375
1758
|
if (!trimmed && attachments.length === 0) return;
|
|
1376
1759
|
if (trimmed) onSend(trimmed);
|
|
@@ -1383,35 +1766,45 @@ var MessageComposer = ({
|
|
|
1383
1766
|
setShowEmoji(false);
|
|
1384
1767
|
if (textareaRef.current) textareaRef.current.style.height = "auto";
|
|
1385
1768
|
}, [text, attachments, onSend, onAttach, isControlled]);
|
|
1386
|
-
const handleKeyDown =
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1769
|
+
const handleKeyDown = useCallback5(
|
|
1770
|
+
(e) => {
|
|
1771
|
+
if (isQuickRepliesOpen && quickRepliesMode === "shortcut") {
|
|
1772
|
+
quickRepliesPicker.handleKeyDown(e);
|
|
1773
|
+
return;
|
|
1774
|
+
}
|
|
1775
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
1776
|
+
e.preventDefault();
|
|
1777
|
+
if (!disabled) sendMessage();
|
|
1778
|
+
}
|
|
1779
|
+
},
|
|
1780
|
+
[sendMessage, disabled, isQuickRepliesOpen, quickRepliesMode, quickRepliesPicker]
|
|
1781
|
+
);
|
|
1782
|
+
const handleInput = useCallback5(() => {
|
|
1393
1783
|
const ta = textareaRef.current;
|
|
1394
1784
|
if (!ta) return;
|
|
1395
1785
|
ta.style.height = "auto";
|
|
1396
1786
|
ta.style.height = `${Math.min(ta.scrollHeight, 100)}px`;
|
|
1397
1787
|
}, []);
|
|
1398
|
-
const handleEmojiSelect =
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1788
|
+
const handleEmojiSelect = useCallback5(
|
|
1789
|
+
(emoji) => {
|
|
1790
|
+
const ta = textareaRef.current;
|
|
1791
|
+
if (!ta) {
|
|
1792
|
+
setText(text + emoji);
|
|
1793
|
+
return;
|
|
1794
|
+
}
|
|
1795
|
+
const start = ta.selectionStart;
|
|
1796
|
+
const end = ta.selectionEnd;
|
|
1797
|
+
const newText = text.slice(0, start) + emoji + text.slice(end);
|
|
1798
|
+
setText(newText);
|
|
1799
|
+
requestAnimationFrame(() => {
|
|
1800
|
+
ta.focus();
|
|
1801
|
+
ta.setSelectionRange(start + emoji.length, start + emoji.length);
|
|
1802
|
+
handleInput();
|
|
1803
|
+
});
|
|
1804
|
+
},
|
|
1805
|
+
[text, setText, handleInput]
|
|
1806
|
+
);
|
|
1807
|
+
const handleFileChange = useCallback5((e) => {
|
|
1415
1808
|
const files = e.target.files;
|
|
1416
1809
|
if (!files) return;
|
|
1417
1810
|
const previews = [];
|
|
@@ -1422,7 +1815,7 @@ var MessageComposer = ({
|
|
|
1422
1815
|
setAttachments((prev) => [...prev, ...previews]);
|
|
1423
1816
|
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
1424
1817
|
}, []);
|
|
1425
|
-
const removeAttachment =
|
|
1818
|
+
const removeAttachment = useCallback5((index) => {
|
|
1426
1819
|
setAttachments((prev) => {
|
|
1427
1820
|
const next = [...prev];
|
|
1428
1821
|
if (next[index].previewUrl) URL.revokeObjectURL(next[index].previewUrl);
|
|
@@ -1430,36 +1823,22 @@ var MessageComposer = ({
|
|
|
1430
1823
|
return next;
|
|
1431
1824
|
});
|
|
1432
1825
|
}, []);
|
|
1433
|
-
const
|
|
1434
|
-
const ta = textareaRef.current;
|
|
1435
|
-
if (!ta) return;
|
|
1436
|
-
const start = ta.selectionStart;
|
|
1437
|
-
const end = ta.selectionEnd;
|
|
1438
|
-
const sel = text.slice(start, end);
|
|
1439
|
-
if (sel) {
|
|
1440
|
-
setText(text.slice(0, start) + marker + sel + marker + text.slice(end));
|
|
1441
|
-
requestAnimationFrame(() => {
|
|
1442
|
-
ta.focus();
|
|
1443
|
-
ta.setSelectionRange(start + marker.length + sel.length + marker.length, start + marker.length + sel.length + marker.length);
|
|
1444
|
-
});
|
|
1445
|
-
}
|
|
1446
|
-
}, [text, setText]);
|
|
1447
|
-
const effectiveIdleAction = idleAction ?? (onAttach ? /* @__PURE__ */ jsx14(AudioRecorderButton, { onRecorded: (file) => onAttach(file) }) : void 0);
|
|
1826
|
+
const effectiveIdleAction = idleAction ?? (onAttach ? /* @__PURE__ */ jsx15(AudioRecorderButton, { onRecorded: (file) => onAttach(file) }) : void 0);
|
|
1448
1827
|
const canSend = text.trim().length > 0 || attachments.length > 0;
|
|
1449
1828
|
const remaining = maxLength ? maxLength - text.length : null;
|
|
1450
1829
|
return (
|
|
1451
1830
|
/* A barra é a superfície (cinza, largura cheia, sem raio) e o campo dentro é que arredonda —
|
|
1452
1831
|
ordem do WhatsApp. Invertido, o pill arredondado ia até a borda da tela e os cantos
|
|
1453
1832
|
descobriam o fundo branco da página, que lia como defeito. */
|
|
1454
|
-
/* @__PURE__ */
|
|
1455
|
-
quickReplies && quickReplies.length > 0 && /* @__PURE__ */
|
|
1833
|
+
/* @__PURE__ */ jsxs11("div", { className: cn(COMPOSER_BAR_CLASS, className), children: [
|
|
1834
|
+
quickReplies && quickReplies.length > 0 && /* @__PURE__ */ jsx15(
|
|
1456
1835
|
"div",
|
|
1457
1836
|
{
|
|
1458
1837
|
className: cn(
|
|
1459
1838
|
"mb-2 flex flex-nowrap gap-1 overflow-x-auto px-1 sm:flex-wrap sm:overflow-x-visible [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
1460
1839
|
classNames?.quickReplies
|
|
1461
1840
|
),
|
|
1462
|
-
children: quickReplies.map((quickReply) => /* @__PURE__ */
|
|
1841
|
+
children: quickReplies.map((quickReply) => /* @__PURE__ */ jsx15(
|
|
1463
1842
|
"button",
|
|
1464
1843
|
{
|
|
1465
1844
|
"data-cv-tooltip": quickReply.label,
|
|
@@ -1476,45 +1855,127 @@ var MessageComposer = ({
|
|
|
1476
1855
|
))
|
|
1477
1856
|
}
|
|
1478
1857
|
),
|
|
1479
|
-
attachments.length > 0 && /* @__PURE__ */
|
|
1480
|
-
a.previewUrl ? /* @__PURE__ */
|
|
1481
|
-
/* @__PURE__ */
|
|
1482
|
-
/* @__PURE__ */
|
|
1858
|
+
attachments.length > 0 && /* @__PURE__ */ jsx15("div", { className: "flex gap-2 px-1 pb-2 overflow-x-auto", children: attachments.map((a, i) => /* @__PURE__ */ jsxs11("div", { className: "relative flex-shrink-0", children: [
|
|
1859
|
+
a.previewUrl ? /* @__PURE__ */ jsx15("img", { src: a.previewUrl, alt: "", className: "w-16 h-16 object-cover rounded-lg border border-gray-200" }) : /* @__PURE__ */ jsx15("div", { className: "w-16 h-16 bg-gray-100 rounded-lg border border-gray-200 flex items-center justify-center", children: /* @__PURE__ */ jsxs11("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "#9ca3af", strokeWidth: "1.5", children: [
|
|
1860
|
+
/* @__PURE__ */ jsx15("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
1861
|
+
/* @__PURE__ */ jsx15("polyline", { points: "14 2 14 8 20 8" })
|
|
1483
1862
|
] }) }),
|
|
1484
|
-
/* @__PURE__ */
|
|
1863
|
+
/* @__PURE__ */ jsx15(
|
|
1864
|
+
"button",
|
|
1865
|
+
{
|
|
1866
|
+
"data-cv-tooltip": removeAttachmentLabel,
|
|
1867
|
+
"aria-label": removeAttachmentLabel,
|
|
1868
|
+
onClick: () => removeAttachment(i),
|
|
1869
|
+
className: "absolute -top-2 -right-2 w-5 h-5 bg-gray-600 text-white rounded-full flex items-center justify-center hover:bg-gray-800 text-xs",
|
|
1870
|
+
children: "\u2715"
|
|
1871
|
+
}
|
|
1872
|
+
)
|
|
1485
1873
|
] }, i)) }),
|
|
1486
|
-
/* @__PURE__ */
|
|
1487
|
-
showEmojiButton && /* @__PURE__ */
|
|
1488
|
-
/* @__PURE__ */
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1874
|
+
/* @__PURE__ */ jsxs11("div", { className: cn("flex items-end gap-1.5 rounded-xl bg-white px-3 py-2", classNames?.field), children: [
|
|
1875
|
+
showEmojiButton && /* @__PURE__ */ jsxs11("div", { className: "relative flex-shrink-0", children: [
|
|
1876
|
+
/* @__PURE__ */ jsx15(
|
|
1877
|
+
"button",
|
|
1878
|
+
{
|
|
1879
|
+
"data-cv-tooltip": emojiLabel,
|
|
1880
|
+
onClick: () => setShowEmoji((v) => !v),
|
|
1881
|
+
className: "w-9 h-9 flex items-center justify-center rounded-full text-gray-500 hover:bg-gray-200 transition-colors",
|
|
1882
|
+
"aria-label": emojiLabel,
|
|
1883
|
+
children: /* @__PURE__ */ jsxs11("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
1884
|
+
/* @__PURE__ */ jsx15("circle", { cx: "12", cy: "12", r: "10" }),
|
|
1885
|
+
/* @__PURE__ */ jsx15("path", { d: "M8 14s1.5 2 4 2 4-2 4-2" }),
|
|
1886
|
+
/* @__PURE__ */ jsx15("circle", { cx: "9", cy: "9", r: "0.5", fill: "currentColor" }),
|
|
1887
|
+
/* @__PURE__ */ jsx15("circle", { cx: "15", cy: "9", r: "0.5", fill: "currentColor" })
|
|
1888
|
+
] })
|
|
1889
|
+
}
|
|
1890
|
+
),
|
|
1891
|
+
showEmoji && /* @__PURE__ */ jsx15("div", { className: "absolute bottom-full left-0 mb-2 z-10", children: /* @__PURE__ */ jsx15(EmojiPicker, { onSelect: handleEmojiSelect }) })
|
|
1495
1892
|
] }),
|
|
1496
|
-
/* @__PURE__ */
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1893
|
+
/* @__PURE__ */ jsxs11("div", { className: "relative flex-1", children: [
|
|
1894
|
+
/* @__PURE__ */ jsx15(
|
|
1895
|
+
"textarea",
|
|
1896
|
+
{
|
|
1897
|
+
ref: textareaRef,
|
|
1898
|
+
value: text,
|
|
1899
|
+
onChange: (e) => {
|
|
1900
|
+
setText(e.target.value);
|
|
1901
|
+
setCaretPosition(e.target.selectionStart);
|
|
1902
|
+
handleInput();
|
|
1903
|
+
},
|
|
1904
|
+
onKeyDown: handleKeyDown,
|
|
1905
|
+
onKeyUp: trackCaret,
|
|
1906
|
+
onClick: trackCaret,
|
|
1907
|
+
onSelect: trackCaret,
|
|
1908
|
+
placeholder,
|
|
1909
|
+
rows: 1,
|
|
1910
|
+
disabled,
|
|
1911
|
+
role: showQuickRepliesButton ? "combobox" : void 0,
|
|
1912
|
+
"aria-expanded": showQuickRepliesButton ? isQuickRepliesOpen : void 0,
|
|
1913
|
+
"aria-controls": showQuickRepliesButton ? quickRepliesListboxId : void 0,
|
|
1914
|
+
"aria-activedescendant": isQuickRepliesOpen && quickRepliesMode === "shortcut" ? `${quickRepliesListboxId}-option-${quickRepliesPicker.highlightedIndex}` : void 0,
|
|
1915
|
+
className: "w-full resize-none bg-transparent text-[15px] text-[#3b4a54] placeholder-[#8696a0] outline-none py-1.5 max-h-[100px] leading-relaxed",
|
|
1916
|
+
style: { fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" }
|
|
1917
|
+
}
|
|
1918
|
+
),
|
|
1919
|
+
isQuickRepliesOpen && /* @__PURE__ */ jsx15("div", { ref: quickRepliesPopoverRef, className: "absolute bottom-full left-0 mb-2 z-10", children: /* @__PURE__ */ jsx15(
|
|
1920
|
+
QuickRepliesPicker,
|
|
1921
|
+
{
|
|
1922
|
+
id: quickRepliesListboxId,
|
|
1923
|
+
items: quickRepliesPicker.items,
|
|
1924
|
+
search: quickRepliesTerm,
|
|
1925
|
+
highlightedIndex: quickRepliesPicker.highlightedIndex,
|
|
1926
|
+
isLoading: quickRepliesPicker.isLoading,
|
|
1927
|
+
hasError: quickRepliesPicker.hasError,
|
|
1928
|
+
onHover: quickRepliesPicker.setHighlightedIndex,
|
|
1929
|
+
onSelect: insertSavedQuickReply,
|
|
1930
|
+
labels: savedQuickReplies?.labels,
|
|
1931
|
+
variables: savedQuickReplies?.variables,
|
|
1932
|
+
hasAttachmentsCapability: savedQuickReplies?.hasAttachmentsCapability,
|
|
1933
|
+
ownSearch: quickRepliesMode === "button" ? {
|
|
1934
|
+
value: quickRepliesTerm,
|
|
1935
|
+
onChange: setQuickRepliesTerm,
|
|
1936
|
+
onKeyDown: quickRepliesPicker.handleKeyDown,
|
|
1937
|
+
label: quickRepliesLabel
|
|
1938
|
+
} : void 0
|
|
1504
1939
|
},
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1940
|
+
quickRepliesMode
|
|
1941
|
+
) })
|
|
1942
|
+
] }),
|
|
1943
|
+
showQuickRepliesButton && /* @__PURE__ */ jsx15(
|
|
1944
|
+
"button",
|
|
1945
|
+
{
|
|
1946
|
+
ref: quickRepliesTriggerRef,
|
|
1947
|
+
type: "button",
|
|
1948
|
+
"data-cv-tooltip": quickRepliesLabel,
|
|
1949
|
+
"aria-label": quickRepliesLabel,
|
|
1950
|
+
onClick: openQuickRepliesViaButton,
|
|
1951
|
+
className: "w-9 h-9 flex items-center justify-center rounded-full text-gray-500 hover:bg-gray-200 flex-shrink-0 transition-colors",
|
|
1952
|
+
children: /* @__PURE__ */ jsx15("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx15("polygon", { points: "13 2 3 14 12 14 11 22 21 10 12 10 13 2" }) })
|
|
1511
1953
|
}
|
|
1512
1954
|
),
|
|
1513
|
-
showAttachButton && /* @__PURE__ */
|
|
1514
|
-
/* @__PURE__ */
|
|
1515
|
-
|
|
1955
|
+
showAttachButton && /* @__PURE__ */ jsxs11(Fragment3, { children: [
|
|
1956
|
+
/* @__PURE__ */ jsx15(
|
|
1957
|
+
"input",
|
|
1958
|
+
{
|
|
1959
|
+
ref: fileInputRef,
|
|
1960
|
+
type: "file",
|
|
1961
|
+
multiple: true,
|
|
1962
|
+
accept: acceptedFileTypes,
|
|
1963
|
+
onChange: handleFileChange,
|
|
1964
|
+
className: "hidden"
|
|
1965
|
+
}
|
|
1966
|
+
),
|
|
1967
|
+
/* @__PURE__ */ jsx15(
|
|
1968
|
+
"button",
|
|
1969
|
+
{
|
|
1970
|
+
"data-cv-tooltip": attachLabel,
|
|
1971
|
+
onClick: () => fileInputRef.current?.click(),
|
|
1972
|
+
className: "w-9 h-9 flex items-center justify-center rounded-full text-gray-500 hover:bg-gray-200 flex-shrink-0 transition-colors",
|
|
1973
|
+
"aria-label": attachLabel,
|
|
1974
|
+
children: /* @__PURE__ */ jsx15("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx15("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" }) })
|
|
1975
|
+
}
|
|
1976
|
+
)
|
|
1516
1977
|
] }),
|
|
1517
|
-
!canSend && effectiveIdleAction ? /* @__PURE__ */
|
|
1978
|
+
!canSend && effectiveIdleAction ? /* @__PURE__ */ jsx15("div", { className: "flex-shrink-0", children: effectiveIdleAction }) : /* @__PURE__ */ jsx15(
|
|
1518
1979
|
"button",
|
|
1519
1980
|
{
|
|
1520
1981
|
"data-cv-tooltip": sendLabel,
|
|
@@ -1522,20 +1983,76 @@ var MessageComposer = ({
|
|
|
1522
1983
|
disabled: !canSend || disabled,
|
|
1523
1984
|
className: `w-10 h-10 flex items-center justify-center rounded-full flex-shrink-0 transition-all ${canSend && !disabled ? "bg-[#00a884] text-white hover:bg-[#06cf9c] shadow-sm" : "bg-gray-200 text-gray-400 cursor-not-allowed"}`,
|
|
1524
1985
|
"aria-label": sendLabel,
|
|
1525
|
-
children: /* @__PURE__ */
|
|
1986
|
+
children: /* @__PURE__ */ jsx15("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx15("path", { d: "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" }) })
|
|
1526
1987
|
}
|
|
1527
1988
|
)
|
|
1528
1989
|
] }),
|
|
1529
|
-
remaining !== null && /* @__PURE__ */
|
|
1990
|
+
remaining !== null && /* @__PURE__ */ jsx15("div", { className: "flex justify-end mt-1 pr-1", children: /* @__PURE__ */ jsx15("span", { className: `text-xs ${remaining < 20 ? "text-red-500" : "text-gray-400"}`, children: remaining }) })
|
|
1530
1991
|
] })
|
|
1531
1992
|
);
|
|
1532
1993
|
};
|
|
1533
1994
|
|
|
1995
|
+
// src/quickReplies/quickReplySearch.ts
|
|
1996
|
+
var DIACRITIC_PATTERN = /[\u0300-\u036f]/g;
|
|
1997
|
+
function normalizeForSearchWithMap(value) {
|
|
1998
|
+
let normalized = "";
|
|
1999
|
+
const originalIndexOf = [];
|
|
2000
|
+
let originalCursor = 0;
|
|
2001
|
+
for (const char of value) {
|
|
2002
|
+
const piece = char.normalize("NFD").replace(DIACRITIC_PATTERN, "").toLowerCase();
|
|
2003
|
+
for (let i = 0; i < piece.length; i++) originalIndexOf.push(originalCursor);
|
|
2004
|
+
normalized += piece;
|
|
2005
|
+
originalCursor += char.length;
|
|
2006
|
+
}
|
|
2007
|
+
return { normalized, originalIndexOf };
|
|
2008
|
+
}
|
|
2009
|
+
function normalizeForSearch(value) {
|
|
2010
|
+
return normalizeForSearchWithMap(value).normalized;
|
|
2011
|
+
}
|
|
2012
|
+
function filterQuickReplies({
|
|
2013
|
+
quickReplies,
|
|
2014
|
+
search,
|
|
2015
|
+
variables
|
|
2016
|
+
}) {
|
|
2017
|
+
const term = normalizeForSearch(search.trim());
|
|
2018
|
+
if (!term) return quickReplies;
|
|
2019
|
+
return quickReplies.filter((quickReply) => {
|
|
2020
|
+
const body = applyQuickReplyVariables(quickReply.body, variables);
|
|
2021
|
+
return normalizeForSearch(quickReply.title).includes(term) || normalizeForSearch(quickReply.shortcut).includes(term) || normalizeForSearch(body).includes(term);
|
|
2022
|
+
});
|
|
2023
|
+
}
|
|
2024
|
+
function highlightMatch(text, search) {
|
|
2025
|
+
const term = search.trim();
|
|
2026
|
+
if (!term) return [{ text, isMatch: false }];
|
|
2027
|
+
const { normalized: normalizedText, originalIndexOf } = normalizeForSearchWithMap(text);
|
|
2028
|
+
const normalizedTerm = normalizeForSearch(term);
|
|
2029
|
+
if (!normalizedTerm) return [{ text, isMatch: false }];
|
|
2030
|
+
const originalIndexAt = (normalizedIndex) => normalizedIndex < originalIndexOf.length ? originalIndexOf[normalizedIndex] : text.length;
|
|
2031
|
+
const segments = [];
|
|
2032
|
+
let normalizedCursor = 0;
|
|
2033
|
+
let originalCursor = 0;
|
|
2034
|
+
while (normalizedCursor < normalizedText.length) {
|
|
2035
|
+
const matchIndex = normalizedText.indexOf(normalizedTerm, normalizedCursor);
|
|
2036
|
+
if (matchIndex === -1) break;
|
|
2037
|
+
const matchOriginalStart = originalIndexAt(matchIndex);
|
|
2038
|
+
if (matchOriginalStart > originalCursor) {
|
|
2039
|
+
segments.push({ text: text.slice(originalCursor, matchOriginalStart), isMatch: false });
|
|
2040
|
+
}
|
|
2041
|
+
const matchNormalizedEnd = matchIndex + normalizedTerm.length;
|
|
2042
|
+
const matchOriginalEnd = originalIndexAt(matchNormalizedEnd);
|
|
2043
|
+
segments.push({ text: text.slice(matchOriginalStart, matchOriginalEnd), isMatch: true });
|
|
2044
|
+
normalizedCursor = matchNormalizedEnd;
|
|
2045
|
+
originalCursor = matchOriginalEnd;
|
|
2046
|
+
}
|
|
2047
|
+
if (originalCursor < text.length) segments.push({ text: text.slice(originalCursor), isMatch: false });
|
|
2048
|
+
return segments;
|
|
2049
|
+
}
|
|
2050
|
+
|
|
1534
2051
|
// src/DateDivider.tsx
|
|
1535
|
-
import { jsx as
|
|
2052
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
1536
2053
|
function DateDivider({ iso, className, classNames }) {
|
|
1537
2054
|
const { dateDivider } = useConversationLocales();
|
|
1538
|
-
return /* @__PURE__ */
|
|
2055
|
+
return /* @__PURE__ */ jsx16("div", { className: cn("flex justify-center sticky top-0 z-10 my-2 pointer-events-none", classNames?.root, className), children: /* @__PURE__ */ jsx16(
|
|
1539
2056
|
"span",
|
|
1540
2057
|
{
|
|
1541
2058
|
className: cn(
|
|
@@ -1681,13 +2198,13 @@ function contactFlag(params) {
|
|
|
1681
2198
|
}
|
|
1682
2199
|
|
|
1683
2200
|
// src/hooks/useAsyncResource.ts
|
|
1684
|
-
import { useCallback as
|
|
2201
|
+
import { useCallback as useCallback6, useEffect as useEffect6, useRef as useRef6, useState as useState10 } from "react";
|
|
1685
2202
|
function useAsyncResource(fetcher, deps) {
|
|
1686
|
-
const [data, setData] =
|
|
1687
|
-
const [loading, setLoading] =
|
|
1688
|
-
const [error, setError] =
|
|
1689
|
-
const requestIdRef =
|
|
1690
|
-
const load =
|
|
2203
|
+
const [data, setData] = useState10(void 0);
|
|
2204
|
+
const [loading, setLoading] = useState10(false);
|
|
2205
|
+
const [error, setError] = useState10(void 0);
|
|
2206
|
+
const requestIdRef = useRef6(0);
|
|
2207
|
+
const load = useCallback6(async () => {
|
|
1691
2208
|
const requestId = ++requestIdRef.current;
|
|
1692
2209
|
setLoading(true);
|
|
1693
2210
|
setError(void 0);
|
|
@@ -1700,7 +2217,7 @@ function useAsyncResource(fetcher, deps) {
|
|
|
1700
2217
|
if (requestId === requestIdRef.current) setLoading(false);
|
|
1701
2218
|
}
|
|
1702
2219
|
}, deps);
|
|
1703
|
-
|
|
2220
|
+
useEffect6(() => {
|
|
1704
2221
|
load();
|
|
1705
2222
|
}, [load]);
|
|
1706
2223
|
return { data, loading, error, refetch: load };
|
|
@@ -1735,7 +2252,7 @@ function useConversationDocuments(conversationId, params) {
|
|
|
1735
2252
|
}
|
|
1736
2253
|
|
|
1737
2254
|
// src/ConversationDocumentsPanel.tsx
|
|
1738
|
-
import { useState as
|
|
2255
|
+
import { useState as useState11 } from "react";
|
|
1739
2256
|
import { ArrowUpDown, Bot, Download, Eye, Users } from "lucide-react";
|
|
1740
2257
|
|
|
1741
2258
|
// src/pagination.constant.ts
|
|
@@ -1747,7 +2264,7 @@ var PAGINATION_LABELS = {
|
|
|
1747
2264
|
};
|
|
1748
2265
|
|
|
1749
2266
|
// src/ConversationDocumentsPanel.tsx
|
|
1750
|
-
import { jsx as
|
|
2267
|
+
import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1751
2268
|
var DOCUMENT_SOURCE_FILTER = {
|
|
1752
2269
|
ALL: "all",
|
|
1753
2270
|
CUSTOMER: "customer",
|
|
@@ -1787,12 +2304,12 @@ function ConversationDocumentsPanel({
|
|
|
1787
2304
|
}) {
|
|
1788
2305
|
const labels = { ...DEFAULT_CONVERSATION_DOCUMENTS_LABELS, ...labelsOverride };
|
|
1789
2306
|
const context = useConversations();
|
|
1790
|
-
const [search, setSearch] =
|
|
1791
|
-
const [sourceFilter, setSourceFilter] =
|
|
1792
|
-
const [sortDirection, setSortDirection] =
|
|
1793
|
-
const [page, setPage] =
|
|
1794
|
-
const [selectedIds, setSelectedIds] =
|
|
1795
|
-
const [archiveError, setArchiveError] =
|
|
2307
|
+
const [search, setSearch] = useState11("");
|
|
2308
|
+
const [sourceFilter, setSourceFilter] = useState11(DOCUMENT_SOURCE_FILTER.ALL);
|
|
2309
|
+
const [sortDirection, setSortDirection] = useState11("desc");
|
|
2310
|
+
const [page, setPage] = useState11(1);
|
|
2311
|
+
const [selectedIds, setSelectedIds] = useState11([]);
|
|
2312
|
+
const [archiveError, setArchiveError] = useState11(false);
|
|
1796
2313
|
const hasFilters = search !== "" || sourceFilter !== DOCUMENT_SOURCE_FILTER.ALL || sortDirection !== "desc";
|
|
1797
2314
|
const { documents, total, loading, error } = useConversationDocuments(open ? conversationId : void 0, {
|
|
1798
2315
|
search,
|
|
@@ -1843,10 +2360,10 @@ function ConversationDocumentsPanel({
|
|
|
1843
2360
|
}
|
|
1844
2361
|
}
|
|
1845
2362
|
if (!open) return null;
|
|
1846
|
-
return /* @__PURE__ */
|
|
1847
|
-
/* @__PURE__ */
|
|
1848
|
-
/* @__PURE__ */
|
|
1849
|
-
/* @__PURE__ */
|
|
2363
|
+
return /* @__PURE__ */ jsx17("div", { className: cn("border-b", classNames?.root, className), children: /* @__PURE__ */ jsxs12("section", { className: cn("px-4 py-3", classNames?.body), children: [
|
|
2364
|
+
/* @__PURE__ */ jsx17("p", { className: cn("mb-2 text-sm font-medium", classNames?.title), children: labels.title }),
|
|
2365
|
+
/* @__PURE__ */ jsxs12("div", { className: cn("mb-2 flex flex-wrap items-center gap-2 border-b pb-2", classNames?.filters), children: [
|
|
2366
|
+
/* @__PURE__ */ jsx17(
|
|
1850
2367
|
"input",
|
|
1851
2368
|
{
|
|
1852
2369
|
type: "search",
|
|
@@ -1857,7 +2374,7 @@ function ConversationDocumentsPanel({
|
|
|
1857
2374
|
className: cn("w-full rounded-md border px-3 py-2 text-sm sm:w-52", classNames?.search)
|
|
1858
2375
|
}
|
|
1859
2376
|
),
|
|
1860
|
-
/* @__PURE__ */
|
|
2377
|
+
/* @__PURE__ */ jsxs12(
|
|
1861
2378
|
"select",
|
|
1862
2379
|
{
|
|
1863
2380
|
value: sourceFilter,
|
|
@@ -1865,13 +2382,13 @@ function ConversationDocumentsPanel({
|
|
|
1865
2382
|
"aria-label": labels.sourceFilterAll,
|
|
1866
2383
|
className: cn("w-full rounded-md border px-2 py-2 text-sm sm:w-36", classNames?.sourceSelect),
|
|
1867
2384
|
children: [
|
|
1868
|
-
/* @__PURE__ */
|
|
1869
|
-
/* @__PURE__ */
|
|
1870
|
-
/* @__PURE__ */
|
|
2385
|
+
/* @__PURE__ */ jsx17("option", { value: DOCUMENT_SOURCE_FILTER.ALL, children: labels.sourceFilterAll }),
|
|
2386
|
+
/* @__PURE__ */ jsx17("option", { value: DOCUMENT_SOURCE_FILTER.CUSTOMER, children: labels.sourceFilterCustomer }),
|
|
2387
|
+
/* @__PURE__ */ jsx17("option", { value: DOCUMENT_SOURCE_FILTER.TEAM, children: labels.sourceFilterTeam })
|
|
1871
2388
|
]
|
|
1872
2389
|
}
|
|
1873
2390
|
),
|
|
1874
|
-
/* @__PURE__ */
|
|
2391
|
+
/* @__PURE__ */ jsxs12(
|
|
1875
2392
|
"button",
|
|
1876
2393
|
{
|
|
1877
2394
|
"data-cv-tooltip": sortDirection === "desc" ? labels.sortMostRecent : labels.sortOldest,
|
|
@@ -1880,12 +2397,12 @@ function ConversationDocumentsPanel({
|
|
|
1880
2397
|
onClick: () => applyFilter(() => setSortDirection(sortDirection === "desc" ? "asc" : "desc")),
|
|
1881
2398
|
className: cn("cv-header-action inline-flex items-center gap-1", classNames?.sortButton),
|
|
1882
2399
|
children: [
|
|
1883
|
-
/* @__PURE__ */
|
|
2400
|
+
/* @__PURE__ */ jsx17(ArrowUpDown, { size: 14 }),
|
|
1884
2401
|
sortDirection === "desc" ? labels.sortMostRecent : labels.sortOldest
|
|
1885
2402
|
]
|
|
1886
2403
|
}
|
|
1887
2404
|
),
|
|
1888
|
-
hasFilters ? /* @__PURE__ */
|
|
2405
|
+
hasFilters ? /* @__PURE__ */ jsx17(
|
|
1889
2406
|
"button",
|
|
1890
2407
|
{
|
|
1891
2408
|
"data-cv-tooltip": labels.clearFilters,
|
|
@@ -1901,12 +2418,12 @@ function ConversationDocumentsPanel({
|
|
|
1901
2418
|
}
|
|
1902
2419
|
) : null
|
|
1903
2420
|
] }),
|
|
1904
|
-
loading ? /* @__PURE__ */
|
|
1905
|
-
error ? /* @__PURE__ */
|
|
1906
|
-
!loading && !error && documents.length === 0 ? /* @__PURE__ */
|
|
1907
|
-
canArchive && documents.length > 0 ? /* @__PURE__ */
|
|
1908
|
-
/* @__PURE__ */
|
|
1909
|
-
/* @__PURE__ */
|
|
2421
|
+
loading ? /* @__PURE__ */ jsx17("p", { className: cn("text-xs text-gray-500", classNames?.status), children: labels.loading }) : null,
|
|
2422
|
+
error ? /* @__PURE__ */ jsx17("p", { role: "alert", className: cn("text-xs text-red-600 dark:text-red-400", classNames?.status), children: labels.failure }) : null,
|
|
2423
|
+
!loading && !error && documents.length === 0 ? /* @__PURE__ */ jsx17("p", { className: cn("text-xs text-gray-500", classNames?.status), children: hasFilters ? labels.noResults : labels.empty }) : null,
|
|
2424
|
+
canArchive && documents.length > 0 ? /* @__PURE__ */ jsxs12("div", { className: cn("mb-2 flex flex-wrap items-center gap-3 text-xs", classNames?.selectionBar), children: [
|
|
2425
|
+
/* @__PURE__ */ jsxs12("label", { className: "inline-flex items-center gap-1.5", children: [
|
|
2426
|
+
/* @__PURE__ */ jsx17(
|
|
1910
2427
|
"input",
|
|
1911
2428
|
{
|
|
1912
2429
|
type: "checkbox",
|
|
@@ -1917,13 +2434,13 @@ function ConversationDocumentsPanel({
|
|
|
1917
2434
|
),
|
|
1918
2435
|
labels.selectAll
|
|
1919
2436
|
] }),
|
|
1920
|
-
selectedIds.length > 0 ? /* @__PURE__ */
|
|
1921
|
-
archiveError ? /* @__PURE__ */
|
|
2437
|
+
selectedIds.length > 0 ? /* @__PURE__ */ jsx17("button", { "data-cv-tooltip": labels.downloadSelected(selectedIds.length), "aria-label": labels.downloadSelected(selectedIds.length), type: "button", onClick: () => void handleDownloadSelected(), className: "cv-header-action", children: labels.downloadSelected(selectedIds.length) }) : null,
|
|
2438
|
+
archiveError ? /* @__PURE__ */ jsx17("span", { role: "alert", className: "text-red-600 dark:text-red-400", children: labels.archiveFailed }) : null
|
|
1922
2439
|
] }) : null,
|
|
1923
|
-
/* @__PURE__ */
|
|
2440
|
+
/* @__PURE__ */ jsx17("ul", { className: cn("space-y-2", classNames?.list), children: documents.map((document2) => {
|
|
1924
2441
|
const isFromCustomer = !TEAM_SOURCES.has(document2.source);
|
|
1925
2442
|
const SourceIcon = isFromCustomer ? Users : Bot;
|
|
1926
|
-
return /* @__PURE__ */
|
|
2443
|
+
return /* @__PURE__ */ jsxs12(
|
|
1927
2444
|
"li",
|
|
1928
2445
|
{
|
|
1929
2446
|
className: cn(
|
|
@@ -1931,8 +2448,8 @@ function ConversationDocumentsPanel({
|
|
|
1931
2448
|
classNames?.item
|
|
1932
2449
|
),
|
|
1933
2450
|
children: [
|
|
1934
|
-
/* @__PURE__ */
|
|
1935
|
-
canArchive ? /* @__PURE__ */
|
|
2451
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
2452
|
+
canArchive ? /* @__PURE__ */ jsx17(
|
|
1936
2453
|
"input",
|
|
1937
2454
|
{
|
|
1938
2455
|
type: "checkbox",
|
|
@@ -1942,9 +2459,9 @@ function ConversationDocumentsPanel({
|
|
|
1942
2459
|
className: cn("shrink-0", classNames?.checkbox)
|
|
1943
2460
|
}
|
|
1944
2461
|
) : null,
|
|
1945
|
-
/* @__PURE__ */
|
|
1946
|
-
/* @__PURE__ */
|
|
1947
|
-
/* @__PURE__ */
|
|
2462
|
+
/* @__PURE__ */ jsx17(FileIcon, { filename: document2.filename, mimeType: document2.mimeType }),
|
|
2463
|
+
/* @__PURE__ */ jsxs12("div", { className: "min-w-0 flex-1", children: [
|
|
2464
|
+
/* @__PURE__ */ jsxs12(
|
|
1948
2465
|
"div",
|
|
1949
2466
|
{
|
|
1950
2467
|
className: cn(
|
|
@@ -1953,12 +2470,12 @@ function ConversationDocumentsPanel({
|
|
|
1953
2470
|
classNames?.sourceBadge
|
|
1954
2471
|
),
|
|
1955
2472
|
children: [
|
|
1956
|
-
/* @__PURE__ */
|
|
2473
|
+
/* @__PURE__ */ jsx17(SourceIcon, { size: 11 }),
|
|
1957
2474
|
isFromCustomer ? labels.sourceFilterCustomer : labels.sourceFilterTeam
|
|
1958
2475
|
]
|
|
1959
2476
|
}
|
|
1960
2477
|
),
|
|
1961
|
-
/* @__PURE__ */
|
|
2478
|
+
/* @__PURE__ */ jsx17(
|
|
1962
2479
|
"div",
|
|
1963
2480
|
{
|
|
1964
2481
|
className: cn("truncate text-sm font-medium", classNames?.filename),
|
|
@@ -1966,15 +2483,15 @@ function ConversationDocumentsPanel({
|
|
|
1966
2483
|
children: document2.filename
|
|
1967
2484
|
}
|
|
1968
2485
|
),
|
|
1969
|
-
/* @__PURE__ */
|
|
2486
|
+
/* @__PURE__ */ jsxs12("div", { className: cn("text-xs text-gray-500 dark:text-gray-400", classNames?.meta), children: [
|
|
1970
2487
|
formatDateTime(document2.linkedAt),
|
|
1971
2488
|
" \xB7 ",
|
|
1972
2489
|
formatFileSize(document2.sizeBytes)
|
|
1973
2490
|
] })
|
|
1974
2491
|
] })
|
|
1975
2492
|
] }),
|
|
1976
|
-
/* @__PURE__ */
|
|
1977
|
-
/* @__PURE__ */
|
|
2493
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex shrink-0 gap-1", children: [
|
|
2494
|
+
/* @__PURE__ */ jsx17(
|
|
1978
2495
|
"button",
|
|
1979
2496
|
{
|
|
1980
2497
|
type: "button",
|
|
@@ -1982,10 +2499,10 @@ function ConversationDocumentsPanel({
|
|
|
1982
2499
|
"data-cv-tooltip": labels.view,
|
|
1983
2500
|
"aria-label": `${labels.view}: ${document2.filename}`,
|
|
1984
2501
|
className: cn("cv-header-icon", classNames?.viewButton),
|
|
1985
|
-
children: /* @__PURE__ */
|
|
2502
|
+
children: /* @__PURE__ */ jsx17(Eye, { size: 14 })
|
|
1986
2503
|
}
|
|
1987
2504
|
),
|
|
1988
|
-
/* @__PURE__ */
|
|
2505
|
+
/* @__PURE__ */ jsx17(
|
|
1989
2506
|
"button",
|
|
1990
2507
|
{
|
|
1991
2508
|
type: "button",
|
|
@@ -1993,7 +2510,7 @@ function ConversationDocumentsPanel({
|
|
|
1993
2510
|
"data-cv-tooltip": labels.download,
|
|
1994
2511
|
"aria-label": `${labels.download}: ${document2.filename}`,
|
|
1995
2512
|
className: cn("cv-header-icon", classNames?.downloadButton),
|
|
1996
|
-
children: /* @__PURE__ */
|
|
2513
|
+
children: /* @__PURE__ */ jsx17(Download, { size: 14 })
|
|
1997
2514
|
}
|
|
1998
2515
|
)
|
|
1999
2516
|
] })
|
|
@@ -2002,7 +2519,7 @@ function ConversationDocumentsPanel({
|
|
|
2002
2519
|
document2.id
|
|
2003
2520
|
);
|
|
2004
2521
|
}) }),
|
|
2005
|
-
total > perPage ? /* @__PURE__ */
|
|
2522
|
+
total > perPage ? /* @__PURE__ */ jsxs12(
|
|
2006
2523
|
"div",
|
|
2007
2524
|
{
|
|
2008
2525
|
className: cn(
|
|
@@ -2010,9 +2527,9 @@ function ConversationDocumentsPanel({
|
|
|
2010
2527
|
classNames?.pagination
|
|
2011
2528
|
),
|
|
2012
2529
|
children: [
|
|
2013
|
-
/* @__PURE__ */
|
|
2014
|
-
/* @__PURE__ */
|
|
2015
|
-
/* @__PURE__ */
|
|
2530
|
+
/* @__PURE__ */ jsx17("span", { className: "text-gray-400", children: labels.total(total) }),
|
|
2531
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2", children: [
|
|
2532
|
+
/* @__PURE__ */ jsx17(
|
|
2016
2533
|
"button",
|
|
2017
2534
|
{
|
|
2018
2535
|
type: "button",
|
|
@@ -2024,8 +2541,8 @@ function ConversationDocumentsPanel({
|
|
|
2024
2541
|
children: "\u2039"
|
|
2025
2542
|
}
|
|
2026
2543
|
),
|
|
2027
|
-
/* @__PURE__ */
|
|
2028
|
-
/* @__PURE__ */
|
|
2544
|
+
/* @__PURE__ */ jsx17("span", { className: "text-gray-500", children: labels.page(page, lastPage) }),
|
|
2545
|
+
/* @__PURE__ */ jsx17(
|
|
2029
2546
|
"button",
|
|
2030
2547
|
{
|
|
2031
2548
|
type: "button",
|
|
@@ -2045,9 +2562,9 @@ function ConversationDocumentsPanel({
|
|
|
2045
2562
|
}
|
|
2046
2563
|
|
|
2047
2564
|
// src/DocumentsLibrary.tsx
|
|
2048
|
-
import { useEffect as
|
|
2565
|
+
import { useEffect as useEffect7, useRef as useRef7, useState as useState12 } from "react";
|
|
2049
2566
|
import { ArrowUpDown as ArrowUpDown2, Bot as Bot2, Download as Download2, Eye as Eye2, MessageSquare, Upload, Users as Users2 } from "lucide-react";
|
|
2050
|
-
import { Fragment as Fragment4, jsx as
|
|
2567
|
+
import { Fragment as Fragment4, jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2051
2568
|
var DEFAULT_DOCUMENTS_LIBRARY_LABELS = {
|
|
2052
2569
|
title: "Documentos",
|
|
2053
2570
|
searchPlaceholder: "Buscar por nome do arquivo ou telefone",
|
|
@@ -2080,23 +2597,23 @@ function DocumentsLibrary({
|
|
|
2080
2597
|
}) {
|
|
2081
2598
|
const labels = { ...DEFAULT_DOCUMENTS_LIBRARY_LABELS, ...labelsOverride };
|
|
2082
2599
|
const context = useConversations();
|
|
2083
|
-
const [search, setSearch] =
|
|
2084
|
-
const [sourceFilter, setSourceFilter] =
|
|
2085
|
-
const [sortDirection, setSortDirection] =
|
|
2086
|
-
const [page, setPage] =
|
|
2087
|
-
const [documents, setDocuments] =
|
|
2088
|
-
const [total, setTotal] =
|
|
2089
|
-
const [loading, setLoading] =
|
|
2090
|
-
const [failed, setFailed] =
|
|
2091
|
-
const [uploading, setUploading] =
|
|
2092
|
-
const [uploadFailed, setUploadFailed] =
|
|
2093
|
-
const [reloadToken, setReloadToken] =
|
|
2094
|
-
const fileInputRef =
|
|
2600
|
+
const [search, setSearch] = useState12("");
|
|
2601
|
+
const [sourceFilter, setSourceFilter] = useState12(DOCUMENT_SOURCE_FILTER.ALL);
|
|
2602
|
+
const [sortDirection, setSortDirection] = useState12("desc");
|
|
2603
|
+
const [page, setPage] = useState12(1);
|
|
2604
|
+
const [documents, setDocuments] = useState12([]);
|
|
2605
|
+
const [total, setTotal] = useState12(0);
|
|
2606
|
+
const [loading, setLoading] = useState12(false);
|
|
2607
|
+
const [failed, setFailed] = useState12(false);
|
|
2608
|
+
const [uploading, setUploading] = useState12(false);
|
|
2609
|
+
const [uploadFailed, setUploadFailed] = useState12(false);
|
|
2610
|
+
const [reloadToken, setReloadToken] = useState12(0);
|
|
2611
|
+
const fileInputRef = useRef7(null);
|
|
2095
2612
|
const hasFilters = search !== "" || sourceFilter !== DOCUMENT_SOURCE_FILTER.ALL || sortDirection !== "desc";
|
|
2096
2613
|
const lastPage = Math.max(1, Math.ceil(total / perPage));
|
|
2097
2614
|
const fetchAll = context?.api.getAllDocuments;
|
|
2098
2615
|
const uploadDocument = context?.api.uploadDocument;
|
|
2099
|
-
|
|
2616
|
+
useEffect7(() => {
|
|
2100
2617
|
if (!fetchAll) return;
|
|
2101
2618
|
let active = true;
|
|
2102
2619
|
setLoading(true);
|
|
@@ -2142,10 +2659,10 @@ function DocumentsLibrary({
|
|
|
2142
2659
|
}
|
|
2143
2660
|
}
|
|
2144
2661
|
if (!fetchAll) return null;
|
|
2145
|
-
return /* @__PURE__ */
|
|
2146
|
-
/* @__PURE__ */
|
|
2147
|
-
/* @__PURE__ */
|
|
2148
|
-
/* @__PURE__ */
|
|
2662
|
+
return /* @__PURE__ */ jsxs13("div", { className: cn("space-y-3", classNames?.root, className), children: [
|
|
2663
|
+
/* @__PURE__ */ jsx18("h2", { className: cn("text-lg font-semibold", classNames?.title), children: labels.title }),
|
|
2664
|
+
/* @__PURE__ */ jsxs13("div", { className: cn("flex flex-wrap items-center gap-2", classNames?.filters), children: [
|
|
2665
|
+
/* @__PURE__ */ jsx18(
|
|
2149
2666
|
"input",
|
|
2150
2667
|
{
|
|
2151
2668
|
type: "search",
|
|
@@ -2156,7 +2673,7 @@ function DocumentsLibrary({
|
|
|
2156
2673
|
className: cn("w-full rounded-md border px-3 py-2 text-sm sm:w-64", classNames?.search)
|
|
2157
2674
|
}
|
|
2158
2675
|
),
|
|
2159
|
-
/* @__PURE__ */
|
|
2676
|
+
/* @__PURE__ */ jsxs13(
|
|
2160
2677
|
"select",
|
|
2161
2678
|
{
|
|
2162
2679
|
value: sourceFilter,
|
|
@@ -2164,13 +2681,13 @@ function DocumentsLibrary({
|
|
|
2164
2681
|
"aria-label": labels.sourceFilterAll,
|
|
2165
2682
|
className: cn("w-full rounded-md border px-2 py-2 text-sm sm:w-40", classNames?.sourceSelect),
|
|
2166
2683
|
children: [
|
|
2167
|
-
/* @__PURE__ */
|
|
2168
|
-
/* @__PURE__ */
|
|
2169
|
-
/* @__PURE__ */
|
|
2684
|
+
/* @__PURE__ */ jsx18("option", { value: DOCUMENT_SOURCE_FILTER.ALL, children: labels.sourceFilterAll }),
|
|
2685
|
+
/* @__PURE__ */ jsx18("option", { value: DOCUMENT_SOURCE_FILTER.CUSTOMER, children: labels.sourceFilterCustomer }),
|
|
2686
|
+
/* @__PURE__ */ jsx18("option", { value: DOCUMENT_SOURCE_FILTER.TEAM, children: labels.sourceFilterTeam })
|
|
2170
2687
|
]
|
|
2171
2688
|
}
|
|
2172
2689
|
),
|
|
2173
|
-
/* @__PURE__ */
|
|
2690
|
+
/* @__PURE__ */ jsxs13(
|
|
2174
2691
|
"button",
|
|
2175
2692
|
{
|
|
2176
2693
|
"data-cv-tooltip": sortDirection === "desc" ? labels.sortMostRecent : labels.sortOldest,
|
|
@@ -2179,12 +2696,12 @@ function DocumentsLibrary({
|
|
|
2179
2696
|
onClick: () => applyFilter(() => setSortDirection(sortDirection === "desc" ? "asc" : "desc")),
|
|
2180
2697
|
className: cn("cv-header-action inline-flex items-center gap-1", classNames?.sortButton),
|
|
2181
2698
|
children: [
|
|
2182
|
-
/* @__PURE__ */
|
|
2699
|
+
/* @__PURE__ */ jsx18(ArrowUpDown2, { size: 14 }),
|
|
2183
2700
|
sortDirection === "desc" ? labels.sortMostRecent : labels.sortOldest
|
|
2184
2701
|
]
|
|
2185
2702
|
}
|
|
2186
2703
|
),
|
|
2187
|
-
hasFilters ? /* @__PURE__ */
|
|
2704
|
+
hasFilters ? /* @__PURE__ */ jsx18(
|
|
2188
2705
|
"button",
|
|
2189
2706
|
{
|
|
2190
2707
|
"data-cv-tooltip": labels.clearFilters,
|
|
@@ -2199,8 +2716,8 @@ function DocumentsLibrary({
|
|
|
2199
2716
|
children: labels.clearFilters
|
|
2200
2717
|
}
|
|
2201
2718
|
) : null,
|
|
2202
|
-
uploadDocument ? /* @__PURE__ */
|
|
2203
|
-
/* @__PURE__ */
|
|
2719
|
+
uploadDocument ? /* @__PURE__ */ jsxs13(Fragment4, { children: [
|
|
2720
|
+
/* @__PURE__ */ jsx18(
|
|
2204
2721
|
"input",
|
|
2205
2722
|
{
|
|
2206
2723
|
ref: fileInputRef,
|
|
@@ -2213,7 +2730,7 @@ function DocumentsLibrary({
|
|
|
2213
2730
|
}
|
|
2214
2731
|
}
|
|
2215
2732
|
),
|
|
2216
|
-
/* @__PURE__ */
|
|
2733
|
+
/* @__PURE__ */ jsxs13(
|
|
2217
2734
|
"button",
|
|
2218
2735
|
{
|
|
2219
2736
|
"data-cv-tooltip": labels.upload,
|
|
@@ -2223,21 +2740,21 @@ function DocumentsLibrary({
|
|
|
2223
2740
|
disabled: uploading,
|
|
2224
2741
|
className: "cv-header-action ml-auto inline-flex items-center gap-1 disabled:opacity-40",
|
|
2225
2742
|
children: [
|
|
2226
|
-
/* @__PURE__ */
|
|
2743
|
+
/* @__PURE__ */ jsx18(Upload, { size: 14, "aria-hidden": "true" }),
|
|
2227
2744
|
labels.upload
|
|
2228
2745
|
]
|
|
2229
2746
|
}
|
|
2230
2747
|
)
|
|
2231
2748
|
] }) : null
|
|
2232
2749
|
] }),
|
|
2233
|
-
loading ? /* @__PURE__ */
|
|
2234
|
-
failed ? /* @__PURE__ */
|
|
2235
|
-
uploadFailed ? /* @__PURE__ */
|
|
2236
|
-
!loading && !failed && documents.length === 0 ? /* @__PURE__ */
|
|
2237
|
-
/* @__PURE__ */
|
|
2750
|
+
loading ? /* @__PURE__ */ jsx18("p", { className: cn("text-sm text-gray-500", classNames?.status), children: labels.loading }) : null,
|
|
2751
|
+
failed ? /* @__PURE__ */ jsx18("p", { role: "alert", className: cn("text-sm text-red-600 dark:text-red-400", classNames?.status), children: labels.failure }) : null,
|
|
2752
|
+
uploadFailed ? /* @__PURE__ */ jsx18("p", { role: "alert", className: cn("text-sm text-red-600 dark:text-red-400", classNames?.status), children: labels.uploadError }) : null,
|
|
2753
|
+
!loading && !failed && documents.length === 0 ? /* @__PURE__ */ jsx18("p", { className: cn("text-sm text-gray-500", classNames?.status), children: hasFilters ? labels.noResults : labels.empty }) : null,
|
|
2754
|
+
/* @__PURE__ */ jsx18("ul", { className: cn("space-y-2", classNames?.list), children: documents.map((document2) => {
|
|
2238
2755
|
const isFromCustomer = !TEAM_SOURCES2.has(document2.source);
|
|
2239
2756
|
const SourceIcon = isFromCustomer ? Users2 : Bot2;
|
|
2240
|
-
return /* @__PURE__ */
|
|
2757
|
+
return /* @__PURE__ */ jsxs13(
|
|
2241
2758
|
"li",
|
|
2242
2759
|
{
|
|
2243
2760
|
className: cn(
|
|
@@ -2245,23 +2762,23 @@ function DocumentsLibrary({
|
|
|
2245
2762
|
classNames?.item
|
|
2246
2763
|
),
|
|
2247
2764
|
children: [
|
|
2248
|
-
/* @__PURE__ */
|
|
2249
|
-
/* @__PURE__ */
|
|
2250
|
-
/* @__PURE__ */
|
|
2251
|
-
/* @__PURE__ */
|
|
2252
|
-
/* @__PURE__ */
|
|
2253
|
-
/* @__PURE__ */
|
|
2254
|
-
/* @__PURE__ */
|
|
2765
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [
|
|
2766
|
+
/* @__PURE__ */ jsx18(FileIcon, { filename: document2.filename, mimeType: document2.mimeType }),
|
|
2767
|
+
/* @__PURE__ */ jsxs13("div", { className: "min-w-0 flex-1", children: [
|
|
2768
|
+
/* @__PURE__ */ jsx18("div", { className: cn("truncate text-sm font-medium", classNames?.filename), "data-cv-tooltip": document2.filename, children: document2.filename }),
|
|
2769
|
+
/* @__PURE__ */ jsxs13("div", { className: cn("flex flex-wrap items-center gap-x-2 text-xs text-gray-500", classNames?.meta), children: [
|
|
2770
|
+
/* @__PURE__ */ jsxs13("span", { className: "inline-flex items-center gap-1", children: [
|
|
2771
|
+
/* @__PURE__ */ jsx18(SourceIcon, { size: 11 }),
|
|
2255
2772
|
isFromCustomer ? labels.sourceFilterCustomer : labels.sourceFilterTeam
|
|
2256
2773
|
] }),
|
|
2257
|
-
/* @__PURE__ */
|
|
2258
|
-
/* @__PURE__ */
|
|
2259
|
-
/* @__PURE__ */
|
|
2260
|
-
/* @__PURE__ */
|
|
2774
|
+
/* @__PURE__ */ jsx18("span", { children: "\xB7" }),
|
|
2775
|
+
/* @__PURE__ */ jsx18("span", { children: formatDateTime(document2.linkedAt) }),
|
|
2776
|
+
/* @__PURE__ */ jsx18("span", { children: "\xB7" }),
|
|
2777
|
+
/* @__PURE__ */ jsx18("span", { children: formatFileSize(document2.sizeBytes) })
|
|
2261
2778
|
] })
|
|
2262
2779
|
] })
|
|
2263
2780
|
] }),
|
|
2264
|
-
onOpenConversation ? /* @__PURE__ */
|
|
2781
|
+
onOpenConversation ? /* @__PURE__ */ jsxs13(
|
|
2265
2782
|
"button",
|
|
2266
2783
|
{
|
|
2267
2784
|
type: "button",
|
|
@@ -2270,13 +2787,13 @@ function DocumentsLibrary({
|
|
|
2270
2787
|
"aria-label": labels.openConversation,
|
|
2271
2788
|
className: cn("cv-header-action inline-flex shrink-0 items-center gap-1", classNames?.conversationLink),
|
|
2272
2789
|
children: [
|
|
2273
|
-
/* @__PURE__ */
|
|
2790
|
+
/* @__PURE__ */ jsx18(MessageSquare, { size: 12 }),
|
|
2274
2791
|
formatPhone(document2.conversationId)
|
|
2275
2792
|
]
|
|
2276
2793
|
}
|
|
2277
|
-
) : /* @__PURE__ */
|
|
2278
|
-
/* @__PURE__ */
|
|
2279
|
-
/* @__PURE__ */
|
|
2794
|
+
) : /* @__PURE__ */ jsx18("span", { className: cn("shrink-0 text-xs text-gray-500", classNames?.conversationLink), children: formatPhone(document2.conversationId) }),
|
|
2795
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex shrink-0 gap-1", children: [
|
|
2796
|
+
/* @__PURE__ */ jsx18(
|
|
2280
2797
|
"button",
|
|
2281
2798
|
{
|
|
2282
2799
|
type: "button",
|
|
@@ -2284,10 +2801,10 @@ function DocumentsLibrary({
|
|
|
2284
2801
|
"data-cv-tooltip": labels.view,
|
|
2285
2802
|
"aria-label": `${labels.view}: ${document2.filename}`,
|
|
2286
2803
|
className: "cv-header-icon",
|
|
2287
|
-
children: /* @__PURE__ */
|
|
2804
|
+
children: /* @__PURE__ */ jsx18(Eye2, { size: 14 })
|
|
2288
2805
|
}
|
|
2289
2806
|
),
|
|
2290
|
-
/* @__PURE__ */
|
|
2807
|
+
/* @__PURE__ */ jsx18(
|
|
2291
2808
|
"button",
|
|
2292
2809
|
{
|
|
2293
2810
|
type: "button",
|
|
@@ -2295,7 +2812,7 @@ function DocumentsLibrary({
|
|
|
2295
2812
|
"data-cv-tooltip": labels.download,
|
|
2296
2813
|
"aria-label": `${labels.download}: ${document2.filename}`,
|
|
2297
2814
|
className: "cv-header-icon",
|
|
2298
|
-
children: /* @__PURE__ */
|
|
2815
|
+
children: /* @__PURE__ */ jsx18(Download2, { size: 14 })
|
|
2299
2816
|
}
|
|
2300
2817
|
)
|
|
2301
2818
|
] })
|
|
@@ -2304,10 +2821,10 @@ function DocumentsLibrary({
|
|
|
2304
2821
|
`${document2.conversationId}:${document2.id}`
|
|
2305
2822
|
);
|
|
2306
2823
|
}) }),
|
|
2307
|
-
total > perPage ? /* @__PURE__ */
|
|
2308
|
-
/* @__PURE__ */
|
|
2309
|
-
/* @__PURE__ */
|
|
2310
|
-
/* @__PURE__ */
|
|
2824
|
+
total > perPage ? /* @__PURE__ */ jsxs13("div", { className: cn("flex items-center justify-between border-t pt-2 text-xs dark:border-gray-700", classNames?.pagination), children: [
|
|
2825
|
+
/* @__PURE__ */ jsx18("span", { className: "text-gray-400", children: labels.total(total) }),
|
|
2826
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2", children: [
|
|
2827
|
+
/* @__PURE__ */ jsx18(
|
|
2311
2828
|
"button",
|
|
2312
2829
|
{
|
|
2313
2830
|
"data-cv-tooltip": PAGINATION_LABELS.previous,
|
|
@@ -2319,8 +2836,8 @@ function DocumentsLibrary({
|
|
|
2319
2836
|
children: "\u2039"
|
|
2320
2837
|
}
|
|
2321
2838
|
),
|
|
2322
|
-
/* @__PURE__ */
|
|
2323
|
-
/* @__PURE__ */
|
|
2839
|
+
/* @__PURE__ */ jsx18("span", { className: "text-gray-500", children: labels.page(page, lastPage) }),
|
|
2840
|
+
/* @__PURE__ */ jsx18(
|
|
2324
2841
|
"button",
|
|
2325
2842
|
{
|
|
2326
2843
|
"data-cv-tooltip": PAGINATION_LABELS.next,
|
|
@@ -2384,8 +2901,8 @@ function toConversationSimulatorClient({
|
|
|
2384
2901
|
}
|
|
2385
2902
|
|
|
2386
2903
|
// src/preview/ConversationPreview.tsx
|
|
2387
|
-
import { useCallback as
|
|
2388
|
-
import { jsx as
|
|
2904
|
+
import { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo4, useRef as useRef8, useState as useState13 } from "react";
|
|
2905
|
+
import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2389
2906
|
function mediaTypeOf(mimeType) {
|
|
2390
2907
|
return mediaKindOf(mimeType);
|
|
2391
2908
|
}
|
|
@@ -2429,19 +2946,19 @@ function ConversationPreview({
|
|
|
2429
2946
|
pollIntervalMs,
|
|
2430
2947
|
uploadMedia
|
|
2431
2948
|
}) {
|
|
2432
|
-
const [messages, setMessages] =
|
|
2433
|
-
const [failure, setFailure] =
|
|
2434
|
-
const [loadFailure, setLoadFailure] =
|
|
2435
|
-
const [isRecording, setIsRecording] =
|
|
2436
|
-
const [pendingLocal, setPendingLocal] =
|
|
2437
|
-
const loadMessagesRef =
|
|
2438
|
-
const bottomRef =
|
|
2949
|
+
const [messages, setMessages] = useState13([]);
|
|
2950
|
+
const [failure, setFailure] = useState13(void 0);
|
|
2951
|
+
const [loadFailure, setLoadFailure] = useState13(void 0);
|
|
2952
|
+
const [isRecording, setIsRecording] = useState13(false);
|
|
2953
|
+
const [pendingLocal, setPendingLocal] = useState13([]);
|
|
2954
|
+
const loadMessagesRef = useRef8(loadMessages);
|
|
2955
|
+
const bottomRef = useRef8(null);
|
|
2439
2956
|
loadMessagesRef.current = loadMessages;
|
|
2440
2957
|
const simulator = useMemo4(
|
|
2441
2958
|
() => isConversationSimulatorClient(client) ? client : toConversationSimulatorClient({ client, ...uploadMedia ? { uploadMedia } : {} }),
|
|
2442
2959
|
[client, uploadMedia]
|
|
2443
2960
|
);
|
|
2444
|
-
const refresh =
|
|
2961
|
+
const refresh = useCallback7(async () => {
|
|
2445
2962
|
try {
|
|
2446
2963
|
const loaded = await loadMessagesRef.current(conversationId);
|
|
2447
2964
|
setMessages(loaded);
|
|
@@ -2456,10 +2973,10 @@ function ConversationPreview({
|
|
|
2456
2973
|
setLoadFailure(describeLoadFailure(error));
|
|
2457
2974
|
}
|
|
2458
2975
|
}, [conversationId]);
|
|
2459
|
-
|
|
2976
|
+
useEffect8(() => {
|
|
2460
2977
|
void refresh();
|
|
2461
2978
|
}, [refresh]);
|
|
2462
|
-
|
|
2979
|
+
useEffect8(() => {
|
|
2463
2980
|
const source = sse.connectConversationStream(conversationId);
|
|
2464
2981
|
const handler = () => {
|
|
2465
2982
|
void refresh();
|
|
@@ -2470,12 +2987,12 @@ function ConversationPreview({
|
|
|
2470
2987
|
source.close();
|
|
2471
2988
|
};
|
|
2472
2989
|
}, [sse, conversationId, refresh]);
|
|
2473
|
-
|
|
2990
|
+
useEffect8(() => {
|
|
2474
2991
|
if (!pollIntervalMs) return;
|
|
2475
2992
|
const timer = setInterval(() => void refresh(), pollIntervalMs);
|
|
2476
2993
|
return () => clearInterval(timer);
|
|
2477
2994
|
}, [pollIntervalMs, refresh]);
|
|
2478
|
-
|
|
2995
|
+
useEffect8(() => {
|
|
2479
2996
|
bottomRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
|
2480
2997
|
}, [messages]);
|
|
2481
2998
|
const rendered = useMemo4(() => decorate([...messages, ...pendingLocal]), [messages, pendingLocal]);
|
|
@@ -2535,11 +3052,11 @@ function ConversationPreview({
|
|
|
2535
3052
|
setFailure(error instanceof Error ? error.message : "Falha ao enviar o arquivo.");
|
|
2536
3053
|
}
|
|
2537
3054
|
}
|
|
2538
|
-
return /* @__PURE__ */
|
|
2539
|
-
/* @__PURE__ */
|
|
2540
|
-
rendered.map(({ message, isFirstInGroup, showDateDivider }) => /* @__PURE__ */
|
|
2541
|
-
showDateDivider ? /* @__PURE__ */
|
|
2542
|
-
/* @__PURE__ */
|
|
3055
|
+
return /* @__PURE__ */ jsxs14("div", { className: "flex h-full min-h-0 flex-col", children: [
|
|
3056
|
+
/* @__PURE__ */ jsxs14(ConversationWallpaper, { className: "flex-1 min-h-0 overflow-y-auto px-4 py-3", children: [
|
|
3057
|
+
rendered.map(({ message, isFirstInGroup, showDateDivider }) => /* @__PURE__ */ jsxs14("div", { children: [
|
|
3058
|
+
showDateDivider ? /* @__PURE__ */ jsx19(DateDivider, { iso: message.timestamp }) : null,
|
|
3059
|
+
/* @__PURE__ */ jsx19(
|
|
2543
3060
|
MessageBubble,
|
|
2544
3061
|
{
|
|
2545
3062
|
message,
|
|
@@ -2549,17 +3066,17 @@ function ConversationPreview({
|
|
|
2549
3066
|
}
|
|
2550
3067
|
)
|
|
2551
3068
|
] }, message.id)),
|
|
2552
|
-
/* @__PURE__ */
|
|
3069
|
+
/* @__PURE__ */ jsx19("div", { ref: bottomRef })
|
|
2553
3070
|
] }),
|
|
2554
|
-
failure ? /* @__PURE__ */
|
|
2555
|
-
loadFailure ? /* @__PURE__ */
|
|
2556
|
-
/* @__PURE__ */
|
|
3071
|
+
failure ? /* @__PURE__ */ jsx19("p", { role: "alert", className: "px-4 py-2 text-sm text-red-600 dark:text-red-400", children: failure }) : null,
|
|
3072
|
+
loadFailure ? /* @__PURE__ */ jsx19("p", { role: "status", className: "px-4 py-2 text-sm text-amber-700 dark:text-amber-400", children: loadFailure }) : null,
|
|
3073
|
+
/* @__PURE__ */ jsx19(
|
|
2557
3074
|
MessageComposer,
|
|
2558
3075
|
{
|
|
2559
3076
|
onSend: (text) => void handleSend(text),
|
|
2560
3077
|
onAttach: canAttachFile ? (file) => void handleAttach(file) : void 0,
|
|
2561
3078
|
placeholder: isRecording ? "Gravando\u2026 toque no quadrado para ouvir" : placeholder ?? "Escreva como o cliente\u2026",
|
|
2562
|
-
idleAction: canRecordAudio ? /* @__PURE__ */
|
|
3079
|
+
idleAction: canRecordAudio ? /* @__PURE__ */ jsx19(
|
|
2563
3080
|
AudioRecorderButton,
|
|
2564
3081
|
{
|
|
2565
3082
|
onRecorded: (file) => void handleAttach(file),
|
|
@@ -2573,7 +3090,7 @@ function ConversationPreview({
|
|
|
2573
3090
|
}
|
|
2574
3091
|
|
|
2575
3092
|
// src/preview/ConversationSimulatorPanel.tsx
|
|
2576
|
-
import { jsx as
|
|
3093
|
+
import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2577
3094
|
var DEFAULT_CONVERSATION_SIMULATOR_PANEL_LABELS = {
|
|
2578
3095
|
title: "Simulador do cliente",
|
|
2579
3096
|
destinationHint: "entrega no webhook real",
|
|
@@ -2615,18 +3132,18 @@ function ConversationSimulatorPanel({
|
|
|
2615
3132
|
}) {
|
|
2616
3133
|
const text = { ...simulatorPanelLabelsOf(channel), ...labels };
|
|
2617
3134
|
const subtitle = [displayHandle ?? displayNumber ?? previewProps.conversationId, text.destinationHint].join(" \xB7 ");
|
|
2618
|
-
return /* @__PURE__ */
|
|
2619
|
-
/* @__PURE__ */
|
|
2620
|
-
/* @__PURE__ */
|
|
2621
|
-
/* @__PURE__ */
|
|
2622
|
-
/* @__PURE__ */
|
|
3135
|
+
return /* @__PURE__ */ jsxs15("aside", { className: "cv-simulator-panel", "aria-label": text.title, children: [
|
|
3136
|
+
/* @__PURE__ */ jsxs15("header", { className: "cv-simulator-panel__header", children: [
|
|
3137
|
+
/* @__PURE__ */ jsxs15("div", { className: "cv-simulator-panel__heading", children: [
|
|
3138
|
+
/* @__PURE__ */ jsx20("h2", { className: "cv-simulator-panel__title", children: text.title }),
|
|
3139
|
+
/* @__PURE__ */ jsx20("p", { className: "cv-simulator-panel__subtitle", children: subtitle })
|
|
2623
3140
|
] }),
|
|
2624
|
-
/* @__PURE__ */
|
|
3141
|
+
/* @__PURE__ */ jsxs15("div", { className: "cv-simulator-panel__actions", children: [
|
|
2625
3142
|
headerActions,
|
|
2626
|
-
/* @__PURE__ */
|
|
3143
|
+
/* @__PURE__ */ jsx20("button", { type: "button", onClick: onClose, "data-cv-tooltip": text.close, "aria-label": text.close, className: "cv-simulator-panel__close", children: /* @__PURE__ */ jsx20("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", children: /* @__PURE__ */ jsx20("path", { d: "M18 6 6 18M6 6l12 12" }) }) })
|
|
2627
3144
|
] })
|
|
2628
3145
|
] }),
|
|
2629
|
-
/* @__PURE__ */
|
|
3146
|
+
/* @__PURE__ */ jsx20("div", { className: "cv-simulator-panel__body", children: /* @__PURE__ */ jsx20(ConversationPreview, { ...previewProps, placeholder: text.placeholder }) })
|
|
2630
3147
|
] });
|
|
2631
3148
|
}
|
|
2632
3149
|
|
|
@@ -2667,6 +3184,14 @@ export {
|
|
|
2667
3184
|
COMPOSER_MONOSPACE_CLASS,
|
|
2668
3185
|
COMPOSER_COMPACT_WIDTH,
|
|
2669
3186
|
QUICK_REPLY_PILL_CLASS,
|
|
3187
|
+
normalizeForSearch,
|
|
3188
|
+
filterQuickReplies,
|
|
3189
|
+
highlightMatch,
|
|
3190
|
+
DEFAULT_QUICK_REPLIES_PICKER_LABELS,
|
|
3191
|
+
DEFAULT_QUICK_REPLIES_WORKSPACE_LABELS,
|
|
3192
|
+
QuickRepliesPicker,
|
|
3193
|
+
useQuickRepliesPicker,
|
|
3194
|
+
detectQuickReplyShortcut,
|
|
2670
3195
|
applyQuickReplyVariables,
|
|
2671
3196
|
resolveQuickReply,
|
|
2672
3197
|
DEFAULT_MESSAGE_COMPOSER_LABELS,
|