@fayz-ai/plugin-conversations 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data/supabase.d.ts.map +1 -1
- package/dist/index.js +302 -109
- package/dist/index.js.map +1 -1
- package/dist/migrations/index.d.ts +1 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/views/InboxView.d.ts.map +1 -1
- package/dist/views/MediaBubble.d.ts +8 -0
- package/dist/views/MediaBubble.d.ts.map +1 -0
- package/dist/views/MessageThread.d.ts.map +1 -1
- package/dist/views/NewConversationPanel.d.ts +5 -4
- package/dist/views/NewConversationPanel.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import
|
|
3
|
-
import { Loader2, MessageSquare, AlertTriangle, Pause, Play, Send, RefreshCw, Plus, Clock, CheckCircle2, Check, ShieldCheck, ShieldAlert, QrCode, Zap, ExternalLink, SquarePen, Globe, Mail, Instagram, Phone, Search, User, Inbox, CheckCheck, ChevronLeft, Archive, PanelRight, X, MapPin, Tag, StickyNote, Link2, MoreVertical, Snowflake, Sun, Flame, Building2, UserRound, Copy } from 'lucide-react';
|
|
4
|
-
import { toast, Button, Input, defineKpiWidget, defineTableWidget, PageHeaderActions, cn, Badge, FilterChip, Skeleton, KpiCard, TableWidget } from '@fayz-ai/ui';
|
|
1
|
+
import * as React12 from 'react';
|
|
2
|
+
import React12__default, { useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
|
3
|
+
import { Loader2, MessageSquare, AlertTriangle, Pause, Play, Send, RefreshCw, Plus, Clock, CheckCircle2, Check, ShieldCheck, ShieldAlert, QrCode, Zap, ExternalLink, SquarePen, Globe, Mail, Instagram, Phone, Search, User, Inbox, CheckCheck, ChevronLeft, Archive, PanelRight, X, MapPin, Tag, StickyNote, Link2, MoreVertical, Snowflake, Sun, Flame, Building2, UserRound, Copy, FileText, Download } from 'lucide-react';
|
|
4
|
+
import { toast, Button, Input, defineKpiWidget, defineTableWidget, PageHeaderActions, cn, Badge, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, ModalFooter, FilterChip, Skeleton, KpiCard, TableWidget } from '@fayz-ai/ui';
|
|
5
5
|
import { createConnectionStore, connectionRuns, connectionStatus, getActiveTenantId, getSupabaseClientOptional, useActiveTenantId, registerTranslations, useTranslation, countByTenant, CONNECTOR_RUNTIME_TOKEN_HEADER, connectorRuntimeToken, errorMessage } from '@fayz-ai/core';
|
|
6
6
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
7
|
-
import { SettingsGroup, PluginSettingsPanel, useNavContribution,
|
|
7
|
+
import { SettingsGroup, PluginSettingsPanel, useNavContribution, useRightRailStore, PageActions, useLimitGuard, ContactPicker, invalidateLimit } from '@fayz-ai/admin';
|
|
8
8
|
import { useStore } from 'zustand';
|
|
9
9
|
import { createStore } from 'zustand/vanilla';
|
|
10
10
|
|
|
@@ -211,12 +211,12 @@ function Bar({ c }) {
|
|
|
211
211
|
] });
|
|
212
212
|
}
|
|
213
213
|
function CampaignsView() {
|
|
214
|
-
const [rows, setRows] =
|
|
215
|
-
const [templates, setTemplates] =
|
|
216
|
-
const [providers, setProviders] =
|
|
217
|
-
const [running, setRunning] =
|
|
218
|
-
const stop =
|
|
219
|
-
const load =
|
|
214
|
+
const [rows, setRows] = React12__default.useState(null);
|
|
215
|
+
const [templates, setTemplates] = React12__default.useState([]);
|
|
216
|
+
const [providers, setProviders] = React12__default.useState([]);
|
|
217
|
+
const [running, setRunning] = React12__default.useState(null);
|
|
218
|
+
const stop = React12__default.useRef(false);
|
|
219
|
+
const load = React12__default.useCallback(async () => {
|
|
220
220
|
try {
|
|
221
221
|
const [c, t, p] = await Promise.all([
|
|
222
222
|
campaignsApi.list(),
|
|
@@ -231,7 +231,7 @@ function CampaignsView() {
|
|
|
231
231
|
setRows([]);
|
|
232
232
|
}
|
|
233
233
|
}, []);
|
|
234
|
-
|
|
234
|
+
React12__default.useEffect(() => {
|
|
235
235
|
void load();
|
|
236
236
|
}, [load]);
|
|
237
237
|
const active = providers.find((p) => p.isActive);
|
|
@@ -485,9 +485,9 @@ function avisarNoSistema(titulo, corpo, tag) {
|
|
|
485
485
|
}
|
|
486
486
|
function InboxWatcher({ label, route = "/conversations", section = "main", position = 1 }) {
|
|
487
487
|
const tenantId = useActiveTenantId();
|
|
488
|
-
const [naoLidas, setNaoLidas] =
|
|
489
|
-
const podeTocar =
|
|
490
|
-
|
|
488
|
+
const [naoLidas, setNaoLidas] = React12.useState(0);
|
|
489
|
+
const podeTocar = React12.useRef(false);
|
|
490
|
+
React12.useEffect(() => {
|
|
491
491
|
const liberar = () => {
|
|
492
492
|
podeTocar.current = true;
|
|
493
493
|
void pedirPermissao();
|
|
@@ -499,7 +499,7 @@ function InboxWatcher({ label, route = "/conversations", section = "main", posit
|
|
|
499
499
|
for (const ev of ["pointerdown", "keydown", "touchstart"]) window.removeEventListener(ev, liberar);
|
|
500
500
|
};
|
|
501
501
|
}, []);
|
|
502
|
-
const contar =
|
|
502
|
+
const contar = React12.useCallback(async () => {
|
|
503
503
|
const supabase = getSupabaseClientOptional();
|
|
504
504
|
if (!supabase) return;
|
|
505
505
|
const { data } = await supabase.from(T.conversations).select("id, status, last_message_direction, unread_count").eq("status", "open");
|
|
@@ -511,10 +511,10 @@ function InboxWatcher({ label, route = "/conversations", section = "main", posit
|
|
|
511
511
|
})).length;
|
|
512
512
|
setNaoLidas(n);
|
|
513
513
|
}, []);
|
|
514
|
-
|
|
514
|
+
React12.useEffect(() => {
|
|
515
515
|
void contar();
|
|
516
516
|
}, [contar]);
|
|
517
|
-
|
|
517
|
+
React12.useEffect(() => {
|
|
518
518
|
if (!tenantId) return;
|
|
519
519
|
return assinarChegada(tenantId, ({ conversationId }) => {
|
|
520
520
|
void contar();
|
|
@@ -549,14 +549,14 @@ function slots(body) {
|
|
|
549
549
|
return found.size;
|
|
550
550
|
}
|
|
551
551
|
function TemplatesView() {
|
|
552
|
-
const [mine, setMine] =
|
|
553
|
-
const [theirs, setTheirs] =
|
|
554
|
-
const [providers, setProviders] =
|
|
555
|
-
const [busy, setBusy] =
|
|
556
|
-
const [draft, setDraft] =
|
|
552
|
+
const [mine, setMine] = React12__default.useState(null);
|
|
553
|
+
const [theirs, setTheirs] = React12__default.useState([]);
|
|
554
|
+
const [providers, setProviders] = React12__default.useState([]);
|
|
555
|
+
const [busy, setBusy] = React12__default.useState(null);
|
|
556
|
+
const [draft, setDraft] = React12__default.useState({ name: "", body: "", variables: "" });
|
|
557
557
|
const active = providers.find((p) => p.isActive);
|
|
558
558
|
const supportsTemplates = active?.capabilities?.templates !== false;
|
|
559
|
-
const load =
|
|
559
|
+
const load = React12__default.useCallback(async () => {
|
|
560
560
|
try {
|
|
561
561
|
const [m, p] = await Promise.all([campaignsApi.templates(), providersApi.list()]);
|
|
562
562
|
setMine(m);
|
|
@@ -566,7 +566,7 @@ function TemplatesView() {
|
|
|
566
566
|
setMine([]);
|
|
567
567
|
}
|
|
568
568
|
}, []);
|
|
569
|
-
|
|
569
|
+
React12__default.useEffect(() => {
|
|
570
570
|
void load();
|
|
571
571
|
}, [load]);
|
|
572
572
|
const sync = async () => {
|
|
@@ -757,8 +757,8 @@ function TemplatesView() {
|
|
|
757
757
|
var DEFAULT_CONVERSATIONS_CONFIG = {
|
|
758
758
|
contactKind: "contact"
|
|
759
759
|
};
|
|
760
|
-
var StoreContext =
|
|
761
|
-
var ConfigContext =
|
|
760
|
+
var StoreContext = React12__default.createContext(null);
|
|
761
|
+
var ConfigContext = React12__default.createContext(DEFAULT_CONVERSATIONS_CONFIG);
|
|
762
762
|
function ConversationsContextProvider({
|
|
763
763
|
store: store2,
|
|
764
764
|
config = DEFAULT_CONVERSATIONS_CONFIG,
|
|
@@ -767,12 +767,12 @@ function ConversationsContextProvider({
|
|
|
767
767
|
return /* @__PURE__ */ jsx(StoreContext.Provider, { value: store2, children: /* @__PURE__ */ jsx(ConfigContext.Provider, { value: config, children }) });
|
|
768
768
|
}
|
|
769
769
|
function useConversationsStore(selector) {
|
|
770
|
-
const store2 =
|
|
770
|
+
const store2 = React12__default.useContext(StoreContext);
|
|
771
771
|
if (!store2) throw new Error("useConversationsStore must be used within ConversationsPage");
|
|
772
772
|
return useStore(store2, selector);
|
|
773
773
|
}
|
|
774
774
|
function useConversationsConfig() {
|
|
775
|
-
return
|
|
775
|
+
return React12__default.useContext(ConfigContext);
|
|
776
776
|
}
|
|
777
777
|
var CHANNEL_ICON = {
|
|
778
778
|
sms: Phone,
|
|
@@ -789,10 +789,10 @@ var CHANNEL_ACCENT = {
|
|
|
789
789
|
webchat: { color: "#f59e0b", badge: "bg-[#f59e0b]/12 text-[#b45309] dark:text-[#fcd34d]" }
|
|
790
790
|
};
|
|
791
791
|
function useMediaQuery(query) {
|
|
792
|
-
const [matches, setMatches] =
|
|
792
|
+
const [matches, setMatches] = React12__default.useState(
|
|
793
793
|
() => typeof window !== "undefined" && window.matchMedia(query).matches
|
|
794
794
|
);
|
|
795
|
-
|
|
795
|
+
React12__default.useEffect(() => {
|
|
796
796
|
if (typeof window === "undefined") return;
|
|
797
797
|
const mql = window.matchMedia(query);
|
|
798
798
|
const onChange = () => setMatches(mql.matches);
|
|
@@ -881,7 +881,7 @@ function ConversationList({ className }) {
|
|
|
881
881
|
setLeadOwnerFilter,
|
|
882
882
|
setSearch
|
|
883
883
|
} = useConversationsStore((s) => s);
|
|
884
|
-
const donos =
|
|
884
|
+
const donos = React12__default.useMemo(() => {
|
|
885
885
|
const vistos = /* @__PURE__ */ new Map();
|
|
886
886
|
for (const c of conversations) {
|
|
887
887
|
if (c.leadOwnerId) vistos.set(c.leadOwnerId, c.leadOwnerName ?? c.leadOwnerId);
|
|
@@ -1016,9 +1016,9 @@ function ConversationList({ className }) {
|
|
|
1016
1016
|
] });
|
|
1017
1017
|
}
|
|
1018
1018
|
function useSendWindow(conversationId) {
|
|
1019
|
-
const [row, setRow] =
|
|
1020
|
-
const [providers, setProviders] =
|
|
1021
|
-
|
|
1019
|
+
const [row, setRow] = React12__default.useState(null);
|
|
1020
|
+
const [providers, setProviders] = React12__default.useState(null);
|
|
1021
|
+
React12__default.useEffect(() => {
|
|
1022
1022
|
let alive = true;
|
|
1023
1023
|
providersApi.list().then((p) => {
|
|
1024
1024
|
if (alive) setProviders(p);
|
|
@@ -1029,7 +1029,7 @@ function useSendWindow(conversationId) {
|
|
|
1029
1029
|
alive = false;
|
|
1030
1030
|
};
|
|
1031
1031
|
}, []);
|
|
1032
|
-
|
|
1032
|
+
React12__default.useEffect(() => {
|
|
1033
1033
|
let alive = true;
|
|
1034
1034
|
if (!conversationId) {
|
|
1035
1035
|
setRow(null);
|
|
@@ -1050,7 +1050,7 @@ function useSendWindow(conversationId) {
|
|
|
1050
1050
|
};
|
|
1051
1051
|
}, [conversationId]);
|
|
1052
1052
|
const provider = (providers ?? []).find((p) => p.isActive);
|
|
1053
|
-
const mode =
|
|
1053
|
+
const mode = React12__default.useMemo(() => {
|
|
1054
1054
|
if (!provider) return { kind: "blocked", reason: "no_provider" };
|
|
1055
1055
|
if (!provider.capabilities?.requires_template) {
|
|
1056
1056
|
return { kind: "free", until: null, minutesLeft: null };
|
|
@@ -1125,10 +1125,10 @@ function DeliveryMark({ m }) {
|
|
|
1125
1125
|
] });
|
|
1126
1126
|
}
|
|
1127
1127
|
function MessageMenu({ m }) {
|
|
1128
|
-
const [open, setOpen] =
|
|
1129
|
-
const [detail, setDetail] =
|
|
1130
|
-
const [loading, setLoading] =
|
|
1131
|
-
const [err, setErr] =
|
|
1128
|
+
const [open, setOpen] = React12__default.useState(false);
|
|
1129
|
+
const [detail, setDetail] = React12__default.useState(null);
|
|
1130
|
+
const [loading, setLoading] = React12__default.useState(false);
|
|
1131
|
+
const [err, setErr] = React12__default.useState(null);
|
|
1132
1132
|
async function load() {
|
|
1133
1133
|
setOpen(true);
|
|
1134
1134
|
if (!m.providerMessageId) return;
|
|
@@ -1199,8 +1199,136 @@ function MessageMenu({ m }) {
|
|
|
1199
1199
|
] }) })
|
|
1200
1200
|
] });
|
|
1201
1201
|
}
|
|
1202
|
+
var COM_ARQUIVO = /* @__PURE__ */ new Set(["image", "video", "audio", "document", "sticker"]);
|
|
1203
|
+
function temArquivo(m) {
|
|
1204
|
+
return !!m.mediaPath && COM_ARQUIVO.has(String(m.messageType));
|
|
1205
|
+
}
|
|
1206
|
+
function useUrlAssinada(m, visivel) {
|
|
1207
|
+
const [url, setUrl] = React12.useState(null);
|
|
1208
|
+
const [erro, setErro] = React12.useState(false);
|
|
1209
|
+
React12.useEffect(() => {
|
|
1210
|
+
if (!visivel || url || erro || !temArquivo(m)) return;
|
|
1211
|
+
let vivo = true;
|
|
1212
|
+
(async () => {
|
|
1213
|
+
try {
|
|
1214
|
+
const sb = getSupabaseClientOptional();
|
|
1215
|
+
const { data, error } = await sb.functions.invoke("conversations-provider", {
|
|
1216
|
+
body: { tenantId: getActiveTenantId(), action: "media_url", messageId: m.id }
|
|
1217
|
+
});
|
|
1218
|
+
if (error || data?.error) throw new Error("falhou");
|
|
1219
|
+
if (vivo && data?.url) setUrl(data.url);
|
|
1220
|
+
else if (vivo) setErro(true);
|
|
1221
|
+
} catch {
|
|
1222
|
+
if (vivo) setErro(true);
|
|
1223
|
+
}
|
|
1224
|
+
})();
|
|
1225
|
+
return () => {
|
|
1226
|
+
vivo = false;
|
|
1227
|
+
};
|
|
1228
|
+
}, [visivel, m.id, url, erro]);
|
|
1229
|
+
return { url, erro };
|
|
1230
|
+
}
|
|
1231
|
+
function tamanho(bytes) {
|
|
1232
|
+
if (!bytes || bytes <= 0) return "";
|
|
1233
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
1234
|
+
if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
|
|
1235
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1236
|
+
}
|
|
1237
|
+
function duracao(seg) {
|
|
1238
|
+
if (!seg || seg <= 0) return "";
|
|
1239
|
+
const m = Math.floor(seg / 60);
|
|
1240
|
+
const s = Math.floor(seg % 60);
|
|
1241
|
+
return `${m}:${String(s).padStart(2, "0")}`;
|
|
1242
|
+
}
|
|
1243
|
+
function MediaBubble({ m, outbound }) {
|
|
1244
|
+
const ref = React12.useRef(null);
|
|
1245
|
+
const [visivel, setVisivel] = React12.useState(false);
|
|
1246
|
+
const { url, erro } = useUrlAssinada(m, visivel);
|
|
1247
|
+
React12.useEffect(() => {
|
|
1248
|
+
const el = ref.current;
|
|
1249
|
+
if (!el || typeof IntersectionObserver === "undefined") {
|
|
1250
|
+
setVisivel(true);
|
|
1251
|
+
return;
|
|
1252
|
+
}
|
|
1253
|
+
const obs = new IntersectionObserver((entradas) => {
|
|
1254
|
+
if (entradas.some((e) => e.isIntersecting)) {
|
|
1255
|
+
setVisivel(true);
|
|
1256
|
+
obs.disconnect();
|
|
1257
|
+
}
|
|
1258
|
+
}, { rootMargin: "200px" });
|
|
1259
|
+
obs.observe(el);
|
|
1260
|
+
return () => obs.disconnect();
|
|
1261
|
+
}, []);
|
|
1262
|
+
const tipo = String(m.messageType);
|
|
1263
|
+
const p = m.payload ?? {};
|
|
1264
|
+
const legenda = p.caption ?? null;
|
|
1265
|
+
const rotulo = /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap break-words", children: m.body });
|
|
1266
|
+
if (erro) {
|
|
1267
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: "space-y-1", children: [
|
|
1268
|
+
rotulo,
|
|
1269
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs opacity-60", children: "O arquivo n\xE3o carregou." })
|
|
1270
|
+
] });
|
|
1271
|
+
}
|
|
1272
|
+
if (!url) {
|
|
1273
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: "space-y-1", children: [
|
|
1274
|
+
rotulo,
|
|
1275
|
+
/* @__PURE__ */ jsx("div", { className: "h-1 w-24 animate-pulse rounded bg-current opacity-20" })
|
|
1276
|
+
] });
|
|
1277
|
+
}
|
|
1278
|
+
if (tipo === "image" || tipo === "sticker") {
|
|
1279
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: "space-y-1", children: [
|
|
1280
|
+
/* @__PURE__ */ jsx("a", { href: url, target: "_blank", rel: "noreferrer", children: /* @__PURE__ */ jsx(
|
|
1281
|
+
"img",
|
|
1282
|
+
{
|
|
1283
|
+
src: url,
|
|
1284
|
+
alt: legenda ?? (tipo === "sticker" ? "Figurinha" : "Imagem recebida"),
|
|
1285
|
+
className: tipo === "sticker" ? "max-h-32 w-auto" : "max-h-80 w-auto rounded-lg",
|
|
1286
|
+
loading: "lazy"
|
|
1287
|
+
}
|
|
1288
|
+
) }),
|
|
1289
|
+
legenda ? /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap break-words", children: legenda }) : null
|
|
1290
|
+
] });
|
|
1291
|
+
}
|
|
1292
|
+
if (tipo === "video") {
|
|
1293
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: "space-y-1", children: [
|
|
1294
|
+
/* @__PURE__ */ jsx("video", { src: url, controls: true, preload: "metadata", className: "max-h-80 w-auto rounded-lg" }),
|
|
1295
|
+
legenda ? /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap break-words", children: legenda }) : null
|
|
1296
|
+
] });
|
|
1297
|
+
}
|
|
1298
|
+
if (tipo === "audio") {
|
|
1299
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: "space-y-1", children: [
|
|
1300
|
+
/* @__PURE__ */ jsx("audio", { src: url, controls: true, preload: "metadata", className: "h-9 w-64 max-w-full" }),
|
|
1301
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs opacity-60", children: [
|
|
1302
|
+
p.ptt ? "Mensagem de voz" : "\xC1udio",
|
|
1303
|
+
duracao(p.seconds) ? ` \xB7 ${duracao(p.seconds)}` : ""
|
|
1304
|
+
] })
|
|
1305
|
+
] });
|
|
1306
|
+
}
|
|
1307
|
+
const nome = p.fileName ?? "Documento";
|
|
1308
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: "space-y-1", children: [
|
|
1309
|
+
/* @__PURE__ */ jsxs(
|
|
1310
|
+
"a",
|
|
1311
|
+
{
|
|
1312
|
+
href: url,
|
|
1313
|
+
target: "_blank",
|
|
1314
|
+
rel: "noreferrer",
|
|
1315
|
+
download: nome,
|
|
1316
|
+
className: `flex items-center gap-2 rounded-lg border p-2 ${outbound ? "border-white/30" : "border-black/10"}`,
|
|
1317
|
+
children: [
|
|
1318
|
+
/* @__PURE__ */ jsx(FileText, { className: "h-5 w-5 shrink-0 opacity-70" }),
|
|
1319
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
|
|
1320
|
+
/* @__PURE__ */ jsx("span", { className: "block truncate text-sm", children: nome }),
|
|
1321
|
+
tamanho(p.fileLength) ? /* @__PURE__ */ jsx("span", { className: "block text-xs opacity-60", children: tamanho(p.fileLength) }) : null
|
|
1322
|
+
] }),
|
|
1323
|
+
/* @__PURE__ */ jsx(Download, { className: "h-4 w-4 shrink-0 opacity-70" })
|
|
1324
|
+
]
|
|
1325
|
+
}
|
|
1326
|
+
),
|
|
1327
|
+
legenda ? /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap break-words", children: legenda }) : null
|
|
1328
|
+
] });
|
|
1329
|
+
}
|
|
1202
1330
|
function ContactCard({ contacts, outbound }) {
|
|
1203
|
-
const [copied, setCopied] =
|
|
1331
|
+
const [copied, setCopied] = React12__default.useState(null);
|
|
1204
1332
|
const copy = (value) => {
|
|
1205
1333
|
void navigator.clipboard?.writeText(value);
|
|
1206
1334
|
setCopied(value);
|
|
@@ -1242,6 +1370,7 @@ function ContactCard({ contacts, outbound }) {
|
|
|
1242
1370
|
function MessageBody({ m, outbound }) {
|
|
1243
1371
|
const contacts = m.messageType === "contact" ? m.payload?.contacts ?? [] : [];
|
|
1244
1372
|
if (contacts.length > 0) return /* @__PURE__ */ jsx(ContactCard, { contacts, outbound });
|
|
1373
|
+
if (temArquivo(m)) return /* @__PURE__ */ jsx(MediaBubble, { m, outbound });
|
|
1245
1374
|
return /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap break-words", children: m.body });
|
|
1246
1375
|
}
|
|
1247
1376
|
function buildRows(messages) {
|
|
@@ -1264,14 +1393,14 @@ function buildRows(messages) {
|
|
|
1264
1393
|
function MessageThread({ selected, onTogglePanel, panelOpen, onBack, className }) {
|
|
1265
1394
|
const t = useTranslation();
|
|
1266
1395
|
const { messages, sending, send, setStatus, refreshMessages } = useConversationsStore((s) => s);
|
|
1267
|
-
const [draft, setDraft] =
|
|
1396
|
+
const [draft, setDraft] = React12__default.useState("");
|
|
1268
1397
|
const win = useSendWindow(selected.id);
|
|
1269
1398
|
const canType = win.mode.kind === "free";
|
|
1270
|
-
const threadRef =
|
|
1271
|
-
|
|
1399
|
+
const threadRef = React12__default.useRef(null);
|
|
1400
|
+
React12__default.useEffect(() => {
|
|
1272
1401
|
threadRef.current?.scrollTo({ top: threadRef.current.scrollHeight, behavior: "smooth" });
|
|
1273
1402
|
}, [messages.length, selected.id]);
|
|
1274
|
-
|
|
1403
|
+
React12__default.useEffect(() => {
|
|
1275
1404
|
if (!selected.id) return;
|
|
1276
1405
|
let timer = null;
|
|
1277
1406
|
const start = () => {
|
|
@@ -1300,7 +1429,7 @@ function MessageThread({ selected, onTogglePanel, panelOpen, onBack, className }
|
|
|
1300
1429
|
await send(body);
|
|
1301
1430
|
}
|
|
1302
1431
|
const accent = CHANNEL_ACCENT[selected.channel];
|
|
1303
|
-
const rows =
|
|
1432
|
+
const rows = React12__default.useMemo(() => buildRows(messages), [messages]);
|
|
1304
1433
|
return /* @__PURE__ */ jsxs("section", { className: cn("flex min-w-0 flex-1 flex-col bg-muted/20", className), children: [
|
|
1305
1434
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 border-b border-border bg-card px-3 py-2.5 md:px-5", children: [
|
|
1306
1435
|
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2 md:gap-3", children: [
|
|
@@ -1308,7 +1437,7 @@ function MessageThread({ selected, onTogglePanel, panelOpen, onBack, className }
|
|
|
1308
1437
|
/* @__PURE__ */ jsx(Avatar, { name: selected.contactName, accent: selected.accent, size: "sm", channel: selected.channel }),
|
|
1309
1438
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
1310
1439
|
/* @__PURE__ */ jsx("p", { className: "truncate text-sm font-semibold text-foreground", children: selected.contactName }),
|
|
1311
|
-
/* @__PURE__ */ jsxs("p", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
|
|
1440
|
+
!panelOpen && /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
|
|
1312
1441
|
/* @__PURE__ */ jsx(ChannelBadge, { channel: selected.channel }),
|
|
1313
1442
|
/* @__PURE__ */ jsx("span", { className: "truncate", children: selected.contactHandle })
|
|
1314
1443
|
] })
|
|
@@ -1412,8 +1541,8 @@ var TEMP = {
|
|
|
1412
1541
|
cold: { icon: Snowflake, cls: "bg-info-soft text-info-soft-foreground", label: "Frio" }
|
|
1413
1542
|
};
|
|
1414
1543
|
function LeadCard({ personId, handle }) {
|
|
1415
|
-
const [lead, setLead] =
|
|
1416
|
-
|
|
1544
|
+
const [lead, setLead] = React12__default.useState(void 0);
|
|
1545
|
+
React12__default.useEffect(() => {
|
|
1417
1546
|
let alive = true;
|
|
1418
1547
|
const sb = getSupabaseClientOptional();
|
|
1419
1548
|
const tenantId = getActiveTenantId();
|
|
@@ -1580,14 +1709,14 @@ function NewConversationPanel({
|
|
|
1580
1709
|
const create = useConversationsStore((s) => s.create);
|
|
1581
1710
|
const config = useConversationsConfig();
|
|
1582
1711
|
const guardConversations = useLimitGuard("conversations_month");
|
|
1583
|
-
const [channel, setChannel] =
|
|
1584
|
-
const [contact, setContact] =
|
|
1585
|
-
const [typedHandle, setTypedHandle] =
|
|
1586
|
-
const [creatingContact, setCreatingContact] =
|
|
1587
|
-
const [firstMessage, setFirstMessage] =
|
|
1588
|
-
const [submitting, setSubmitting] =
|
|
1589
|
-
const [pickerKey, setPickerKey] =
|
|
1590
|
-
|
|
1712
|
+
const [channel, setChannel] = React12__default.useState("whatsapp");
|
|
1713
|
+
const [contact, setContact] = React12__default.useState(null);
|
|
1714
|
+
const [typedHandle, setTypedHandle] = React12__default.useState("");
|
|
1715
|
+
const [creatingContact, setCreatingContact] = React12__default.useState(false);
|
|
1716
|
+
const [firstMessage, setFirstMessage] = React12__default.useState("");
|
|
1717
|
+
const [submitting, setSubmitting] = React12__default.useState(false);
|
|
1718
|
+
const [pickerKey, setPickerKey] = React12__default.useState(0);
|
|
1719
|
+
React12__default.useEffect(() => {
|
|
1591
1720
|
if (open) {
|
|
1592
1721
|
setChannel("whatsapp");
|
|
1593
1722
|
setContact(null);
|
|
@@ -1624,14 +1753,10 @@ function NewConversationPanel({
|
|
|
1624
1753
|
setSubmitting(false);
|
|
1625
1754
|
}
|
|
1626
1755
|
}
|
|
1627
|
-
return /* @__PURE__ */ jsx(
|
|
1628
|
-
|
|
1629
|
-
{
|
|
1630
|
-
|
|
1631
|
-
open,
|
|
1632
|
-
onClose: () => onOpenChange(false),
|
|
1633
|
-
width: "max-w-md",
|
|
1634
|
-
children: /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto px-5 py-4", children: [
|
|
1756
|
+
return /* @__PURE__ */ jsx(Modal, { open, onOpenChange, children: /* @__PURE__ */ jsxs(ModalContent, { className: "max-w-md", children: [
|
|
1757
|
+
/* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(ModalTitle, { children: t("conversations.new.title") }) }),
|
|
1758
|
+
/* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "flex min-h-0 flex-1 flex-col overflow-hidden", children: [
|
|
1759
|
+
/* @__PURE__ */ jsxs(ModalBody, { className: "space-y-4", children: [
|
|
1635
1760
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
1636
1761
|
/* @__PURE__ */ jsx("label", { className: "mb-1.5 block text-xs font-medium text-muted-foreground", children: t("conversations.new.channel") }),
|
|
1637
1762
|
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: CHANNELS.map((ch) => {
|
|
@@ -1695,20 +1820,20 @@ function NewConversationPanel({
|
|
|
1695
1820
|
className: "max-h-40 min-h-[64px] w-full resize-none rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground outline-none focus:border-primary"
|
|
1696
1821
|
}
|
|
1697
1822
|
)
|
|
1698
|
-
] })
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
}
|
|
1702
|
-
);
|
|
1823
|
+
] })
|
|
1824
|
+
] }),
|
|
1825
|
+
/* @__PURE__ */ jsx(ModalFooter, { children: /* @__PURE__ */ jsx(Button, { type: "submit", disabled: !canSubmit, className: "w-full", children: submitting ? t("conversations.new.creating") : t("conversations.new.create") }) })
|
|
1826
|
+
] })
|
|
1827
|
+
] }) });
|
|
1703
1828
|
}
|
|
1704
1829
|
function useCaixaAoVivo() {
|
|
1705
1830
|
const tenantId = useActiveTenantId();
|
|
1706
1831
|
const load = useConversationsStore((s) => s.load);
|
|
1707
1832
|
const refreshMessages = useConversationsStore((s) => s.refreshMessages);
|
|
1708
1833
|
const selectedId = useConversationsStore((s) => s.selectedId);
|
|
1709
|
-
const abertoRef =
|
|
1834
|
+
const abertoRef = React12.useRef(selectedId);
|
|
1710
1835
|
abertoRef.current = selectedId;
|
|
1711
|
-
|
|
1836
|
+
React12.useEffect(() => {
|
|
1712
1837
|
if (!tenantId) return;
|
|
1713
1838
|
return assinarChegada(tenantId, ({ conversationId }) => {
|
|
1714
1839
|
void load();
|
|
@@ -1723,26 +1848,26 @@ function InboxView() {
|
|
|
1723
1848
|
const { conversations, selectedId, deselect } = useConversationsStore((s) => s);
|
|
1724
1849
|
useCaixaAoVivo();
|
|
1725
1850
|
const isWidePanel = useMediaQuery("(min-width: 1280px)");
|
|
1726
|
-
const
|
|
1727
|
-
const [
|
|
1851
|
+
const railOpen = useRightRailStore((s) => s.open);
|
|
1852
|
+
const [panelOpen, setPanelOpen] = React12__default.useState(false);
|
|
1853
|
+
const [newOpen, setNewOpen] = React12__default.useState(false);
|
|
1728
1854
|
const selected = conversations.find((c) => c.id === selectedId) ?? null;
|
|
1729
|
-
|
|
1730
|
-
setPanelOpen(isWidePanel);
|
|
1731
|
-
}, [isWidePanel]);
|
|
1855
|
+
React12__default.useEffect(() => {
|
|
1856
|
+
setPanelOpen(isWidePanel && !railOpen);
|
|
1857
|
+
}, [isWidePanel, railOpen]);
|
|
1858
|
+
const newActions = React12__default.useMemo(() => [{
|
|
1859
|
+
id: "new-conversation",
|
|
1860
|
+
label: t("conversations.list.new"),
|
|
1861
|
+
icon: SquarePen,
|
|
1862
|
+
intent: "primary",
|
|
1863
|
+
// Starting a conversation creates a thread — the FAB is a "+".
|
|
1864
|
+
creates: true,
|
|
1865
|
+
testId: "conversations-new",
|
|
1866
|
+
permission: { feature: "conversations", action: "create" },
|
|
1867
|
+
onSelect: () => setNewOpen(true)
|
|
1868
|
+
}], [t]);
|
|
1732
1869
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1733
|
-
/* @__PURE__ */ jsx(
|
|
1734
|
-
Button,
|
|
1735
|
-
{
|
|
1736
|
-
size: "sm",
|
|
1737
|
-
onClick: () => setNewOpen(true),
|
|
1738
|
-
"aria-label": t("conversations.list.new"),
|
|
1739
|
-
"data-testid": "conversations-new",
|
|
1740
|
-
children: [
|
|
1741
|
-
/* @__PURE__ */ jsx(SquarePen, { className: "h-3.5 w-3.5 sm:mr-1.5" }),
|
|
1742
|
-
/* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: t("conversations.list.new") })
|
|
1743
|
-
]
|
|
1744
|
-
}
|
|
1745
|
-
) }) }),
|
|
1870
|
+
/* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsx(PageActions, { actions: newActions }) }),
|
|
1746
1871
|
/* @__PURE__ */ jsx(NewConversationPanel, { open: newOpen, onOpenChange: setNewOpen }),
|
|
1747
1872
|
/* @__PURE__ */ jsxs("div", { className: "relative flex h-full min-h-0 overflow-hidden bg-background", children: [
|
|
1748
1873
|
/* @__PURE__ */ jsx(ConversationList, { className: cn(selected ? "hidden lg:flex" : "flex") }),
|
|
@@ -1799,7 +1924,7 @@ function requestedContact() {
|
|
|
1799
1924
|
}
|
|
1800
1925
|
}
|
|
1801
1926
|
function ConversationsPage({ store: store2, config }) {
|
|
1802
|
-
|
|
1927
|
+
React12__default.useEffect(() => {
|
|
1803
1928
|
const wanted = requestedContact();
|
|
1804
1929
|
if (!wanted) {
|
|
1805
1930
|
void store2.getState().load();
|
|
@@ -2128,7 +2253,8 @@ function mapMessage(r) {
|
|
|
2128
2253
|
// migration 012 genuinely does not know what it was, and the rows that most
|
|
2129
2254
|
// need saying so are the empty ones that a 'text' default would call fine.
|
|
2130
2255
|
messageType: r.message_type ?? null,
|
|
2131
|
-
payload: r.payload ?? null
|
|
2256
|
+
payload: r.payload ?? null,
|
|
2257
|
+
mediaPath: r.media_path ?? null
|
|
2132
2258
|
};
|
|
2133
2259
|
}
|
|
2134
2260
|
function createSupabaseConversationsProvider(config) {
|
|
@@ -2887,22 +3013,22 @@ function NumberRow({ n }) {
|
|
|
2887
3013
|
] });
|
|
2888
3014
|
}
|
|
2889
3015
|
function WhatsAppProviders() {
|
|
2890
|
-
const [rows, setRows] =
|
|
2891
|
-
const [draft, setDraft] =
|
|
2892
|
-
const [busy, setBusy] =
|
|
2893
|
-
const [numbers, setNumbers] =
|
|
2894
|
-
const [qr, setQr] =
|
|
2895
|
-
const load =
|
|
3016
|
+
const [rows, setRows] = React12__default.useState(null);
|
|
3017
|
+
const [draft, setDraft] = React12__default.useState({});
|
|
3018
|
+
const [busy, setBusy] = React12__default.useState(null);
|
|
3019
|
+
const [numbers, setNumbers] = React12__default.useState({});
|
|
3020
|
+
const [qr, setQr] = React12__default.useState(null);
|
|
3021
|
+
const load = React12__default.useCallback(async () => {
|
|
2896
3022
|
try {
|
|
2897
3023
|
setRows(await providersApi.list());
|
|
2898
3024
|
} catch {
|
|
2899
3025
|
setRows([]);
|
|
2900
3026
|
}
|
|
2901
3027
|
}, []);
|
|
2902
|
-
|
|
3028
|
+
React12__default.useEffect(() => {
|
|
2903
3029
|
void load();
|
|
2904
3030
|
}, [load]);
|
|
2905
|
-
const byId =
|
|
3031
|
+
const byId = React12__default.useMemo(
|
|
2906
3032
|
() => Object.fromEntries((rows ?? []).map((r) => [r.provider, r])),
|
|
2907
3033
|
[rows]
|
|
2908
3034
|
);
|
|
@@ -3137,9 +3263,9 @@ function ChannelRow({ account }) {
|
|
|
3137
3263
|
}
|
|
3138
3264
|
function ConversationsGeneralSettings() {
|
|
3139
3265
|
const t = useTranslation();
|
|
3140
|
-
const [channels, setChannels] =
|
|
3141
|
-
const [failed, setFailed] =
|
|
3142
|
-
|
|
3266
|
+
const [channels, setChannels] = React12.useState(null);
|
|
3267
|
+
const [failed, setFailed] = React12.useState(false);
|
|
3268
|
+
React12.useEffect(() => {
|
|
3143
3269
|
let cancelled = false;
|
|
3144
3270
|
listMessagingChannels().then((rows) => {
|
|
3145
3271
|
if (!cancelled) setChannels(rows);
|
|
@@ -5595,6 +5721,72 @@ COMMENT ON COLUMN public.plg_conversation_messages.message_type IS
|
|
|
5595
5721
|
COMMENT ON COLUMN public.plg_conversation_messages.payload IS
|
|
5596
5722
|
'The structured remainder that \`body\` cannot hold \u2014 parsed vCards, media metadata, coordinates. Never credentials, thumbnails or decryption keys; never delivery status, which is read live (#504).';
|
|
5597
5723
|
`;
|
|
5724
|
+
var MIGRATION_013_A_MIDIA_FICA_CONOSCO = `-- ---------------------------------------------------------------------------
|
|
5725
|
+
-- 013_a_midia_fica_conosco.sql
|
|
5726
|
+
--
|
|
5727
|
+
-- \u2500\u2500 o que a 012 resolveu, e o que ela n\xE3o resolveu \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5728
|
+
--
|
|
5729
|
+
-- A 012 fez a mensagem que n\xE3o \xE9 texto parar de chegar como bolha vazia:
|
|
5730
|
+
-- \`message_type\` diz que \xE9 imagem, \`payload\` guarda mimetype, tamanho e
|
|
5731
|
+
-- dura\xE7\xE3o. Funcionou \u2014 um \xE1udio de 23 segundos entrou classificado como
|
|
5732
|
+
-- \`audio\`, \`ptt: true\`, \`audio/ogg; codecs=opus\`, 55.825 bytes.
|
|
5733
|
+
--
|
|
5734
|
+
-- E a tela mostra \`[\xE1udio]\`. Porque saber QUE existe um arquivo n\xE3o \xE9 ter o
|
|
5735
|
+
-- arquivo. Nada no banco aponta para bytes nenhuns: o WhatsApp entrega m\xEDdia
|
|
5736
|
+
-- cifrada num CDN pr\xF3prio, e quem decifra \xE9 o provedor.
|
|
5737
|
+
--
|
|
5738
|
+
-- \u2500\u2500 por que uma coluna, e n\xE3o um campo no payload \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5739
|
+
--
|
|
5740
|
+
-- A 012 escreveu que \`payload\` \xE9 "a forma da mensagem, que n\xE3o muda depois que
|
|
5741
|
+
-- ela chega". Onde o arquivo foi parar \xE9 decidido DEPOIS \u2014 no upload, que pode
|
|
5742
|
+
-- falhar, ser refeito, ou ainda n\xE3o ter acontecido. Enfiar isso no \`payload\`
|
|
5743
|
+
-- contradiz a \xFAnica frase que diz quando \`payload\` pode ser lido sem medo.
|
|
5744
|
+
--
|
|
5745
|
+
-- Em coluna, a pergunta que importa vira consulta:
|
|
5746
|
+
--
|
|
5747
|
+
-- SELECT count(*) FROM plg_conversation_messages
|
|
5748
|
+
-- WHERE message_type IN ('image','video','audio','document','sticker')
|
|
5749
|
+
-- AND media_path IS NULL;
|
|
5750
|
+
--
|
|
5751
|
+
-- "quanta m\xEDdia eu recebi e n\xE3o guardei" \u2014 que num campo de JSON seria uma
|
|
5752
|
+
-- varredura e aqui \xE9 um \xEDndice.
|
|
5753
|
+
--
|
|
5754
|
+
-- \u2500\u2500 por que guardar, em vez de buscar no provedor quando algu\xE9m abrir \u2500\u2500\u2500
|
|
5755
|
+
--
|
|
5756
|
+
-- A Evolution decifra sob demanda, e seria mais barato n\xE3o copiar nada. Mas ela
|
|
5757
|
+
-- \xE9 local-only, poda o que \xE9 antigo, e a inst\xE2ncia roda numa m\xE1quina que nem
|
|
5758
|
+
-- sempre est\xE1 de p\xE9. Essa era exatamente a obje\xE7\xE3o da 012 contra depender dela
|
|
5759
|
+
-- para ler um vCard: uma linha que precisa de um segundo sistema para ser
|
|
5760
|
+
-- leg\xEDvel n\xE3o \xE9 registro. Vale igual para os bytes.
|
|
5761
|
+
--
|
|
5762
|
+
-- O destino \xE9 o balde \`attachments\` \u2014 privado, 25 MB, j\xE1 existente e j\xE1 em uso.
|
|
5763
|
+
-- Uma foto que um lead mandou no WhatsApp n\xE3o pode ser p\xFAblica, e um balde novo
|
|
5764
|
+
-- seria mais uma lista de mimetypes para algu\xE9m manter desatualizada.
|
|
5765
|
+
--
|
|
5766
|
+
-- \u2500\u2500 nulo \xE9 um estado leg\xEDtimo, n\xE3o uma falha \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5767
|
+
--
|
|
5768
|
+
-- \`media_path\` \xE9 NULL em tr\xEAs situa\xE7\xF5es diferentes e todas normais: a mensagem
|
|
5769
|
+
-- \xE9 texto; a linha \xE9 anterior a esta migra\xE7\xE3o; ou o upload ainda n\xE3o aconteceu.
|
|
5770
|
+
-- Quem l\xEA distingue pela combina\xE7\xE3o com \`message_type\`, que \xE9 o que torna a
|
|
5771
|
+
-- consulta acima poss\xEDvel. Um default inventaria um caminho para arquivo que
|
|
5772
|
+
-- n\xE3o existe.
|
|
5773
|
+
--
|
|
5774
|
+
-- Idempotente e replay-safe.
|
|
5775
|
+
-- ---------------------------------------------------------------------------
|
|
5776
|
+
|
|
5777
|
+
ALTER TABLE public.plg_conversation_messages
|
|
5778
|
+
ADD COLUMN IF NOT EXISTS media_path text;
|
|
5779
|
+
|
|
5780
|
+
COMMENT ON COLUMN public.plg_conversation_messages.media_path IS
|
|
5781
|
+
'Onde os bytes ficaram no balde \`attachments\`, ou NULL: texto, linha anterior \xE0 013, ou upload que ainda n\xE3o aconteceu. Distingue-se pela combina\xE7\xE3o com \`message_type\` (013).';
|
|
5782
|
+
|
|
5783
|
+
-- Parcial: s\xF3 a m\xEDdia sem arquivo interessa, e \xE9 a minoria. O \xEDndice fica do
|
|
5784
|
+
-- tamanho do problema em vez do tamanho da tabela.
|
|
5785
|
+
CREATE INDEX IF NOT EXISTS plg_conversation_messages_midia_sem_arquivo
|
|
5786
|
+
ON public.plg_conversation_messages (tenant_id, at DESC)
|
|
5787
|
+
WHERE media_path IS NULL
|
|
5788
|
+
AND message_type IN ('image', 'video', 'audio', 'document', 'sticker');
|
|
5789
|
+
`;
|
|
5598
5790
|
var MIGRATIONS = [
|
|
5599
5791
|
{ id: "000_baseline", sql: MIGRATION_000_BASELINE },
|
|
5600
5792
|
{ id: "001_a_caixa_sabe_quem_falou_por_ultimo", sql: MIGRATION_001_A_CAIXA_SABE_QUEM_FALOU_POR_ULTIMO },
|
|
@@ -5608,7 +5800,8 @@ var MIGRATIONS = [
|
|
|
5608
5800
|
{ id: "009_a_mensagem_inteira_atravessa_o_realtime", sql: MIGRATION_009_A_MENSAGEM_INTEIRA_ATRAVESSA_O_REALTIME },
|
|
5609
5801
|
{ id: "010_a_chegada_e_anunciada_por_conta", sql: MIGRATION_010_A_CHEGADA_E_ANUNCIADA_POR_CONTA },
|
|
5610
5802
|
{ id: "011_o_anuncio_e_uma_campainha_nao_um_recado", sql: MIGRATION_011_O_ANUNCIO_E_UMA_CAMPAINHA_NAO_UM_RECADO },
|
|
5611
|
-
{ id: "012_a_rich_message_keeps_its_shape", sql: MIGRATION_012_A_RICH_MESSAGE_KEEPS_ITS_SHAPE }
|
|
5803
|
+
{ id: "012_a_rich_message_keeps_its_shape", sql: MIGRATION_012_A_RICH_MESSAGE_KEEPS_ITS_SHAPE },
|
|
5804
|
+
{ id: "013_a_midia_fica_conosco", sql: MIGRATION_013_A_MIDIA_FICA_CONOSCO }
|
|
5612
5805
|
];
|
|
5613
5806
|
|
|
5614
5807
|
// src/index.ts
|
|
@@ -5642,11 +5835,11 @@ function createConversationsPlugin(options) {
|
|
|
5642
5835
|
contactEntityDef: options?.contactEntityDef
|
|
5643
5836
|
};
|
|
5644
5837
|
const dashboardWidgets = createConversationsDashboardWidgets({ store: store2, config });
|
|
5645
|
-
const PageComponent = () =>
|
|
5838
|
+
const PageComponent = () => React12__default.createElement(ConversationsPage, { store: store2, config });
|
|
5646
5839
|
PageComponent.displayName = "ConversationsPage";
|
|
5647
|
-
const CampaignsPageComponent = () =>
|
|
5840
|
+
const CampaignsPageComponent = () => React12__default.createElement(CampaignsView);
|
|
5648
5841
|
CampaignsPageComponent.displayName = "ConversationsCampaignsPage";
|
|
5649
|
-
const TemplatesPageComponent = () =>
|
|
5842
|
+
const TemplatesPageComponent = () => React12__default.createElement(TemplatesView);
|
|
5650
5843
|
TemplatesPageComponent.displayName = "ConversationsTemplatesPage";
|
|
5651
5844
|
return {
|
|
5652
5845
|
id: "conversations",
|
|
@@ -5722,7 +5915,7 @@ function createConversationsPlugin(options) {
|
|
|
5722
5915
|
// quando ele serve para alguma coisa.
|
|
5723
5916
|
zone: "shell.topbar.end",
|
|
5724
5917
|
component: (() => {
|
|
5725
|
-
const W = () =>
|
|
5918
|
+
const W = () => React12__default.createElement(InboxWatcher, {
|
|
5726
5919
|
label: options?.navLabel ?? "Conversations",
|
|
5727
5920
|
section: options?.navSection ?? "main",
|
|
5728
5921
|
position: options?.navPosition ?? 1
|