@decido/discovery-studio 0.1.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/index.d.mts +102 -0
- package/dist/index.d.ts +102 -0
- package/dist/index.js +2054 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2040 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +48 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2040 @@
|
|
|
1
|
+
import React8, { memo, useState, useEffect, useRef, useCallback } from 'react';
|
|
2
|
+
import { io } from 'socket.io-client';
|
|
3
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
+
import { kernel } from '@decido/kernel-bridge';
|
|
5
|
+
import { Handle, Position, MarkerType } from '@xyflow/react';
|
|
6
|
+
import { FlowEditor } from '@decido/canvas-ai';
|
|
7
|
+
import { BaseNode } from '@decido/macia-core';
|
|
8
|
+
import { Info, Reply, MessageCircle, GitBranch, Brain, Headphones, ShoppingCart, Bot } from 'lucide-react';
|
|
9
|
+
|
|
10
|
+
// src/DiscoveryStudio.tsx
|
|
11
|
+
var API_URL = import.meta.env?.VITE_API_BASE_URL || "http://localhost:3001";
|
|
12
|
+
var DEMO_TEMPLATES = [
|
|
13
|
+
{ id: "t1", label: "Confirmaci\xF3n Pedido", icon: "fas fa-check-circle" },
|
|
14
|
+
{ id: "t2", label: "Estado de Env\xEDo", icon: "fas fa-truck" },
|
|
15
|
+
{ id: "t3", label: "Cotizaci\xF3n", icon: "fas fa-file-invoice" },
|
|
16
|
+
{ id: "t4", label: "Bienvenida", icon: "fas fa-hand-wave" }
|
|
17
|
+
];
|
|
18
|
+
var DEMO_AUTOMATIONS = [
|
|
19
|
+
{ id: "a1", label: "Auto-respuesta horario", active: true },
|
|
20
|
+
{ id: "a2", label: "Crear pedido autom\xE1tico", active: true },
|
|
21
|
+
{ id: "a3", label: "Escalamiento a asesor", active: false },
|
|
22
|
+
{ id: "a4", label: "Encuesta satisfacci\xF3n", active: true }
|
|
23
|
+
];
|
|
24
|
+
var Section = ({
|
|
25
|
+
title,
|
|
26
|
+
icon,
|
|
27
|
+
count,
|
|
28
|
+
defaultOpen = true,
|
|
29
|
+
children
|
|
30
|
+
}) => {
|
|
31
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
32
|
+
return /* @__PURE__ */ jsxs("div", { className: "border-b", style: { borderColor: "var(--border-color)" }, children: [
|
|
33
|
+
/* @__PURE__ */ jsxs(
|
|
34
|
+
"button",
|
|
35
|
+
{
|
|
36
|
+
onClick: () => setOpen((p) => !p),
|
|
37
|
+
className: "w-full flex items-center gap-2 px-3 py-2 text-[10px] font-black uppercase tracking-widest transition-all hover:bg-white/5",
|
|
38
|
+
style: { color: "var(--text-secondary)" },
|
|
39
|
+
children: [
|
|
40
|
+
/* @__PURE__ */ jsx("i", { className: `fas fa-chevron-${open ? "down" : "right"} text-[8px] w-3` }),
|
|
41
|
+
/* @__PURE__ */ jsx("i", { className: `${icon} text-[10px]` }),
|
|
42
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 text-left", children: title }),
|
|
43
|
+
count !== void 0 && /* @__PURE__ */ jsx("span", { className: "px-1.5 py-0.5 rounded text-[9px] font-bold", style: { background: "var(--bg-muted)", color: "var(--text-secondary)" }, children: count })
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
),
|
|
47
|
+
open && /* @__PURE__ */ jsx("div", { className: "pb-1", children })
|
|
48
|
+
] });
|
|
49
|
+
};
|
|
50
|
+
var SideExplorer = ({ selectedContact, onSelectContact }) => {
|
|
51
|
+
const [filter, setFilter] = useState("");
|
|
52
|
+
const [conversations, setConversations] = useState([]);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
const fetchConversations = async () => {
|
|
55
|
+
try {
|
|
56
|
+
const res = await fetch(`${API_URL}/api/whatsapp/conversations`);
|
|
57
|
+
const data = await res.json();
|
|
58
|
+
setConversations(data.map((item) => ({
|
|
59
|
+
...item,
|
|
60
|
+
last_activity: new Date(item.last_activity)
|
|
61
|
+
})));
|
|
62
|
+
} catch (err) {
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
fetchConversations();
|
|
66
|
+
const s = io(API_URL, { transports: ["websocket", "polling"] });
|
|
67
|
+
s.on("wa:message_received", fetchConversations);
|
|
68
|
+
s.on("wa:message_sent", fetchConversations);
|
|
69
|
+
return () => {
|
|
70
|
+
s.disconnect();
|
|
71
|
+
};
|
|
72
|
+
}, []);
|
|
73
|
+
const filtered = conversations.filter(
|
|
74
|
+
(c) => c.phone.includes(filter)
|
|
75
|
+
);
|
|
76
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full overflow-hidden", children: [
|
|
77
|
+
/* @__PURE__ */ jsx("div", { className: "p-2 shrink-0", children: /* @__PURE__ */ jsxs(
|
|
78
|
+
"div",
|
|
79
|
+
{
|
|
80
|
+
className: "flex items-center gap-2 px-2.5 py-1.5 rounded-lg text-xs",
|
|
81
|
+
style: { background: "var(--bg-muted)", border: "1px solid var(--border-color)" },
|
|
82
|
+
children: [
|
|
83
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-search text-[10px]", style: { color: "var(--text-secondary)" } }),
|
|
84
|
+
/* @__PURE__ */ jsx(
|
|
85
|
+
"input",
|
|
86
|
+
{
|
|
87
|
+
type: "text",
|
|
88
|
+
placeholder: "Filtrar...",
|
|
89
|
+
className: "flex-1 bg-transparent outline-none text-xs",
|
|
90
|
+
style: { color: "var(--text-primary)" },
|
|
91
|
+
value: filter,
|
|
92
|
+
onChange: (e) => setFilter(e.target.value)
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
) }),
|
|
98
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto scrollbar-thin", children: [
|
|
99
|
+
/* @__PURE__ */ jsxs(Section, { title: "Conversaciones", icon: "fas fa-comments", count: filtered.length, children: [
|
|
100
|
+
filtered.map((conv) => /* @__PURE__ */ jsxs(
|
|
101
|
+
"button",
|
|
102
|
+
{
|
|
103
|
+
onClick: () => onSelectContact(conv.phone),
|
|
104
|
+
className: "w-full flex items-start gap-2.5 px-3 py-2 text-left transition-all rounded-md mx-1",
|
|
105
|
+
style: {
|
|
106
|
+
background: selectedContact === conv.phone ? "var(--bg-muted)" : "transparent",
|
|
107
|
+
width: "calc(100% - 8px)"
|
|
108
|
+
},
|
|
109
|
+
onMouseEnter: (e) => {
|
|
110
|
+
if (selectedContact !== conv.phone) e.currentTarget.style.background = "var(--bg-muted)";
|
|
111
|
+
},
|
|
112
|
+
onMouseLeave: (e) => {
|
|
113
|
+
if (selectedContact !== conv.phone) e.currentTarget.style.background = "transparent";
|
|
114
|
+
},
|
|
115
|
+
children: [
|
|
116
|
+
/* @__PURE__ */ jsx(
|
|
117
|
+
"div",
|
|
118
|
+
{
|
|
119
|
+
className: "w-8 h-8 rounded-full flex items-center justify-center shrink-0 text-white text-[10px] font-bold",
|
|
120
|
+
style: { background: "var(--brand-primary)" },
|
|
121
|
+
children: /* @__PURE__ */ jsx("i", { className: "fab fa-whatsapp text-sm" })
|
|
122
|
+
}
|
|
123
|
+
),
|
|
124
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
125
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
126
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs font-bold truncate", style: { color: "var(--text-primary)" }, children: [
|
|
127
|
+
"+",
|
|
128
|
+
conv.phone
|
|
129
|
+
] }),
|
|
130
|
+
/* @__PURE__ */ jsx("span", { className: "text-[9px] shrink-0 ml-1", style: { color: "var(--text-secondary)" }, children: conv.last_activity.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) })
|
|
131
|
+
] }),
|
|
132
|
+
/* @__PURE__ */ jsx("p", { className: "text-[10px] truncate mt-0.5", style: { color: "var(--text-secondary)" }, children: conv.last_message || "Media" })
|
|
133
|
+
] })
|
|
134
|
+
]
|
|
135
|
+
},
|
|
136
|
+
conv.phone
|
|
137
|
+
)),
|
|
138
|
+
filtered.length === 0 && /* @__PURE__ */ jsxs("div", { className: "px-4 py-3 pb-4 text-center", children: [
|
|
139
|
+
/* @__PURE__ */ jsx("i", { className: "fab fa-whatsapp text-2xl mb-2", style: { color: "#25D366" } }),
|
|
140
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs", style: { color: "var(--text-secondary)" }, children: "No hay chats activos. Manda un WhatsApp al n\xFAmero Business para empezar." })
|
|
141
|
+
] })
|
|
142
|
+
] }),
|
|
143
|
+
/* @__PURE__ */ jsx(Section, { title: "Plantillas", icon: "fas fa-file-alt", count: DEMO_TEMPLATES.length, defaultOpen: false, children: DEMO_TEMPLATES.map((tpl) => /* @__PURE__ */ jsxs(
|
|
144
|
+
"div",
|
|
145
|
+
{
|
|
146
|
+
className: "flex items-center gap-2 px-3 py-1.5 mx-1 rounded-md cursor-pointer transition-all",
|
|
147
|
+
style: { width: "calc(100% - 8px)" },
|
|
148
|
+
onMouseEnter: (e) => e.currentTarget.style.background = "var(--bg-muted)",
|
|
149
|
+
onMouseLeave: (e) => e.currentTarget.style.background = "transparent",
|
|
150
|
+
children: [
|
|
151
|
+
/* @__PURE__ */ jsx("i", { className: `${tpl.icon} text-[10px]`, style: { color: "var(--brand-primary)" } }),
|
|
152
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs", style: { color: "var(--text-primary)" }, children: tpl.label })
|
|
153
|
+
]
|
|
154
|
+
},
|
|
155
|
+
tpl.id
|
|
156
|
+
)) }),
|
|
157
|
+
/* @__PURE__ */ jsx(Section, { title: "Automatizaciones", icon: "fas fa-robot", count: DEMO_AUTOMATIONS.filter((a) => a.active).length, defaultOpen: false, children: DEMO_AUTOMATIONS.map((auto) => /* @__PURE__ */ jsxs(
|
|
158
|
+
"div",
|
|
159
|
+
{
|
|
160
|
+
className: "flex items-center gap-2 px-3 py-1.5 mx-1 rounded-md",
|
|
161
|
+
style: { width: "calc(100% - 8px)" },
|
|
162
|
+
children: [
|
|
163
|
+
/* @__PURE__ */ jsx("span", { className: `w-1.5 h-1.5 rounded-full ${auto.active ? "bg-green-500" : "bg-slate-400"}` }),
|
|
164
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs flex-1", style: { color: "var(--text-primary)" }, children: auto.label }),
|
|
165
|
+
/* @__PURE__ */ jsx("span", { className: "text-[9px] font-bold", style: { color: auto.active ? "#22c55e" : "var(--text-secondary)" }, children: auto.active ? "ON" : "OFF" })
|
|
166
|
+
]
|
|
167
|
+
},
|
|
168
|
+
auto.id
|
|
169
|
+
)) })
|
|
170
|
+
] })
|
|
171
|
+
] });
|
|
172
|
+
};
|
|
173
|
+
var CONTACT_DETAILS = {
|
|
174
|
+
c1: {
|
|
175
|
+
name: "Mar\xEDa Garc\xEDa",
|
|
176
|
+
phone: "+57 301 234 5678",
|
|
177
|
+
email: "maria@gmail.com",
|
|
178
|
+
city: "Bogot\xE1",
|
|
179
|
+
totalOrders: 8,
|
|
180
|
+
totalSpent: "$4,250,000",
|
|
181
|
+
lastOrder: "PED-1847",
|
|
182
|
+
sentiment: "neutral",
|
|
183
|
+
tags: ["VIP", "Frecuente", "Muebler\xEDa"],
|
|
184
|
+
timeline: [
|
|
185
|
+
{ time: "2m", event: "Pregunt\xF3 por estado de pedido", icon: "fas fa-comment" },
|
|
186
|
+
{ time: "1d", event: "Pedido PED-1847 en PRODUCCI\xD3N", icon: "fas fa-industry" },
|
|
187
|
+
{ time: "3d", event: "Confirm\xF3 cotizaci\xF3n mesa roble", icon: "fas fa-check" },
|
|
188
|
+
{ time: "1w", event: "Solicit\xF3 cat\xE1logo digital", icon: "fas fa-book" }
|
|
189
|
+
]
|
|
190
|
+
},
|
|
191
|
+
c2: {
|
|
192
|
+
name: "Carlos Ruiz",
|
|
193
|
+
phone: "+57 310 987 6543",
|
|
194
|
+
email: "cruiz@empresa.co",
|
|
195
|
+
city: "Medell\xEDn",
|
|
196
|
+
totalOrders: 3,
|
|
197
|
+
totalSpent: "$1,890,000",
|
|
198
|
+
lastOrder: "PED-1832",
|
|
199
|
+
sentiment: "positive",
|
|
200
|
+
tags: ["Empresa", "Nuevo"],
|
|
201
|
+
timeline: [
|
|
202
|
+
{ time: "15m", event: "Solicit\xF3 cotizaci\xF3n de mesa", icon: "fas fa-comment" },
|
|
203
|
+
{ time: "2d", event: "Primer contacto v\xEDa WhatsApp", icon: "fas fa-phone" }
|
|
204
|
+
]
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
var SENTIMENTS = {
|
|
208
|
+
positive: { icon: "fas fa-smile", color: "#22c55e", label: "Positivo" },
|
|
209
|
+
neutral: { icon: "fas fa-meh", color: "#f59e0b", label: "Neutral" },
|
|
210
|
+
negative: { icon: "fas fa-frown", color: "#ef4444", label: "Negativo" }
|
|
211
|
+
};
|
|
212
|
+
var InfoRow = ({ label, value }) => /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center py-1.5", children: [
|
|
213
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-bold uppercase tracking-wider", style: { color: "var(--text-secondary)" }, children: label }),
|
|
214
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold", style: { color: "var(--text-primary)" }, children: value })
|
|
215
|
+
] });
|
|
216
|
+
var InspectorPanel = ({ selectedContact }) => {
|
|
217
|
+
const contact = selectedContact ? CONTACT_DETAILS[selectedContact] : null;
|
|
218
|
+
if (!contact) {
|
|
219
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center justify-center gap-3 p-6", children: [
|
|
220
|
+
/* @__PURE__ */ jsx(
|
|
221
|
+
"div",
|
|
222
|
+
{
|
|
223
|
+
className: "w-16 h-16 rounded-2xl flex items-center justify-center",
|
|
224
|
+
style: { background: "var(--bg-muted)" },
|
|
225
|
+
children: /* @__PURE__ */ jsx("i", { className: "fas fa-user-slash text-xl", style: { color: "var(--text-secondary)" } })
|
|
226
|
+
}
|
|
227
|
+
),
|
|
228
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-center font-medium", style: { color: "var(--text-secondary)" }, children: [
|
|
229
|
+
"Selecciona un contacto",
|
|
230
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
231
|
+
"para ver detalles"
|
|
232
|
+
] })
|
|
233
|
+
] });
|
|
234
|
+
}
|
|
235
|
+
const sentiment = SENTIMENTS[contact.sentiment];
|
|
236
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full overflow-y-auto scrollbar-thin", children: [
|
|
237
|
+
/* @__PURE__ */ jsxs("div", { className: "p-4 text-center border-b", style: { borderColor: "var(--border-color)" }, children: [
|
|
238
|
+
/* @__PURE__ */ jsx(
|
|
239
|
+
"div",
|
|
240
|
+
{
|
|
241
|
+
className: "w-14 h-14 rounded-full mx-auto flex items-center justify-center text-white font-bold text-lg mb-3",
|
|
242
|
+
style: { background: "var(--brand-primary)" },
|
|
243
|
+
children: contact.name.split(" ").map((n) => n[0]).join("")
|
|
244
|
+
}
|
|
245
|
+
),
|
|
246
|
+
/* @__PURE__ */ jsx("h3", { className: "font-bold text-sm", style: { color: "var(--text-primary)" }, children: contact.name }),
|
|
247
|
+
/* @__PURE__ */ jsx("p", { className: "text-[10px] mt-0.5", style: { color: "var(--text-secondary)" }, children: contact.phone }),
|
|
248
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap justify-center gap-1 mt-3", children: contact.tags.map((tag) => /* @__PURE__ */ jsx(
|
|
249
|
+
"span",
|
|
250
|
+
{
|
|
251
|
+
className: "px-2 py-0.5 rounded-full text-[9px] font-bold",
|
|
252
|
+
style: { background: "var(--bg-muted)", color: "var(--brand-primary)", border: "1px solid var(--border-color)" },
|
|
253
|
+
children: tag
|
|
254
|
+
},
|
|
255
|
+
tag
|
|
256
|
+
)) })
|
|
257
|
+
] }),
|
|
258
|
+
/* @__PURE__ */ jsxs("div", { className: "px-4 py-3 border-b", style: { borderColor: "var(--border-color)" }, children: [
|
|
259
|
+
/* @__PURE__ */ jsx("div", { className: "text-[10px] font-black uppercase tracking-widest mb-2", style: { color: "var(--text-secondary)" }, children: "Sentimiento IA" }),
|
|
260
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-2 rounded-lg", style: { background: "var(--bg-muted)" }, children: [
|
|
261
|
+
/* @__PURE__ */ jsx("i", { className: `${sentiment.icon} text-lg`, style: { color: sentiment.color } }),
|
|
262
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
263
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-bold", style: { color: sentiment.color }, children: sentiment.label }),
|
|
264
|
+
/* @__PURE__ */ jsx("div", { className: "w-full h-1.5 rounded-full mt-1", style: { background: "var(--border-color)" }, children: /* @__PURE__ */ jsx("div", { className: "h-full rounded-full transition-all", style: {
|
|
265
|
+
width: contact.sentiment === "positive" ? "80%" : contact.sentiment === "neutral" ? "50%" : "25%",
|
|
266
|
+
background: sentiment.color
|
|
267
|
+
} }) })
|
|
268
|
+
] })
|
|
269
|
+
] })
|
|
270
|
+
] }),
|
|
271
|
+
/* @__PURE__ */ jsxs("div", { className: "px-4 py-3 border-b", style: { borderColor: "var(--border-color)" }, children: [
|
|
272
|
+
/* @__PURE__ */ jsx("div", { className: "text-[10px] font-black uppercase tracking-widest mb-2", style: { color: "var(--text-secondary)" }, children: "Resumen Cliente" }),
|
|
273
|
+
/* @__PURE__ */ jsx(InfoRow, { label: "Pedidos", value: String(contact.totalOrders) }),
|
|
274
|
+
/* @__PURE__ */ jsx(InfoRow, { label: "Total", value: contact.totalSpent }),
|
|
275
|
+
/* @__PURE__ */ jsx(InfoRow, { label: "\xDAltimo", value: contact.lastOrder }),
|
|
276
|
+
/* @__PURE__ */ jsx(InfoRow, { label: "Ciudad", value: contact.city }),
|
|
277
|
+
/* @__PURE__ */ jsx(InfoRow, { label: "Email", value: contact.email })
|
|
278
|
+
] }),
|
|
279
|
+
/* @__PURE__ */ jsxs("div", { className: "px-4 py-3", children: [
|
|
280
|
+
/* @__PURE__ */ jsx("div", { className: "text-[10px] font-black uppercase tracking-widest mb-3", style: { color: "var(--text-secondary)" }, children: "Actividad Reciente" }),
|
|
281
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-0", children: contact.timeline.map((event, i) => /* @__PURE__ */ jsxs("div", { className: "flex gap-3 relative", children: [
|
|
282
|
+
i < contact.timeline.length - 1 && /* @__PURE__ */ jsx("div", { className: "absolute left-[9px] top-5 w-px h-full", style: { background: "var(--border-color)" } }),
|
|
283
|
+
/* @__PURE__ */ jsx(
|
|
284
|
+
"div",
|
|
285
|
+
{
|
|
286
|
+
className: "w-5 h-5 rounded-full flex items-center justify-center shrink-0 z-10",
|
|
287
|
+
style: { background: "var(--bg-muted)", border: "1px solid var(--border-color)" },
|
|
288
|
+
children: /* @__PURE__ */ jsx("i", { className: `${event.icon} text-[8px]`, style: { color: "var(--brand-primary)" } })
|
|
289
|
+
}
|
|
290
|
+
),
|
|
291
|
+
/* @__PURE__ */ jsxs("div", { className: "pb-4 min-w-0", children: [
|
|
292
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] font-medium leading-tight", style: { color: "var(--text-primary)" }, children: event.event }),
|
|
293
|
+
/* @__PURE__ */ jsxs("span", { className: "text-[9px]", style: { color: "var(--text-secondary)" }, children: [
|
|
294
|
+
"Hace ",
|
|
295
|
+
event.time
|
|
296
|
+
] })
|
|
297
|
+
] })
|
|
298
|
+
] }, i)) })
|
|
299
|
+
] })
|
|
300
|
+
] });
|
|
301
|
+
};
|
|
302
|
+
var AgentPanel = () => {
|
|
303
|
+
const [messages, setMessages] = useState([
|
|
304
|
+
{ id: "1", text: "Soy tu Agente Vocal asignado. \xBFEn qu\xE9 te ayudo con tus flujos?", type: "system" }
|
|
305
|
+
]);
|
|
306
|
+
const [input, setInput] = useState("");
|
|
307
|
+
const [isTyping, setIsTyping] = useState(false);
|
|
308
|
+
const scrollRef = useRef(null);
|
|
309
|
+
useEffect(() => {
|
|
310
|
+
if (scrollRef.current) {
|
|
311
|
+
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
|
|
312
|
+
}
|
|
313
|
+
}, [messages]);
|
|
314
|
+
useEffect(() => {
|
|
315
|
+
const unsubscribe = kernel.onEvent((payload) => {
|
|
316
|
+
if (payload.event_type === "message_sent" && payload.data?.target === "vocal_domain_agent") ; else if (payload.event_type === "message_sent" && payload.data?.intent === "vocal_response") {
|
|
317
|
+
setMessages((prev) => [...prev, { id: Date.now().toString(), text: payload.data.payload, type: "agent" }]);
|
|
318
|
+
setIsTyping(false);
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
return () => unsubscribe();
|
|
322
|
+
}, []);
|
|
323
|
+
const handleSend = async () => {
|
|
324
|
+
if (!input.trim()) return;
|
|
325
|
+
const userMsg = input;
|
|
326
|
+
setInput("");
|
|
327
|
+
setMessages((prev) => [...prev, { id: Date.now().toString(), text: userMsg, type: "user" }]);
|
|
328
|
+
setIsTyping(true);
|
|
329
|
+
try {
|
|
330
|
+
await kernel.execute("spawn_task", {
|
|
331
|
+
target_id: "vocal_domain_agent",
|
|
332
|
+
role: "vocal_domain",
|
|
333
|
+
intent: "user_prompt",
|
|
334
|
+
payload: userMsg
|
|
335
|
+
});
|
|
336
|
+
setTimeout(() => {
|
|
337
|
+
setIsTyping(false);
|
|
338
|
+
setMessages((prev) => {
|
|
339
|
+
const hasAgentResponse = prev.some((m) => m.type === "agent" && parseInt(m.id) > Date.now() - 2e3);
|
|
340
|
+
if (!hasAgentResponse) {
|
|
341
|
+
return [...prev, {
|
|
342
|
+
id: Date.now().toString(),
|
|
343
|
+
text: "Evaluando el dise\xF1o de tu flujo actual... Parece \xF3ptimo para WhatsApp Business.",
|
|
344
|
+
type: "agent"
|
|
345
|
+
}];
|
|
346
|
+
}
|
|
347
|
+
return prev;
|
|
348
|
+
});
|
|
349
|
+
}, 1500);
|
|
350
|
+
} catch (error) {
|
|
351
|
+
console.error("Error contacting agent:", error);
|
|
352
|
+
setIsTyping(false);
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
return /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col font-sans", style: { background: "var(--bg-elevated)", color: "var(--text-primary)" }, children: [
|
|
356
|
+
/* @__PURE__ */ jsxs("div", { className: "h-11 shrink-0 flex items-center px-3 border-b gap-2", style: { borderColor: "var(--border-color)" }, children: [
|
|
357
|
+
/* @__PURE__ */ jsx("div", { className: "w-6 h-6 rounded-full bg-emerald-500/20 flex items-center justify-center border border-emerald-500/50", children: /* @__PURE__ */ jsx("i", { className: "fas fa-robot text-emerald-400 text-xs text-brand animate-pulse" }) }),
|
|
358
|
+
/* @__PURE__ */ jsx("span", { className: "font-bold text-xs", children: "Agente Decido" }),
|
|
359
|
+
/* @__PURE__ */ jsx("span", { className: "ml-auto px-1.5 py-0.5 rounded text-[9px] font-bold bg-emerald-500/10 text-emerald-500 border border-emerald-500/20", children: "VOCAL DOMAIN" })
|
|
360
|
+
] }),
|
|
361
|
+
/* @__PURE__ */ jsxs("div", { ref: scrollRef, className: "flex-1 min-h-0 overflow-y-auto p-3 space-y-3", children: [
|
|
362
|
+
messages.map((msg) => /* @__PURE__ */ jsxs("div", { className: `flex flex-col max-w-[90%] ${msg.type === "user" ? "ml-auto items-end" : "mr-auto items-start"}`, children: [
|
|
363
|
+
msg.type === "system" && /* @__PURE__ */ jsx("div", { className: "text-[10px] text-center w-full my-2 italic", style: { color: "var(--text-secondary)" }, children: msg.text }),
|
|
364
|
+
msg.type !== "system" && /* @__PURE__ */ jsx(
|
|
365
|
+
"div",
|
|
366
|
+
{
|
|
367
|
+
className: `text-xs px-3 py-2 rounded-xl leading-relaxed ${msg.type === "user" ? "bg-brand text-white rounded-br-sm" : "bg-white/5 border border-white/10 rounded-bl-sm"}`,
|
|
368
|
+
children: msg.text
|
|
369
|
+
}
|
|
370
|
+
)
|
|
371
|
+
] }, msg.id)),
|
|
372
|
+
isTyping && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 p-2 bg-white/5 w-fit rounded-lg border border-white/10 rounded-bl-sm", children: [
|
|
373
|
+
/* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500/50 animate-bounce", style: { animationDelay: "0ms" } }),
|
|
374
|
+
/* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500/50 animate-bounce", style: { animationDelay: "150ms" } }),
|
|
375
|
+
/* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500/50 animate-bounce", style: { animationDelay: "300ms" } })
|
|
376
|
+
] })
|
|
377
|
+
] }),
|
|
378
|
+
/* @__PURE__ */ jsx("div", { className: "p-2 shrink-0 border-t", style: { borderColor: "var(--border-color)" }, children: /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2 bg-white/5 border border-white/10 rounded-lg p-1.5 focus-within:border-emerald-500/50 transition-colors", children: [
|
|
379
|
+
/* @__PURE__ */ jsx(
|
|
380
|
+
"textarea",
|
|
381
|
+
{
|
|
382
|
+
value: input,
|
|
383
|
+
onChange: (e) => setInput(e.target.value),
|
|
384
|
+
onKeyDown: (e) => {
|
|
385
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
386
|
+
e.preventDefault();
|
|
387
|
+
handleSend();
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
placeholder: "Preg\xFAntale al Agente...",
|
|
391
|
+
className: "flex-1 bg-transparent resize-none text-xs outline-none p-1.5 min-h-[32px] max-h-[100px]",
|
|
392
|
+
rows: input.split("\n").length > 1 ? Math.min(input.split("\n").length, 4) : 1
|
|
393
|
+
}
|
|
394
|
+
),
|
|
395
|
+
/* @__PURE__ */ jsx(
|
|
396
|
+
"button",
|
|
397
|
+
{
|
|
398
|
+
onClick: handleSend,
|
|
399
|
+
disabled: !input.trim() || isTyping,
|
|
400
|
+
className: "w-8 h-8 shrink-0 rounded-md bg-white/10 hover:bg-white/20 text-emerald-400 flex items-center justify-center transition-all disabled:opacity-50 disabled:cursor-not-allowed",
|
|
401
|
+
children: /* @__PURE__ */ jsx("i", { className: "fas fa-paper-plane text-xs" })
|
|
402
|
+
}
|
|
403
|
+
)
|
|
404
|
+
] }) })
|
|
405
|
+
] });
|
|
406
|
+
};
|
|
407
|
+
var API_URL2 = import.meta.env?.VITE_API_BASE_URL || "http://localhost:3001";
|
|
408
|
+
var ChatTab = ({ selectedContact }) => {
|
|
409
|
+
const [messages, setMessages] = useState([]);
|
|
410
|
+
const [input, setInput] = useState("");
|
|
411
|
+
const [opMode, setOpMode] = useState("COPILOT");
|
|
412
|
+
const [socket, setSocket] = useState(null);
|
|
413
|
+
const chatEndRef = useRef(null);
|
|
414
|
+
const fetchMessages = useCallback(async () => {
|
|
415
|
+
if (!selectedContact) {
|
|
416
|
+
setMessages([]);
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
try {
|
|
420
|
+
const res = await fetch(`${API_URL2}/api/whatsapp/messages?phone=${selectedContact}&limit=50`);
|
|
421
|
+
const data = await res.json();
|
|
422
|
+
const formatted = data.reverse().map((dbMsg) => ({
|
|
423
|
+
id: dbMsg.id.toString(),
|
|
424
|
+
text: dbMsg.body || (dbMsg.message_type === "image" ? "\u{1F4F8} [Imagen]" : "\u{1F4CE} [Archivo]"),
|
|
425
|
+
sender: dbMsg.direction === "INBOUND" ? "user" : "bot",
|
|
426
|
+
timestamp: new Date(dbMsg.created_at),
|
|
427
|
+
isIncoming: dbMsg.direction === "INBOUND",
|
|
428
|
+
status: dbMsg.direction === "OUTBOUND" ? "sent" : void 0
|
|
429
|
+
}));
|
|
430
|
+
setMessages(formatted);
|
|
431
|
+
} catch (error) {
|
|
432
|
+
console.error("Failed to fetch messages:", error);
|
|
433
|
+
}
|
|
434
|
+
}, [selectedContact]);
|
|
435
|
+
useEffect(() => {
|
|
436
|
+
fetchMessages();
|
|
437
|
+
const s = io(API_URL2, { transports: ["websocket", "polling"] });
|
|
438
|
+
s.on("connect", () => console.log("[ChatTab] Connected to WebSocket"));
|
|
439
|
+
s.on("wa:message_received", (data) => {
|
|
440
|
+
if (selectedContact && data.from === selectedContact) {
|
|
441
|
+
fetchMessages();
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
s.on("wa:message_sent", (data) => {
|
|
445
|
+
if (selectedContact && data.to === selectedContact) {
|
|
446
|
+
fetchMessages();
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
s.on("wa:status_update", (data) => {
|
|
450
|
+
if (selectedContact) fetchMessages();
|
|
451
|
+
});
|
|
452
|
+
setSocket(s);
|
|
453
|
+
return () => {
|
|
454
|
+
s.disconnect();
|
|
455
|
+
};
|
|
456
|
+
}, [selectedContact, fetchMessages]);
|
|
457
|
+
useEffect(() => {
|
|
458
|
+
chatEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
459
|
+
}, [messages]);
|
|
460
|
+
const handleSend = async () => {
|
|
461
|
+
if (!input.trim() || !selectedContact) return;
|
|
462
|
+
const originalInput = input;
|
|
463
|
+
setInput("");
|
|
464
|
+
const optimisticMsg = {
|
|
465
|
+
id: `temp-${Date.now()}`,
|
|
466
|
+
text: originalInput,
|
|
467
|
+
sender: "bot",
|
|
468
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
469
|
+
isIncoming: false,
|
|
470
|
+
status: "sent"
|
|
471
|
+
};
|
|
472
|
+
setMessages((prev) => [...prev, optimisticMsg]);
|
|
473
|
+
try {
|
|
474
|
+
await fetch(`${API_URL2}/api/whatsapp/send-chat`, {
|
|
475
|
+
method: "POST",
|
|
476
|
+
headers: { "Content-Type": "application/json" },
|
|
477
|
+
body: JSON.stringify({ to: selectedContact, text: originalInput })
|
|
478
|
+
});
|
|
479
|
+
} catch (error) {
|
|
480
|
+
console.error("Send failed:", error);
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col min-h-0 overflow-hidden relative", children: [
|
|
484
|
+
/* @__PURE__ */ jsxs(
|
|
485
|
+
"div",
|
|
486
|
+
{
|
|
487
|
+
className: "h-12 shrink-0 flex items-center justify-between px-4 border-b",
|
|
488
|
+
style: { background: "var(--bg-elevated)", borderColor: "var(--border-color)" },
|
|
489
|
+
children: [
|
|
490
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
491
|
+
/* @__PURE__ */ jsx(
|
|
492
|
+
"div",
|
|
493
|
+
{
|
|
494
|
+
className: "w-8 h-8 rounded-full flex items-center justify-center text-white text-[10px] font-bold",
|
|
495
|
+
style: { background: "#25D366" },
|
|
496
|
+
children: /* @__PURE__ */ jsx("i", { className: "fab fa-whatsapp text-sm" })
|
|
497
|
+
}
|
|
498
|
+
),
|
|
499
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
500
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-bold", style: { color: "var(--text-primary)" }, children: selectedContact ? "+" + selectedContact : "Seleccionar contacto" }),
|
|
501
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] block", style: { color: "var(--text-secondary)" }, children: selectedContact ? "en l\xEDnea" : "\u2014" })
|
|
502
|
+
] })
|
|
503
|
+
] }),
|
|
504
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 p-0.5 rounded-lg", style: { background: "var(--bg-muted)" }, children: ["MANUAL", "COPILOT", "AUTO"].map((mode) => /* @__PURE__ */ jsxs(
|
|
505
|
+
"button",
|
|
506
|
+
{
|
|
507
|
+
onClick: () => setOpMode(mode),
|
|
508
|
+
className: "px-2.5 py-1 rounded-md text-[9px] font-black tracking-wide transition-all",
|
|
509
|
+
style: {
|
|
510
|
+
background: opMode === mode ? "var(--brand-primary)" : "transparent",
|
|
511
|
+
color: opMode === mode ? "white" : "var(--text-secondary)"
|
|
512
|
+
},
|
|
513
|
+
children: [
|
|
514
|
+
mode === "COPILOT" && /* @__PURE__ */ jsx("i", { className: "fas fa-wand-sparkles mr-1 text-[8px]" }),
|
|
515
|
+
mode
|
|
516
|
+
]
|
|
517
|
+
},
|
|
518
|
+
mode
|
|
519
|
+
)) })
|
|
520
|
+
]
|
|
521
|
+
}
|
|
522
|
+
),
|
|
523
|
+
/* @__PURE__ */ jsxs(
|
|
524
|
+
"div",
|
|
525
|
+
{
|
|
526
|
+
className: "flex-1 overflow-y-auto p-4 space-y-3 scrollbar-thin",
|
|
527
|
+
style: { background: "var(--bg-primary)" },
|
|
528
|
+
children: [
|
|
529
|
+
/* @__PURE__ */ jsx(
|
|
530
|
+
"div",
|
|
531
|
+
{
|
|
532
|
+
className: "absolute inset-0 opacity-[0.02] pointer-events-none",
|
|
533
|
+
style: { backgroundImage: `url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23888' fill-opacity='0.4'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")` }
|
|
534
|
+
}
|
|
535
|
+
),
|
|
536
|
+
/* @__PURE__ */ jsxs("div", { className: "relative z-10 space-y-3", children: [
|
|
537
|
+
messages.map((msg) => /* @__PURE__ */ jsx("div", { className: `flex ${msg.sender === "system" ? "justify-center" : msg.isIncoming ? "justify-start" : "justify-end"}`, children: msg.sender === "system" ? /* @__PURE__ */ jsxs(
|
|
538
|
+
"span",
|
|
539
|
+
{
|
|
540
|
+
className: "px-3 py-1 rounded-full text-[9px] font-bold uppercase tracking-widest",
|
|
541
|
+
style: { background: "var(--bg-muted)", color: "var(--text-secondary)", border: "1px solid var(--border-color)" },
|
|
542
|
+
children: [
|
|
543
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-info-circle mr-1" }),
|
|
544
|
+
msg.text
|
|
545
|
+
]
|
|
546
|
+
}
|
|
547
|
+
) : msg.sender === "copilot" ? /* @__PURE__ */ jsxs(
|
|
548
|
+
"div",
|
|
549
|
+
{
|
|
550
|
+
className: "max-w-[75%] p-3 rounded-xl rounded-bl-none shadow-lg border",
|
|
551
|
+
style: { background: "linear-gradient(135deg, rgba(99,102,241,0.15), rgba(168,85,247,0.15))", borderColor: "rgba(139,92,246,0.3)" },
|
|
552
|
+
children: [
|
|
553
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 mb-1.5", children: [
|
|
554
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-wand-sparkles text-[10px]", style: { color: "#a855f7" } }),
|
|
555
|
+
/* @__PURE__ */ jsx("span", { className: "text-[9px] font-black uppercase tracking-wide", style: { color: "#a855f7" }, children: "CoPilot IA" })
|
|
556
|
+
] }),
|
|
557
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs italic leading-relaxed", style: { color: "var(--text-primary)" }, children: msg.text }),
|
|
558
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-2 flex gap-1.5", children: [
|
|
559
|
+
/* @__PURE__ */ jsx(
|
|
560
|
+
"button",
|
|
561
|
+
{
|
|
562
|
+
className: "flex-1 px-2 py-1 rounded-md text-[9px] font-bold transition-all",
|
|
563
|
+
style: { background: "var(--bg-muted)", color: "var(--text-secondary)", border: "1px solid var(--border-color)" },
|
|
564
|
+
children: "Ignorar"
|
|
565
|
+
}
|
|
566
|
+
),
|
|
567
|
+
/* @__PURE__ */ jsx(
|
|
568
|
+
"button",
|
|
569
|
+
{
|
|
570
|
+
className: "flex-1 px-2 py-1 rounded-md text-[9px] font-bold transition-all text-white",
|
|
571
|
+
style: { background: "#8b5cf6" },
|
|
572
|
+
children: "Aplicar"
|
|
573
|
+
}
|
|
574
|
+
)
|
|
575
|
+
] })
|
|
576
|
+
]
|
|
577
|
+
}
|
|
578
|
+
) : /* @__PURE__ */ jsxs(
|
|
579
|
+
"div",
|
|
580
|
+
{
|
|
581
|
+
className: `max-w-[70%] p-3 rounded-xl shadow-sm text-xs leading-relaxed ${msg.isIncoming ? "rounded-tl-none" : "rounded-tr-none"}`,
|
|
582
|
+
style: {
|
|
583
|
+
background: msg.isIncoming ? "var(--bg-elevated)" : "rgba(37,211,102,0.15)",
|
|
584
|
+
color: "var(--text-primary)",
|
|
585
|
+
border: msg.isIncoming ? "1px solid var(--border-color)" : "1px solid rgba(37,211,102,0.2)"
|
|
586
|
+
},
|
|
587
|
+
children: [
|
|
588
|
+
/* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap", children: msg.text }),
|
|
589
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-1 mt-1.5", children: [
|
|
590
|
+
/* @__PURE__ */ jsx("span", { className: "text-[9px]", style: { color: "var(--text-secondary)" }, children: msg.timestamp.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) }),
|
|
591
|
+
!msg.isIncoming && msg.status && /* @__PURE__ */ jsx(
|
|
592
|
+
"i",
|
|
593
|
+
{
|
|
594
|
+
className: `fas fa-check-double text-[9px] ${msg.status === "read" ? "text-blue-400" : ""}`,
|
|
595
|
+
style: { color: msg.status === "read" ? "#38bdf8" : "var(--text-secondary)" }
|
|
596
|
+
}
|
|
597
|
+
)
|
|
598
|
+
] })
|
|
599
|
+
]
|
|
600
|
+
}
|
|
601
|
+
) }, msg.id)),
|
|
602
|
+
/* @__PURE__ */ jsx("div", { ref: chatEndRef })
|
|
603
|
+
] })
|
|
604
|
+
]
|
|
605
|
+
}
|
|
606
|
+
),
|
|
607
|
+
/* @__PURE__ */ jsxs("div", { className: "shrink-0 p-3 border-t", style: { background: "var(--bg-elevated)", borderColor: "var(--border-color)" }, children: [
|
|
608
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
609
|
+
/* @__PURE__ */ jsx(
|
|
610
|
+
"button",
|
|
611
|
+
{
|
|
612
|
+
className: "w-8 h-8 rounded-lg flex items-center justify-center transition-all",
|
|
613
|
+
style: { color: "var(--text-secondary)" },
|
|
614
|
+
onMouseEnter: (e) => e.currentTarget.style.background = "var(--bg-muted)",
|
|
615
|
+
onMouseLeave: (e) => e.currentTarget.style.background = "transparent",
|
|
616
|
+
children: /* @__PURE__ */ jsx("i", { className: "fas fa-paperclip text-sm" })
|
|
617
|
+
}
|
|
618
|
+
),
|
|
619
|
+
/* @__PURE__ */ jsxs(
|
|
620
|
+
"div",
|
|
621
|
+
{
|
|
622
|
+
className: "flex-1 flex items-center gap-2 px-3 py-2 rounded-xl",
|
|
623
|
+
style: { background: "var(--bg-muted)", border: "1px solid var(--border-color)" },
|
|
624
|
+
children: [
|
|
625
|
+
/* @__PURE__ */ jsx(
|
|
626
|
+
"input",
|
|
627
|
+
{
|
|
628
|
+
type: "text",
|
|
629
|
+
placeholder: "Escribe un mensaje...",
|
|
630
|
+
className: "flex-1 bg-transparent outline-none text-xs",
|
|
631
|
+
style: { color: "var(--text-primary)" },
|
|
632
|
+
value: input,
|
|
633
|
+
onChange: (e) => setInput(e.target.value),
|
|
634
|
+
onKeyDown: (e) => e.key === "Enter" && handleSend()
|
|
635
|
+
}
|
|
636
|
+
),
|
|
637
|
+
/* @__PURE__ */ jsx("button", { className: "text-xs", style: { color: "var(--text-secondary)" }, children: /* @__PURE__ */ jsx("i", { className: "fas fa-face-smile" }) })
|
|
638
|
+
]
|
|
639
|
+
}
|
|
640
|
+
),
|
|
641
|
+
/* @__PURE__ */ jsx(
|
|
642
|
+
"button",
|
|
643
|
+
{
|
|
644
|
+
onClick: handleSend,
|
|
645
|
+
className: "w-9 h-9 rounded-xl flex items-center justify-center text-white transition-all shadow-md",
|
|
646
|
+
style: { background: "#25D366" },
|
|
647
|
+
children: /* @__PURE__ */ jsx("i", { className: `fas ${input.trim() ? "fa-paper-plane" : "fa-microphone"} text-sm` })
|
|
648
|
+
}
|
|
649
|
+
)
|
|
650
|
+
] }),
|
|
651
|
+
opMode === "COPILOT" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-2 px-2", children: [
|
|
652
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-wand-sparkles text-[9px]", style: { color: "#a855f7" } }),
|
|
653
|
+
/* @__PURE__ */ jsx("span", { className: "text-[9px]", style: { color: "var(--text-secondary)" }, children: "CoPilot activo \u2014 sugerencias autom\xE1ticas" })
|
|
654
|
+
] })
|
|
655
|
+
] })
|
|
656
|
+
] });
|
|
657
|
+
};
|
|
658
|
+
var MESSAGE_CONFIG = {
|
|
659
|
+
incoming: { icon: /* @__PURE__ */ jsx(MessageCircle, { size: 14 }), colorClass: "text-emerald-400", bgClass: "from-emerald-500/10 to-transparent" },
|
|
660
|
+
outgoing: { icon: /* @__PURE__ */ jsx(Reply, { size: 14 }), colorClass: "text-blue-400", bgClass: "from-blue-500/10 to-transparent" },
|
|
661
|
+
system: { icon: /* @__PURE__ */ jsx(Info, { size: 14 }), colorClass: "text-purple-400", bgClass: "from-purple-500/10 to-transparent" }
|
|
662
|
+
};
|
|
663
|
+
var MessageNode = memo(({ id, data, selected }) => {
|
|
664
|
+
const nodeData = data || {};
|
|
665
|
+
const config = MESSAGE_CONFIG[nodeData.type] || MESSAGE_CONFIG.incoming;
|
|
666
|
+
const titleElement = /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center w-full min-w-[140px]", children: [
|
|
667
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
668
|
+
/* @__PURE__ */ jsx("span", { className: config.colorClass, children: config.icon }),
|
|
669
|
+
/* @__PURE__ */ jsx("span", { children: nodeData.label })
|
|
670
|
+
] }),
|
|
671
|
+
nodeData.time && /* @__PURE__ */ jsx("span", { className: "text-[9px] text-zinc-500 font-mono tracking-wider ml-4", children: nodeData.time })
|
|
672
|
+
] });
|
|
673
|
+
return /* @__PURE__ */ jsxs(
|
|
674
|
+
BaseNode,
|
|
675
|
+
{
|
|
676
|
+
id,
|
|
677
|
+
selected,
|
|
678
|
+
title: titleElement,
|
|
679
|
+
className: `border border-white/5 bg-linear-to-br ${config.bgClass} backdrop-blur-md`,
|
|
680
|
+
children: [
|
|
681
|
+
/* @__PURE__ */ jsx(Handle, { type: "target", position: Position.Left, className: "!w-2 !h-2 !bg-zinc-800 !border-[1.5px] !border-zinc-400" }),
|
|
682
|
+
/* @__PURE__ */ jsx("div", { className: "p-3 text-xs leading-relaxed text-zinc-300 font-light break-words max-w-[240px]", children: nodeData.text }),
|
|
683
|
+
/* @__PURE__ */ jsx(Handle, { type: "source", position: Position.Right, className: `!w-2 !h-2 !bg-zinc-800 !border-[1.5px] ${config.colorClass.replace("text-", "border-")}` })
|
|
684
|
+
]
|
|
685
|
+
}
|
|
686
|
+
);
|
|
687
|
+
});
|
|
688
|
+
MessageNode.displayName = "MessageNode";
|
|
689
|
+
var ACTION_CONFIG = {
|
|
690
|
+
reply: { icon: /* @__PURE__ */ jsx(Bot, { size: 14 }), colorClass: "text-emerald-400", bgClass: "from-emerald-500/10 to-transparent" },
|
|
691
|
+
create_order: { icon: /* @__PURE__ */ jsx(ShoppingCart, { size: 14 }), colorClass: "text-amber-400", bgClass: "from-amber-500/10 to-transparent" },
|
|
692
|
+
escalate: { icon: /* @__PURE__ */ jsx(Headphones, { size: 14 }), colorClass: "text-rose-400", bgClass: "from-rose-500/10 to-transparent" },
|
|
693
|
+
analyze: { icon: /* @__PURE__ */ jsx(Brain, { size: 14 }), colorClass: "text-violet-400", bgClass: "from-violet-500/10 to-transparent" },
|
|
694
|
+
decision: { icon: /* @__PURE__ */ jsx(GitBranch, { size: 14 }), colorClass: "text-cyan-400", bgClass: "from-cyan-500/10 to-transparent" }
|
|
695
|
+
};
|
|
696
|
+
var BotActionNode = memo(({ id, data, selected }) => {
|
|
697
|
+
const nodeData = data || {};
|
|
698
|
+
const config = ACTION_CONFIG[nodeData?.actionType] || ACTION_CONFIG.reply;
|
|
699
|
+
const titleElement = /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
700
|
+
/* @__PURE__ */ jsx("span", { className: config.colorClass, children: config.icon }),
|
|
701
|
+
/* @__PURE__ */ jsx("span", { children: nodeData?.label || "Action" })
|
|
702
|
+
] });
|
|
703
|
+
return /* @__PURE__ */ jsxs(
|
|
704
|
+
BaseNode,
|
|
705
|
+
{
|
|
706
|
+
id,
|
|
707
|
+
selected,
|
|
708
|
+
title: titleElement,
|
|
709
|
+
hideTarget: true,
|
|
710
|
+
hideSource: true,
|
|
711
|
+
className: `min-w-[200px] border border-white/5 bg-linear-to-br ${config.bgClass} backdrop-blur-md`,
|
|
712
|
+
children: [
|
|
713
|
+
/* @__PURE__ */ jsx(Handle, { type: "target", position: Position.Left, className: "!w-2 !h-2 !bg-zinc-800 !border-[1.5px] !border-zinc-400" }),
|
|
714
|
+
nodeData.description && /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-xs text-zinc-400 font-light leading-relaxed", children: nodeData.description }),
|
|
715
|
+
/* @__PURE__ */ jsx(Handle, { type: "source", position: Position.Right, className: `!w-2 !h-2 !bg-zinc-800 !border-[1.5px] ${config.colorClass.replace("text-", "border-")}` }),
|
|
716
|
+
nodeData.actionType === "decision" && /* @__PURE__ */ jsx(Handle, { type: "source", position: Position.Bottom, id: "no", className: "!w-2 !h-2 !bg-zinc-800 !border-[1.5px] border-rose-500" })
|
|
717
|
+
]
|
|
718
|
+
}
|
|
719
|
+
);
|
|
720
|
+
});
|
|
721
|
+
BotActionNode.displayName = "BotActionNode";
|
|
722
|
+
var nodeTypes = {
|
|
723
|
+
messageNode: MessageNode,
|
|
724
|
+
botAction: BotActionNode
|
|
725
|
+
};
|
|
726
|
+
var initialNodes = [
|
|
727
|
+
// Trigger
|
|
728
|
+
{
|
|
729
|
+
id: "trigger",
|
|
730
|
+
type: "messageNode",
|
|
731
|
+
position: { x: 50, y: 300 },
|
|
732
|
+
data: { label: "Mensaje Entrante de WhatsApp", type: "incoming", text: "Hola, \xBFc\xF3mo va mi pedido XJ-901?", time: "10:05 AM" }
|
|
733
|
+
},
|
|
734
|
+
// AI Intent Recognition
|
|
735
|
+
{
|
|
736
|
+
id: "ai-intent",
|
|
737
|
+
type: "botAction",
|
|
738
|
+
position: { x: 400, y: 280 },
|
|
739
|
+
data: { label: "Agente IA: Reconocimiento", actionType: "analyze", description: 'Detectar Intenci\xF3n: "Estado de Pedido"' }
|
|
740
|
+
},
|
|
741
|
+
// Database Check
|
|
742
|
+
{
|
|
743
|
+
id: "db-check",
|
|
744
|
+
type: "botAction",
|
|
745
|
+
position: { x: 750, y: 150 },
|
|
746
|
+
data: { label: "Consultar ERP", actionType: "decision", description: "API REST: /orders/XJ-901" }
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
id: "escalate-human",
|
|
750
|
+
type: "botAction",
|
|
751
|
+
position: { x: 750, y: 400 },
|
|
752
|
+
data: { label: "Evaluar Sentimiento (Frustrado)", actionType: "escalate", description: "Ruteo Inmediato a Humano" }
|
|
753
|
+
},
|
|
754
|
+
// Responses
|
|
755
|
+
{
|
|
756
|
+
id: "reply-status",
|
|
757
|
+
type: "messageNode",
|
|
758
|
+
position: { x: 1050, y: 150 },
|
|
759
|
+
data: { label: "Respuesta Autom\xE1tica WhatsApp", type: "outgoing", text: 'Tu pedido XJ-901 est\xE1 "En Producci\xF3n" y se entregar\xE1 el Viernes.', time: "10:06 AM" }
|
|
760
|
+
},
|
|
761
|
+
{
|
|
762
|
+
id: "assign-agent",
|
|
763
|
+
type: "messageNode",
|
|
764
|
+
position: { x: 1050, y: 400 },
|
|
765
|
+
data: { label: "Soporte Asignado", type: "system", text: "Asignando Chat #3421 al Asesor de Ventas: Carlos" }
|
|
766
|
+
}
|
|
767
|
+
];
|
|
768
|
+
var initialEdges = [
|
|
769
|
+
{ id: "e1", source: "trigger", target: "ai-intent", animated: true, style: { stroke: "#22c55e" }, markerEnd: { type: MarkerType.ArrowClosed, color: "#22c55e" } },
|
|
770
|
+
{ id: "e2", source: "ai-intent", target: "db-check", label: "Intent: Query Order", animated: true, style: { stroke: "#3b82f6" }, markerEnd: { type: MarkerType.ArrowClosed, color: "#3b82f6" } },
|
|
771
|
+
{ id: "e3", source: "db-check", target: "reply-status", label: "Pedido Encontrado", style: { stroke: "#22c55e" }, markerEnd: { type: MarkerType.ArrowClosed, color: "#22c55e" } },
|
|
772
|
+
{ id: "e4", source: "ai-intent", target: "escalate-human", label: "Intent: Queja/Reclamo", style: { stroke: "#ef4444" }, markerEnd: { type: MarkerType.ArrowClosed, color: "#ef4444" } },
|
|
773
|
+
{ id: "e5", source: "db-check", sourceHandle: "no", target: "escalate-human", label: "Pedido No Encontrado", style: { stroke: "#ef4444", strokeDasharray: "5 5" }, markerEnd: { type: MarkerType.ArrowClosed, color: "#ef4444" } },
|
|
774
|
+
{ id: "e6", source: "escalate-human", target: "assign-agent", style: { stroke: "#f59e0b" }, markerEnd: { type: MarkerType.ArrowClosed, color: "#f59e0b" } }
|
|
775
|
+
];
|
|
776
|
+
var FlowCanvasTab = () => {
|
|
777
|
+
const [nodes, setNodes] = useState(initialNodes);
|
|
778
|
+
const [edges, setEdges] = useState(initialEdges);
|
|
779
|
+
const onNodesChange = useCallback((changes) => {
|
|
780
|
+
}, []);
|
|
781
|
+
const onEdgesChange = useCallback((changes) => {
|
|
782
|
+
}, []);
|
|
783
|
+
const onConnect = useCallback((params) => {
|
|
784
|
+
setEdges((eds) => [...eds, { ...params, id: `e-${Date.now()}`, animated: true }]);
|
|
785
|
+
}, [setEdges]);
|
|
786
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex-1 min-h-0 flex flex-col overflow-hidden", children: [
|
|
787
|
+
/* @__PURE__ */ jsxs(
|
|
788
|
+
"div",
|
|
789
|
+
{
|
|
790
|
+
className: "h-9 shrink-0 flex items-center gap-2 px-3 border-b",
|
|
791
|
+
style: { background: "var(--bg-elevated)", borderColor: "var(--border-color)" },
|
|
792
|
+
children: [
|
|
793
|
+
/* @__PURE__ */ jsxs("span", { className: "text-[10px] font-black uppercase tracking-widest", style: { color: "var(--text-secondary)" }, children: [
|
|
794
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-project-diagram mr-1.5" }),
|
|
795
|
+
"Flujo de Conversaci\xF3n"
|
|
796
|
+
] }),
|
|
797
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1" }),
|
|
798
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: [
|
|
799
|
+
{ icon: "fas fa-comment-dots", label: "Mensaje", color: "#25D366" },
|
|
800
|
+
{ icon: "fas fa-brain", label: "IA", color: "#8b5cf6" },
|
|
801
|
+
{ icon: "fas fa-code-branch", label: "Decisi\xF3n", color: "#06b6d4" },
|
|
802
|
+
{ icon: "fas fa-cart-plus", label: "Pedido", color: "#f59e0b" }
|
|
803
|
+
].map((item) => /* @__PURE__ */ jsxs(
|
|
804
|
+
"div",
|
|
805
|
+
{
|
|
806
|
+
className: "flex items-center gap-1 px-2 py-1 rounded-md text-[9px] font-bold cursor-grab transition-all",
|
|
807
|
+
style: { border: "1px dashed var(--border-color)", color: item.color },
|
|
808
|
+
title: `Arrastra para agregar: ${item.label}`,
|
|
809
|
+
children: [
|
|
810
|
+
/* @__PURE__ */ jsx("i", { className: item.icon }),
|
|
811
|
+
/* @__PURE__ */ jsx("span", { children: item.label })
|
|
812
|
+
]
|
|
813
|
+
},
|
|
814
|
+
item.label
|
|
815
|
+
)) }),
|
|
816
|
+
/* @__PURE__ */ jsx("div", { className: "h-5 w-px mx-1", style: { background: "var(--border-color)" } }),
|
|
817
|
+
/* @__PURE__ */ jsx(
|
|
818
|
+
"button",
|
|
819
|
+
{
|
|
820
|
+
className: "px-2 py-1 rounded-md text-[9px] font-bold transition-all",
|
|
821
|
+
style: { color: "var(--text-secondary)" },
|
|
822
|
+
title: "Fit view",
|
|
823
|
+
children: /* @__PURE__ */ jsx("i", { className: "fas fa-compress-arrows-alt" })
|
|
824
|
+
}
|
|
825
|
+
)
|
|
826
|
+
]
|
|
827
|
+
}
|
|
828
|
+
),
|
|
829
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 relative", children: /* @__PURE__ */ jsx(
|
|
830
|
+
FlowEditor,
|
|
831
|
+
{
|
|
832
|
+
nodes,
|
|
833
|
+
edges,
|
|
834
|
+
onNodesChange,
|
|
835
|
+
onEdgesChange,
|
|
836
|
+
onConnect,
|
|
837
|
+
nodeTypes
|
|
838
|
+
}
|
|
839
|
+
) })
|
|
840
|
+
] });
|
|
841
|
+
};
|
|
842
|
+
var HOURLY_DATA = [
|
|
843
|
+
{ hour: "6AM", sent: 2, received: 5 },
|
|
844
|
+
{ hour: "7AM", sent: 8, received: 12 },
|
|
845
|
+
{ hour: "8AM", sent: 15, received: 22 },
|
|
846
|
+
{ hour: "9AM", sent: 28, received: 35 },
|
|
847
|
+
{ hour: "10AM", sent: 42, received: 48 },
|
|
848
|
+
{ hour: "11AM", sent: 38, received: 41 },
|
|
849
|
+
{ hour: "12PM", sent: 20, received: 25 },
|
|
850
|
+
{ hour: "1PM", sent: 15, received: 18 },
|
|
851
|
+
{ hour: "2PM", sent: 30, received: 33 },
|
|
852
|
+
{ hour: "3PM", sent: 45, received: 52 },
|
|
853
|
+
{ hour: "4PM", sent: 35, received: 40 },
|
|
854
|
+
{ hour: "5PM", sent: 22, received: 28 },
|
|
855
|
+
{ hour: "6PM", sent: 10, received: 15 }
|
|
856
|
+
];
|
|
857
|
+
var KPI_CARDS = [
|
|
858
|
+
{ label: "Mensajes Hoy", value: "347", change: "+12%", icon: "fas fa-paper-plane", color: "#22c55e", positive: true },
|
|
859
|
+
{ label: "Tiempo Respuesta", value: "2.4s", change: "-18%", icon: "fas fa-clock", color: "#3b82f6", positive: true },
|
|
860
|
+
{ label: "Tasa Conversi\xF3n", value: "24.5%", change: "+3.2%", icon: "fas fa-funnel-dollar", color: "#f59e0b", positive: true },
|
|
861
|
+
{ label: "Chats Activos", value: "12", change: "+2", icon: "fas fa-comments", color: "#8b5cf6", positive: true },
|
|
862
|
+
{ label: "Pedidos v\xEDa WA", value: "8", change: "+1", icon: "fas fa-cart-plus", color: "#06b6d4", positive: true },
|
|
863
|
+
{ label: "Escalamientos", value: "3", change: "+1", icon: "fas fa-exclamation-triangle", color: "#ef4444", positive: false }
|
|
864
|
+
];
|
|
865
|
+
var TOP_INTENTS = [
|
|
866
|
+
{ intent: "Estado de Pedido", count: 156, pct: 45 },
|
|
867
|
+
{ intent: "Cotizaci\xF3n", count: 89, pct: 26 },
|
|
868
|
+
{ intent: "Cat\xE1logo", count: 52, pct: 15 },
|
|
869
|
+
{ intent: "Reclamo", count: 28, pct: 8 },
|
|
870
|
+
{ intent: "Otro", count: 22, pct: 6 }
|
|
871
|
+
];
|
|
872
|
+
var INTENT_COLORS = ["#22c55e", "#3b82f6", "#f59e0b", "#ef4444", "#6b7280"];
|
|
873
|
+
var BarChart = ({ data }) => {
|
|
874
|
+
const max = Math.max(...data.map((d) => Math.max(d.sent, d.received)));
|
|
875
|
+
return /* @__PURE__ */ jsx("div", { className: "flex items-end gap-1 h-32", children: data.map((d, i) => /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center gap-0.5", children: [
|
|
876
|
+
/* @__PURE__ */ jsxs("div", { className: "w-full flex items-end gap-px", style: { height: "100px" }, children: [
|
|
877
|
+
/* @__PURE__ */ jsx(
|
|
878
|
+
"div",
|
|
879
|
+
{
|
|
880
|
+
className: "flex-1 rounded-t-sm transition-all duration-500",
|
|
881
|
+
style: { height: `${d.received / max * 100}%`, background: "rgba(37,211,102,0.6)" },
|
|
882
|
+
title: `Recibidos: ${d.received}`
|
|
883
|
+
}
|
|
884
|
+
),
|
|
885
|
+
/* @__PURE__ */ jsx(
|
|
886
|
+
"div",
|
|
887
|
+
{
|
|
888
|
+
className: "flex-1 rounded-t-sm transition-all duration-500",
|
|
889
|
+
style: { height: `${d.sent / max * 100}%`, background: "rgba(59,130,246,0.6)" },
|
|
890
|
+
title: `Enviados: ${d.sent}`
|
|
891
|
+
}
|
|
892
|
+
)
|
|
893
|
+
] }),
|
|
894
|
+
/* @__PURE__ */ jsx("span", { className: "text-[7px] font-bold", style: { color: "var(--text-secondary)" }, children: d.hour })
|
|
895
|
+
] }, i)) });
|
|
896
|
+
};
|
|
897
|
+
var AnalyticsTab = () => {
|
|
898
|
+
const [animatedValues, setAnimatedValues] = useState({});
|
|
899
|
+
useEffect(() => {
|
|
900
|
+
const timer = setTimeout(() => {
|
|
901
|
+
const vals = {};
|
|
902
|
+
TOP_INTENTS.forEach((intent) => {
|
|
903
|
+
vals[intent.intent] = intent.pct;
|
|
904
|
+
});
|
|
905
|
+
setAnimatedValues(vals);
|
|
906
|
+
}, 200);
|
|
907
|
+
return () => clearTimeout(timer);
|
|
908
|
+
}, []);
|
|
909
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto p-4 space-y-4 scrollbar-thin", style: { background: "var(--bg-primary)" }, children: [
|
|
910
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-3", children: KPI_CARDS.map((kpi, i) => /* @__PURE__ */ jsxs(
|
|
911
|
+
"div",
|
|
912
|
+
{
|
|
913
|
+
className: "p-3 rounded-xl border transition-all hover:shadow-lg",
|
|
914
|
+
style: { background: "var(--bg-elevated)", borderColor: "var(--border-color)", animationDelay: `${i * 80}ms` },
|
|
915
|
+
children: [
|
|
916
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
917
|
+
/* @__PURE__ */ jsx(
|
|
918
|
+
"div",
|
|
919
|
+
{
|
|
920
|
+
className: "w-8 h-8 rounded-lg flex items-center justify-center",
|
|
921
|
+
style: { background: `${kpi.color}15` },
|
|
922
|
+
children: /* @__PURE__ */ jsx("i", { className: `${kpi.icon} text-xs`, style: { color: kpi.color } })
|
|
923
|
+
}
|
|
924
|
+
),
|
|
925
|
+
/* @__PURE__ */ jsx(
|
|
926
|
+
"span",
|
|
927
|
+
{
|
|
928
|
+
className: `text-[10px] font-bold px-1.5 py-0.5 rounded ${kpi.positive ? "text-green-500" : "text-red-500"}`,
|
|
929
|
+
style: { background: kpi.positive ? "rgba(34,197,94,0.1)" : "rgba(239,68,68,0.1)" },
|
|
930
|
+
children: kpi.change
|
|
931
|
+
}
|
|
932
|
+
)
|
|
933
|
+
] }),
|
|
934
|
+
/* @__PURE__ */ jsx("div", { className: "text-xl font-black", style: { color: "var(--text-primary)" }, children: kpi.value }),
|
|
935
|
+
/* @__PURE__ */ jsx("div", { className: "text-[10px] font-medium mt-0.5", style: { color: "var(--text-secondary)" }, children: kpi.label })
|
|
936
|
+
]
|
|
937
|
+
},
|
|
938
|
+
kpi.label
|
|
939
|
+
)) }),
|
|
940
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
941
|
+
/* @__PURE__ */ jsxs("div", { className: "p-4 rounded-xl border", style: { background: "var(--bg-elevated)", borderColor: "var(--border-color)" }, children: [
|
|
942
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-4", children: [
|
|
943
|
+
/* @__PURE__ */ jsxs("h3", { className: "text-xs font-bold", style: { color: "var(--text-primary)" }, children: [
|
|
944
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-chart-bar mr-2", style: { color: "var(--brand-primary)" } }),
|
|
945
|
+
"Actividad por Hora"
|
|
946
|
+
] }),
|
|
947
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-[9px]", children: [
|
|
948
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
|
|
949
|
+
/* @__PURE__ */ jsx("span", { className: "w-2 h-2 rounded-sm", style: { background: "rgba(37,211,102,0.6)" } }),
|
|
950
|
+
/* @__PURE__ */ jsx("span", { style: { color: "var(--text-secondary)" }, children: "Recibidos" })
|
|
951
|
+
] }),
|
|
952
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
|
|
953
|
+
/* @__PURE__ */ jsx("span", { className: "w-2 h-2 rounded-sm", style: { background: "rgba(59,130,246,0.6)" } }),
|
|
954
|
+
/* @__PURE__ */ jsx("span", { style: { color: "var(--text-secondary)" }, children: "Enviados" })
|
|
955
|
+
] })
|
|
956
|
+
] })
|
|
957
|
+
] }),
|
|
958
|
+
/* @__PURE__ */ jsx(BarChart, { data: HOURLY_DATA })
|
|
959
|
+
] }),
|
|
960
|
+
/* @__PURE__ */ jsxs("div", { className: "p-4 rounded-xl border", style: { background: "var(--bg-elevated)", borderColor: "var(--border-color)" }, children: [
|
|
961
|
+
/* @__PURE__ */ jsxs("h3", { className: "text-xs font-bold mb-4", style: { color: "var(--text-primary)" }, children: [
|
|
962
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-brain mr-2", style: { color: "var(--brand-primary)" } }),
|
|
963
|
+
"Intenciones Detectadas"
|
|
964
|
+
] }),
|
|
965
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-3", children: TOP_INTENTS.map((intent, i) => /* @__PURE__ */ jsxs("div", { children: [
|
|
966
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-1", children: [
|
|
967
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-semibold", style: { color: "var(--text-primary)" }, children: intent.intent }),
|
|
968
|
+
/* @__PURE__ */ jsxs("span", { className: "text-[10px] font-bold", style: { color: "var(--text-secondary)" }, children: [
|
|
969
|
+
intent.count,
|
|
970
|
+
" (",
|
|
971
|
+
intent.pct,
|
|
972
|
+
"%)"
|
|
973
|
+
] })
|
|
974
|
+
] }),
|
|
975
|
+
/* @__PURE__ */ jsx("div", { className: "h-2 rounded-full overflow-hidden", style: { background: "var(--bg-muted)" }, children: /* @__PURE__ */ jsx(
|
|
976
|
+
"div",
|
|
977
|
+
{
|
|
978
|
+
className: "h-full rounded-full transition-all duration-1000 ease-out",
|
|
979
|
+
style: {
|
|
980
|
+
width: `${animatedValues[intent.intent] || 0}%`,
|
|
981
|
+
background: INTENT_COLORS[i]
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
) })
|
|
985
|
+
] }, intent.intent)) })
|
|
986
|
+
] })
|
|
987
|
+
] }),
|
|
988
|
+
/* @__PURE__ */ jsxs("div", { className: "p-4 rounded-xl border", style: { background: "var(--bg-elevated)", borderColor: "var(--border-color)" }, children: [
|
|
989
|
+
/* @__PURE__ */ jsxs("h3", { className: "text-xs font-bold mb-4", style: { color: "var(--text-primary)" }, children: [
|
|
990
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-fire-alt mr-2", style: { color: "var(--brand-primary)" } }),
|
|
991
|
+
"Heatmap Semanal"
|
|
992
|
+
] }),
|
|
993
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-1", style: { gridTemplateColumns: "auto repeat(24, 1fr)" }, children: [
|
|
994
|
+
/* @__PURE__ */ jsx("div", {}),
|
|
995
|
+
Array.from({ length: 24 }, (_, i) => /* @__PURE__ */ jsx("div", { className: "text-[7px] text-center font-bold", style: { color: "var(--text-secondary)" }, children: i }, i)),
|
|
996
|
+
["Lun", "Mar", "Mi\xE9", "Jue", "Vie", "S\xE1b", "Dom"].map((day, di) => /* @__PURE__ */ jsxs(React8.Fragment, { children: [
|
|
997
|
+
/* @__PURE__ */ jsx("div", { className: "text-[9px] font-bold pr-2 flex items-center", style: { color: "var(--text-secondary)" }, children: day }),
|
|
998
|
+
Array.from({ length: 24 }, (_, hi) => {
|
|
999
|
+
const intensity = Math.random();
|
|
1000
|
+
const isWeekend = di >= 5;
|
|
1001
|
+
const isWorkHour = hi >= 7 && hi <= 18;
|
|
1002
|
+
const adjustedIntensity = (isWeekend ? 0.3 : 1) * (isWorkHour ? 1 : 0.4) * intensity;
|
|
1003
|
+
return /* @__PURE__ */ jsx(
|
|
1004
|
+
"div",
|
|
1005
|
+
{
|
|
1006
|
+
className: "aspect-square rounded-sm transition-all hover:ring-1 hover:ring-white/30 cursor-pointer",
|
|
1007
|
+
style: {
|
|
1008
|
+
background: adjustedIntensity > 0.6 ? "#22c55e" : adjustedIntensity > 0.3 ? "rgba(34,197,94,0.4)" : adjustedIntensity > 0.1 ? "rgba(34,197,94,0.15)" : "var(--bg-muted)"
|
|
1009
|
+
},
|
|
1010
|
+
title: `${day} ${hi}:00 \u2014 ${Math.floor(adjustedIntensity * 50)} mensajes`
|
|
1011
|
+
},
|
|
1012
|
+
hi
|
|
1013
|
+
);
|
|
1014
|
+
})
|
|
1015
|
+
] }, day))
|
|
1016
|
+
] })
|
|
1017
|
+
] })
|
|
1018
|
+
] });
|
|
1019
|
+
};
|
|
1020
|
+
var ApiTesterTab = () => {
|
|
1021
|
+
const [phone, setPhone] = useState("");
|
|
1022
|
+
const [msgType, setMsgType] = useState("text");
|
|
1023
|
+
const [payloadText, setPayloadText] = useState("Hola desde Decido OS \u{1F680}");
|
|
1024
|
+
const [templateName, setTemplateName] = useState("hello_world");
|
|
1025
|
+
const [templateLanguage, setTemplateLanguage] = useState("en_US");
|
|
1026
|
+
const [loading, setLoading] = useState(false);
|
|
1027
|
+
const [result, setResult] = useState(null);
|
|
1028
|
+
const [savedPhones, setSavedPhones] = useState([]);
|
|
1029
|
+
const [newPhoneName, setNewPhoneName] = useState("");
|
|
1030
|
+
const [showPhoneSave, setShowPhoneSave] = useState(false);
|
|
1031
|
+
const [templateVariables, setTemplateVariables] = useState([]);
|
|
1032
|
+
const [templates, setTemplates] = useState([]);
|
|
1033
|
+
const [fetchingTemplates, setFetchingTemplates] = useState(false);
|
|
1034
|
+
React8.useEffect(() => {
|
|
1035
|
+
const saved = localStorage.getItem("wa_api_tester_phones");
|
|
1036
|
+
if (saved) {
|
|
1037
|
+
try {
|
|
1038
|
+
setSavedPhones(JSON.parse(saved));
|
|
1039
|
+
} catch (e) {
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
fetchTemplates();
|
|
1043
|
+
}, []);
|
|
1044
|
+
React8.useEffect(() => {
|
|
1045
|
+
const selected = templates.find((t) => t.name === templateName && t.language === templateLanguage);
|
|
1046
|
+
if (selected) {
|
|
1047
|
+
const bodyComponent = selected.components?.find((c) => c.type === "BODY" || c.type === "body");
|
|
1048
|
+
if (bodyComponent && bodyComponent.text) {
|
|
1049
|
+
const matches = bodyComponent.text.match(/\{\{\d+\}\}/g);
|
|
1050
|
+
if (matches) {
|
|
1051
|
+
const maxVar = Math.max(...matches.map((m) => parseInt(m.replace(/\{|\}/g, ""))));
|
|
1052
|
+
setTemplateVariables((prev) => {
|
|
1053
|
+
const next = [...prev];
|
|
1054
|
+
while (next.length < maxVar) next.push("");
|
|
1055
|
+
return next.slice(0, maxVar);
|
|
1056
|
+
});
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
setTemplateVariables([]);
|
|
1062
|
+
}, [templateName, templateLanguage, templates]);
|
|
1063
|
+
const fetchTemplates = async () => {
|
|
1064
|
+
setFetchingTemplates(true);
|
|
1065
|
+
try {
|
|
1066
|
+
const API_URL3 = import.meta.env?.VITE_API_BASE_URL || "http://localhost:3001";
|
|
1067
|
+
const res = await fetch(`${API_URL3}/api/whatsapp/templates`);
|
|
1068
|
+
if (res.ok) {
|
|
1069
|
+
const data = await res.json();
|
|
1070
|
+
if (!data.error && Array.isArray(data)) {
|
|
1071
|
+
setTemplates(data);
|
|
1072
|
+
if (data.length > 0) {
|
|
1073
|
+
setTemplateName(data[0].name);
|
|
1074
|
+
setTemplateLanguage(data[0].language);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
} catch (err) {
|
|
1079
|
+
console.error("Failed to fetch templates", err);
|
|
1080
|
+
} finally {
|
|
1081
|
+
setFetchingTemplates(false);
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1084
|
+
const handleSavePhone = () => {
|
|
1085
|
+
if (!phone || !newPhoneName) return;
|
|
1086
|
+
const newList = [...savedPhones, { name: newPhoneName, number: phone }];
|
|
1087
|
+
setSavedPhones(newList);
|
|
1088
|
+
localStorage.setItem("wa_api_tester_phones", JSON.stringify(newList));
|
|
1089
|
+
setNewPhoneName("");
|
|
1090
|
+
setShowPhoneSave(false);
|
|
1091
|
+
};
|
|
1092
|
+
const handleDeletePhone = (number) => {
|
|
1093
|
+
const newList = savedPhones.filter((p) => p.number !== number);
|
|
1094
|
+
setSavedPhones(newList);
|
|
1095
|
+
localStorage.setItem("wa_api_tester_phones", JSON.stringify(newList));
|
|
1096
|
+
if (phone === number) setPhone("");
|
|
1097
|
+
};
|
|
1098
|
+
const handleSend = async () => {
|
|
1099
|
+
if (!phone) {
|
|
1100
|
+
setResult({ error: "Ingresa un n\xFAmero de tel\xE9fono v\xE1lido (ej. 52155...)" });
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
setLoading(true);
|
|
1104
|
+
setResult(null);
|
|
1105
|
+
try {
|
|
1106
|
+
const payload = {};
|
|
1107
|
+
if (msgType === "text") {
|
|
1108
|
+
payload.text = payloadText;
|
|
1109
|
+
} else if (msgType === "template") {
|
|
1110
|
+
payload.templateName = templateName;
|
|
1111
|
+
payload.language = templateLanguage;
|
|
1112
|
+
payload.components = [];
|
|
1113
|
+
if (templateVariables.length > 0) {
|
|
1114
|
+
payload.components.push({
|
|
1115
|
+
type: "body",
|
|
1116
|
+
parameters: templateVariables.map((v) => ({ type: "text", text: v || "n/a" }))
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
} else if (msgType === "interactive") {
|
|
1120
|
+
payload.bodyText = payloadText;
|
|
1121
|
+
payload.buttons = [
|
|
1122
|
+
{ id: "opt_1", title: "S\xED, me interesa" },
|
|
1123
|
+
{ id: "opt_2", title: "No, gracias" }
|
|
1124
|
+
];
|
|
1125
|
+
}
|
|
1126
|
+
const API_URL3 = import.meta.env?.VITE_API_BASE_URL || "http://localhost:3001";
|
|
1127
|
+
const res = await fetch(`${API_URL3}/api/whatsapp/send-test`, {
|
|
1128
|
+
method: "POST",
|
|
1129
|
+
headers: {
|
|
1130
|
+
"Content-Type": "application/json"
|
|
1131
|
+
},
|
|
1132
|
+
body: JSON.stringify({
|
|
1133
|
+
to: phone,
|
|
1134
|
+
type: msgType,
|
|
1135
|
+
payload
|
|
1136
|
+
})
|
|
1137
|
+
});
|
|
1138
|
+
const data = await res.json();
|
|
1139
|
+
setResult(data);
|
|
1140
|
+
} catch (err) {
|
|
1141
|
+
setResult({ error: err.message });
|
|
1142
|
+
} finally {
|
|
1143
|
+
setLoading(false);
|
|
1144
|
+
}
|
|
1145
|
+
};
|
|
1146
|
+
return /* @__PURE__ */ jsx("div", { className: "flex-1 flex flex-col min-h-0 overflow-y-auto p-6", style: { background: "var(--bg-primary)", color: "var(--text-primary)" }, children: /* @__PURE__ */ jsxs("div", { className: "max-w-2xl mx-auto w-full space-y-6", children: [
|
|
1147
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1148
|
+
/* @__PURE__ */ jsx("h2", { className: "text-xl font-bold mb-1", children: "WhatsApp API Tester" }),
|
|
1149
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm", style: { color: "var(--text-secondary)" }, children: "Prueba el env\xEDo de diferentes formatos soportados por Meta Cloud API directamente." })
|
|
1150
|
+
] }),
|
|
1151
|
+
/* @__PURE__ */ jsxs("div", { className: "p-5 rounded-xl border space-y-4", style: { background: "var(--bg-elevated)", borderColor: "var(--border-color)" }, children: [
|
|
1152
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1153
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
1154
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-bold uppercase tracking-wider", style: { color: "var(--text-secondary)" }, children: "Tel\xE9fono Destino (Sandbox)" }),
|
|
1155
|
+
phone && !savedPhones.find((p) => p.number === phone) && /* @__PURE__ */ jsx(
|
|
1156
|
+
"button",
|
|
1157
|
+
{
|
|
1158
|
+
onClick: () => setShowPhoneSave(!showPhoneSave),
|
|
1159
|
+
className: "text-[10px] font-bold text-indigo-400 hover:text-indigo-300 transition-colors",
|
|
1160
|
+
children: "+ Guardar N\xFAmero"
|
|
1161
|
+
}
|
|
1162
|
+
)
|
|
1163
|
+
] }),
|
|
1164
|
+
showPhoneSave && /* @__PURE__ */ jsxs("div", { className: "flex gap-2 mb-2 p-2 rounded-lg bg-indigo-500/10 border border-indigo-500/30", children: [
|
|
1165
|
+
/* @__PURE__ */ jsx(
|
|
1166
|
+
"input",
|
|
1167
|
+
{
|
|
1168
|
+
type: "text",
|
|
1169
|
+
placeholder: "Nombre (ej. Mi Celular)",
|
|
1170
|
+
className: "flex-1 px-3 py-1.5 text-xs rounded border outline-none bg-black/20 text-white border-transparent focus:border-indigo-500",
|
|
1171
|
+
value: newPhoneName,
|
|
1172
|
+
onChange: (e) => setNewPhoneName(e.target.value)
|
|
1173
|
+
}
|
|
1174
|
+
),
|
|
1175
|
+
/* @__PURE__ */ jsx("button", { onClick: handleSavePhone, className: "px-3 py-1.5 bg-indigo-500 text-white rounded text-xs font-bold hover:bg-indigo-600", children: "Guardar" }),
|
|
1176
|
+
/* @__PURE__ */ jsx("button", { onClick: () => setShowPhoneSave(false), className: "px-3 py-1.5 bg-white/10 text-white rounded text-xs hover:bg-white/20", children: "Cancelar" })
|
|
1177
|
+
] }),
|
|
1178
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
1179
|
+
savedPhones.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 mb-1", children: savedPhones.map((p, idx) => /* @__PURE__ */ jsxs(
|
|
1180
|
+
"div",
|
|
1181
|
+
{
|
|
1182
|
+
className: `flex items-center gap-2 px-3 py-1.5 rounded-full border border-indigo-500/30 text-xs cursor-pointer transition-colors ${phone === p.number ? "bg-indigo-500 text-white" : "bg-transparent text-indigo-300 hover:bg-indigo-500/10"}`,
|
|
1183
|
+
onClick: () => setPhone(p.number),
|
|
1184
|
+
children: [
|
|
1185
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-user-circle" }),
|
|
1186
|
+
/* @__PURE__ */ jsx("span", { className: "font-bold", children: p.name }),
|
|
1187
|
+
/* @__PURE__ */ jsx(
|
|
1188
|
+
"button",
|
|
1189
|
+
{
|
|
1190
|
+
onClick: (e) => {
|
|
1191
|
+
e.stopPropagation();
|
|
1192
|
+
handleDeletePhone(p.number);
|
|
1193
|
+
},
|
|
1194
|
+
className: "w-4 h-4 rounded-full flex items-center justify-center hover:bg-red-500/50 hover:text-white text-indigo-300 transition-colors",
|
|
1195
|
+
children: /* @__PURE__ */ jsx("i", { className: "fas fa-times text-[8px]" })
|
|
1196
|
+
}
|
|
1197
|
+
)
|
|
1198
|
+
]
|
|
1199
|
+
},
|
|
1200
|
+
idx
|
|
1201
|
+
)) }),
|
|
1202
|
+
/* @__PURE__ */ jsx(
|
|
1203
|
+
"input",
|
|
1204
|
+
{
|
|
1205
|
+
type: "text",
|
|
1206
|
+
placeholder: "Ej. 52155... (Incluye c\xF3digo de pa\xEDs)",
|
|
1207
|
+
className: "w-full px-4 py-2 text-sm rounded-lg border outline-none transition-all focus:border-indigo-500 font-mono",
|
|
1208
|
+
style: { background: "var(--bg-primary)", borderColor: "var(--border-color)", color: "var(--text-primary)" },
|
|
1209
|
+
value: phone,
|
|
1210
|
+
onChange: (e) => setPhone(e.target.value)
|
|
1211
|
+
}
|
|
1212
|
+
),
|
|
1213
|
+
/* @__PURE__ */ jsxs("p", { className: "text-[10px] mt-1 text-amber-500/80", children: [
|
|
1214
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-exclamation-triangle mr-1" }),
|
|
1215
|
+
"Aseg\xFArate de que este n\xFAmero est\xE9 registrado en Meta for Developers si tu app est\xE1 en modo desarrollo."
|
|
1216
|
+
] })
|
|
1217
|
+
] })
|
|
1218
|
+
] }),
|
|
1219
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1220
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-bold uppercase tracking-wider mb-2", style: { color: "var(--text-secondary)" }, children: "Tipo de Mensaje" }),
|
|
1221
|
+
/* @__PURE__ */ jsx("div", { className: "flex gap-2", children: ["text", "template", "interactive"].map((type) => /* @__PURE__ */ jsx(
|
|
1222
|
+
"button",
|
|
1223
|
+
{
|
|
1224
|
+
onClick: () => setMsgType(type),
|
|
1225
|
+
className: `px-4 py-2 text-sm font-medium rounded-lg transition-all capitalize border ${msgType === type ? "border-indigo-500 bg-indigo-500/10 text-indigo-400" : "hover:bg-white/5 opacity-70"}`,
|
|
1226
|
+
style: { borderColor: msgType === type ? "" : "var(--border-color)" },
|
|
1227
|
+
children: type
|
|
1228
|
+
},
|
|
1229
|
+
type
|
|
1230
|
+
)) })
|
|
1231
|
+
] }),
|
|
1232
|
+
/* @__PURE__ */ jsxs("div", { className: "pt-2", children: [
|
|
1233
|
+
msgType === "text" && /* @__PURE__ */ jsxs("div", { children: [
|
|
1234
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-bold uppercase tracking-wider mb-2", style: { color: "var(--text-secondary)" }, children: "Mensaje de Texto" }),
|
|
1235
|
+
/* @__PURE__ */ jsx(
|
|
1236
|
+
"textarea",
|
|
1237
|
+
{
|
|
1238
|
+
className: "w-full px-4 py-2 text-sm rounded-lg border outline-none min-h-[100px]",
|
|
1239
|
+
style: { background: "var(--bg-primary)", borderColor: "var(--border-color)", color: "var(--text-primary)" },
|
|
1240
|
+
value: payloadText,
|
|
1241
|
+
onChange: (e) => setPayloadText(e.target.value)
|
|
1242
|
+
}
|
|
1243
|
+
)
|
|
1244
|
+
] }),
|
|
1245
|
+
msgType === "template" && /* @__PURE__ */ jsxs("div", { children: [
|
|
1246
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-bold uppercase tracking-wider mb-2", style: { color: "var(--text-secondary)" }, children: "Seleccionar Template (Aprobado)" }),
|
|
1247
|
+
fetchingTemplates ? /* @__PURE__ */ jsx("div", { className: "text-xs p-2 text-indigo-400", children: "Cargando plantillas de Meta..." }) : templates.length > 0 ? /* @__PURE__ */ jsx(
|
|
1248
|
+
"select",
|
|
1249
|
+
{
|
|
1250
|
+
className: "w-full px-4 py-2 text-sm rounded-lg border outline-none font-mono",
|
|
1251
|
+
style: { background: "var(--bg-primary)", borderColor: "var(--border-color)", color: "var(--text-primary)" },
|
|
1252
|
+
value: `${templateName}::${templateLanguage}`,
|
|
1253
|
+
onChange: (e) => {
|
|
1254
|
+
const [name, lang] = e.target.value.split("::");
|
|
1255
|
+
setTemplateName(name);
|
|
1256
|
+
setTemplateLanguage(lang);
|
|
1257
|
+
},
|
|
1258
|
+
children: templates.filter((t) => t.status === "APPROVED").map((t) => /* @__PURE__ */ jsxs("option", { value: `${t.name}::${t.language}`, children: [
|
|
1259
|
+
t.name,
|
|
1260
|
+
" (",
|
|
1261
|
+
t.language,
|
|
1262
|
+
") [",
|
|
1263
|
+
t.category,
|
|
1264
|
+
"]"
|
|
1265
|
+
] }, `${t.id || t.name}_${t.language}`))
|
|
1266
|
+
}
|
|
1267
|
+
) : /* @__PURE__ */ jsx(
|
|
1268
|
+
"input",
|
|
1269
|
+
{
|
|
1270
|
+
type: "text",
|
|
1271
|
+
placeholder: "No se pudieron cargar, ingresa el nombre manual (ej. hello_world)",
|
|
1272
|
+
className: "w-full px-4 py-2 text-sm rounded-lg border outline-none",
|
|
1273
|
+
style: { background: "var(--bg-primary)", borderColor: "var(--border-color)", color: "var(--text-primary)" },
|
|
1274
|
+
value: templateName,
|
|
1275
|
+
onChange: (e) => setTemplateName(e.target.value)
|
|
1276
|
+
}
|
|
1277
|
+
),
|
|
1278
|
+
templateVariables.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-4 p-3 rounded bg-black/20 border border-white/5 space-y-3", children: [
|
|
1279
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-bold text-indigo-300", children: "Variables Requeridas (Cuerpo)" }),
|
|
1280
|
+
templateVariables.map((val, idx) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1281
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-mono text-white/50 w-8", children: `{{${idx + 1}}}` }),
|
|
1282
|
+
/* @__PURE__ */ jsx(
|
|
1283
|
+
"input",
|
|
1284
|
+
{
|
|
1285
|
+
type: "text",
|
|
1286
|
+
placeholder: `Valor para la variable (opcional)`,
|
|
1287
|
+
className: "flex-1 px-3 py-1.5 text-xs rounded border outline-none bg-black/40 text-white border-transparent focus:border-indigo-500",
|
|
1288
|
+
value: val,
|
|
1289
|
+
onChange: (e) => {
|
|
1290
|
+
const newVars = [...templateVariables];
|
|
1291
|
+
newVars[idx] = e.target.value;
|
|
1292
|
+
setTemplateVariables(newVars);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
)
|
|
1296
|
+
] }, idx))
|
|
1297
|
+
] }),
|
|
1298
|
+
/* @__PURE__ */ jsx("p", { className: "text-[10px] mt-2", style: { color: "var(--text-secondary)" }, children: "Si la plantilla usa variables din\xE1micas en encabezados o links, la API intentar\xE1 autocompletarlos si no se incluyen aqu\xED." })
|
|
1299
|
+
] }),
|
|
1300
|
+
msgType === "interactive" && /* @__PURE__ */ jsxs("div", { children: [
|
|
1301
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-bold uppercase tracking-wider mb-2", style: { color: "var(--text-secondary)" }, children: "Texto Principal (Con Botones)" }),
|
|
1302
|
+
/* @__PURE__ */ jsx(
|
|
1303
|
+
"textarea",
|
|
1304
|
+
{
|
|
1305
|
+
className: "w-full px-4 py-2 text-sm rounded-lg border outline-none min-h-[80px]",
|
|
1306
|
+
style: { background: "var(--bg-primary)", borderColor: "var(--border-color)", color: "var(--text-primary)" },
|
|
1307
|
+
value: payloadText,
|
|
1308
|
+
onChange: (e) => setPayloadText(e.target.value)
|
|
1309
|
+
}
|
|
1310
|
+
),
|
|
1311
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-3 flex gap-2", children: [
|
|
1312
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 py-1.5 rounded bg-indigo-500/20 text-indigo-400 text-xs font-bold border border-indigo-500/30", children: "Bot\xF3n: S\xED, me interesa" }),
|
|
1313
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 py-1.5 rounded bg-indigo-500/20 text-indigo-400 text-xs font-bold border border-indigo-500/30", children: "Bot\xF3n: No, gracias" })
|
|
1314
|
+
] })
|
|
1315
|
+
] })
|
|
1316
|
+
] }),
|
|
1317
|
+
/* @__PURE__ */ jsx("div", { className: "pt-4 border-t flex justify-end", style: { borderColor: "var(--border-color)" }, children: /* @__PURE__ */ jsxs(
|
|
1318
|
+
"button",
|
|
1319
|
+
{
|
|
1320
|
+
onClick: handleSend,
|
|
1321
|
+
disabled: loading,
|
|
1322
|
+
className: `px-6 py-2 rounded-lg font-bold text-sm text-white flex items-center gap-2 ${loading ? "opacity-50 cursor-not-allowed" : "hover:bg-indigo-600"} bg-indigo-500 transition-colors`,
|
|
1323
|
+
children: [
|
|
1324
|
+
loading ? /* @__PURE__ */ jsx("i", { className: "fas fa-spinner fa-spin" }) : /* @__PURE__ */ jsx("i", { className: "fab fa-whatsapp" }),
|
|
1325
|
+
loading ? "Enviando..." : "Enviar Prueba"
|
|
1326
|
+
]
|
|
1327
|
+
}
|
|
1328
|
+
) })
|
|
1329
|
+
] }),
|
|
1330
|
+
result && /* @__PURE__ */ jsxs("div", { className: `p-4 rounded-xl border ${result.error || !result.success ? "bg-red-500/10 border-red-500/30" : "bg-green-500/10 border-green-500/30"}`, children: [
|
|
1331
|
+
/* @__PURE__ */ jsx("h3", { className: `text-sm font-bold mb-2 ${result.error || !result.success ? "text-red-400" : "text-green-400"}`, children: result.error || !result.success ? "Error en el env\xEDo" : "\xA1Mensaje enviado con \xE9xito!" }),
|
|
1332
|
+
/* @__PURE__ */ jsx("pre", { className: "text-[10px] overflow-x-auto p-3 rounded bg-black/50 text-slate-300", children: JSON.stringify(result, null, 2) })
|
|
1333
|
+
] })
|
|
1334
|
+
] }) });
|
|
1335
|
+
};
|
|
1336
|
+
var TemplateManagerTab = () => {
|
|
1337
|
+
const [templates, setTemplates] = useState([]);
|
|
1338
|
+
const [loading, setLoading] = useState(true);
|
|
1339
|
+
const [error, setError] = useState(null);
|
|
1340
|
+
const [creating, setCreating] = useState(false);
|
|
1341
|
+
const [name, setName] = useState("");
|
|
1342
|
+
const [category, setCategory] = useState("UTILITY");
|
|
1343
|
+
const [language, setLanguage] = useState("es");
|
|
1344
|
+
const [headerText, setHeaderText] = useState("");
|
|
1345
|
+
const [bodyText, setBodyText] = useState("Hola {{1}}, tu pedido est\xE1 listo.");
|
|
1346
|
+
const [footerText, setFooterText] = useState("");
|
|
1347
|
+
const [buttons, setButtons] = useState([]);
|
|
1348
|
+
useEffect(() => {
|
|
1349
|
+
fetchTemplates();
|
|
1350
|
+
}, []);
|
|
1351
|
+
const fetchTemplates = async () => {
|
|
1352
|
+
setLoading(true);
|
|
1353
|
+
setError(null);
|
|
1354
|
+
try {
|
|
1355
|
+
const API_URL3 = import.meta.env?.VITE_API_BASE_URL || "http://localhost:3001";
|
|
1356
|
+
const res = await fetch(`${API_URL3}/api/whatsapp/templates`);
|
|
1357
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
1358
|
+
const data = await res.json();
|
|
1359
|
+
if (data.error) throw new Error(data.error);
|
|
1360
|
+
setTemplates(data || []);
|
|
1361
|
+
} catch (err) {
|
|
1362
|
+
setError(err.message);
|
|
1363
|
+
} finally {
|
|
1364
|
+
setLoading(false);
|
|
1365
|
+
}
|
|
1366
|
+
};
|
|
1367
|
+
const handleCreate = async () => {
|
|
1368
|
+
if (!name || !bodyText) {
|
|
1369
|
+
setError("Por favor completa el nombre y el texto.");
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
setLoading(true);
|
|
1373
|
+
try {
|
|
1374
|
+
const API_URL3 = import.meta.env?.VITE_API_BASE_URL || "http://localhost:3001";
|
|
1375
|
+
const components = [];
|
|
1376
|
+
if (headerText.trim()) {
|
|
1377
|
+
components.push({ type: "HEADER", format: "TEXT", text: headerText });
|
|
1378
|
+
}
|
|
1379
|
+
const varMatches = bodyText.match(/\{\{\d+\}\}/g);
|
|
1380
|
+
let exampleBody = void 0;
|
|
1381
|
+
if (varMatches && varMatches.length > 0) {
|
|
1382
|
+
const dummyVars = varMatches.map((_, i) => `Variable${i + 1}`);
|
|
1383
|
+
exampleBody = { body_text: [dummyVars] };
|
|
1384
|
+
}
|
|
1385
|
+
components.push({
|
|
1386
|
+
type: "BODY",
|
|
1387
|
+
text: bodyText,
|
|
1388
|
+
...exampleBody ? { example: exampleBody } : {}
|
|
1389
|
+
});
|
|
1390
|
+
if (footerText.trim()) {
|
|
1391
|
+
components.push({ type: "FOOTER", text: footerText });
|
|
1392
|
+
}
|
|
1393
|
+
if (buttons.length > 0) {
|
|
1394
|
+
components.push({
|
|
1395
|
+
type: "BUTTONS",
|
|
1396
|
+
buttons: buttons.map((b) => {
|
|
1397
|
+
if (b.type === "URL") return { type: "URL", text: b.text, url: b.url };
|
|
1398
|
+
return { type: "QUICK_REPLY", text: b.text };
|
|
1399
|
+
})
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
const payload = {
|
|
1403
|
+
name: name.toLowerCase().replace(/[^a-z0-9_]/g, "_"),
|
|
1404
|
+
language,
|
|
1405
|
+
category,
|
|
1406
|
+
components
|
|
1407
|
+
};
|
|
1408
|
+
const res = await fetch(`${API_URL3}/api/whatsapp/templates`, {
|
|
1409
|
+
method: "POST",
|
|
1410
|
+
headers: { "Content-Type": "application/json" },
|
|
1411
|
+
body: JSON.stringify(payload)
|
|
1412
|
+
});
|
|
1413
|
+
const data = await res.json();
|
|
1414
|
+
if (!res.ok || data.error) throw new Error(data.error || "Error al crear la plantilla");
|
|
1415
|
+
setCreating(false);
|
|
1416
|
+
setName("");
|
|
1417
|
+
setHeaderText("");
|
|
1418
|
+
setFooterText("");
|
|
1419
|
+
setButtons([]);
|
|
1420
|
+
setBodyText("Hola {{1}}, tu pedido est\xE1 listo.");
|
|
1421
|
+
await fetchTemplates();
|
|
1422
|
+
} catch (err) {
|
|
1423
|
+
setError(err.message);
|
|
1424
|
+
setLoading(false);
|
|
1425
|
+
}
|
|
1426
|
+
};
|
|
1427
|
+
const handleDelete = async (templateName) => {
|
|
1428
|
+
if (!window.confirm(`\xBFSeguro que deseas eliminar la plantilla '${templateName}' permanentemente de Meta?`)) return;
|
|
1429
|
+
setLoading(true);
|
|
1430
|
+
try {
|
|
1431
|
+
const API_URL3 = import.meta.env?.VITE_API_BASE_URL || "http://localhost:3001";
|
|
1432
|
+
const res = await fetch(`${API_URL3}/api/whatsapp/templates/${templateName}`, {
|
|
1433
|
+
method: "DELETE"
|
|
1434
|
+
});
|
|
1435
|
+
const data = await res.json();
|
|
1436
|
+
if (!res.ok || data.error) throw new Error(data.error || "Error al eliminar");
|
|
1437
|
+
await fetchTemplates();
|
|
1438
|
+
} catch (err) {
|
|
1439
|
+
setError(err.message);
|
|
1440
|
+
setLoading(false);
|
|
1441
|
+
}
|
|
1442
|
+
};
|
|
1443
|
+
return /* @__PURE__ */ jsx("div", { className: "flex-1 flex flex-col min-h-0 overflow-y-auto p-6", style: { background: "var(--bg-primary)", color: "var(--text-primary)" }, children: /* @__PURE__ */ jsxs("div", { className: "max-w-4xl mx-auto w-full space-y-6", children: [
|
|
1444
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
1445
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1446
|
+
/* @__PURE__ */ jsx("h2", { className: "text-xl font-bold mb-1", children: "Gestor de Plantillas (Meta)" }),
|
|
1447
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm", style: { color: "var(--text-secondary)" }, children: "Crea y administra tus plantillas oficiales de WhatsApp sin salir de Decido OS." })
|
|
1448
|
+
] }),
|
|
1449
|
+
/* @__PURE__ */ jsx(
|
|
1450
|
+
"button",
|
|
1451
|
+
{
|
|
1452
|
+
onClick: () => setCreating(!creating),
|
|
1453
|
+
className: "px-4 py-2 bg-indigo-500 hover:bg-indigo-600 text-white text-sm font-bold rounded-lg transition-colors",
|
|
1454
|
+
children: creating ? "Ver Lista" : "+ Nueva Plantilla"
|
|
1455
|
+
}
|
|
1456
|
+
)
|
|
1457
|
+
] }),
|
|
1458
|
+
error && /* @__PURE__ */ jsxs("div", { className: "p-4 rounded-lg bg-red-500/10 border border-red-500/30 text-red-400 text-sm font-medium", children: [
|
|
1459
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-exclamation-triangle mr-2" }),
|
|
1460
|
+
" ",
|
|
1461
|
+
error
|
|
1462
|
+
] }),
|
|
1463
|
+
creating ? /* @__PURE__ */ jsxs("div", { className: "p-6 rounded-xl border space-y-4", style: { background: "var(--bg-elevated)", borderColor: "var(--border-color)" }, children: [
|
|
1464
|
+
/* @__PURE__ */ jsx("h3", { className: "font-bold text-lg border-b pb-2 mb-4", style: { borderColor: "var(--border-color)" }, children: "Crear Nueva Plantilla" }),
|
|
1465
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
|
|
1466
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1467
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-bold uppercase tracking-wider mb-2", style: { color: "var(--text-secondary)" }, children: "Nombre de la Plantilla" }),
|
|
1468
|
+
/* @__PURE__ */ jsx(
|
|
1469
|
+
"input",
|
|
1470
|
+
{
|
|
1471
|
+
type: "text",
|
|
1472
|
+
placeholder: "ej. welcome_message_01",
|
|
1473
|
+
className: "w-full px-4 py-2 text-sm rounded-lg border outline-none font-mono",
|
|
1474
|
+
style: { background: "var(--bg-primary)", borderColor: "var(--border-color)", color: "var(--text-primary)" },
|
|
1475
|
+
value: name,
|
|
1476
|
+
onChange: (e) => setName(e.target.value.toLowerCase().replace(/[^a-z0-9_]/g, "_"))
|
|
1477
|
+
}
|
|
1478
|
+
),
|
|
1479
|
+
/* @__PURE__ */ jsx("p", { className: "text-[10px] mt-1", style: { color: "var(--text-secondary)" }, children: "Solo min\xFAsculas y guiones bajos (_)" })
|
|
1480
|
+
] }),
|
|
1481
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1482
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-bold uppercase tracking-wider mb-2", style: { color: "var(--text-secondary)" }, children: "Categor\xEDa" }),
|
|
1483
|
+
/* @__PURE__ */ jsxs(
|
|
1484
|
+
"select",
|
|
1485
|
+
{
|
|
1486
|
+
className: "w-full px-4 py-2 text-sm rounded-lg border outline-none",
|
|
1487
|
+
style: { background: "var(--bg-primary)", borderColor: "var(--border-color)", color: "var(--text-primary)" },
|
|
1488
|
+
value: category,
|
|
1489
|
+
onChange: (e) => setCategory(e.target.value),
|
|
1490
|
+
children: [
|
|
1491
|
+
/* @__PURE__ */ jsx("option", { value: "UTILITY", children: "Utilidad (Avisos, tracking, alertas)" }),
|
|
1492
|
+
/* @__PURE__ */ jsx("option", { value: "MARKETING", children: "Marketing (Promociones, ventas)" }),
|
|
1493
|
+
/* @__PURE__ */ jsx("option", { value: "AUTHENTICATION", children: "Autenticaci\xF3n (OTPs)" })
|
|
1494
|
+
]
|
|
1495
|
+
}
|
|
1496
|
+
)
|
|
1497
|
+
] })
|
|
1498
|
+
] }),
|
|
1499
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1500
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-bold uppercase tracking-wider mb-2", style: { color: "var(--text-secondary)" }, children: "Idioma (Locale)" }),
|
|
1501
|
+
/* @__PURE__ */ jsxs(
|
|
1502
|
+
"select",
|
|
1503
|
+
{
|
|
1504
|
+
className: "w-full px-4 py-2 text-sm rounded-lg border outline-none max-w-xs",
|
|
1505
|
+
style: { background: "var(--bg-primary)", borderColor: "var(--border-color)", color: "var(--text-primary)" },
|
|
1506
|
+
value: language,
|
|
1507
|
+
onChange: (e) => setLanguage(e.target.value),
|
|
1508
|
+
children: [
|
|
1509
|
+
/* @__PURE__ */ jsx("option", { value: "es", children: "Espa\xF1ol (es)" }),
|
|
1510
|
+
/* @__PURE__ */ jsx("option", { value: "es_LA", children: "Espa\xF1ol Latino (es_LA)" }),
|
|
1511
|
+
/* @__PURE__ */ jsx("option", { value: "en_US", children: "Ingl\xE9s (en_US)" })
|
|
1512
|
+
]
|
|
1513
|
+
}
|
|
1514
|
+
)
|
|
1515
|
+
] }),
|
|
1516
|
+
/* @__PURE__ */ jsxs("div", { className: "pt-4 border-t space-y-4", style: { borderColor: "var(--border-color)" }, children: [
|
|
1517
|
+
/* @__PURE__ */ jsx("h4", { className: "text-xs font-bold uppercase tracking-wider", style: { color: "var(--text-secondary)" }, children: "Estructura del Mensaje" }),
|
|
1518
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1519
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-bold mb-2", children: "Encabezado (Opcional)" }),
|
|
1520
|
+
/* @__PURE__ */ jsx(
|
|
1521
|
+
"input",
|
|
1522
|
+
{
|
|
1523
|
+
type: "text",
|
|
1524
|
+
placeholder: "Ej. \xA1Alerta de Promoci\xF3n!",
|
|
1525
|
+
className: "w-full px-4 py-2 text-sm rounded-lg border outline-none",
|
|
1526
|
+
style: { background: "var(--bg-primary)", borderColor: "var(--border-color)", color: "var(--text-primary)" },
|
|
1527
|
+
value: headerText,
|
|
1528
|
+
onChange: (e) => setHeaderText(e.target.value)
|
|
1529
|
+
}
|
|
1530
|
+
)
|
|
1531
|
+
] }),
|
|
1532
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1533
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-bold mb-2", children: "Cuerpo (Obligatorio)" }),
|
|
1534
|
+
/* @__PURE__ */ jsx(
|
|
1535
|
+
"textarea",
|
|
1536
|
+
{
|
|
1537
|
+
className: "w-full px-4 py-2 text-sm rounded-lg border outline-none min-h-[100px]",
|
|
1538
|
+
style: { background: "var(--bg-primary)", borderColor: "var(--border-color)", color: "var(--text-primary)" },
|
|
1539
|
+
value: bodyText,
|
|
1540
|
+
onChange: (e) => setBodyText(e.target.value)
|
|
1541
|
+
}
|
|
1542
|
+
),
|
|
1543
|
+
/* @__PURE__ */ jsxs("p", { className: "text-[10px] mt-1", style: { color: "var(--text-secondary)" }, children: [
|
|
1544
|
+
"Usa ",
|
|
1545
|
+
"{{",
|
|
1546
|
+
"1",
|
|
1547
|
+
"}}",
|
|
1548
|
+
", ",
|
|
1549
|
+
"{{",
|
|
1550
|
+
"2",
|
|
1551
|
+
"}}",
|
|
1552
|
+
" para variables que se llenar\xE1n din\xE1micamente."
|
|
1553
|
+
] })
|
|
1554
|
+
] }),
|
|
1555
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1556
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-bold mb-2", children: "Pie de p\xE1gina (Opcional)" }),
|
|
1557
|
+
/* @__PURE__ */ jsx(
|
|
1558
|
+
"input",
|
|
1559
|
+
{
|
|
1560
|
+
type: "text",
|
|
1561
|
+
placeholder: "Ej. Responde STOP para cancelar",
|
|
1562
|
+
className: "w-full px-4 py-2 text-sm rounded-lg border outline-none",
|
|
1563
|
+
style: { background: "var(--bg-primary)", borderColor: "var(--border-color)", color: "var(--text-primary)" },
|
|
1564
|
+
value: footerText,
|
|
1565
|
+
onChange: (e) => setFooterText(e.target.value)
|
|
1566
|
+
}
|
|
1567
|
+
)
|
|
1568
|
+
] }),
|
|
1569
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1570
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
1571
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-bold", children: "Botones (M\xE1x 3)" }),
|
|
1572
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
1573
|
+
/* @__PURE__ */ jsx(
|
|
1574
|
+
"button",
|
|
1575
|
+
{
|
|
1576
|
+
onClick: () => {
|
|
1577
|
+
if (buttons.length < 3) setButtons([...buttons, { type: "QUICK_REPLY", text: "Nuevo Bot\xF3n" }]);
|
|
1578
|
+
},
|
|
1579
|
+
className: "px-2 py-1 text-[10px] bg-white/10 hover:bg-white/20 rounded font-bold transition-colors",
|
|
1580
|
+
disabled: buttons.length >= 3,
|
|
1581
|
+
children: "+ Respuesta R\xE1pida"
|
|
1582
|
+
}
|
|
1583
|
+
),
|
|
1584
|
+
/* @__PURE__ */ jsx(
|
|
1585
|
+
"button",
|
|
1586
|
+
{
|
|
1587
|
+
onClick: () => {
|
|
1588
|
+
if (buttons.length < 3) setButtons([...buttons, { type: "URL", text: "Saber M\xE1s", url: "https://" }]);
|
|
1589
|
+
},
|
|
1590
|
+
className: "px-2 py-1 text-[10px] bg-white/10 hover:bg-white/20 rounded font-bold transition-colors",
|
|
1591
|
+
disabled: buttons.length >= 3,
|
|
1592
|
+
children: "+ Enlace Web (URL)"
|
|
1593
|
+
}
|
|
1594
|
+
)
|
|
1595
|
+
] })
|
|
1596
|
+
] }),
|
|
1597
|
+
buttons.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-2", children: buttons.map((btn, idx) => /* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-start bg-black/20 p-2 rounded-lg border", style: { borderColor: "var(--border-color)" }, children: [
|
|
1598
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-2", children: [
|
|
1599
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1600
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-bold px-2 py-1 bg-white/10 rounded", children: btn.type === "URL" ? "\u{1F310} URL" : "\u21AA\uFE0F RESPUESTA" }),
|
|
1601
|
+
/* @__PURE__ */ jsx(
|
|
1602
|
+
"input",
|
|
1603
|
+
{
|
|
1604
|
+
type: "text",
|
|
1605
|
+
placeholder: "Texto del bot\xF3n (ej. Comprar)",
|
|
1606
|
+
className: "flex-1 px-3 py-1.5 text-xs rounded border outline-none",
|
|
1607
|
+
style: { background: "var(--bg-primary)", borderColor: "var(--border-color)", color: "var(--text-primary)" },
|
|
1608
|
+
value: btn.text,
|
|
1609
|
+
onChange: (e) => {
|
|
1610
|
+
const newBtns = [...buttons];
|
|
1611
|
+
newBtns[idx].text = e.target.value;
|
|
1612
|
+
setButtons(newBtns);
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
)
|
|
1616
|
+
] }),
|
|
1617
|
+
btn.type === "URL" && /* @__PURE__ */ jsx(
|
|
1618
|
+
"input",
|
|
1619
|
+
{
|
|
1620
|
+
type: "text",
|
|
1621
|
+
placeholder: "https://tulink.com",
|
|
1622
|
+
className: "w-full px-3 py-1.5 text-xs rounded border outline-none",
|
|
1623
|
+
style: { background: "var(--bg-primary)", borderColor: "var(--border-color)", color: "var(--text-primary)" },
|
|
1624
|
+
value: btn.url || "",
|
|
1625
|
+
onChange: (e) => {
|
|
1626
|
+
const newBtns = [...buttons];
|
|
1627
|
+
newBtns[idx].url = e.target.value;
|
|
1628
|
+
setButtons(newBtns);
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
)
|
|
1632
|
+
] }),
|
|
1633
|
+
/* @__PURE__ */ jsx(
|
|
1634
|
+
"button",
|
|
1635
|
+
{
|
|
1636
|
+
onClick: () => setButtons(buttons.filter((_, i) => i !== idx)),
|
|
1637
|
+
className: "w-8 h-8 flex items-center justify-center text-red-400 hover:bg-red-500/20 rounded",
|
|
1638
|
+
children: /* @__PURE__ */ jsx("i", { className: "fas fa-times" })
|
|
1639
|
+
}
|
|
1640
|
+
)
|
|
1641
|
+
] }, idx)) })
|
|
1642
|
+
] })
|
|
1643
|
+
] }),
|
|
1644
|
+
/* @__PURE__ */ jsx("div", { className: "pt-4 border-t flex justify-end", style: { borderColor: "var(--border-color)" }, children: /* @__PURE__ */ jsxs(
|
|
1645
|
+
"button",
|
|
1646
|
+
{
|
|
1647
|
+
onClick: handleCreate,
|
|
1648
|
+
disabled: loading || !name || !bodyText,
|
|
1649
|
+
className: `px-6 py-2 rounded-lg font-bold text-sm text-white flex items-center gap-2 ${loading ? "opacity-50 cursor-not-allowed" : "hover:bg-green-600"} bg-green-500 transition-colors`,
|
|
1650
|
+
children: [
|
|
1651
|
+
loading ? /* @__PURE__ */ jsx("i", { className: "fas fa-spinner fa-spin" }) : /* @__PURE__ */ jsx("i", { className: "fas fa-paper-plane" }),
|
|
1652
|
+
"Enviar a Meta para Aprobaci\xF3n"
|
|
1653
|
+
]
|
|
1654
|
+
}
|
|
1655
|
+
) })
|
|
1656
|
+
] }) : /* @__PURE__ */ jsxs("div", { className: "rounded-xl border overflow-hidden", style: { background: "var(--bg-elevated)", borderColor: "var(--border-color)" }, children: [
|
|
1657
|
+
/* @__PURE__ */ jsxs("div", { className: "flex bg-black/20 p-4 border-b text-xs font-bold uppercase tracking-wider", style: { borderColor: "var(--border-color)", color: "var(--text-secondary)" }, children: [
|
|
1658
|
+
/* @__PURE__ */ jsx("div", { className: "flex-[2]", children: "Nombre" }),
|
|
1659
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1", children: "Categor\xEDa" }),
|
|
1660
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1", children: "Idioma" }),
|
|
1661
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1", children: "Estado" }),
|
|
1662
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 text-right", children: "Acci\xF3n" })
|
|
1663
|
+
] }),
|
|
1664
|
+
loading ? /* @__PURE__ */ jsxs("div", { className: "p-8 text-center text-sm", style: { color: "var(--text-secondary)" }, children: [
|
|
1665
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-spinner fa-spin mr-2" }),
|
|
1666
|
+
" Cargando plantillas desde Meta..."
|
|
1667
|
+
] }) : templates.length === 0 ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center text-sm", style: { color: "var(--text-secondary)" }, children: "No hay plantillas creadas en esta WABA (WhatsApp Business Account)." }) : /* @__PURE__ */ jsx("div", { className: "divide-y", style: { borderColor: "var(--border-color)" }, children: templates.map((tpl) => /* @__PURE__ */ jsxs("div", { className: "flex items-center p-4 hover:bg-white/5 transition-colors text-sm", children: [
|
|
1668
|
+
/* @__PURE__ */ jsx("div", { className: "flex-[2] font-mono font-bold", children: tpl.name }),
|
|
1669
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 text-[11px] font-bold", children: /* @__PURE__ */ jsx("span", { className: "px-2 py-1 rounded-md bg-white/5", children: tpl.category }) }),
|
|
1670
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1", children: tpl.language }),
|
|
1671
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 flex items-center gap-2", children: [
|
|
1672
|
+
tpl.status === "APPROVED" && /* @__PURE__ */ jsx("span", { className: "w-2 h-2 rounded-full bg-green-500" }),
|
|
1673
|
+
tpl.status === "PENDING" && /* @__PURE__ */ jsx("span", { className: "w-2 h-2 rounded-full bg-amber-500" }),
|
|
1674
|
+
tpl.status === "REJECTED" && /* @__PURE__ */ jsx("span", { className: "w-2 h-2 rounded-full bg-red-500" }),
|
|
1675
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-bold", children: tpl.status })
|
|
1676
|
+
] }),
|
|
1677
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 text-right", children: /* @__PURE__ */ jsx(
|
|
1678
|
+
"button",
|
|
1679
|
+
{
|
|
1680
|
+
onClick: () => handleDelete(tpl.name),
|
|
1681
|
+
className: "w-8 h-8 rounded-full hover:bg-red-500/20 text-red-400 transition-colors",
|
|
1682
|
+
title: "Eliminar Plantilla",
|
|
1683
|
+
children: /* @__PURE__ */ jsx("i", { className: "fas fa-trash" })
|
|
1684
|
+
}
|
|
1685
|
+
) })
|
|
1686
|
+
] }, tpl.id)) })
|
|
1687
|
+
] })
|
|
1688
|
+
] }) });
|
|
1689
|
+
};
|
|
1690
|
+
var useStatusMetrics = () => {
|
|
1691
|
+
const [metrics, setMetrics] = useState({
|
|
1692
|
+
activeChats: 12,
|
|
1693
|
+
avgResponse: "2.4s",
|
|
1694
|
+
todayMessages: 347,
|
|
1695
|
+
botUptime: "99.8%",
|
|
1696
|
+
queuedMessages: 3
|
|
1697
|
+
});
|
|
1698
|
+
useEffect(() => {
|
|
1699
|
+
const interval = setInterval(() => {
|
|
1700
|
+
setMetrics((prev) => ({
|
|
1701
|
+
...prev,
|
|
1702
|
+
activeChats: prev.activeChats + Math.floor(Math.random() * 3) - 1,
|
|
1703
|
+
todayMessages: prev.todayMessages + Math.floor(Math.random() * 5),
|
|
1704
|
+
queuedMessages: Math.max(0, prev.queuedMessages + Math.floor(Math.random() * 3) - 1)
|
|
1705
|
+
}));
|
|
1706
|
+
}, 8e3);
|
|
1707
|
+
return () => clearInterval(interval);
|
|
1708
|
+
}, []);
|
|
1709
|
+
return metrics;
|
|
1710
|
+
};
|
|
1711
|
+
var StatusBarMetrics = React8.memo(() => {
|
|
1712
|
+
const metrics = useStatusMetrics();
|
|
1713
|
+
return /* @__PURE__ */ jsxs(
|
|
1714
|
+
"div",
|
|
1715
|
+
{
|
|
1716
|
+
className: "h-6 shrink-0 flex items-center justify-between px-3 text-[10px] font-medium border-t",
|
|
1717
|
+
style: { background: "var(--brand-primary)", borderColor: "transparent", color: "white" },
|
|
1718
|
+
children: [
|
|
1719
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
1720
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
|
|
1721
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-comments" }),
|
|
1722
|
+
" ",
|
|
1723
|
+
metrics.activeChats,
|
|
1724
|
+
" chats activos"
|
|
1725
|
+
] }),
|
|
1726
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
|
|
1727
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-clock" }),
|
|
1728
|
+
" Resp: ",
|
|
1729
|
+
metrics.avgResponse
|
|
1730
|
+
] }),
|
|
1731
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
|
|
1732
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-paper-plane" }),
|
|
1733
|
+
" ",
|
|
1734
|
+
metrics.todayMessages,
|
|
1735
|
+
" hoy"
|
|
1736
|
+
] })
|
|
1737
|
+
] }),
|
|
1738
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
1739
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
|
|
1740
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-inbox" }),
|
|
1741
|
+
" ",
|
|
1742
|
+
metrics.queuedMessages,
|
|
1743
|
+
" en cola"
|
|
1744
|
+
] }),
|
|
1745
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
|
|
1746
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-robot" }),
|
|
1747
|
+
" Uptime: ",
|
|
1748
|
+
metrics.botUptime
|
|
1749
|
+
] }),
|
|
1750
|
+
/* @__PURE__ */ jsx("span", { className: "opacity-70", children: "WhatsApp Business API" })
|
|
1751
|
+
] })
|
|
1752
|
+
]
|
|
1753
|
+
}
|
|
1754
|
+
);
|
|
1755
|
+
});
|
|
1756
|
+
var TABS = [
|
|
1757
|
+
{ id: "chat", label: "Live Chat", icon: "fas fa-comments" },
|
|
1758
|
+
{ id: "flow", label: "Flow Canvas", icon: "fas fa-project-diagram" },
|
|
1759
|
+
{ id: "analytics", label: "Analytics", icon: "fas fa-chart-bar" },
|
|
1760
|
+
{ id: "api_tester", label: "API Tester", icon: "fas fa-vial" },
|
|
1761
|
+
{ id: "templates", label: "Templates", icon: "fas fa-layer-group" }
|
|
1762
|
+
];
|
|
1763
|
+
var DiscoveryStudio = ({ gatewayStatus = "connected", activeProvider = "Meta Cloud API" }) => {
|
|
1764
|
+
const [activeTab, setActiveTab] = useState("chat");
|
|
1765
|
+
const [explorerOpen, setExplorerOpen] = useState(true);
|
|
1766
|
+
const [inspectorOpen, setInspectorOpen] = useState(false);
|
|
1767
|
+
const [agentOpen, setAgentOpen] = useState(true);
|
|
1768
|
+
const [selectedContact, setSelectedContact] = useState(null);
|
|
1769
|
+
const [cmdOpen, setCmdOpen] = useState(false);
|
|
1770
|
+
const [cmdQuery, setCmdQuery] = useState("");
|
|
1771
|
+
const cmdInputRef = useRef(null);
|
|
1772
|
+
useEffect(() => {
|
|
1773
|
+
const handleKeyDown = (e) => {
|
|
1774
|
+
if ((e.metaKey || e.ctrlKey) && e.key === "k") {
|
|
1775
|
+
e.preventDefault();
|
|
1776
|
+
setCmdOpen((prev) => !prev);
|
|
1777
|
+
setCmdQuery("");
|
|
1778
|
+
}
|
|
1779
|
+
if (e.key === "Escape") setCmdOpen(false);
|
|
1780
|
+
};
|
|
1781
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
1782
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1783
|
+
}, []);
|
|
1784
|
+
useEffect(() => {
|
|
1785
|
+
if (cmdOpen && cmdInputRef.current) {
|
|
1786
|
+
cmdInputRef.current.focus();
|
|
1787
|
+
}
|
|
1788
|
+
}, [cmdOpen]);
|
|
1789
|
+
const commands = [
|
|
1790
|
+
{ id: "chat", label: "Abrir Chat en Vivo", icon: "fas fa-comments", action: () => setActiveTab("chat") },
|
|
1791
|
+
{ id: "flow", label: "Abrir Flow Canvas", icon: "fas fa-project-diagram", action: () => setActiveTab("flow") },
|
|
1792
|
+
{ id: "analytics", label: "Abrir Analytics", icon: "fas fa-chart-bar", action: () => setActiveTab("analytics") },
|
|
1793
|
+
{ id: "explorer", label: explorerOpen ? "Cerrar Explorer" : "Abrir Explorer", icon: "fas fa-folder-tree", action: () => setExplorerOpen((p) => !p) },
|
|
1794
|
+
{ id: "inspector", label: inspectorOpen ? "Cerrar Inspector" : "Abrir Inspector", icon: "fas fa-info-circle", action: () => setInspectorOpen((p) => !p) },
|
|
1795
|
+
{ id: "agent", label: agentOpen ? "Ocultar Copiloto" : "Mostrar Copiloto", icon: "fas fa-robot", action: () => setAgentOpen((p) => !p) },
|
|
1796
|
+
{ id: "demo", label: "Activar Modo Demo", icon: "fas fa-play-circle", action: () => {
|
|
1797
|
+
} }
|
|
1798
|
+
];
|
|
1799
|
+
const filteredCommands = commands.filter(
|
|
1800
|
+
(c) => c.label.toLowerCase().includes(cmdQuery.toLowerCase())
|
|
1801
|
+
);
|
|
1802
|
+
const runCommand = (cmd) => {
|
|
1803
|
+
cmd.action();
|
|
1804
|
+
setCmdOpen(false);
|
|
1805
|
+
};
|
|
1806
|
+
return /* @__PURE__ */ jsxs("div", { className: "h-full w-full flex flex-col overflow-hidden relative font-sans", style: { background: "var(--bg-primary)" }, children: [
|
|
1807
|
+
/* @__PURE__ */ jsxs(
|
|
1808
|
+
"div",
|
|
1809
|
+
{
|
|
1810
|
+
className: "h-11 shrink-0 flex items-center justify-between px-3 gap-2 border-b",
|
|
1811
|
+
style: { background: "var(--bg-elevated)", borderColor: "var(--border-color)" },
|
|
1812
|
+
children: [
|
|
1813
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1814
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-2 py-1 rounded-lg", style: { background: "var(--bg-muted)" }, children: [
|
|
1815
|
+
/* @__PURE__ */ jsx("i", { className: "fab fa-whatsapp text-green-500 text-lg" }),
|
|
1816
|
+
/* @__PURE__ */ jsx("span", { className: "font-black text-xs uppercase tracking-widest", style: { color: "var(--text-primary)" }, children: "Discovery Studio" })
|
|
1817
|
+
] }),
|
|
1818
|
+
/* @__PURE__ */ jsx("div", { className: "h-5 w-px mx-1", style: { background: "var(--border-color)" } }),
|
|
1819
|
+
/* @__PURE__ */ jsx(
|
|
1820
|
+
"button",
|
|
1821
|
+
{
|
|
1822
|
+
onClick: () => setExplorerOpen((p) => !p),
|
|
1823
|
+
className: `w-7 h-7 rounded-md flex items-center justify-center text-xs transition-all ${explorerOpen ? "text-brand" : ""}`,
|
|
1824
|
+
style: { background: explorerOpen ? "var(--bg-muted)" : "transparent", color: explorerOpen ? "var(--brand-primary)" : "var(--text-secondary)" },
|
|
1825
|
+
title: "Toggle Explorer",
|
|
1826
|
+
children: /* @__PURE__ */ jsx("i", { className: "fas fa-folder-tree" })
|
|
1827
|
+
}
|
|
1828
|
+
),
|
|
1829
|
+
/* @__PURE__ */ jsx(
|
|
1830
|
+
"button",
|
|
1831
|
+
{
|
|
1832
|
+
onClick: () => setInspectorOpen((p) => !p),
|
|
1833
|
+
className: `w-7 h-7 rounded-md flex items-center justify-center text-xs transition-all`,
|
|
1834
|
+
style: { background: inspectorOpen ? "var(--bg-muted)" : "transparent", color: inspectorOpen ? "var(--text-primary)" : "var(--text-secondary)" },
|
|
1835
|
+
title: "Toggle Inspector",
|
|
1836
|
+
children: /* @__PURE__ */ jsx("i", { className: "fas fa-columns" })
|
|
1837
|
+
}
|
|
1838
|
+
),
|
|
1839
|
+
/* @__PURE__ */ jsx(
|
|
1840
|
+
"button",
|
|
1841
|
+
{
|
|
1842
|
+
onClick: () => setAgentOpen((p) => !p),
|
|
1843
|
+
className: `w-7 h-7 rounded-md flex items-center justify-center text-xs transition-all border border-emerald-500/20`,
|
|
1844
|
+
style: { background: agentOpen ? "rgba(16, 185, 129, 0.1)" : "transparent", color: agentOpen ? "#10b981" : "var(--text-secondary)" },
|
|
1845
|
+
title: "Toggle Agent Copilot",
|
|
1846
|
+
children: /* @__PURE__ */ jsx("i", { className: "fas fa-robot" })
|
|
1847
|
+
}
|
|
1848
|
+
)
|
|
1849
|
+
] }),
|
|
1850
|
+
/* @__PURE__ */ jsxs(
|
|
1851
|
+
"button",
|
|
1852
|
+
{
|
|
1853
|
+
onClick: () => setCmdOpen(true),
|
|
1854
|
+
className: "flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs transition-all hover:border-brand-primary",
|
|
1855
|
+
style: { background: "var(--bg-muted)", border: "1px solid var(--border-color)", color: "var(--text-secondary)" },
|
|
1856
|
+
children: [
|
|
1857
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-search text-[10px]" }),
|
|
1858
|
+
/* @__PURE__ */ jsx("span", { children: "Buscar comandos..." }),
|
|
1859
|
+
/* @__PURE__ */ jsx(
|
|
1860
|
+
"kbd",
|
|
1861
|
+
{
|
|
1862
|
+
className: "ml-4 px-1.5 py-0.5 rounded text-[9px] font-mono font-bold",
|
|
1863
|
+
style: { background: "var(--bg-elevated)", border: "1px solid var(--border-color)" },
|
|
1864
|
+
children: "\u2318K"
|
|
1865
|
+
}
|
|
1866
|
+
)
|
|
1867
|
+
]
|
|
1868
|
+
}
|
|
1869
|
+
),
|
|
1870
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1871
|
+
/* @__PURE__ */ jsxs(
|
|
1872
|
+
"div",
|
|
1873
|
+
{
|
|
1874
|
+
className: "flex items-center gap-1.5 px-2 py-1 rounded-lg text-[10px] font-bold",
|
|
1875
|
+
style: { background: gatewayStatus === "connected" ? "rgba(34,197,94,0.1)" : "rgba(239,68,68,0.1)", color: gatewayStatus === "connected" ? "#22c55e" : "#ef4444" },
|
|
1876
|
+
children: [
|
|
1877
|
+
/* @__PURE__ */ jsx("span", { className: `w-1.5 h-1.5 rounded-full ${gatewayStatus === "connected" ? "bg-green-500 animate-pulse" : "bg-red-500"}` }),
|
|
1878
|
+
gatewayStatus === "connected" ? `CONNECTED: ${activeProvider}` : "DISCONNECTED"
|
|
1879
|
+
]
|
|
1880
|
+
}
|
|
1881
|
+
),
|
|
1882
|
+
/* @__PURE__ */ jsx(
|
|
1883
|
+
"button",
|
|
1884
|
+
{
|
|
1885
|
+
className: "w-7 h-7 rounded-md flex items-center justify-center text-xs transition-all",
|
|
1886
|
+
style: { color: "var(--text-secondary)" },
|
|
1887
|
+
title: "Settings",
|
|
1888
|
+
children: /* @__PURE__ */ jsx("i", { className: "fas fa-cog" })
|
|
1889
|
+
}
|
|
1890
|
+
)
|
|
1891
|
+
] })
|
|
1892
|
+
]
|
|
1893
|
+
}
|
|
1894
|
+
),
|
|
1895
|
+
/* @__PURE__ */ jsxs(
|
|
1896
|
+
"div",
|
|
1897
|
+
{
|
|
1898
|
+
className: "h-9 shrink-0 flex items-end px-1 gap-px border-b",
|
|
1899
|
+
style: { background: "var(--bg-muted)", borderColor: "var(--border-color)" },
|
|
1900
|
+
children: [
|
|
1901
|
+
TABS.map((tab) => /* @__PURE__ */ jsxs(
|
|
1902
|
+
"button",
|
|
1903
|
+
{
|
|
1904
|
+
onClick: () => setActiveTab(tab.id),
|
|
1905
|
+
className: `flex items-center gap-2 px-4 py-1.5 text-xs font-semibold rounded-t-lg transition-all relative ${activeTab === tab.id ? "font-bold" : "opacity-60 hover:opacity-80"}`,
|
|
1906
|
+
style: {
|
|
1907
|
+
background: activeTab === tab.id ? "var(--bg-primary)" : "transparent",
|
|
1908
|
+
color: activeTab === tab.id ? "var(--text-primary)" : "var(--text-secondary)",
|
|
1909
|
+
borderBottom: activeTab === tab.id ? "2px solid var(--brand-primary)" : "2px solid transparent"
|
|
1910
|
+
},
|
|
1911
|
+
children: [
|
|
1912
|
+
/* @__PURE__ */ jsx("i", { className: `${tab.icon} text-[10px]` }),
|
|
1913
|
+
tab.label
|
|
1914
|
+
]
|
|
1915
|
+
},
|
|
1916
|
+
tab.id
|
|
1917
|
+
)),
|
|
1918
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1" }),
|
|
1919
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 px-2 pb-1", children: /* @__PURE__ */ jsx(
|
|
1920
|
+
"button",
|
|
1921
|
+
{
|
|
1922
|
+
className: "w-6 h-6 rounded flex items-center justify-center text-[10px] transition-all hover:bg-white/10",
|
|
1923
|
+
style: { color: "var(--text-secondary)" },
|
|
1924
|
+
title: "Split view",
|
|
1925
|
+
children: /* @__PURE__ */ jsx("i", { className: "fas fa-columns" })
|
|
1926
|
+
}
|
|
1927
|
+
) })
|
|
1928
|
+
]
|
|
1929
|
+
}
|
|
1930
|
+
),
|
|
1931
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 flex min-h-0 overflow-hidden", children: [
|
|
1932
|
+
explorerOpen && /* @__PURE__ */ jsx(
|
|
1933
|
+
"div",
|
|
1934
|
+
{
|
|
1935
|
+
className: "w-60 shrink-0 flex flex-col border-r overflow-hidden animate-fade-in",
|
|
1936
|
+
style: { background: "var(--bg-elevated)", borderColor: "var(--border-color)" },
|
|
1937
|
+
children: /* @__PURE__ */ jsx(
|
|
1938
|
+
SideExplorer,
|
|
1939
|
+
{
|
|
1940
|
+
selectedContact,
|
|
1941
|
+
onSelectContact: setSelectedContact
|
|
1942
|
+
}
|
|
1943
|
+
)
|
|
1944
|
+
}
|
|
1945
|
+
),
|
|
1946
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0 flex flex-col overflow-hidden", children: [
|
|
1947
|
+
activeTab === "chat" && /* @__PURE__ */ jsx(ChatTab, { selectedContact }),
|
|
1948
|
+
activeTab === "flow" && /* @__PURE__ */ jsx(FlowCanvasTab, {}),
|
|
1949
|
+
activeTab === "analytics" && /* @__PURE__ */ jsx(AnalyticsTab, {}),
|
|
1950
|
+
activeTab === "api_tester" && /* @__PURE__ */ jsx(ApiTesterTab, {}),
|
|
1951
|
+
activeTab === "templates" && /* @__PURE__ */ jsx(TemplateManagerTab, {})
|
|
1952
|
+
] }),
|
|
1953
|
+
inspectorOpen && /* @__PURE__ */ jsx(
|
|
1954
|
+
"div",
|
|
1955
|
+
{
|
|
1956
|
+
className: "w-72 shrink-0 flex flex-col border-l overflow-hidden animate-fade-in",
|
|
1957
|
+
style: { background: "var(--bg-elevated)", borderColor: "var(--border-color)" },
|
|
1958
|
+
children: /* @__PURE__ */ jsx(InspectorPanel, { selectedContact })
|
|
1959
|
+
}
|
|
1960
|
+
),
|
|
1961
|
+
agentOpen && /* @__PURE__ */ jsx(
|
|
1962
|
+
"div",
|
|
1963
|
+
{
|
|
1964
|
+
className: "w-80 shrink-0 flex flex-col border-l overflow-hidden animate-fade-in relative shadow-[-10px_0_30px_rgba(0,0,0,0.1)]",
|
|
1965
|
+
style: { background: "var(--bg-elevated)", borderColor: "var(--border-color)" },
|
|
1966
|
+
children: /* @__PURE__ */ jsx(AgentPanel, {})
|
|
1967
|
+
}
|
|
1968
|
+
)
|
|
1969
|
+
] }),
|
|
1970
|
+
/* @__PURE__ */ jsx(StatusBarMetrics, {}),
|
|
1971
|
+
cmdOpen && /* @__PURE__ */ jsxs(
|
|
1972
|
+
"div",
|
|
1973
|
+
{
|
|
1974
|
+
className: "absolute inset-0 z-50 flex items-start justify-center pt-[15%]",
|
|
1975
|
+
onClick: () => setCmdOpen(false),
|
|
1976
|
+
children: [
|
|
1977
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/40 backdrop-blur-sm" }),
|
|
1978
|
+
/* @__PURE__ */ jsxs(
|
|
1979
|
+
"div",
|
|
1980
|
+
{
|
|
1981
|
+
className: "relative w-[520px] max-h-[400px] rounded-xl overflow-hidden shadow-2xl border animate-scale-up",
|
|
1982
|
+
style: { background: "var(--bg-elevated)", borderColor: "var(--border-color)" },
|
|
1983
|
+
onClick: (e) => e.stopPropagation(),
|
|
1984
|
+
children: [
|
|
1985
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-4 py-3 border-b", style: { borderColor: "var(--border-color)" }, children: [
|
|
1986
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-search text-xs", style: { color: "var(--text-secondary)" } }),
|
|
1987
|
+
/* @__PURE__ */ jsx(
|
|
1988
|
+
"input",
|
|
1989
|
+
{
|
|
1990
|
+
ref: cmdInputRef,
|
|
1991
|
+
type: "text",
|
|
1992
|
+
placeholder: "Escribe un comando...",
|
|
1993
|
+
className: "flex-1 bg-transparent outline-none text-sm font-medium",
|
|
1994
|
+
style: { color: "var(--text-primary)" },
|
|
1995
|
+
value: cmdQuery,
|
|
1996
|
+
onChange: (e) => setCmdQuery(e.target.value)
|
|
1997
|
+
}
|
|
1998
|
+
),
|
|
1999
|
+
/* @__PURE__ */ jsx(
|
|
2000
|
+
"kbd",
|
|
2001
|
+
{
|
|
2002
|
+
className: "px-1.5 py-0.5 rounded text-[9px] font-mono",
|
|
2003
|
+
style: { background: "var(--bg-muted)", color: "var(--text-secondary)" },
|
|
2004
|
+
children: "ESC"
|
|
2005
|
+
}
|
|
2006
|
+
)
|
|
2007
|
+
] }),
|
|
2008
|
+
/* @__PURE__ */ jsxs("div", { className: "max-h-[320px] overflow-y-auto p-1", children: [
|
|
2009
|
+
filteredCommands.map((cmd, i) => /* @__PURE__ */ jsxs(
|
|
2010
|
+
"button",
|
|
2011
|
+
{
|
|
2012
|
+
onClick: () => runCommand(cmd),
|
|
2013
|
+
className: "w-full flex items-center gap-3 px-4 py-2.5 rounded-lg text-sm transition-all text-left",
|
|
2014
|
+
style: { color: "var(--text-primary)" },
|
|
2015
|
+
onMouseEnter: (e) => e.currentTarget.style.background = "var(--bg-muted)",
|
|
2016
|
+
onMouseLeave: (e) => e.currentTarget.style.background = "transparent",
|
|
2017
|
+
children: [
|
|
2018
|
+
/* @__PURE__ */ jsx("i", { className: `${cmd.icon} w-5 text-center text-xs`, style: { color: "var(--brand-primary)" } }),
|
|
2019
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: cmd.label })
|
|
2020
|
+
]
|
|
2021
|
+
},
|
|
2022
|
+
cmd.id
|
|
2023
|
+
)),
|
|
2024
|
+
filteredCommands.length === 0 && /* @__PURE__ */ jsxs("div", { className: "py-8 text-center text-xs", style: { color: "var(--text-secondary)" }, children: [
|
|
2025
|
+
/* @__PURE__ */ jsx("i", { className: "fas fa-search-minus text-lg mb-2 block opacity-30" }),
|
|
2026
|
+
"No se encontraron comandos"
|
|
2027
|
+
] })
|
|
2028
|
+
] })
|
|
2029
|
+
]
|
|
2030
|
+
}
|
|
2031
|
+
)
|
|
2032
|
+
]
|
|
2033
|
+
}
|
|
2034
|
+
)
|
|
2035
|
+
] });
|
|
2036
|
+
};
|
|
2037
|
+
|
|
2038
|
+
export { AgentPanel, AnalyticsTab, BotActionNode, ChatTab, DiscoveryStudio, FlowCanvasTab, InspectorPanel, MessageNode, SideExplorer };
|
|
2039
|
+
//# sourceMappingURL=index.mjs.map
|
|
2040
|
+
//# sourceMappingURL=index.mjs.map
|