@adatechnology/conversations-ui 0.1.0-rc.4 → 0.1.0-rc.6
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-LITPZCWW.js +1465 -0
- package/dist/index.d.ts +223 -29
- package/dist/index.js +316 -366
- package/dist/preview/index.d.ts +92 -3
- package/dist/preview/index.js +627 -103
- package/dist/types-CeixG2Z9.d.ts +324 -0
- package/package.json +2 -2
- package/src/Avatar.tsx +13 -2
- package/src/ConversationDocumentsPanel.tsx +342 -24
- package/src/ConversationListItem.tsx +18 -2
- package/src/DocumentsLibrary.tsx +322 -0
- package/src/FileIcon.test.ts +83 -0
- package/src/FileIcon.tsx +88 -11
- package/src/Lightbox.tsx +18 -3
- package/src/MediaRenderer.tsx +5 -2
- package/src/MessageBubble.tsx +18 -2
- package/src/MessageComposer.tsx +20 -3
- package/src/WhatsAppMessageEditor.tsx +28 -4
- package/src/hooks/useConversationActions.ts +56 -0
- package/src/hooks/useConversationDocuments.ts +11 -7
- package/src/hooks/useConversationList.ts +15 -9
- package/src/hooks/useConversationMessages.ts +2 -2
- package/src/index.ts +32 -11
- package/src/lib/cn.test.ts +29 -0
- package/src/lib/createMediaUrlResolver.ts +33 -0
- package/src/lib/paginated.test.ts +33 -0
- package/src/lib/paginated.ts +26 -0
- package/src/preview/MediaTypesPreview.tsx +87 -0
- package/src/preview/createMockConversationsApi.ts +175 -15
- package/src/preview/index.ts +6 -1
- package/src/preview/mockDocumentsSearch.test.ts +57 -0
- package/src/preview/preview.test.ts +5 -3
- package/src/preview/previewFileSamples.test.ts +151 -0
- package/src/preview/previewFileSamples.ts +74 -0
- package/src/preview/previewFixtures.ts +288 -1
- package/src/preview/previewMediaSource.test.ts +62 -0
- package/src/preview/previewMediaSource.ts +91 -0
- package/src/providers/types.ts +127 -9
- package/src/settings/WhatsAppCreateTemplateForm.tsx +3 -1
- package/src/useWaitingNotifications.ts +74 -29
- package/dist/chunk-4R6Y43DQ.js +0 -726
- package/dist/types-C0PtaO7S.d.ts +0 -207
package/dist/index.js
CHANGED
|
@@ -4,9 +4,17 @@ import {
|
|
|
4
4
|
} from "./chunk-NV2RZ5KT.js";
|
|
5
5
|
import {
|
|
6
6
|
AudioPlayer,
|
|
7
|
+
ConversationDocumentsPanel,
|
|
7
8
|
ConversationLocalesProvider,
|
|
8
9
|
ConversationWallpaper,
|
|
10
|
+
ConversationsProvider,
|
|
11
|
+
DEFAULT_CONVERSATION_DOCUMENTS_LABELS,
|
|
12
|
+
DEFAULT_DOCUMENTS_LIBRARY_LABELS,
|
|
13
|
+
DEFAULT_LIGHTBOX_LABELS,
|
|
14
|
+
DEFAULT_MESSAGE_COMPOSER_LABELS,
|
|
15
|
+
DOCUMENT_SOURCE_FILTER,
|
|
9
16
|
DateDivider,
|
|
17
|
+
DocumentsLibrary,
|
|
10
18
|
EmojiPicker,
|
|
11
19
|
FileIcon,
|
|
12
20
|
Lightbox,
|
|
@@ -15,10 +23,21 @@ import {
|
|
|
15
23
|
MessageComposer,
|
|
16
24
|
StatusTicks,
|
|
17
25
|
cn,
|
|
26
|
+
conversationsOf,
|
|
27
|
+
createMediaUrlResolver,
|
|
28
|
+
formatDateTime,
|
|
18
29
|
formatFileSize,
|
|
30
|
+
formatPhone,
|
|
19
31
|
formatTimestamp,
|
|
20
|
-
|
|
21
|
-
|
|
32
|
+
isSameDay,
|
|
33
|
+
phoneCountryFlag,
|
|
34
|
+
phoneInitials,
|
|
35
|
+
totalOf,
|
|
36
|
+
useAsyncResource,
|
|
37
|
+
useConversationDocuments,
|
|
38
|
+
useConversationLocales,
|
|
39
|
+
useConversations
|
|
40
|
+
} from "./chunk-LITPZCWW.js";
|
|
22
41
|
import {
|
|
23
42
|
htmlToWA,
|
|
24
43
|
parseWhatsAppFormatting,
|
|
@@ -30,6 +49,15 @@ import {
|
|
|
30
49
|
import { useRef } from "react";
|
|
31
50
|
import { Bold, Italic, Strikethrough } from "lucide-react";
|
|
32
51
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
52
|
+
var DEFAULT_WHATSAPP_MESSAGE_EDITOR_LABELS = {
|
|
53
|
+
bold: "Negrito",
|
|
54
|
+
boldHint: "Negrito (*texto*)",
|
|
55
|
+
italic: "It\xE1lico",
|
|
56
|
+
italicHint: "It\xE1lico (_texto_)",
|
|
57
|
+
strikethrough: "Tachado",
|
|
58
|
+
strikethroughHint: "Tachado (~texto~)",
|
|
59
|
+
insertPlaceholder: (token) => `Inserir ${token}`
|
|
60
|
+
};
|
|
33
61
|
var INLINE_TOKEN = /(\*[^*\n]+\*|_[^_\n]+_|~[^~\n]+~|`[^`\n]+`|\{[a-zA-Z_]+\})/g;
|
|
34
62
|
function renderLine(line, lineKey) {
|
|
35
63
|
const nodes = [];
|
|
@@ -65,8 +93,10 @@ function WhatsAppMessageEditor({
|
|
|
65
93
|
placeholders = [],
|
|
66
94
|
rows = 4,
|
|
67
95
|
previewLabel = "Pr\xE9via (como aparece no WhatsApp)",
|
|
68
|
-
emptyPreviewText = "Sua mensagem aparecer\xE1 aqui\u2026"
|
|
96
|
+
emptyPreviewText = "Sua mensagem aparecer\xE1 aqui\u2026",
|
|
97
|
+
labels
|
|
69
98
|
}) {
|
|
99
|
+
const editorLabels = { ...DEFAULT_WHATSAPP_MESSAGE_EDITOR_LABELS, ...labels };
|
|
70
100
|
const textareaRef = useRef(null);
|
|
71
101
|
function wrapSelection(marker) {
|
|
72
102
|
const textarea = textareaRef.current;
|
|
@@ -97,9 +127,9 @@ function WhatsAppMessageEditor({
|
|
|
97
127
|
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";
|
|
98
128
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
99
129
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5 mb-2", children: [
|
|
100
|
-
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => wrapSelection("*"), className: toolbarButtonClass, title:
|
|
101
|
-
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => wrapSelection("_"), className: toolbarButtonClass, title:
|
|
102
|
-
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => wrapSelection("~"), className: toolbarButtonClass, title:
|
|
130
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => wrapSelection("*"), className: toolbarButtonClass, title: editorLabels.boldHint, "aria-label": editorLabels.bold, children: /* @__PURE__ */ jsx(Bold, { size: 15 }) }),
|
|
131
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => wrapSelection("_"), className: toolbarButtonClass, title: editorLabels.italicHint, "aria-label": editorLabels.italic, children: /* @__PURE__ */ jsx(Italic, { size: 15 }) }),
|
|
132
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => wrapSelection("~"), className: toolbarButtonClass, title: editorLabels.strikethroughHint, "aria-label": editorLabels.strikethrough, children: /* @__PURE__ */ jsx(Strikethrough, { size: 15 }) }),
|
|
103
133
|
placeholders.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
104
134
|
/* @__PURE__ */ jsx("span", { className: "mx-1 h-5 w-px bg-gray-200 dark:bg-gray-600" }),
|
|
105
135
|
placeholders.map((token) => /* @__PURE__ */ jsx(
|
|
@@ -108,7 +138,7 @@ function WhatsAppMessageEditor({
|
|
|
108
138
|
type: "button",
|
|
109
139
|
onClick: () => insertAtCursor(token),
|
|
110
140
|
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",
|
|
111
|
-
title:
|
|
141
|
+
title: editorLabels.insertPlaceholder(token),
|
|
112
142
|
children: token
|
|
113
143
|
},
|
|
114
144
|
token
|
|
@@ -268,6 +298,9 @@ function SimpleEmojiPicker({ onSelect, label = "Emojis", pickerWidth = "280px",
|
|
|
268
298
|
|
|
269
299
|
// src/Avatar.tsx
|
|
270
300
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
301
|
+
var DEFAULT_AVATAR_LABELS = {
|
|
302
|
+
unnamedContact: "Contato sem nome"
|
|
303
|
+
};
|
|
271
304
|
var sizeClasses = {
|
|
272
305
|
sm: "w-6 h-6 text-xs",
|
|
273
306
|
md: "w-8 h-8 text-sm",
|
|
@@ -293,8 +326,9 @@ function getBgColor(name) {
|
|
|
293
326
|
const hash = name.charCodeAt(0) + (name.charCodeAt(name.length - 1) || 0);
|
|
294
327
|
return bgColors[hash % bgColors.length];
|
|
295
328
|
}
|
|
296
|
-
function Avatar({ name, avatarUrl, size = "md", className = "" }) {
|
|
329
|
+
function Avatar({ name, avatarUrl, size = "md", className = "", labels }) {
|
|
297
330
|
const sizeClass = sizeClasses[size];
|
|
331
|
+
const unnamedContactLabel = labels?.unnamedContact ?? DEFAULT_AVATAR_LABELS.unnamedContact;
|
|
298
332
|
if (avatarUrl) {
|
|
299
333
|
return /* @__PURE__ */ jsx3(
|
|
300
334
|
"img",
|
|
@@ -312,7 +346,7 @@ function Avatar({ name, avatarUrl, size = "md", className = "" }) {
|
|
|
312
346
|
{
|
|
313
347
|
className: `${sizeClass} ${bgColor} rounded-full flex items-center justify-center text-white flex-shrink-0 ${className}`,
|
|
314
348
|
role: "img",
|
|
315
|
-
"aria-label":
|
|
349
|
+
"aria-label": unnamedContactLabel,
|
|
316
350
|
children: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", className: "h-[60%] w-[60%]", "aria-hidden": true, children: /* @__PURE__ */ jsx3("path", { d: "M12 12a5 5 0 1 0 0-10 5 5 0 0 0 0 10Zm0 2c-4.42 0-8 2.24-8 5v1h16v-1c0-2.76-3.58-5-8-5Z" }) })
|
|
317
351
|
}
|
|
318
352
|
);
|
|
@@ -330,51 +364,6 @@ function Avatar({ name, avatarUrl, size = "md", className = "" }) {
|
|
|
330
364
|
// src/ConversationListItem.tsx
|
|
331
365
|
import { useMemo } from "react";
|
|
332
366
|
|
|
333
|
-
// src/lib/phone.ts
|
|
334
|
-
function formatPhone(number) {
|
|
335
|
-
const digits = number.replace(/\D/g, "");
|
|
336
|
-
if (digits.length === 13) {
|
|
337
|
-
return `+${digits.slice(0, 2)} (${digits.slice(2, 4)}) ${digits.slice(4, 9)}-${digits.slice(9, 13)}`;
|
|
338
|
-
}
|
|
339
|
-
if (digits.length === 12) {
|
|
340
|
-
return `+${digits.slice(0, 2)} (${digits.slice(2, 4)}) ${digits.slice(4, 8)}-${digits.slice(8, 12)}`;
|
|
341
|
-
}
|
|
342
|
-
if (digits.length === 11) {
|
|
343
|
-
return `(${digits.slice(0, 2)}) ${digits.slice(2, 7)}-${digits.slice(7, 11)}`;
|
|
344
|
-
}
|
|
345
|
-
if (digits.length === 10) {
|
|
346
|
-
return `(${digits.slice(0, 2)}) ${digits.slice(2, 6)}-${digits.slice(6, 10)}`;
|
|
347
|
-
}
|
|
348
|
-
return number;
|
|
349
|
-
}
|
|
350
|
-
var COUNTRY_FLAG_BY_DIAL_CODE = {
|
|
351
|
-
"55": "\u{1F1E7}\u{1F1F7}",
|
|
352
|
-
"351": "\u{1F1F5}\u{1F1F9}",
|
|
353
|
-
"34": "\u{1F1EA}\u{1F1F8}",
|
|
354
|
-
"54": "\u{1F1E6}\u{1F1F7}",
|
|
355
|
-
"56": "\u{1F1E8}\u{1F1F1}",
|
|
356
|
-
"57": "\u{1F1E8}\u{1F1F4}",
|
|
357
|
-
"52": "\u{1F1F2}\u{1F1FD}",
|
|
358
|
-
"598": "\u{1F1FA}\u{1F1FE}",
|
|
359
|
-
"595": "\u{1F1F5}\u{1F1FE}",
|
|
360
|
-
"44": "\u{1F1EC}\u{1F1E7}",
|
|
361
|
-
"49": "\u{1F1E9}\u{1F1EA}",
|
|
362
|
-
"39": "\u{1F1EE}\u{1F1F9}",
|
|
363
|
-
"33": "\u{1F1EB}\u{1F1F7}"
|
|
364
|
-
};
|
|
365
|
-
function phoneCountryFlag(number) {
|
|
366
|
-
const digits = number.replace(/\D/g, "");
|
|
367
|
-
for (const length of [3, 2, 1]) {
|
|
368
|
-
const flag = COUNTRY_FLAG_BY_DIAL_CODE[digits.slice(0, length)];
|
|
369
|
-
if (flag) return flag;
|
|
370
|
-
}
|
|
371
|
-
return "";
|
|
372
|
-
}
|
|
373
|
-
function phoneInitials(number) {
|
|
374
|
-
const digits = number.replace(/\D/g, "");
|
|
375
|
-
return digits.slice(-2);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
367
|
// src/conversationChannel.ts
|
|
379
368
|
var CONVERSATION_CHANNEL = {
|
|
380
369
|
WHATSAPP: "whatsapp",
|
|
@@ -456,6 +445,10 @@ function contactFlag(params) {
|
|
|
456
445
|
|
|
457
446
|
// src/ConversationListItem.tsx
|
|
458
447
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
448
|
+
var DEFAULT_CONVERSATION_LIST_ITEM_LABELS = {
|
|
449
|
+
expiredWindow: "Janela expirada",
|
|
450
|
+
warningWindow: "Janela pr\xF3xima do fim"
|
|
451
|
+
};
|
|
459
452
|
function formatRelativeTime(dateStr) {
|
|
460
453
|
try {
|
|
461
454
|
const date = new Date(dateStr);
|
|
@@ -516,8 +509,11 @@ var ConversationListItem = ({
|
|
|
516
509
|
onClick,
|
|
517
510
|
onSelect,
|
|
518
511
|
showDivider = true,
|
|
519
|
-
highlightActive = true
|
|
512
|
+
highlightActive = true,
|
|
513
|
+
labels
|
|
520
514
|
}) => {
|
|
515
|
+
const expiredWindowLabel = labels?.expiredWindow ?? DEFAULT_CONVERSATION_LIST_ITEM_LABELS.expiredWindow;
|
|
516
|
+
const warningWindowLabel = labels?.warningWindow ?? DEFAULT_CONVERSATION_LIST_ITEM_LABELS.warningWindow;
|
|
521
517
|
const isActive = active || selected;
|
|
522
518
|
const windowStatus = useMemo(() => getWindowStatus(conversation.lastInboundAt), [conversation.lastInboundAt]);
|
|
523
519
|
const preview = useMemo(() => lastMessagePreview(conversation), [conversation.lastContent]);
|
|
@@ -549,8 +545,8 @@ var ConversationListItem = ({
|
|
|
549
545
|
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-1.5 min-w-0", children: [
|
|
550
546
|
!conversation.clientName && flag ? /* @__PURE__ */ jsx4("span", { "aria-hidden": true, children: flag }) : null,
|
|
551
547
|
/* @__PURE__ */ jsx4("span", { className: "text-[16px] text-[#111b21] truncate", children: name }),
|
|
552
|
-
windowStatus && windowStatus.label === "expired" && /* @__PURE__ */ jsx4("span", { className: "w-2 h-2 rounded-full bg-red-500 flex-shrink-0", title:
|
|
553
|
-
windowStatus && windowStatus.label === "warning" && /* @__PURE__ */ jsx4("span", { className: "w-2 h-2 rounded-full bg-orange-500 flex-shrink-0", title:
|
|
548
|
+
windowStatus && windowStatus.label === "expired" && /* @__PURE__ */ jsx4("span", { className: "w-2 h-2 rounded-full bg-red-500 flex-shrink-0", title: expiredWindowLabel }),
|
|
549
|
+
windowStatus && windowStatus.label === "warning" && /* @__PURE__ */ jsx4("span", { className: "w-2 h-2 rounded-full bg-orange-500 flex-shrink-0", title: warningWindowLabel })
|
|
554
550
|
] }),
|
|
555
551
|
timestamp && /* @__PURE__ */ jsx4("span", { className: "text-xs text-[#667781] flex-shrink-0", children: timestamp })
|
|
556
552
|
] }),
|
|
@@ -1146,116 +1142,6 @@ function isWindowBlocking(window2) {
|
|
|
1146
1142
|
return window2 === CONVERSATION_WINDOW.EXPIRED;
|
|
1147
1143
|
}
|
|
1148
1144
|
|
|
1149
|
-
// src/ConversationDocumentsPanel.tsx
|
|
1150
|
-
import { useState as useState8 } from "react";
|
|
1151
|
-
|
|
1152
|
-
// src/providers/ConversationsProvider.tsx
|
|
1153
|
-
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
1154
|
-
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
1155
|
-
var ConversationsContext = createContext2(null);
|
|
1156
|
-
function ConversationsProvider({
|
|
1157
|
-
api,
|
|
1158
|
-
sse,
|
|
1159
|
-
children
|
|
1160
|
-
}) {
|
|
1161
|
-
return /* @__PURE__ */ jsx14(ConversationsContext.Provider, { value: { api, sse }, children });
|
|
1162
|
-
}
|
|
1163
|
-
function useConversations() {
|
|
1164
|
-
return useContext2(ConversationsContext);
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
// src/hooks/useAsyncResource.ts
|
|
1168
|
-
import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef3, useState as useState7 } from "react";
|
|
1169
|
-
function useAsyncResource(fetcher, deps) {
|
|
1170
|
-
const [data, setData] = useState7(void 0);
|
|
1171
|
-
const [loading, setLoading] = useState7(false);
|
|
1172
|
-
const [error, setError] = useState7(void 0);
|
|
1173
|
-
const requestIdRef = useRef3(0);
|
|
1174
|
-
const load = useCallback3(async () => {
|
|
1175
|
-
const requestId = ++requestIdRef.current;
|
|
1176
|
-
setLoading(true);
|
|
1177
|
-
setError(void 0);
|
|
1178
|
-
try {
|
|
1179
|
-
const result = await fetcher();
|
|
1180
|
-
if (requestId === requestIdRef.current) setData(result);
|
|
1181
|
-
} catch (err) {
|
|
1182
|
-
if (requestId === requestIdRef.current) setError(err instanceof Error ? err : new Error(String(err)));
|
|
1183
|
-
} finally {
|
|
1184
|
-
if (requestId === requestIdRef.current) setLoading(false);
|
|
1185
|
-
}
|
|
1186
|
-
}, deps);
|
|
1187
|
-
useEffect4(() => {
|
|
1188
|
-
load();
|
|
1189
|
-
}, [load]);
|
|
1190
|
-
return { data, loading, error, refetch: load };
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
// src/hooks/useConversationDocuments.ts
|
|
1194
|
-
function useConversationDocuments(conversationId, params) {
|
|
1195
|
-
const context = useConversations();
|
|
1196
|
-
if (!context) {
|
|
1197
|
-
throw new Error("useConversationDocuments requires an ancestor <ConversationsProvider>");
|
|
1198
|
-
}
|
|
1199
|
-
const { api } = context;
|
|
1200
|
-
const { data, loading, error, refetch } = useAsyncResource(
|
|
1201
|
-
() => conversationId ? api.getDocuments(conversationId, params) : Promise.resolve([]),
|
|
1202
|
-
[conversationId, params?.search, params?.page]
|
|
1203
|
-
);
|
|
1204
|
-
return { documents: data ?? [], loading, error, refetch };
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
// src/ConversationDocumentsPanel.tsx
|
|
1208
|
-
import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1209
|
-
var DEFAULT_CONVERSATION_DOCUMENTS_LABELS = {
|
|
1210
|
-
toggle: "\u{1F4CE} Arquivos",
|
|
1211
|
-
title: "Arquivos da conversa",
|
|
1212
|
-
searchPlaceholder: "Buscar arquivo...",
|
|
1213
|
-
empty: "Nenhum arquivo nesta conversa.",
|
|
1214
|
-
loading: "Carregando arquivos\u2026",
|
|
1215
|
-
failure: "N\xE3o foi poss\xEDvel carregar os arquivos.",
|
|
1216
|
-
download: "Baixar"
|
|
1217
|
-
};
|
|
1218
|
-
function ConversationDocumentsPanel({
|
|
1219
|
-
conversationId,
|
|
1220
|
-
open,
|
|
1221
|
-
labels: labelsOverride,
|
|
1222
|
-
className,
|
|
1223
|
-
classNames
|
|
1224
|
-
}) {
|
|
1225
|
-
const labels = { ...DEFAULT_CONVERSATION_DOCUMENTS_LABELS, ...labelsOverride };
|
|
1226
|
-
const context = useConversations();
|
|
1227
|
-
const [search, setSearch] = useState8("");
|
|
1228
|
-
const { documents, loading, error } = useConversationDocuments(open ? conversationId : void 0, { search });
|
|
1229
|
-
async function handleDownload(uploadId) {
|
|
1230
|
-
const url = await context?.api.getDocumentUrl(uploadId);
|
|
1231
|
-
if (url) window.open(url, "_blank", "noopener,noreferrer");
|
|
1232
|
-
}
|
|
1233
|
-
if (!open) return null;
|
|
1234
|
-
return /* @__PURE__ */ jsx15("div", { className: cn("border-b", classNames?.root, className), children: /* @__PURE__ */ jsxs12("section", { className: cn("px-4 py-3", classNames?.body), children: [
|
|
1235
|
-
/* @__PURE__ */ jsx15("p", { className: "mb-2 text-sm font-medium", children: labels.title }),
|
|
1236
|
-
/* @__PURE__ */ jsx15(
|
|
1237
|
-
"input",
|
|
1238
|
-
{
|
|
1239
|
-
type: "search",
|
|
1240
|
-
value: search,
|
|
1241
|
-
onChange: (event) => setSearch(event.target.value),
|
|
1242
|
-
placeholder: labels.searchPlaceholder,
|
|
1243
|
-
className: "mb-2 w-full rounded-md border px-3 py-2 text-sm"
|
|
1244
|
-
}
|
|
1245
|
-
),
|
|
1246
|
-
loading ? /* @__PURE__ */ jsx15("p", { className: "text-xs text-gray-500", children: labels.loading }) : null,
|
|
1247
|
-
error ? /* @__PURE__ */ jsx15("p", { className: "text-xs text-red-600 dark:text-red-400", children: labels.failure }) : null,
|
|
1248
|
-
!loading && !error && documents.length === 0 ? /* @__PURE__ */ jsx15("p", { className: "text-xs text-gray-500", children: labels.empty }) : null,
|
|
1249
|
-
/* @__PURE__ */ jsx15("ul", { className: "space-y-1", children: documents.map((document2) => /* @__PURE__ */ jsxs12("li", { className: "flex items-center gap-2 text-xs", children: [
|
|
1250
|
-
/* @__PURE__ */ jsx15(FileIcon, { mimeType: document2.mimeType }),
|
|
1251
|
-
/* @__PURE__ */ jsx15("span", { className: "min-w-0 flex-1 truncate", children: document2.filename }),
|
|
1252
|
-
/* @__PURE__ */ jsx15("span", { className: "text-gray-500", children: formatFileSize(document2.sizeBytes) }),
|
|
1253
|
-
/* @__PURE__ */ jsx15("span", { className: "text-gray-500", children: formatTimestamp(document2.linkedAt) }),
|
|
1254
|
-
/* @__PURE__ */ jsx15("button", { type: "button", onClick: () => void handleDownload(document2.id), className: "cv-header-action", children: labels.download })
|
|
1255
|
-
] }, document2.id)) })
|
|
1256
|
-
] }) });
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
1145
|
// src/conversationTranscript.ts
|
|
1260
1146
|
var SENDER_LABEL = {
|
|
1261
1147
|
customer: "Cliente",
|
|
@@ -1292,53 +1178,67 @@ function downloadTextFile(filename, content) {
|
|
|
1292
1178
|
}
|
|
1293
1179
|
|
|
1294
1180
|
// src/useWaitingNotifications.ts
|
|
1295
|
-
import { useState as
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1181
|
+
import { useState as useState7, useEffect as useEffect4, useRef as useRef3, useCallback as useCallback3 } from "react";
|
|
1182
|
+
var DEFAULT_POLL_INTERVAL_MS = 1e4;
|
|
1183
|
+
var DEFAULT_LIMIT = 50;
|
|
1184
|
+
var DEFAULT_LABELS = {
|
|
1185
|
+
title: (conversation) => conversation.clientName ?? conversation.whatsappNumber,
|
|
1186
|
+
body: (conversation) => conversation.lastContent ?? "Nova mensagem"
|
|
1187
|
+
};
|
|
1188
|
+
function useWaitingNotifications(params) {
|
|
1189
|
+
const conversationsContext = useConversations();
|
|
1190
|
+
const [conversations, setConversations] = useState7([]);
|
|
1191
|
+
const previousUnreadMap = useRef3(/* @__PURE__ */ new Map());
|
|
1192
|
+
const notifiedIds = useRef3(/* @__PURE__ */ new Set());
|
|
1193
|
+
const isPollingRef = useRef3(false);
|
|
1194
|
+
const isEnabled = params?.enabled ?? true;
|
|
1195
|
+
const intervalMs = params?.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
1196
|
+
const icon = params?.icon;
|
|
1197
|
+
const listParams = params?.params;
|
|
1198
|
+
const labelTitle = params?.labels?.title ?? DEFAULT_LABELS.title;
|
|
1199
|
+
const labelBody = params?.labels?.body ?? DEFAULT_LABELS.body;
|
|
1200
|
+
const refresh = useCallback3(async () => {
|
|
1201
|
+
if (!conversationsContext || isPollingRef.current) return;
|
|
1202
|
+
isPollingRef.current = true;
|
|
1303
1203
|
try {
|
|
1304
|
-
const result =
|
|
1204
|
+
const result = conversationsOf(
|
|
1205
|
+
await conversationsContext.api.fetchConversations({ limit: DEFAULT_LIMIT, ...listParams })
|
|
1206
|
+
);
|
|
1305
1207
|
setConversations(result);
|
|
1306
1208
|
const currentMap = /* @__PURE__ */ new Map();
|
|
1307
|
-
for (const
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
if (
|
|
1312
|
-
|
|
1313
|
-
if (
|
|
1314
|
-
|
|
1315
|
-
if (typeof window !== "undefined" && "Notification" in window && Notification.permission === "granted") {
|
|
1316
|
-
const title = conv.clientName ?? conv.whatsappNumber;
|
|
1317
|
-
const body = conv.lastContent ?? "Nova mensagem";
|
|
1318
|
-
new Notification(title, { body, icon: "/favicon.ico" });
|
|
1319
|
-
}
|
|
1209
|
+
for (const conversation of result) currentMap.set(conversation.id, conversation.unread);
|
|
1210
|
+
for (const conversation of result) {
|
|
1211
|
+
if (conversation.unread <= 0) continue;
|
|
1212
|
+
const previousUnread = previousUnreadMap.current.get(conversation.id) ?? 0;
|
|
1213
|
+
if (conversation.unread <= previousUnread || notifiedIds.current.has(conversation.id)) continue;
|
|
1214
|
+
notifiedIds.current.add(conversation.id);
|
|
1215
|
+
if (typeof window !== "undefined" && "Notification" in window && Notification.permission === "granted") {
|
|
1216
|
+
new Notification(labelTitle(conversation), { body: labelBody(conversation), ...icon ? { icon } : {} });
|
|
1320
1217
|
}
|
|
1321
1218
|
}
|
|
1322
1219
|
previousUnreadMap.current = currentMap;
|
|
1323
1220
|
} catch {
|
|
1221
|
+
} finally {
|
|
1222
|
+
isPollingRef.current = false;
|
|
1324
1223
|
}
|
|
1325
|
-
}, [
|
|
1326
|
-
|
|
1224
|
+
}, [conversationsContext, listParams, icon, labelTitle, labelBody]);
|
|
1225
|
+
useEffect4(() => {
|
|
1226
|
+
if (!isEnabled) return;
|
|
1327
1227
|
if (typeof window !== "undefined" && "Notification" in window && Notification.permission === "default") {
|
|
1328
1228
|
Notification.requestPermission();
|
|
1329
1229
|
}
|
|
1330
|
-
|
|
1331
|
-
const interval = setInterval(
|
|
1230
|
+
void refresh();
|
|
1231
|
+
const interval = setInterval(() => void refresh(), intervalMs);
|
|
1332
1232
|
return () => clearInterval(interval);
|
|
1333
|
-
}, [
|
|
1334
|
-
const unreadCount = conversations.reduce((sum,
|
|
1335
|
-
return { unreadCount, conversations };
|
|
1233
|
+
}, [refresh, isEnabled, intervalMs]);
|
|
1234
|
+
const unreadCount = conversations.reduce((sum, conversation) => sum + conversation.unread, 0);
|
|
1235
|
+
return { unreadCount, conversations, refresh };
|
|
1336
1236
|
}
|
|
1337
1237
|
|
|
1338
1238
|
// src/settings/WhatsAppTemplateSettingsForm.tsx
|
|
1339
1239
|
import { Plus, RefreshCw, Save, Trash2 } from "lucide-react";
|
|
1340
|
-
import { jsx as
|
|
1341
|
-
var
|
|
1240
|
+
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1241
|
+
var DEFAULT_LABELS2 = {
|
|
1342
1242
|
sectionTitle: "WhatsApp",
|
|
1343
1243
|
sectionDescription: "Template usado para reabrir a janela de 24h com o cliente.",
|
|
1344
1244
|
templateLabel: "Template aprovado",
|
|
@@ -1372,7 +1272,7 @@ function WhatsAppTemplateSettingsForm({
|
|
|
1372
1272
|
onSave,
|
|
1373
1273
|
labels: labelsOverride
|
|
1374
1274
|
}) {
|
|
1375
|
-
const labels = { ...
|
|
1275
|
+
const labels = { ...DEFAULT_LABELS2, ...labelsOverride };
|
|
1376
1276
|
const selected = templates.find((template) => template.name === selectedTemplateName);
|
|
1377
1277
|
function handleSelect(name) {
|
|
1378
1278
|
const template = templates.find((t) => t.name === name);
|
|
@@ -1396,16 +1296,16 @@ function WhatsAppTemplateSettingsForm({
|
|
|
1396
1296
|
}
|
|
1397
1297
|
onVariablesChange([...variables, token]);
|
|
1398
1298
|
}
|
|
1399
|
-
return /* @__PURE__ */
|
|
1400
|
-
/* @__PURE__ */
|
|
1401
|
-
/* @__PURE__ */
|
|
1402
|
-
/* @__PURE__ */
|
|
1299
|
+
return /* @__PURE__ */ jsxs12("section", { className: "bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 overflow-hidden", children: [
|
|
1300
|
+
/* @__PURE__ */ jsxs12("div", { className: "px-6 py-4 border-b border-gray-100 dark:border-gray-700", children: [
|
|
1301
|
+
/* @__PURE__ */ jsx14("h2", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: labels.sectionTitle }),
|
|
1302
|
+
/* @__PURE__ */ jsx14("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: labels.sectionDescription })
|
|
1403
1303
|
] }),
|
|
1404
|
-
/* @__PURE__ */
|
|
1405
|
-
/* @__PURE__ */
|
|
1406
|
-
/* @__PURE__ */
|
|
1407
|
-
/* @__PURE__ */
|
|
1408
|
-
/* @__PURE__ */
|
|
1304
|
+
/* @__PURE__ */ jsxs12("form", { onSubmit: onSave, className: "p-6 space-y-4", children: [
|
|
1305
|
+
/* @__PURE__ */ jsxs12("div", { children: [
|
|
1306
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between mb-1.5", children: [
|
|
1307
|
+
/* @__PURE__ */ jsx14("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: labels.templateLabel }),
|
|
1308
|
+
/* @__PURE__ */ jsxs12(
|
|
1409
1309
|
"button",
|
|
1410
1310
|
{
|
|
1411
1311
|
type: "button",
|
|
@@ -1413,31 +1313,31 @@ function WhatsAppTemplateSettingsForm({
|
|
|
1413
1313
|
disabled: loadingTemplates,
|
|
1414
1314
|
className: "flex items-center gap-1 text-xs text-blue-600 dark:text-blue-400 hover:underline disabled:opacity-50",
|
|
1415
1315
|
children: [
|
|
1416
|
-
/* @__PURE__ */
|
|
1316
|
+
/* @__PURE__ */ jsx14(RefreshCw, { size: 11, className: loadingTemplates ? "animate-spin" : "" }),
|
|
1417
1317
|
labels.refreshList
|
|
1418
1318
|
]
|
|
1419
1319
|
}
|
|
1420
1320
|
)
|
|
1421
1321
|
] }),
|
|
1422
|
-
templatesError && /* @__PURE__ */
|
|
1322
|
+
templatesError && /* @__PURE__ */ jsxs12("div", { className: "mb-2 rounded-lg bg-amber-50 dark:bg-amber-950/40 border border-amber-200 dark:border-amber-800 px-3 py-2 text-xs text-amber-700 dark:text-amber-400", children: [
|
|
1423
1323
|
labels.errorLoading,
|
|
1424
|
-
/* @__PURE__ */
|
|
1425
|
-
/* @__PURE__ */
|
|
1324
|
+
/* @__PURE__ */ jsx14("br", {}),
|
|
1325
|
+
/* @__PURE__ */ jsxs12("span", { className: "text-gray-500 dark:text-gray-400 mt-0.5 block", children: [
|
|
1426
1326
|
labels.currentNameSaved,
|
|
1427
1327
|
" ",
|
|
1428
|
-
/* @__PURE__ */
|
|
1328
|
+
/* @__PURE__ */ jsx14("strong", { children: selectedTemplateName || "\u2014" })
|
|
1429
1329
|
] })
|
|
1430
1330
|
] }),
|
|
1431
|
-
loadingTemplates && /* @__PURE__ */
|
|
1432
|
-
!loadingTemplates && !templatesError && /* @__PURE__ */
|
|
1331
|
+
loadingTemplates && /* @__PURE__ */ jsx14("div", { className: "h-10 rounded-xl bg-gray-100 dark:bg-gray-700 animate-pulse" }),
|
|
1332
|
+
!loadingTemplates && !templatesError && /* @__PURE__ */ jsxs12(
|
|
1433
1333
|
"select",
|
|
1434
1334
|
{
|
|
1435
1335
|
value: selectedTemplateName,
|
|
1436
1336
|
onChange: (e) => handleSelect(e.target.value),
|
|
1437
1337
|
className: "w-full border border-gray-200 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 focus:border-transparent transition-all",
|
|
1438
1338
|
children: [
|
|
1439
|
-
/* @__PURE__ */
|
|
1440
|
-
templates.map((template) => /* @__PURE__ */
|
|
1339
|
+
/* @__PURE__ */ jsx14("option", { value: "", children: labels.selectPlaceholder }),
|
|
1340
|
+
templates.map((template) => /* @__PURE__ */ jsxs12("option", { value: template.name, disabled: template.status !== "APPROVED", children: [
|
|
1441
1341
|
template.displayName,
|
|
1442
1342
|
" \xB7 ",
|
|
1443
1343
|
template.shortId,
|
|
@@ -1449,27 +1349,27 @@ function WhatsAppTemplateSettingsForm({
|
|
|
1449
1349
|
]
|
|
1450
1350
|
}
|
|
1451
1351
|
),
|
|
1452
|
-
selected?.bodyText && /* @__PURE__ */
|
|
1352
|
+
selected?.bodyText && /* @__PURE__ */ jsx14("div", { className: "mt-2 rounded-lg bg-gray-50 dark:bg-gray-700/50 border border-gray-200 dark:border-gray-600 px-3 py-2 text-xs text-gray-600 dark:text-gray-300 whitespace-pre-wrap", children: selected.bodyText })
|
|
1453
1353
|
] }),
|
|
1454
|
-
/* @__PURE__ */
|
|
1455
|
-
/* @__PURE__ */
|
|
1456
|
-
/* @__PURE__ */
|
|
1457
|
-
/* @__PURE__ */
|
|
1354
|
+
/* @__PURE__ */ jsxs12("div", { children: [
|
|
1355
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between mb-1.5", children: [
|
|
1356
|
+
/* @__PURE__ */ jsx14("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: labels.variablesLabel }),
|
|
1357
|
+
/* @__PURE__ */ jsxs12(
|
|
1458
1358
|
"button",
|
|
1459
1359
|
{
|
|
1460
1360
|
type: "button",
|
|
1461
1361
|
onClick: () => onVariablesChange([...variables, ""]),
|
|
1462
1362
|
className: "flex items-center gap-1 text-xs text-blue-600 dark:text-blue-400 hover:underline",
|
|
1463
1363
|
children: [
|
|
1464
|
-
/* @__PURE__ */
|
|
1364
|
+
/* @__PURE__ */ jsx14(Plus, { size: 12 }),
|
|
1465
1365
|
labels.addVariable
|
|
1466
1366
|
]
|
|
1467
1367
|
}
|
|
1468
1368
|
)
|
|
1469
1369
|
] }),
|
|
1470
|
-
availableVariables.length > 0 && /* @__PURE__ */
|
|
1471
|
-
/* @__PURE__ */
|
|
1472
|
-
/* @__PURE__ */
|
|
1370
|
+
availableVariables.length > 0 && /* @__PURE__ */ jsxs12("div", { className: "mb-3 rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700/40 p-2.5", children: [
|
|
1371
|
+
/* @__PURE__ */ jsx14("p", { className: "text-xs font-medium text-gray-600 dark:text-gray-300 mb-1.5", children: labels.variablesAvailableTitle }),
|
|
1372
|
+
/* @__PURE__ */ jsx14("div", { className: "flex flex-wrap gap-1.5", children: availableVariables.map((available) => /* @__PURE__ */ jsxs12(
|
|
1473
1373
|
"button",
|
|
1474
1374
|
{
|
|
1475
1375
|
type: "button",
|
|
@@ -1477,8 +1377,8 @@ function WhatsAppTemplateSettingsForm({
|
|
|
1477
1377
|
title: `Inserir ${available.token}`,
|
|
1478
1378
|
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",
|
|
1479
1379
|
children: [
|
|
1480
|
-
/* @__PURE__ */
|
|
1481
|
-
/* @__PURE__ */
|
|
1380
|
+
/* @__PURE__ */ jsx14("code", { className: "text-blue-600 dark:text-blue-300", children: available.token }),
|
|
1381
|
+
/* @__PURE__ */ jsxs12("span", { className: "text-gray-400 dark:text-gray-500", children: [
|
|
1482
1382
|
"\xB7 ",
|
|
1483
1383
|
available.label
|
|
1484
1384
|
] })
|
|
@@ -1486,13 +1386,13 @@ function WhatsAppTemplateSettingsForm({
|
|
|
1486
1386
|
},
|
|
1487
1387
|
available.token
|
|
1488
1388
|
)) }),
|
|
1489
|
-
/* @__PURE__ */
|
|
1389
|
+
/* @__PURE__ */ jsx14("p", { className: "mt-1.5 text-[11px] text-gray-400 dark:text-gray-500", children: labels.variablesAvailableHint })
|
|
1490
1390
|
] }),
|
|
1491
|
-
/* @__PURE__ */
|
|
1492
|
-
variables.length === 0 && /* @__PURE__ */
|
|
1493
|
-
/* @__PURE__ */
|
|
1494
|
-
/* @__PURE__ */
|
|
1495
|
-
/* @__PURE__ */
|
|
1391
|
+
/* @__PURE__ */ jsx14("p", { className: "text-xs text-gray-400 dark:text-gray-500 mb-2", children: labels.variablesMappingHint }),
|
|
1392
|
+
variables.length === 0 && /* @__PURE__ */ jsx14("p", { className: "text-xs text-gray-400 dark:text-gray-500 italic", children: labels.noVariables }),
|
|
1393
|
+
/* @__PURE__ */ jsx14("div", { className: "space-y-2", children: variables.map((variable, index) => /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2", children: [
|
|
1394
|
+
/* @__PURE__ */ jsx14("span", { className: "text-xs text-gray-400 dark:text-gray-500 w-6 text-right flex-shrink-0", children: `{{${index + 1}}}` }),
|
|
1395
|
+
/* @__PURE__ */ jsx14(
|
|
1496
1396
|
"input",
|
|
1497
1397
|
{
|
|
1498
1398
|
type: "text",
|
|
@@ -1502,27 +1402,27 @@ function WhatsAppTemplateSettingsForm({
|
|
|
1502
1402
|
className: "flex-1 border border-gray-200 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 focus:border-transparent transition-all placeholder:text-gray-400 dark:placeholder:text-gray-500"
|
|
1503
1403
|
}
|
|
1504
1404
|
),
|
|
1505
|
-
/* @__PURE__ */
|
|
1405
|
+
/* @__PURE__ */ jsx14(
|
|
1506
1406
|
"button",
|
|
1507
1407
|
{
|
|
1508
1408
|
type: "button",
|
|
1509
1409
|
onClick: () => removeVariable(index),
|
|
1510
1410
|
className: "text-gray-400 hover:text-red-500 dark:hover:text-red-400 transition-colors flex-shrink-0",
|
|
1511
1411
|
title: labels.removeVariable,
|
|
1512
|
-
children: /* @__PURE__ */
|
|
1412
|
+
children: /* @__PURE__ */ jsx14(Trash2, { size: 14 })
|
|
1513
1413
|
}
|
|
1514
1414
|
)
|
|
1515
1415
|
] }, index)) })
|
|
1516
1416
|
] }),
|
|
1517
|
-
saveSuccess && /* @__PURE__ */
|
|
1518
|
-
/* @__PURE__ */
|
|
1417
|
+
saveSuccess && /* @__PURE__ */ jsx14("div", { className: "bg-green-50 dark:bg-green-950/40 border border-green-200 dark:border-green-800 rounded-xl px-4 py-3 text-sm text-green-700 dark:text-green-400", children: labels.saveSuccess }),
|
|
1418
|
+
/* @__PURE__ */ jsx14("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs12(
|
|
1519
1419
|
"button",
|
|
1520
1420
|
{
|
|
1521
1421
|
type: "submit",
|
|
1522
1422
|
disabled: saving || !selectedTemplateName.trim(),
|
|
1523
1423
|
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",
|
|
1524
1424
|
children: [
|
|
1525
|
-
saving ? /* @__PURE__ */
|
|
1425
|
+
saving ? /* @__PURE__ */ jsx14("span", { className: "w-4 h-4 border-2 border-white/40 border-t-white rounded-full animate-spin" }) : /* @__PURE__ */ jsx14(Save, { size: 14 }),
|
|
1526
1426
|
saving ? labels.saving : labels.save
|
|
1527
1427
|
]
|
|
1528
1428
|
}
|
|
@@ -1533,12 +1433,13 @@ function WhatsAppTemplateSettingsForm({
|
|
|
1533
1433
|
|
|
1534
1434
|
// src/settings/WhatsAppCreateTemplateForm.tsx
|
|
1535
1435
|
import { SendHorizonal } from "lucide-react";
|
|
1536
|
-
import { jsx as
|
|
1537
|
-
var
|
|
1436
|
+
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1437
|
+
var DEFAULT_LABELS3 = {
|
|
1538
1438
|
sectionTitle: "Criar novo template",
|
|
1539
1439
|
sectionDescription: "Envia um template para aprova\xE7\xE3o da Meta.",
|
|
1540
1440
|
nameLabel: "Nome do template",
|
|
1541
1441
|
nameHint: "Somente letras min\xFAsculas, n\xFAmeros e underscore.",
|
|
1442
|
+
namePlaceholder: "reengajamento_cliente",
|
|
1542
1443
|
categoryLabel: "Categoria",
|
|
1543
1444
|
languageLabel: "Idioma",
|
|
1544
1445
|
headerLabel: "Cabe\xE7alho",
|
|
@@ -1584,82 +1485,82 @@ function WhatsAppCreateTemplateForm({
|
|
|
1584
1485
|
labels: labelsOverride,
|
|
1585
1486
|
variableExamples = DEFAULT_VARIABLE_EXAMPLES
|
|
1586
1487
|
}) {
|
|
1587
|
-
const labels = { ...
|
|
1488
|
+
const labels = { ...DEFAULT_LABELS3, ...labelsOverride };
|
|
1588
1489
|
const detectedVariables = detectVariables(value.bodyText);
|
|
1589
1490
|
function set(key, next) {
|
|
1590
1491
|
onChange({ ...value, [key]: next });
|
|
1591
1492
|
}
|
|
1592
|
-
return /* @__PURE__ */
|
|
1593
|
-
/* @__PURE__ */
|
|
1594
|
-
/* @__PURE__ */
|
|
1595
|
-
/* @__PURE__ */
|
|
1493
|
+
return /* @__PURE__ */ jsxs13("section", { className: "bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 overflow-hidden", children: [
|
|
1494
|
+
/* @__PURE__ */ jsxs13("div", { className: "px-6 py-4 border-b border-gray-100 dark:border-gray-700", children: [
|
|
1495
|
+
/* @__PURE__ */ jsx15("h2", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: labels.sectionTitle }),
|
|
1496
|
+
/* @__PURE__ */ jsx15("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: labels.sectionDescription })
|
|
1596
1497
|
] }),
|
|
1597
|
-
/* @__PURE__ */
|
|
1598
|
-
/* @__PURE__ */
|
|
1599
|
-
/* @__PURE__ */
|
|
1600
|
-
/* @__PURE__ */
|
|
1601
|
-
/* @__PURE__ */
|
|
1498
|
+
/* @__PURE__ */ jsxs13("form", { onSubmit, className: "p-6 space-y-4", children: [
|
|
1499
|
+
/* @__PURE__ */ jsxs13("div", { children: [
|
|
1500
|
+
/* @__PURE__ */ jsx15("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: labels.nameLabel }),
|
|
1501
|
+
/* @__PURE__ */ jsx15("p", { className: "text-xs text-gray-400 mb-1.5", children: labels.nameHint }),
|
|
1502
|
+
/* @__PURE__ */ jsx15(
|
|
1602
1503
|
"input",
|
|
1603
1504
|
{
|
|
1604
1505
|
type: "text",
|
|
1605
1506
|
value: value.name,
|
|
1606
1507
|
onChange: (e) => set("name", e.target.value.toLowerCase().replace(/[^a-z0-9_]/g, "_")),
|
|
1607
|
-
placeholder:
|
|
1508
|
+
placeholder: labels.namePlaceholder,
|
|
1608
1509
|
className: "w-full border border-gray-200 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 focus:border-transparent transition-all",
|
|
1609
1510
|
required: true
|
|
1610
1511
|
}
|
|
1611
1512
|
)
|
|
1612
1513
|
] }),
|
|
1613
|
-
/* @__PURE__ */
|
|
1614
|
-
/* @__PURE__ */
|
|
1615
|
-
/* @__PURE__ */
|
|
1616
|
-
/* @__PURE__ */
|
|
1514
|
+
/* @__PURE__ */ jsxs13("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
1515
|
+
/* @__PURE__ */ jsxs13("div", { children: [
|
|
1516
|
+
/* @__PURE__ */ jsx15("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: labels.categoryLabel }),
|
|
1517
|
+
/* @__PURE__ */ jsxs13(
|
|
1617
1518
|
"select",
|
|
1618
1519
|
{
|
|
1619
1520
|
value: value.category,
|
|
1620
1521
|
onChange: (e) => set("category", e.target.value),
|
|
1621
1522
|
className: "w-full border border-gray-200 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 focus:border-transparent transition-all",
|
|
1622
1523
|
children: [
|
|
1623
|
-
/* @__PURE__ */
|
|
1624
|
-
/* @__PURE__ */
|
|
1524
|
+
/* @__PURE__ */ jsx15("option", { value: "UTILITY", children: "UTILITY (Transacional)" }),
|
|
1525
|
+
/* @__PURE__ */ jsx15("option", { value: "MARKETING", children: "MARKETING (Promocional)" })
|
|
1625
1526
|
]
|
|
1626
1527
|
}
|
|
1627
1528
|
)
|
|
1628
1529
|
] }),
|
|
1629
|
-
/* @__PURE__ */
|
|
1630
|
-
/* @__PURE__ */
|
|
1631
|
-
/* @__PURE__ */
|
|
1530
|
+
/* @__PURE__ */ jsxs13("div", { children: [
|
|
1531
|
+
/* @__PURE__ */ jsx15("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: labels.languageLabel }),
|
|
1532
|
+
/* @__PURE__ */ jsxs13(
|
|
1632
1533
|
"select",
|
|
1633
1534
|
{
|
|
1634
1535
|
value: value.language,
|
|
1635
1536
|
onChange: (e) => set("language", e.target.value),
|
|
1636
1537
|
className: "w-full border border-gray-200 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 focus:border-transparent transition-all",
|
|
1637
1538
|
children: [
|
|
1638
|
-
/* @__PURE__ */
|
|
1639
|
-
/* @__PURE__ */
|
|
1640
|
-
/* @__PURE__ */
|
|
1539
|
+
/* @__PURE__ */ jsx15("option", { value: "pt_BR", children: "Portugu\xEAs (Brasil)" }),
|
|
1540
|
+
/* @__PURE__ */ jsx15("option", { value: "en_US", children: "Ingl\xEAs (EUA)" }),
|
|
1541
|
+
/* @__PURE__ */ jsx15("option", { value: "es_ES", children: "Espanhol" })
|
|
1641
1542
|
]
|
|
1642
1543
|
}
|
|
1643
1544
|
)
|
|
1644
1545
|
] })
|
|
1645
1546
|
] }),
|
|
1646
|
-
/* @__PURE__ */
|
|
1647
|
-
/* @__PURE__ */
|
|
1648
|
-
/* @__PURE__ */
|
|
1649
|
-
/* @__PURE__ */
|
|
1650
|
-
/* @__PURE__ */
|
|
1547
|
+
/* @__PURE__ */ jsxs13("div", { children: [
|
|
1548
|
+
/* @__PURE__ */ jsx15("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: labels.headerLabel }),
|
|
1549
|
+
/* @__PURE__ */ jsx15("p", { className: "text-xs text-gray-400 mb-1.5", children: labels.headerHint }),
|
|
1550
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex gap-2", children: [
|
|
1551
|
+
/* @__PURE__ */ jsxs13(
|
|
1651
1552
|
"select",
|
|
1652
1553
|
{
|
|
1653
1554
|
value: value.headerType,
|
|
1654
1555
|
onChange: (e) => set("headerType", e.target.value),
|
|
1655
1556
|
className: "border border-gray-200 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 transition-all",
|
|
1656
1557
|
children: [
|
|
1657
|
-
/* @__PURE__ */
|
|
1658
|
-
/* @__PURE__ */
|
|
1558
|
+
/* @__PURE__ */ jsx15("option", { value: "NONE", children: labels.headerNone }),
|
|
1559
|
+
/* @__PURE__ */ jsx15("option", { value: "TEXT", children: labels.headerText })
|
|
1659
1560
|
]
|
|
1660
1561
|
}
|
|
1661
1562
|
),
|
|
1662
|
-
value.headerType === "TEXT" && /* @__PURE__ */
|
|
1563
|
+
value.headerType === "TEXT" && /* @__PURE__ */ jsx15(
|
|
1663
1564
|
"input",
|
|
1664
1565
|
{
|
|
1665
1566
|
type: "text",
|
|
@@ -1672,10 +1573,10 @@ function WhatsAppCreateTemplateForm({
|
|
|
1672
1573
|
)
|
|
1673
1574
|
] })
|
|
1674
1575
|
] }),
|
|
1675
|
-
/* @__PURE__ */
|
|
1676
|
-
/* @__PURE__ */
|
|
1677
|
-
/* @__PURE__ */
|
|
1678
|
-
/* @__PURE__ */
|
|
1576
|
+
/* @__PURE__ */ jsxs13("div", { children: [
|
|
1577
|
+
/* @__PURE__ */ jsx15("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: labels.bodyLabel }),
|
|
1578
|
+
/* @__PURE__ */ jsx15("p", { className: "text-xs text-gray-400 mb-1.5", children: labels.bodyHint }),
|
|
1579
|
+
/* @__PURE__ */ jsx15(
|
|
1679
1580
|
"textarea",
|
|
1680
1581
|
{
|
|
1681
1582
|
value: value.bodyText,
|
|
@@ -1686,26 +1587,26 @@ function WhatsAppCreateTemplateForm({
|
|
|
1686
1587
|
required: true
|
|
1687
1588
|
}
|
|
1688
1589
|
),
|
|
1689
|
-
detectedVariables.length > 0 && /* @__PURE__ */
|
|
1690
|
-
/* @__PURE__ */
|
|
1691
|
-
/* @__PURE__ */
|
|
1692
|
-
/* @__PURE__ */
|
|
1693
|
-
/* @__PURE__ */
|
|
1590
|
+
detectedVariables.length > 0 && /* @__PURE__ */ jsxs13("div", { className: "mt-2 rounded-lg bg-gray-50 dark:bg-gray-700/50 border border-gray-200 dark:border-gray-600 px-3 py-2", children: [
|
|
1591
|
+
/* @__PURE__ */ jsx15("p", { className: "font-medium text-gray-500 dark:text-gray-400 mb-1.5 uppercase tracking-wide text-xs", children: labels.detectedVariables }),
|
|
1592
|
+
/* @__PURE__ */ jsx15("div", { className: "flex flex-wrap gap-2", children: detectedVariables.map((num) => /* @__PURE__ */ jsxs13("span", { className: "inline-flex items-center gap-1 text-xs", children: [
|
|
1593
|
+
/* @__PURE__ */ jsx15("code", { className: "bg-blue-100 dark:bg-blue-900/40 text-blue-700 dark:text-blue-300 px-1.5 py-0.5 rounded font-mono", children: `{{${num}}}` }),
|
|
1594
|
+
/* @__PURE__ */ jsxs13("span", { className: "text-gray-400 dark:text-gray-500", children: [
|
|
1694
1595
|
"= ",
|
|
1695
1596
|
variableExamples[Number(num) - 1] ?? labels.variableLabel(Number(num))
|
|
1696
1597
|
] })
|
|
1697
1598
|
] }, num)) }),
|
|
1698
|
-
/* @__PURE__ */
|
|
1599
|
+
/* @__PURE__ */ jsxs13("p", { className: "text-gray-400 dark:text-gray-500 mt-1.5 text-xs", children: [
|
|
1699
1600
|
labels.configureHintPrefix,
|
|
1700
|
-
/* @__PURE__ */
|
|
1601
|
+
/* @__PURE__ */ jsx15("strong", { children: labels.configureHintLink }),
|
|
1701
1602
|
labels.configureHintSuffix
|
|
1702
1603
|
] })
|
|
1703
1604
|
] })
|
|
1704
1605
|
] }),
|
|
1705
|
-
/* @__PURE__ */
|
|
1706
|
-
/* @__PURE__ */
|
|
1707
|
-
/* @__PURE__ */
|
|
1708
|
-
/* @__PURE__ */
|
|
1606
|
+
/* @__PURE__ */ jsxs13("div", { children: [
|
|
1607
|
+
/* @__PURE__ */ jsx15("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: labels.footerLabel }),
|
|
1608
|
+
/* @__PURE__ */ jsx15("p", { className: "text-xs text-gray-400 mb-1.5", children: labels.footerHint }),
|
|
1609
|
+
/* @__PURE__ */ jsx15(
|
|
1709
1610
|
"input",
|
|
1710
1611
|
{
|
|
1711
1612
|
type: "text",
|
|
@@ -1717,48 +1618,48 @@ function WhatsAppCreateTemplateForm({
|
|
|
1717
1618
|
}
|
|
1718
1619
|
)
|
|
1719
1620
|
] }),
|
|
1720
|
-
/* @__PURE__ */
|
|
1721
|
-
/* @__PURE__ */
|
|
1722
|
-
/* @__PURE__ */
|
|
1723
|
-
/* @__PURE__ */
|
|
1724
|
-
/* @__PURE__ */
|
|
1725
|
-
/* @__PURE__ */
|
|
1726
|
-
/* @__PURE__ */
|
|
1727
|
-
/* @__PURE__ */
|
|
1621
|
+
/* @__PURE__ */ jsxs13("div", { children: [
|
|
1622
|
+
/* @__PURE__ */ jsx15("label", { className: "text-sm font-medium text-gray-700 dark:text-gray-300 mb-2 block", children: labels.previewLabel }),
|
|
1623
|
+
/* @__PURE__ */ jsxs13("div", { className: "rounded-2xl bg-[#e5ddd5] dark:bg-[#1a1a2e] border border-gray-300 dark:border-gray-600 overflow-hidden shadow-inner", children: [
|
|
1624
|
+
/* @__PURE__ */ jsxs13("div", { className: "bg-[#075e54] px-4 py-2.5 flex items-center gap-2", children: [
|
|
1625
|
+
/* @__PURE__ */ jsx15("div", { className: "w-8 h-8 rounded-full bg-white/20 flex items-center justify-center text-white text-xs font-bold", children: previewCompanyName.slice(0, 2).toUpperCase() }),
|
|
1626
|
+
/* @__PURE__ */ jsxs13("div", { children: [
|
|
1627
|
+
/* @__PURE__ */ jsx15("p", { className: "text-white text-xs font-semibold leading-tight", children: previewCompanyName }),
|
|
1628
|
+
/* @__PURE__ */ jsx15("p", { className: "text-white/60 text-xs", children: labels.previewOnline })
|
|
1728
1629
|
] })
|
|
1729
1630
|
] }),
|
|
1730
|
-
/* @__PURE__ */
|
|
1731
|
-
/* @__PURE__ */
|
|
1732
|
-
/* @__PURE__ */
|
|
1733
|
-
/* @__PURE__ */
|
|
1631
|
+
/* @__PURE__ */ jsxs13("div", { className: "px-3 py-4 space-y-3", style: { minHeight: "120px" }, children: [
|
|
1632
|
+
/* @__PURE__ */ jsx15("div", { className: "flex justify-start", style: { maxWidth: "85%" }, children: /* @__PURE__ */ jsxs13("div", { className: "bg-white dark:bg-gray-700 rounded-lg rounded-tl-none px-3 py-2 shadow-sm", children: [
|
|
1633
|
+
/* @__PURE__ */ jsx15("p", { className: "text-gray-500 dark:text-gray-400 leading-tight text-sm", children: labels.previewDescription }),
|
|
1634
|
+
/* @__PURE__ */ jsx15("p", { className: "text-gray-400 dark:text-gray-500 mt-1 text-right text-[9px]", children: "12:00" })
|
|
1734
1635
|
] }) }),
|
|
1735
|
-
/* @__PURE__ */
|
|
1736
|
-
value.headerType === "TEXT" && value.headerText && /* @__PURE__ */
|
|
1737
|
-
/* @__PURE__ */
|
|
1738
|
-
value.footerText && /* @__PURE__ */
|
|
1739
|
-
/* @__PURE__ */
|
|
1636
|
+
/* @__PURE__ */ jsx15("div", { className: "flex justify-end ml-auto", style: { maxWidth: "85%" }, children: /* @__PURE__ */ jsxs13("div", { className: "bg-[#dcf8c6] dark:bg-[#1b5e20] rounded-lg rounded-tr-none px-3 py-2 shadow-sm", children: [
|
|
1637
|
+
value.headerType === "TEXT" && value.headerText && /* @__PURE__ */ jsx15("p", { className: "text-xs font-bold text-gray-700 dark:text-gray-200 mb-1", children: fillPreviewTokens(value.headerText) || labels.previewHeaderFallback }),
|
|
1638
|
+
/* @__PURE__ */ jsx15("p", { className: "text-sm text-gray-800 dark:text-gray-100 leading-relaxed", children: value.bodyText ? fillPreviewTokens(value.bodyText) : /* @__PURE__ */ jsx15("span", { className: "text-gray-400 italic", children: labels.previewBodyPlaceholder }) }),
|
|
1639
|
+
value.footerText && /* @__PURE__ */ jsx15("p", { className: "text-gray-400 dark:text-gray-400 mt-1 text-xs", children: value.footerText }),
|
|
1640
|
+
/* @__PURE__ */ jsx15("p", { className: "text-gray-400 dark:text-gray-400 mt-1 text-right text-[9px]", children: "12:01 \u2713" })
|
|
1740
1641
|
] }) })
|
|
1741
1642
|
] })
|
|
1742
1643
|
] })
|
|
1743
1644
|
] }),
|
|
1744
|
-
result && /* @__PURE__ */
|
|
1645
|
+
result && /* @__PURE__ */ jsxs13(
|
|
1745
1646
|
"div",
|
|
1746
1647
|
{
|
|
1747
1648
|
className: `rounded-xl px-4 py-3 text-sm ${result.ok ? "bg-green-50 dark:bg-green-950/40 border border-green-200 dark:border-green-800 text-green-700 dark:text-green-400" : "bg-red-50 dark:bg-red-950/40 border border-red-200 dark:border-red-800 text-red-700 dark:text-red-400"}`,
|
|
1748
1649
|
children: [
|
|
1749
1650
|
result.message,
|
|
1750
|
-
result.ok && result.status && /* @__PURE__ */
|
|
1651
|
+
result.ok && result.status && /* @__PURE__ */ jsx15("p", { className: "text-xs mt-1 opacity-75", children: labels.successStatus(result.status) })
|
|
1751
1652
|
]
|
|
1752
1653
|
}
|
|
1753
1654
|
),
|
|
1754
|
-
/* @__PURE__ */
|
|
1655
|
+
/* @__PURE__ */ jsx15("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs13(
|
|
1755
1656
|
"button",
|
|
1756
1657
|
{
|
|
1757
1658
|
type: "submit",
|
|
1758
1659
|
disabled: submitting || !value.name || !value.bodyText,
|
|
1759
1660
|
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",
|
|
1760
1661
|
children: [
|
|
1761
|
-
submitting ? /* @__PURE__ */
|
|
1662
|
+
submitting ? /* @__PURE__ */ jsx15("span", { className: "w-4 h-4 border-2 border-white/40 border-t-white rounded-full animate-spin" }) : /* @__PURE__ */ jsx15(SendHorizonal, { size: 14 }),
|
|
1762
1663
|
submitting ? labels.sending : labels.sendForApproval
|
|
1763
1664
|
]
|
|
1764
1665
|
}
|
|
@@ -1769,8 +1670,8 @@ function WhatsAppCreateTemplateForm({
|
|
|
1769
1670
|
|
|
1770
1671
|
// src/settings/WelcomeFarewellForm.tsx
|
|
1771
1672
|
import { LogOut, Mail, Save as Save2 } from "lucide-react";
|
|
1772
|
-
import { jsx as
|
|
1773
|
-
var
|
|
1673
|
+
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1674
|
+
var DEFAULT_LABELS4 = {
|
|
1774
1675
|
sectionTitle: "Boas-vindas e encerramento",
|
|
1775
1676
|
welcomeMessage: "Mensagem de boas-vindas",
|
|
1776
1677
|
welcomeMessagePlaceholder: "Ol\xE1! Sou o assistente virtual da {empresa}...",
|
|
@@ -1796,16 +1697,16 @@ function WelcomeFarewellForm({
|
|
|
1796
1697
|
farewellPlaceholders = DEFAULT_FAREWELL_PLACEHOLDERS,
|
|
1797
1698
|
labels: labelsOverride
|
|
1798
1699
|
}) {
|
|
1799
|
-
const labels = { ...
|
|
1800
|
-
return /* @__PURE__ */
|
|
1801
|
-
/* @__PURE__ */
|
|
1802
|
-
/* @__PURE__ */
|
|
1803
|
-
/* @__PURE__ */
|
|
1804
|
-
/* @__PURE__ */
|
|
1805
|
-
/* @__PURE__ */
|
|
1700
|
+
const labels = { ...DEFAULT_LABELS4, ...labelsOverride };
|
|
1701
|
+
return /* @__PURE__ */ jsxs14("section", { className: "bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 overflow-hidden", children: [
|
|
1702
|
+
/* @__PURE__ */ jsx16("div", { className: "px-6 py-4 border-b border-gray-100 dark:border-gray-700", children: /* @__PURE__ */ jsx16("h2", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: labels.sectionTitle }) }),
|
|
1703
|
+
/* @__PURE__ */ jsxs14("form", { onSubmit: onSave, className: "p-6 space-y-5", children: [
|
|
1704
|
+
/* @__PURE__ */ jsxs14("div", { children: [
|
|
1705
|
+
/* @__PURE__ */ jsxs14("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5 flex items-center gap-1.5", children: [
|
|
1706
|
+
/* @__PURE__ */ jsx16(Mail, { size: 13, className: "text-blue-600 dark:text-blue-400" }),
|
|
1806
1707
|
labels.welcomeMessage
|
|
1807
1708
|
] }),
|
|
1808
|
-
/* @__PURE__ */
|
|
1709
|
+
/* @__PURE__ */ jsx16(
|
|
1809
1710
|
WhatsAppMessageEditor,
|
|
1810
1711
|
{
|
|
1811
1712
|
value: welcomeMessage,
|
|
@@ -1814,14 +1715,14 @@ function WelcomeFarewellForm({
|
|
|
1814
1715
|
placeholders: welcomePlaceholders
|
|
1815
1716
|
}
|
|
1816
1717
|
),
|
|
1817
|
-
/* @__PURE__ */
|
|
1718
|
+
/* @__PURE__ */ jsx16("p", { className: "mt-1.5 text-xs text-gray-500 dark:text-gray-400", children: labels.welcomeMessageHint })
|
|
1818
1719
|
] }),
|
|
1819
|
-
/* @__PURE__ */
|
|
1820
|
-
/* @__PURE__ */
|
|
1821
|
-
/* @__PURE__ */
|
|
1720
|
+
/* @__PURE__ */ jsxs14("div", { children: [
|
|
1721
|
+
/* @__PURE__ */ jsxs14("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5 flex items-center gap-1.5", children: [
|
|
1722
|
+
/* @__PURE__ */ jsx16(LogOut, { size: 13, className: "text-blue-600 dark:text-blue-400" }),
|
|
1822
1723
|
labels.farewellMessage
|
|
1823
1724
|
] }),
|
|
1824
|
-
/* @__PURE__ */
|
|
1725
|
+
/* @__PURE__ */ jsx16(
|
|
1825
1726
|
WhatsAppMessageEditor,
|
|
1826
1727
|
{
|
|
1827
1728
|
value: farewellMessage,
|
|
@@ -1830,17 +1731,17 @@ function WelcomeFarewellForm({
|
|
|
1830
1731
|
placeholders: farewellPlaceholders
|
|
1831
1732
|
}
|
|
1832
1733
|
),
|
|
1833
|
-
/* @__PURE__ */
|
|
1734
|
+
/* @__PURE__ */ jsx16("p", { className: "mt-1.5 text-xs text-gray-500 dark:text-gray-400", children: labels.farewellMessageHint })
|
|
1834
1735
|
] }),
|
|
1835
|
-
saveSuccess && /* @__PURE__ */
|
|
1836
|
-
/* @__PURE__ */
|
|
1736
|
+
saveSuccess && /* @__PURE__ */ jsx16("div", { className: "bg-green-50 dark:bg-green-950/40 border border-green-200 dark:border-green-800 rounded-xl px-4 py-3 text-sm text-green-700 dark:text-green-400", children: labels.saveSuccess }),
|
|
1737
|
+
/* @__PURE__ */ jsx16("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs14(
|
|
1837
1738
|
"button",
|
|
1838
1739
|
{
|
|
1839
1740
|
type: "submit",
|
|
1840
1741
|
disabled: saving,
|
|
1841
1742
|
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",
|
|
1842
1743
|
children: [
|
|
1843
|
-
saving ? /* @__PURE__ */
|
|
1744
|
+
saving ? /* @__PURE__ */ jsx16("span", { className: "w-4 h-4 border-2 border-white/40 border-t-white rounded-full animate-spin" }) : /* @__PURE__ */ jsx16(Save2, { size: 14 }),
|
|
1844
1745
|
saving ? labels.saving : labels.save
|
|
1845
1746
|
]
|
|
1846
1747
|
}
|
|
@@ -1850,8 +1751,8 @@ function WelcomeFarewellForm({
|
|
|
1850
1751
|
}
|
|
1851
1752
|
|
|
1852
1753
|
// src/settings/WhatsAppTemplatesSettings.tsx
|
|
1853
|
-
import { useState as
|
|
1854
|
-
import { jsx as
|
|
1754
|
+
import { useState as useState8 } from "react";
|
|
1755
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1855
1756
|
var TEMPLATE_SETTINGS_TAB = {
|
|
1856
1757
|
SELECT: "select",
|
|
1857
1758
|
CREATE: "create"
|
|
@@ -1866,10 +1767,10 @@ function WhatsAppTemplatesSettings({
|
|
|
1866
1767
|
...settingsProps
|
|
1867
1768
|
}) {
|
|
1868
1769
|
const labels = { ...DEFAULT_TEMPLATES_SETTINGS_LABELS, ...labelsOverride };
|
|
1869
|
-
const [tab, setTab] =
|
|
1870
|
-
return /* @__PURE__ */
|
|
1871
|
-
/* @__PURE__ */
|
|
1872
|
-
/* @__PURE__ */
|
|
1770
|
+
const [tab, setTab] = useState8(TEMPLATE_SETTINGS_TAB.SELECT);
|
|
1771
|
+
return /* @__PURE__ */ jsxs15("div", { className: "space-y-4", children: [
|
|
1772
|
+
/* @__PURE__ */ jsxs15("nav", { className: "flex gap-1 border-b", role: "tablist", children: [
|
|
1773
|
+
/* @__PURE__ */ jsx17(
|
|
1873
1774
|
"button",
|
|
1874
1775
|
{
|
|
1875
1776
|
type: "button",
|
|
@@ -1880,7 +1781,7 @@ function WhatsAppTemplatesSettings({
|
|
|
1880
1781
|
children: labels.selectTab
|
|
1881
1782
|
}
|
|
1882
1783
|
),
|
|
1883
|
-
create ? /* @__PURE__ */
|
|
1784
|
+
create ? /* @__PURE__ */ jsx17(
|
|
1884
1785
|
"button",
|
|
1885
1786
|
{
|
|
1886
1787
|
type: "button",
|
|
@@ -1892,14 +1793,14 @@ function WhatsAppTemplatesSettings({
|
|
|
1892
1793
|
}
|
|
1893
1794
|
) : null
|
|
1894
1795
|
] }),
|
|
1895
|
-
tab === TEMPLATE_SETTINGS_TAB.SELECT ? /* @__PURE__ */
|
|
1796
|
+
tab === TEMPLATE_SETTINGS_TAB.SELECT ? /* @__PURE__ */ jsx17(WhatsAppTemplateSettingsForm, { ...settingsProps }) : create ? /* @__PURE__ */ jsx17(WhatsAppCreateTemplateForm, { ...create }) : null
|
|
1896
1797
|
] });
|
|
1897
1798
|
}
|
|
1898
1799
|
|
|
1899
1800
|
// src/settings/TopicsForm.tsx
|
|
1900
1801
|
import { Megaphone, Save as Save3 } from "lucide-react";
|
|
1901
|
-
import { jsx as
|
|
1902
|
-
var
|
|
1802
|
+
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1803
|
+
var DEFAULT_LABELS5 = {
|
|
1903
1804
|
sectionTitle: "T\xF3picos intermedi\xE1rios",
|
|
1904
1805
|
sectionDescription: "Mensagens autom\xE1ticas para assuntos espec\xEDficos, disparadas quando o cliente demonstra interesse.",
|
|
1905
1806
|
messagePlaceholder: "Digite a mensagem autom\xE1tica para este t\xF3pico...",
|
|
@@ -1915,20 +1816,20 @@ function TopicsForm({
|
|
|
1915
1816
|
saveSuccess = false,
|
|
1916
1817
|
labels: labelsOverride
|
|
1917
1818
|
}) {
|
|
1918
|
-
const labels = { ...
|
|
1919
|
-
return /* @__PURE__ */
|
|
1920
|
-
/* @__PURE__ */
|
|
1921
|
-
/* @__PURE__ */
|
|
1922
|
-
/* @__PURE__ */
|
|
1819
|
+
const labels = { ...DEFAULT_LABELS5, ...labelsOverride };
|
|
1820
|
+
return /* @__PURE__ */ jsxs16("section", { className: "bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 overflow-hidden", children: [
|
|
1821
|
+
/* @__PURE__ */ jsxs16("div", { className: "px-6 py-4 border-b border-gray-100 dark:border-gray-700", children: [
|
|
1822
|
+
/* @__PURE__ */ jsxs16("h2", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100 flex items-center gap-2", children: [
|
|
1823
|
+
/* @__PURE__ */ jsx18(Megaphone, { size: 16, className: "text-orange-600 dark:text-orange-400" }),
|
|
1923
1824
|
labels.sectionTitle
|
|
1924
1825
|
] }),
|
|
1925
|
-
/* @__PURE__ */
|
|
1826
|
+
/* @__PURE__ */ jsx18("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: labels.sectionDescription })
|
|
1926
1827
|
] }),
|
|
1927
|
-
/* @__PURE__ */
|
|
1928
|
-
topics.map((topic) => /* @__PURE__ */
|
|
1929
|
-
/* @__PURE__ */
|
|
1930
|
-
/* @__PURE__ */
|
|
1931
|
-
/* @__PURE__ */
|
|
1828
|
+
/* @__PURE__ */ jsxs16("form", { onSubmit: onSave, className: "p-6 space-y-6", children: [
|
|
1829
|
+
topics.map((topic) => /* @__PURE__ */ jsxs16("div", { className: "space-y-2", children: [
|
|
1830
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex items-start gap-4", children: [
|
|
1831
|
+
/* @__PURE__ */ jsx18("div", { className: "flex-1", children: /* @__PURE__ */ jsx18("p", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: topic.label }) }),
|
|
1832
|
+
/* @__PURE__ */ jsx18(
|
|
1932
1833
|
"button",
|
|
1933
1834
|
{
|
|
1934
1835
|
type: "button",
|
|
@@ -1936,7 +1837,7 @@ function TopicsForm({
|
|
|
1936
1837
|
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"}`,
|
|
1937
1838
|
role: "switch",
|
|
1938
1839
|
"aria-checked": topic.enabled,
|
|
1939
|
-
children: /* @__PURE__ */
|
|
1840
|
+
children: /* @__PURE__ */ jsx18(
|
|
1940
1841
|
"span",
|
|
1941
1842
|
{
|
|
1942
1843
|
className: `pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out ${topic.enabled ? "translate-x-5" : "translate-x-0"}`
|
|
@@ -1945,7 +1846,7 @@ function TopicsForm({
|
|
|
1945
1846
|
}
|
|
1946
1847
|
)
|
|
1947
1848
|
] }),
|
|
1948
|
-
/* @__PURE__ */
|
|
1849
|
+
/* @__PURE__ */ jsx18(
|
|
1949
1850
|
"textarea",
|
|
1950
1851
|
{
|
|
1951
1852
|
value: topic.message,
|
|
@@ -1957,27 +1858,27 @@ function TopicsForm({
|
|
|
1957
1858
|
}
|
|
1958
1859
|
)
|
|
1959
1860
|
] }, topic.key)),
|
|
1960
|
-
/* @__PURE__ */
|
|
1961
|
-
/* @__PURE__ */
|
|
1861
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-3", children: [
|
|
1862
|
+
/* @__PURE__ */ jsxs16(
|
|
1962
1863
|
"button",
|
|
1963
1864
|
{
|
|
1964
1865
|
type: "submit",
|
|
1965
1866
|
disabled: saving,
|
|
1966
1867
|
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",
|
|
1967
1868
|
children: [
|
|
1968
|
-
/* @__PURE__ */
|
|
1869
|
+
/* @__PURE__ */ jsx18(Save3, { size: 14 }),
|
|
1969
1870
|
labels.saveButton
|
|
1970
1871
|
]
|
|
1971
1872
|
}
|
|
1972
1873
|
),
|
|
1973
|
-
saveSuccess && /* @__PURE__ */
|
|
1874
|
+
saveSuccess && /* @__PURE__ */ jsx18("span", { className: "text-sm text-green-600 dark:text-green-400", children: labels.saveSuccess })
|
|
1974
1875
|
] })
|
|
1975
1876
|
] })
|
|
1976
1877
|
] });
|
|
1977
1878
|
}
|
|
1978
1879
|
|
|
1979
1880
|
// src/hooks/useConversationMessages.ts
|
|
1980
|
-
import { useCallback as
|
|
1881
|
+
import { useCallback as useCallback4 } from "react";
|
|
1981
1882
|
function useConversationMessages(conversationId, params) {
|
|
1982
1883
|
const context = useConversations();
|
|
1983
1884
|
if (!context) {
|
|
@@ -1988,7 +1889,7 @@ function useConversationMessages(conversationId, params) {
|
|
|
1988
1889
|
() => api.fetchMessages(conversationId, params),
|
|
1989
1890
|
[conversationId, params?.limit, params?.before]
|
|
1990
1891
|
);
|
|
1991
|
-
const sendMessage =
|
|
1892
|
+
const sendMessage = useCallback4(
|
|
1992
1893
|
async (text) => {
|
|
1993
1894
|
const message = await api.sendMessage(conversationId, text);
|
|
1994
1895
|
await refetch();
|
|
@@ -1996,7 +1897,7 @@ function useConversationMessages(conversationId, params) {
|
|
|
1996
1897
|
},
|
|
1997
1898
|
[api, conversationId, refetch]
|
|
1998
1899
|
);
|
|
1999
|
-
const sendMedia =
|
|
1900
|
+
const sendMedia = useCallback4(
|
|
2000
1901
|
async (mediaData) => {
|
|
2001
1902
|
const message = await api.sendMedia(conversationId, mediaData);
|
|
2002
1903
|
await refetch();
|
|
@@ -2004,14 +1905,14 @@ function useConversationMessages(conversationId, params) {
|
|
|
2004
1905
|
},
|
|
2005
1906
|
[api, conversationId, refetch]
|
|
2006
1907
|
);
|
|
2007
|
-
const sendTemplate =
|
|
1908
|
+
const sendTemplate = useCallback4(
|
|
2008
1909
|
async (templateData) => {
|
|
2009
1910
|
await api.sendTemplate(conversationId, templateData);
|
|
2010
1911
|
await refetch();
|
|
2011
1912
|
},
|
|
2012
1913
|
[api, conversationId, refetch]
|
|
2013
1914
|
);
|
|
2014
|
-
const markRead =
|
|
1915
|
+
const markRead = useCallback4(() => api.markRead(conversationId), [api, conversationId]);
|
|
2015
1916
|
return { messages: data ?? [], loading, error, refetch, sendMessage, sendMedia, sendTemplate, markRead };
|
|
2016
1917
|
}
|
|
2017
1918
|
|
|
@@ -2022,11 +1923,15 @@ function useConversationList(params) {
|
|
|
2022
1923
|
throw new Error("useConversationList requires an ancestor <ConversationsProvider>");
|
|
2023
1924
|
}
|
|
2024
1925
|
const { api } = context;
|
|
1926
|
+
const filtersKey = JSON.stringify(params?.filters ?? {});
|
|
2025
1927
|
const { data, loading, error, refetch } = useAsyncResource(
|
|
2026
1928
|
() => api.fetchConversations(params),
|
|
2027
|
-
[params?.page, params?.limit, params?.waitingHuman, params?.search]
|
|
1929
|
+
[params?.page, params?.limit, params?.waitingHuman, params?.search, filtersKey]
|
|
2028
1930
|
);
|
|
2029
|
-
|
|
1931
|
+
if (data === void 0) {
|
|
1932
|
+
return { conversations: [], total: 0, loading, error, refetch };
|
|
1933
|
+
}
|
|
1934
|
+
return { conversations: conversationsOf(data), total: totalOf(data), loading, error, refetch };
|
|
2030
1935
|
}
|
|
2031
1936
|
|
|
2032
1937
|
// src/hooks/useConversationContext.ts
|
|
@@ -2041,12 +1946,12 @@ function useConversationContext(conversationId) {
|
|
|
2041
1946
|
}
|
|
2042
1947
|
|
|
2043
1948
|
// src/hooks/useConversationRealtime.ts
|
|
2044
|
-
import { useEffect as
|
|
1949
|
+
import { useEffect as useEffect5, useRef as useRef4 } from "react";
|
|
2045
1950
|
function useConversationRealtime(conversationId, onEvent) {
|
|
2046
1951
|
const context = useConversations();
|
|
2047
|
-
const onEventRef =
|
|
1952
|
+
const onEventRef = useRef4(onEvent);
|
|
2048
1953
|
onEventRef.current = onEvent;
|
|
2049
|
-
|
|
1954
|
+
useEffect5(() => {
|
|
2050
1955
|
if (!context || !conversationId) return;
|
|
2051
1956
|
const source = context.sse.connectConversationStream(conversationId);
|
|
2052
1957
|
const handler = (event) => onEventRef.current(event);
|
|
@@ -2059,9 +1964,9 @@ function useConversationRealtime(conversationId, onEvent) {
|
|
|
2059
1964
|
}
|
|
2060
1965
|
function useGlobalRealtime(onEvent) {
|
|
2061
1966
|
const context = useConversations();
|
|
2062
|
-
const onEventRef =
|
|
1967
|
+
const onEventRef = useRef4(onEvent);
|
|
2063
1968
|
onEventRef.current = onEvent;
|
|
2064
|
-
|
|
1969
|
+
useEffect5(() => {
|
|
2065
1970
|
if (!context) return;
|
|
2066
1971
|
const source = context.sse.connectGlobalStream();
|
|
2067
1972
|
const handler = (event) => onEventRef.current(event);
|
|
@@ -2072,6 +1977,38 @@ function useGlobalRealtime(onEvent) {
|
|
|
2072
1977
|
};
|
|
2073
1978
|
}, [context]);
|
|
2074
1979
|
}
|
|
1980
|
+
|
|
1981
|
+
// src/hooks/useConversationActions.ts
|
|
1982
|
+
import { useMemo as useMemo2 } from "react";
|
|
1983
|
+
function useConversationActions(conversationId) {
|
|
1984
|
+
const context = useConversations();
|
|
1985
|
+
if (!context) {
|
|
1986
|
+
throw new Error("useConversationActions requires an ancestor <ConversationsProvider>");
|
|
1987
|
+
}
|
|
1988
|
+
const { api } = context;
|
|
1989
|
+
return useMemo2(
|
|
1990
|
+
() => ({
|
|
1991
|
+
takeover: api.takeover ? () => api.takeover(conversationId) : void 0,
|
|
1992
|
+
release: api.release ? () => api.release(conversationId) : void 0,
|
|
1993
|
+
finalize: api.finalize ? () => api.finalize(conversationId) : void 0
|
|
1994
|
+
}),
|
|
1995
|
+
[api, conversationId]
|
|
1996
|
+
);
|
|
1997
|
+
}
|
|
1998
|
+
function useInboxActions() {
|
|
1999
|
+
const context = useConversations();
|
|
2000
|
+
if (!context) {
|
|
2001
|
+
throw new Error("useInboxActions requires an ancestor <ConversationsProvider>");
|
|
2002
|
+
}
|
|
2003
|
+
const { api } = context;
|
|
2004
|
+
return useMemo2(
|
|
2005
|
+
() => ({
|
|
2006
|
+
markAllRead: api.markAllRead ? () => api.markAllRead() : void 0,
|
|
2007
|
+
listTemplates: api.listTemplates ? () => api.listTemplates() : void 0
|
|
2008
|
+
}),
|
|
2009
|
+
[api]
|
|
2010
|
+
);
|
|
2011
|
+
}
|
|
2075
2012
|
export {
|
|
2076
2013
|
AudioPlayer,
|
|
2077
2014
|
Avatar,
|
|
@@ -2089,13 +2026,21 @@ export {
|
|
|
2089
2026
|
ConversationRow,
|
|
2090
2027
|
ConversationWallpaper,
|
|
2091
2028
|
ConversationsProvider,
|
|
2029
|
+
DEFAULT_AVATAR_LABELS,
|
|
2092
2030
|
DEFAULT_CONVERSATION_CHANNEL,
|
|
2093
2031
|
DEFAULT_CONVERSATION_CONTEXT_LABELS,
|
|
2094
2032
|
DEFAULT_CONVERSATION_DOCUMENTS_LABELS,
|
|
2095
2033
|
DEFAULT_CONVERSATION_HEADER_LABELS,
|
|
2034
|
+
DEFAULT_CONVERSATION_LIST_ITEM_LABELS,
|
|
2035
|
+
DEFAULT_DOCUMENTS_LIBRARY_LABELS,
|
|
2036
|
+
DEFAULT_LIGHTBOX_LABELS,
|
|
2037
|
+
DEFAULT_MESSAGE_COMPOSER_LABELS,
|
|
2096
2038
|
DEFAULT_TEMPLATES_SETTINGS_LABELS,
|
|
2039
|
+
DEFAULT_WHATSAPP_MESSAGE_EDITOR_LABELS,
|
|
2097
2040
|
DEFAULT_WINDOW_EXPIRED_LABELS,
|
|
2041
|
+
DOCUMENT_SOURCE_FILTER,
|
|
2098
2042
|
DateDivider,
|
|
2043
|
+
DocumentsLibrary,
|
|
2099
2044
|
EmojiPicker,
|
|
2100
2045
|
FileIcon,
|
|
2101
2046
|
HANDLE_KIND,
|
|
@@ -2125,17 +2070,21 @@ export {
|
|
|
2125
2070
|
capabilitiesOf,
|
|
2126
2071
|
channelFiltersFor,
|
|
2127
2072
|
contactFlag,
|
|
2073
|
+
createMediaUrlResolver,
|
|
2128
2074
|
downloadTextFile,
|
|
2129
2075
|
formatContactHandle,
|
|
2076
|
+
formatDateTime,
|
|
2130
2077
|
formatFileSize,
|
|
2131
2078
|
formatPhone,
|
|
2132
2079
|
formatStalledFor,
|
|
2133
2080
|
formatTimestamp,
|
|
2134
2081
|
htmlToWA,
|
|
2082
|
+
isSameDay,
|
|
2135
2083
|
isWindowBlocking,
|
|
2136
2084
|
parseWhatsAppFormatting,
|
|
2137
2085
|
phoneInitials,
|
|
2138
2086
|
toast,
|
|
2087
|
+
useConversationActions,
|
|
2139
2088
|
useConversationContext,
|
|
2140
2089
|
useConversationDocuments,
|
|
2141
2090
|
useConversationList,
|
|
@@ -2145,6 +2094,7 @@ export {
|
|
|
2145
2094
|
useConversations,
|
|
2146
2095
|
useDarkMode,
|
|
2147
2096
|
useGlobalRealtime,
|
|
2097
|
+
useInboxActions,
|
|
2148
2098
|
useIsDarkTheme,
|
|
2149
2099
|
useIsNarrow,
|
|
2150
2100
|
useToast,
|