@locdo.tech/botiq-chat-sdk 0.6.0 → 0.7.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/sdk/index.js +1 -1
- package/dist/sdk/{npm-DbbHOVFV.js → npm-ClWjnXje.js} +802 -274
- package/dist/sdk/react.js +1 -1
- package/dist/sdk/vue.js +1 -1
- package/package.json +1 -1
|
@@ -90,23 +90,24 @@ async function f(e, r) {
|
|
|
90
90
|
} catch {
|
|
91
91
|
return n;
|
|
92
92
|
}
|
|
93
|
-
let o = typeof a.name == "string" && a.name.length > 0 ? a.name : n.name, s = a.widgetLanguage === "en" ? "en" : "vi", c = Array.isArray(a.pageActions) ? a.pageActions : void 0, u = typeof a.contactInfo == "string" ? a.contactInfo : void 0, f = a.proactive && typeof a.proactive == "object" ? a.proactive : void 0, p = a.status === "offline" ? "offline" : a.status === "online" ? "online" : void 0
|
|
93
|
+
let o = typeof a.name == "string" && a.name.length > 0 ? a.name : n.name, s = a.widgetLanguage === "en" ? "en" : "vi", c = Array.isArray(a.pageActions) ? a.pageActions : void 0, u = typeof a.contactInfo == "string" ? a.contactInfo : void 0, f = a.proactive && typeof a.proactive == "object" ? a.proactive : void 0, p = a.status === "offline" ? "offline" : a.status === "online" ? "online" : void 0, m = a.imageInput === !0 ? !0 : void 0, h = a.richMessages === !0 ? !0 : void 0, g = {
|
|
94
|
+
...c ? { pageActions: c } : {},
|
|
95
|
+
...u ? { contactInfo: u } : {},
|
|
96
|
+
...f ? { proactive: f } : {},
|
|
97
|
+
...p ? { status: p } : {},
|
|
98
|
+
...m ? { imageInput: m } : {},
|
|
99
|
+
...h ? { richMessages: h } : {}
|
|
100
|
+
};
|
|
94
101
|
return !a.design?.colors || !a.design?.layout || !a.design?.content || !l(a.design) ? {
|
|
95
102
|
name: o,
|
|
96
103
|
design: t,
|
|
97
104
|
widgetLanguage: s,
|
|
98
|
-
...
|
|
99
|
-
...u ? { contactInfo: u } : {},
|
|
100
|
-
...f ? { proactive: f } : {},
|
|
101
|
-
...p ? { status: p } : {}
|
|
105
|
+
...g
|
|
102
106
|
} : {
|
|
103
107
|
name: o,
|
|
104
108
|
design: a.design,
|
|
105
109
|
widgetLanguage: s,
|
|
106
|
-
...
|
|
107
|
-
...u ? { contactInfo: u } : {},
|
|
108
|
-
...f ? { proactive: f } : {},
|
|
109
|
-
...p ? { status: p } : {}
|
|
110
|
+
...g
|
|
110
111
|
};
|
|
111
112
|
}
|
|
112
113
|
function p(t) {
|
|
@@ -223,7 +224,7 @@ var T = /^[a-z][a-z0-9_]{2,40}$/, E = new Set([
|
|
|
223
224
|
}();
|
|
224
225
|
//#endregion
|
|
225
226
|
//#region src/core/api.ts
|
|
226
|
-
async function
|
|
227
|
+
async function O(e, t, n) {
|
|
227
228
|
try {
|
|
228
229
|
let r = new URLSearchParams({ visitorId: n }), i = await fetch(`${e}/widget/conversations?${r.toString()}`, {
|
|
229
230
|
method: "GET",
|
|
@@ -240,9 +241,51 @@ async function ee(e, t, n) {
|
|
|
240
241
|
return [];
|
|
241
242
|
}
|
|
242
243
|
}
|
|
243
|
-
async function
|
|
244
|
+
async function k(e, t, n, r, i) {
|
|
245
|
+
let a = i?.imageUploadError ?? "Image upload failed. Please try again.";
|
|
246
|
+
try {
|
|
247
|
+
let o = new FormData(), s = n.type === "image/webp" ? ".webp" : ".jpg";
|
|
248
|
+
o.append("file", n, `image${s}`);
|
|
249
|
+
let c = await fetch(`${e}/widget/upload`, {
|
|
250
|
+
method: "POST",
|
|
251
|
+
headers: {
|
|
252
|
+
"X-Api-Key": t,
|
|
253
|
+
...r ? { "X-Visitor-Id": r } : {}
|
|
254
|
+
},
|
|
255
|
+
referrerPolicy: "no-referrer-when-downgrade",
|
|
256
|
+
body: o
|
|
257
|
+
});
|
|
258
|
+
if (!c.ok) return c.status === 403 ? {
|
|
259
|
+
ok: !1,
|
|
260
|
+
error: i?.imageUploadPlanError ?? a
|
|
261
|
+
} : c.status === 413 ? {
|
|
262
|
+
ok: !1,
|
|
263
|
+
error: i?.imageUploadTooLarge ?? a
|
|
264
|
+
} : c.status === 429 ? {
|
|
265
|
+
ok: !1,
|
|
266
|
+
error: i?.imageUploadRateLimit ?? a
|
|
267
|
+
} : {
|
|
268
|
+
ok: !1,
|
|
269
|
+
error: a
|
|
270
|
+
};
|
|
271
|
+
let l = await c.json();
|
|
272
|
+
return l.url ? {
|
|
273
|
+
ok: !0,
|
|
274
|
+
url: l.url
|
|
275
|
+
} : {
|
|
276
|
+
ok: !1,
|
|
277
|
+
error: a
|
|
278
|
+
};
|
|
279
|
+
} catch {
|
|
280
|
+
return {
|
|
281
|
+
ok: !1,
|
|
282
|
+
error: a
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
async function ee(e, t, n, r, i, a, o, s) {
|
|
244
287
|
try {
|
|
245
|
-
let
|
|
288
|
+
let c = D.getDefinitions(), l = await fetch(`${e}/widget/chat`, {
|
|
246
289
|
method: "POST",
|
|
247
290
|
headers: {
|
|
248
291
|
"Content-Type": "application/json",
|
|
@@ -254,26 +297,28 @@ async function te(e, t, n, r, i, a, o) {
|
|
|
254
297
|
sessionId: n,
|
|
255
298
|
message: r,
|
|
256
299
|
history: i,
|
|
257
|
-
...
|
|
300
|
+
...c.length > 0 ? { availableActions: c } : {},
|
|
301
|
+
...s?.length ? { attachments: s } : {}
|
|
258
302
|
})
|
|
259
303
|
});
|
|
260
|
-
if (!
|
|
304
|
+
if (!l.ok) return l.status === 401 ? {
|
|
261
305
|
reply: a.errorAuth,
|
|
262
306
|
error: !0
|
|
263
|
-
} :
|
|
307
|
+
} : l.status === 403 ? {
|
|
264
308
|
reply: a.errorForbidden,
|
|
265
309
|
error: !0
|
|
266
|
-
} :
|
|
310
|
+
} : l.status === 429 ? {
|
|
267
311
|
reply: a.errorQuota,
|
|
268
312
|
error: !0
|
|
269
313
|
} : {
|
|
270
314
|
reply: a.errorGeneric,
|
|
271
315
|
error: !0
|
|
272
316
|
};
|
|
273
|
-
let
|
|
317
|
+
let u = await l.json(), d = Array.isArray(u.blocks) && u.blocks.length > 0 ? u.blocks : void 0;
|
|
274
318
|
return {
|
|
275
|
-
reply:
|
|
276
|
-
pageAction:
|
|
319
|
+
reply: u.reply || a.errorMessage,
|
|
320
|
+
pageAction: u.pageAction,
|
|
321
|
+
blocks: d
|
|
277
322
|
};
|
|
278
323
|
} catch {
|
|
279
324
|
return {
|
|
@@ -282,16 +327,16 @@ async function te(e, t, n, r, i, a, o) {
|
|
|
282
327
|
};
|
|
283
328
|
}
|
|
284
329
|
}
|
|
285
|
-
var
|
|
330
|
+
var A = {
|
|
286
331
|
messages: [],
|
|
287
332
|
hasMore: !1
|
|
288
333
|
};
|
|
289
|
-
function
|
|
334
|
+
function te(e) {
|
|
290
335
|
if (!e || typeof e != "object") return !1;
|
|
291
336
|
let t = e;
|
|
292
337
|
return typeof t.id == "string" && (t.role === "user" || t.role === "assistant") && typeof t.content == "string";
|
|
293
338
|
}
|
|
294
|
-
async function
|
|
339
|
+
async function j(e, t, n, r, i, a) {
|
|
295
340
|
try {
|
|
296
341
|
let o = new URLSearchParams({
|
|
297
342
|
sessionId: n,
|
|
@@ -306,26 +351,26 @@ async function A(e, t, n, r, i, a) {
|
|
|
306
351
|
},
|
|
307
352
|
referrerPolicy: "no-referrer-when-downgrade"
|
|
308
353
|
});
|
|
309
|
-
if (!s.ok) return
|
|
354
|
+
if (!s.ok) return A;
|
|
310
355
|
let c = await s.json();
|
|
311
356
|
return {
|
|
312
|
-
messages: Array.isArray(c.messages) ? c.messages.filter(
|
|
357
|
+
messages: Array.isArray(c.messages) ? c.messages.filter(te) : [],
|
|
313
358
|
hasMore: c.hasMore === !0,
|
|
314
359
|
escalated: c.escalated === !0
|
|
315
360
|
};
|
|
316
361
|
} catch {
|
|
317
|
-
return
|
|
362
|
+
return A;
|
|
318
363
|
}
|
|
319
364
|
}
|
|
320
|
-
function
|
|
321
|
-
return
|
|
365
|
+
function M(e, t, n, r, i) {
|
|
366
|
+
return j(e, t, n, void 0, r, i);
|
|
322
367
|
}
|
|
323
368
|
function ne(e, t, n, r, i, a) {
|
|
324
|
-
return
|
|
369
|
+
return j(e, t, n, r, i, a);
|
|
325
370
|
}
|
|
326
371
|
//#endregion
|
|
327
372
|
//#region src/core/state.ts
|
|
328
|
-
var
|
|
373
|
+
var N = {
|
|
329
374
|
messages: [],
|
|
330
375
|
isLoading: !1,
|
|
331
376
|
isOpen: !1,
|
|
@@ -334,26 +379,107 @@ var M = {
|
|
|
334
379
|
unreadCount: 0,
|
|
335
380
|
conversations: [],
|
|
336
381
|
currentSessionId: "",
|
|
337
|
-
escalated: !1
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}
|
|
342
|
-
function F(
|
|
343
|
-
|
|
382
|
+
escalated: !1,
|
|
383
|
+
pendingAttachment: null,
|
|
384
|
+
isUploading: !1,
|
|
385
|
+
uploadError: null
|
|
386
|
+
}, P = /* @__PURE__ */ new Set();
|
|
387
|
+
function F() {
|
|
388
|
+
return N;
|
|
389
|
+
}
|
|
390
|
+
function I(e) {
|
|
391
|
+
Object.assign(N, e);
|
|
344
392
|
let t = {
|
|
345
|
-
...
|
|
346
|
-
messages: [...
|
|
347
|
-
conversations: [...
|
|
393
|
+
...N,
|
|
394
|
+
messages: [...N.messages],
|
|
395
|
+
conversations: [...N.conversations]
|
|
348
396
|
};
|
|
349
|
-
|
|
397
|
+
P.forEach((e) => e(t));
|
|
350
398
|
}
|
|
351
399
|
function re(e) {
|
|
352
|
-
return
|
|
400
|
+
return P.add(e), () => P.delete(e);
|
|
401
|
+
}
|
|
402
|
+
//#endregion
|
|
403
|
+
//#region src/core/upload.ts
|
|
404
|
+
var L = new Set([
|
|
405
|
+
"image/jpeg",
|
|
406
|
+
"image/png",
|
|
407
|
+
"image/webp"
|
|
408
|
+
]), R = 25 * 1024 * 1024, z = 5 * 1024 * 1024, B = 1600, ie = .85, ae = .65;
|
|
409
|
+
function oe(e) {
|
|
410
|
+
return L.has(e);
|
|
411
|
+
}
|
|
412
|
+
function se(e) {
|
|
413
|
+
return oe(e.type) ? e.size > R ? {
|
|
414
|
+
ok: !1,
|
|
415
|
+
error: "Image too large (max 25 MB before compression)."
|
|
416
|
+
} : { ok: !0 } : {
|
|
417
|
+
ok: !1,
|
|
418
|
+
error: "Unsupported image type. Please use JPEG, PNG, or WebP."
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
function ce(e, t) {
|
|
422
|
+
let n = Math.max(e, t);
|
|
423
|
+
if (n <= B) return {
|
|
424
|
+
width: e,
|
|
425
|
+
height: t
|
|
426
|
+
};
|
|
427
|
+
let r = B / n;
|
|
428
|
+
return {
|
|
429
|
+
width: Math.floor(e * r),
|
|
430
|
+
height: Math.floor(t * r)
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
function le(e) {
|
|
434
|
+
let t = se(e);
|
|
435
|
+
return t.ok ? new Promise((t, n) => {
|
|
436
|
+
let r = new Image(), i = URL.createObjectURL(e);
|
|
437
|
+
r.onload = () => {
|
|
438
|
+
URL.revokeObjectURL(i);
|
|
439
|
+
let { width: a, height: o } = ce(r.naturalWidth, r.naturalHeight), s = document.createElement("canvas");
|
|
440
|
+
s.width = a, s.height = o;
|
|
441
|
+
let c = s.getContext("2d");
|
|
442
|
+
if (!c) {
|
|
443
|
+
n(/* @__PURE__ */ Error("Canvas 2D context not available"));
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
c.drawImage(r, 0, 0, a, o);
|
|
447
|
+
let l = e.type === "image/webp" ? "image/webp" : "image/jpeg";
|
|
448
|
+
s.toBlob((e) => {
|
|
449
|
+
if (!e) {
|
|
450
|
+
n(/* @__PURE__ */ Error("Canvas toBlob returned null"));
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
if (e.size <= z) {
|
|
454
|
+
t({
|
|
455
|
+
blob: e,
|
|
456
|
+
mimeType: l
|
|
457
|
+
});
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
s.toBlob((e) => {
|
|
461
|
+
if (!e) {
|
|
462
|
+
n(/* @__PURE__ */ Error("Canvas toBlob (fallback quality) returned null"));
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
if (e.size > z) {
|
|
466
|
+
n(/* @__PURE__ */ Error("Image too large after compression (> 5 MB). Try a smaller image."));
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
t({
|
|
470
|
+
blob: e,
|
|
471
|
+
mimeType: l
|
|
472
|
+
});
|
|
473
|
+
}, l, ae);
|
|
474
|
+
}, l, ie);
|
|
475
|
+
}, r.onerror = () => {
|
|
476
|
+
URL.revokeObjectURL(i), n(/* @__PURE__ */ Error("Failed to load image"));
|
|
477
|
+
}, r.src = i;
|
|
478
|
+
}) : Promise.reject(Error(t.error));
|
|
353
479
|
}
|
|
354
480
|
//#endregion
|
|
355
481
|
//#region src/core/styles.ts
|
|
356
|
-
var
|
|
482
|
+
var V = {
|
|
357
483
|
inter: {
|
|
358
484
|
url: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap",
|
|
359
485
|
family: "'Inter', system-ui, -apple-system, sans-serif"
|
|
@@ -375,21 +501,21 @@ var I = {
|
|
|
375
501
|
family: "'Playfair Display', Georgia, serif"
|
|
376
502
|
}
|
|
377
503
|
};
|
|
378
|
-
function
|
|
504
|
+
function H(e, t) {
|
|
379
505
|
if (!t) return e;
|
|
380
506
|
let n = t.angle ?? 135;
|
|
381
507
|
return t.type === "linear" ? `linear-gradient(${n}deg, ${t.from}, ${t.to})` : `radial-gradient(circle, ${t.from}, ${t.to})`;
|
|
382
508
|
}
|
|
383
|
-
function
|
|
509
|
+
function ue(e) {
|
|
384
510
|
return e.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\\[0-9a-fA-F]{1,6}\s?/g, "x").replace(/@import\b[^;]*;?/gi, "").replace(/url\s*\(\s*["']?\s*(?!data:)[^)]*["']?\s*\)/gi, "url(\"\")").replace(/expression\s*\(/gi, "expression_(").replace(/javascript\s*:/gi, "blocked:").replace(/-moz-binding\s*:/gi, "").replace(/\bbehavior\s*:/gi, "");
|
|
385
511
|
}
|
|
386
|
-
function
|
|
512
|
+
function de(e) {
|
|
387
513
|
let t = e?.bubbleOpen ?? "none", n = e?.typingIndicator ?? "dots-bounce";
|
|
388
514
|
return [t === "fade" ? "@keyframes biq-open-fade { from { opacity: 0; } to { opacity: 1; } }\n.chat-window.open { animation: biq-open-fade .22s ease forwards; }" : t === "slide-up" ? "@keyframes biq-open-slide { from { opacity: 0; transform: scale(1) translateY(20px); } to { opacity: 1; transform: scale(1) translateY(0); } }\n.chat-window.open { animation: biq-open-slide .25s cubic-bezier(.22,1,.36,1) forwards; }" : t === "bounce" ? "@keyframes biq-open-bounce { 0% { opacity: 0; transform: scale(.85) translateY(8px); } 60% { transform: scale(1.03) translateY(-3px); } 100% { opacity: 1; transform: scale(1) translateY(0); } }\n.chat-window.open { animation: biq-open-bounce .35s cubic-bezier(.34,1.56,.64,1) forwards; }" : "", n === "dots-pulse" ? "@keyframes biq-pulse { 0%, 100% { opacity: 0.3; transform: scale(1); } 50% { opacity: 1; transform: scale(1.3); } }\n.typing span { animation: biq-pulse 1.2s infinite ease-in-out; }" : n === "bar" ? ".typing { gap: 3px; align-items: flex-end; }\n.typing span { width: 3px; height: 14px; border-radius: 2px; animation: biq-bar 1s infinite ease-in-out; }\n.typing span:nth-child(1) { animation-delay: 0s; }\n.typing span:nth-child(2) { animation-delay: .15s; height: 20px; }\n.typing span:nth-child(3) { animation-delay: .3s; }\n@keyframes biq-bar { 0%, 100% { transform: scaleY(.4); opacity: .5; } 50% { transform: scaleY(1); opacity: 1; } }" : ""].filter(Boolean).join("\n");
|
|
389
515
|
}
|
|
390
|
-
var
|
|
391
|
-
function
|
|
392
|
-
let { colors: t, layout: n, font: r, gradient: i, animation: a, customCSS: o, whiteLabel: s } = e, c =
|
|
516
|
+
var fe = "\n/* ── Rich Blocks ─────────────────────────── */\n.biq-blocks {\n margin-top: 8px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n max-width: 100%;\n}\n\n/* ── Shared button style ─────────────────── */\n.biq-btn {\n display: inline-block;\n padding: 7px 14px;\n border-radius: 18px;\n font: inherit;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: filter .15s, opacity .15s;\n text-decoration: none;\n border: 1.5px solid #F97316;\n background: transparent;\n color: #F97316;\n line-height: 1.3;\n white-space: nowrap;\n}\n.biq-btn:hover { filter: brightness(1.15); }\n.biq-btn--send { background: #F97316; color: #fff; }\n.biq-btn--send:hover { filter: brightness(0.9); }\n.biq-btn--url { background: transparent; color: #F97316; }\n.biq-btn--page_action { border-style: dashed; }\n\n/* ── Card ────────────────────────────────── */\n.biq-card {\n background: #1A1A1A;\n border: 1px solid #2D2D2D;\n border-radius: 12px;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n min-width: 0;\n text-decoration: none;\n color: inherit;\n transition: border-color .15s;\n}\n.biq-card--link:hover { border-color: #F97316; }\n\n.biq-card-img {\n width: 100%;\n max-height: 160px;\n object-fit: cover;\n display: block;\n}\n\n.biq-card-title {\n font-size: 14px;\n font-weight: 600;\n color: #fff;\n padding: 10px 12px 2px;\n line-height: 1.3;\n}\n\n.biq-card-subtitle {\n font-size: 12px;\n color: #9CA3AF;\n padding: 0 12px 6px;\n line-height: 1.4;\n}\n\n.biq-card-price {\n font-size: 14px;\n font-weight: 600;\n color: #F97316;\n padding: 4px 12px 8px;\n}\n\n.biq-card-btns {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 0 10px 10px;\n}\n\n/* ── Carousel ────────────────────────────── */\n.biq-carousel {\n display: flex;\n flex-direction: row;\n gap: 10px;\n overflow-x: auto;\n padding-bottom: 4px;\n scrollbar-width: thin;\n scrollbar-color: #2D2D2D transparent;\n /* Snap cards into position on scroll */\n scroll-snap-type: x mandatory;\n}\n.biq-carousel::-webkit-scrollbar { height: 4px; }\n.biq-carousel::-webkit-scrollbar-track { background: transparent; }\n.biq-carousel::-webkit-scrollbar-thumb { background: #2D2D2D; border-radius: 2px; }\n\n.biq-carousel .biq-card {\n flex: 0 0 200px;\n scroll-snap-align: start;\n max-width: 200px;\n}\n\n/* ── Quick Replies ───────────────────────── */\n.biq-quick-replies {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 4px;\n}\n\n.biq-qr-pill {\n padding: 5px 14px;\n border-radius: 20px;\n border: 1.5px solid #F97316;\n background: transparent;\n color: #F97316;\n font: inherit;\n font-size: 13px;\n cursor: pointer;\n transition: background .15s, color .15s;\n white-space: nowrap;\n}\n.biq-qr-pill:hover { background: #F97316; color: #fff; }\n\n/* ── Buttons block ───────────────────────── */\n.biq-buttons {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 4px;\n}\n", pe = "\n.botiq-confirm-overlay { position:absolute; inset:0; background:rgba(0,0,0,.7);\n display:flex; align-items:center; justify-content:center; z-index:999; }\n.botiq-confirm-dialog { background:#1A1A1A; border:1px solid #2D2D2D; border-radius:12px;\n padding:16px; max-width:320px; color:#fff; font-size:14px; }\n.botiq-confirm-header { font-weight:600; margin-bottom:8px; }\n.botiq-confirm-reason { color:#9CA3AF; margin-bottom:8px; }\n.botiq-confirm-params { background:#0a0a0a; padding:8px; border-radius:6px; font-size:12px;\n max-height:120px; overflow:auto; white-space:pre-wrap; }\n.botiq-confirm-actions { display:flex; gap:8px; margin-top:12px; }\n.botiq-confirm-yes { flex:1; padding:8px 12px; border-radius:6px; border:none;\n background:#F97316; color:#fff; cursor:pointer; }\n.botiq-confirm-yes[data-risk=\"high\"] { background:#DC2626; }\n.botiq-confirm-no { flex:1; padding:8px 12px; border-radius:6px; background:transparent;\n border:1px solid #2D2D2D; color:#fff; cursor:pointer; }\n.botiq-confirm-countdown { margin-top:8px; font-size:12px; color:#9CA3AF; }\n";
|
|
517
|
+
function me(e) {
|
|
518
|
+
let { colors: t, layout: n, font: r, gradient: i, animation: a, customCSS: o, whiteLabel: s } = e, c = V[r] ?? V.inter, l = n.buttonShape === "square" ? "14px" : "50%", u = n.position === "bottom-left" ? "right: auto; left: 24px;" : "right: 24px;", d = n.position === "bottom-left" ? "bottom left" : "bottom right", f = n.position === "bottom-left" ? "right: auto; left: 0;" : "right: 0;", p = n.fillHeight ? `min(${n.height}px, calc(100dvh - 48px))` : `${n.height}px`, m = H(t.primary, i), h = H(t.header, i), g = H(t.userBubble, i), _ = s ? ".botiq-badge { display: none !important; }" : "";
|
|
393
519
|
return `
|
|
394
520
|
@import url('${c.url}');
|
|
395
521
|
|
|
@@ -577,10 +703,11 @@ function oe(e) {
|
|
|
577
703
|
.msg-list { flex: 1; overflow-y: auto; }
|
|
578
704
|
|
|
579
705
|
.msg-list-item {
|
|
580
|
-
display:
|
|
706
|
+
display: flex;
|
|
707
|
+
align-items: flex-start;
|
|
708
|
+
gap: 10px;
|
|
581
709
|
width: 100%;
|
|
582
710
|
text-align: left;
|
|
583
|
-
gap: 2px;
|
|
584
711
|
padding: 12px 16px;
|
|
585
712
|
background: transparent;
|
|
586
713
|
border: none;
|
|
@@ -591,6 +718,26 @@ function oe(e) {
|
|
|
591
718
|
|
|
592
719
|
.msg-list-item:hover { background: var(--gray-50); }
|
|
593
720
|
|
|
721
|
+
.msg-list-avatar {
|
|
722
|
+
flex-shrink: 0;
|
|
723
|
+
width: 36px;
|
|
724
|
+
height: 36px;
|
|
725
|
+
border-radius: 50%;
|
|
726
|
+
overflow: hidden;
|
|
727
|
+
background: var(--color-primary);
|
|
728
|
+
display: flex;
|
|
729
|
+
align-items: center;
|
|
730
|
+
justify-content: center;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
.msg-list-body {
|
|
734
|
+
flex: 1;
|
|
735
|
+
min-width: 0;
|
|
736
|
+
display: flex;
|
|
737
|
+
flex-direction: column;
|
|
738
|
+
gap: 2px;
|
|
739
|
+
}
|
|
740
|
+
|
|
594
741
|
.msg-list-title {
|
|
595
742
|
color: var(--color-text);
|
|
596
743
|
font-weight: 600;
|
|
@@ -607,7 +754,7 @@ function oe(e) {
|
|
|
607
754
|
|
|
608
755
|
.msg-list-time { color: var(--gray-400); font-size: 10px; }
|
|
609
756
|
|
|
610
|
-
.msg-list-badge { color:
|
|
757
|
+
.msg-list-badge { color: var(--color-primary); font-size: 10px; }
|
|
611
758
|
|
|
612
759
|
.msg-list-empty {
|
|
613
760
|
padding: 24px;
|
|
@@ -642,22 +789,82 @@ function oe(e) {
|
|
|
642
789
|
margin: 8px 18px;
|
|
643
790
|
padding: 14px;
|
|
644
791
|
border-radius: 12px;
|
|
645
|
-
border:
|
|
646
|
-
background:
|
|
647
|
-
color: var(--color-
|
|
792
|
+
border: 1.5px solid var(--color-primary);
|
|
793
|
+
background: transparent;
|
|
794
|
+
color: var(--color-primary);
|
|
648
795
|
text-align: left;
|
|
649
796
|
cursor: pointer;
|
|
650
797
|
font: inherit;
|
|
651
798
|
font-size: 14px;
|
|
652
|
-
|
|
799
|
+
font-weight: 500;
|
|
800
|
+
transition: background .15s, color .15s;
|
|
653
801
|
}
|
|
654
802
|
|
|
655
|
-
.home-start:hover { background: var(--
|
|
803
|
+
.home-start:hover { background: var(--color-primary); color: #fff; }
|
|
656
804
|
|
|
657
805
|
.home-status { margin: 8px 18px; font-size: 12px; }
|
|
658
806
|
.home-status--online { color: #16A34A; }
|
|
659
807
|
.home-status--offline { color: var(--gray-400); }
|
|
660
808
|
|
|
809
|
+
/* ── Home recent conversations ──────────────── */
|
|
810
|
+
.home-recent-label {
|
|
811
|
+
margin: 16px 18px 6px;
|
|
812
|
+
font-size: 11px;
|
|
813
|
+
font-weight: 600;
|
|
814
|
+
text-transform: uppercase;
|
|
815
|
+
letter-spacing: .06em;
|
|
816
|
+
color: var(--gray-400);
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
.home-recent-item {
|
|
820
|
+
display: flex;
|
|
821
|
+
align-items: center;
|
|
822
|
+
gap: 10px;
|
|
823
|
+
width: 100%;
|
|
824
|
+
padding: 10px 18px;
|
|
825
|
+
background: transparent;
|
|
826
|
+
border: none;
|
|
827
|
+
border-bottom: 1px solid var(--gray-100);
|
|
828
|
+
cursor: pointer;
|
|
829
|
+
font: inherit;
|
|
830
|
+
text-align: left;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
.home-recent-item:hover { background: var(--gray-50); }
|
|
834
|
+
|
|
835
|
+
.home-recent-avatar {
|
|
836
|
+
flex-shrink: 0;
|
|
837
|
+
width: 32px;
|
|
838
|
+
height: 32px;
|
|
839
|
+
border-radius: 50%;
|
|
840
|
+
overflow: hidden;
|
|
841
|
+
background: var(--color-primary);
|
|
842
|
+
display: flex;
|
|
843
|
+
align-items: center;
|
|
844
|
+
justify-content: center;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
.home-recent-body { flex: 1; min-width: 0; }
|
|
848
|
+
|
|
849
|
+
.home-recent-title {
|
|
850
|
+
color: var(--color-text);
|
|
851
|
+
font-size: 13px;
|
|
852
|
+
font-weight: 500;
|
|
853
|
+
white-space: nowrap;
|
|
854
|
+
overflow: hidden;
|
|
855
|
+
text-overflow: ellipsis;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
.home-recent-preview {
|
|
859
|
+
color: var(--gray-400);
|
|
860
|
+
font-size: 12px;
|
|
861
|
+
white-space: nowrap;
|
|
862
|
+
overflow: hidden;
|
|
863
|
+
text-overflow: ellipsis;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
.home-recent-time { color: var(--gray-400); font-size: 10px; flex-shrink: 0; }
|
|
867
|
+
|
|
661
868
|
/* ── Messages ───────────────────────────── */
|
|
662
869
|
.messages {
|
|
663
870
|
flex: 1;
|
|
@@ -957,6 +1164,72 @@ function oe(e) {
|
|
|
957
1164
|
.send-btn:disabled { background: var(--gray-200); cursor: not-allowed; filter: none; }
|
|
958
1165
|
.send-btn svg { width: 18px; height: 18px; fill: #fff; }
|
|
959
1166
|
|
|
1167
|
+
/* ── Attach Button ──────────────────────── */
|
|
1168
|
+
.attach-btn {
|
|
1169
|
+
width: 34px; height: 38px;
|
|
1170
|
+
background: transparent; border: none; cursor: pointer;
|
|
1171
|
+
color: var(--gray-400); flex-shrink: 0;
|
|
1172
|
+
display: flex; align-items: center; justify-content: center;
|
|
1173
|
+
border-radius: 8px; transition: color .15s, background .15s;
|
|
1174
|
+
}
|
|
1175
|
+
.attach-btn:hover { color: var(--color-primary); background: rgba(249,115,22,.08); }
|
|
1176
|
+
.attach-btn svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
|
|
1177
|
+
|
|
1178
|
+
/* ── Attach Preview Slot ────────────────── */
|
|
1179
|
+
.attach-preview-slot {
|
|
1180
|
+
margin-bottom: 6px;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
.attach-preview {
|
|
1184
|
+
display: flex;
|
|
1185
|
+
align-items: center;
|
|
1186
|
+
gap: 8px;
|
|
1187
|
+
padding: 6px 8px;
|
|
1188
|
+
background: var(--gray-50);
|
|
1189
|
+
border: 1px solid var(--gray-200);
|
|
1190
|
+
border-radius: 10px;
|
|
1191
|
+
position: relative;
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
.attach-preview-img {
|
|
1195
|
+
width: 48px;
|
|
1196
|
+
height: 48px;
|
|
1197
|
+
object-fit: cover;
|
|
1198
|
+
border-radius: 6px;
|
|
1199
|
+
flex-shrink: 0;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
.attach-preview-img--uploading {
|
|
1203
|
+
opacity: 0.5;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
.attach-preview-status {
|
|
1207
|
+
font-size: 12px;
|
|
1208
|
+
color: var(--gray-400);
|
|
1209
|
+
flex: 1;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
.attach-preview-error {
|
|
1213
|
+
font-size: 12px;
|
|
1214
|
+
color: #DC2626;
|
|
1215
|
+
flex: 1;
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
.attach-preview-remove {
|
|
1219
|
+
width: 22px; height: 22px;
|
|
1220
|
+
border-radius: 50%;
|
|
1221
|
+
background: var(--gray-200);
|
|
1222
|
+
border: none;
|
|
1223
|
+
cursor: pointer;
|
|
1224
|
+
color: var(--color-text);
|
|
1225
|
+
font-size: 14px;
|
|
1226
|
+
line-height: 1;
|
|
1227
|
+
display: flex; align-items: center; justify-content: center;
|
|
1228
|
+
flex-shrink: 0;
|
|
1229
|
+
transition: background .15s;
|
|
1230
|
+
}
|
|
1231
|
+
.attach-preview-remove:hover { background: #DC2626; color: #fff; }
|
|
1232
|
+
|
|
960
1233
|
.emoji-btn {
|
|
961
1234
|
width: 34px; height: 38px;
|
|
962
1235
|
background: transparent; border: none; cursor: pointer;
|
|
@@ -978,9 +1251,10 @@ function oe(e) {
|
|
|
978
1251
|
.emoji-item:hover { background: var(--gray-100); }
|
|
979
1252
|
|
|
980
1253
|
${_}
|
|
981
|
-
${
|
|
982
|
-
${o ?
|
|
983
|
-
${
|
|
1254
|
+
${de(a)}
|
|
1255
|
+
${o ? ue(o) : ""}
|
|
1256
|
+
${pe}
|
|
1257
|
+
${fe}
|
|
984
1258
|
@media (max-width: 480px) {
|
|
985
1259
|
:host { bottom: 0; right: 0; left: 0; }
|
|
986
1260
|
.chat-window {
|
|
@@ -997,18 +1271,18 @@ ${ae}
|
|
|
997
1271
|
}
|
|
998
1272
|
//#endregion
|
|
999
1273
|
//#region src/core/timeago.ts
|
|
1000
|
-
function
|
|
1274
|
+
function U(e) {
|
|
1001
1275
|
return String(e).padStart(2, "0");
|
|
1002
1276
|
}
|
|
1003
|
-
function
|
|
1277
|
+
function W(e, t, n) {
|
|
1004
1278
|
let r = Math.max(0, Math.floor((t - e) / 1e3));
|
|
1005
1279
|
if (r < 60) return n === "vi" ? "vừa xong" : "just now";
|
|
1006
1280
|
let i = Math.floor(r / 60);
|
|
1007
1281
|
if (i < 60) return n === "vi" ? `${i} phút` : `${i} min`;
|
|
1008
1282
|
let a = new Date(e);
|
|
1009
|
-
return `${
|
|
1283
|
+
return `${U(a.getHours())}:${U(a.getMinutes())}`;
|
|
1010
1284
|
}
|
|
1011
|
-
function
|
|
1285
|
+
function he(e, t, n) {
|
|
1012
1286
|
let r = (e) => {
|
|
1013
1287
|
let t = new Date(e);
|
|
1014
1288
|
return new Date(t.getFullYear(), t.getMonth(), t.getDate()).getTime();
|
|
@@ -1016,85 +1290,103 @@ function se(e, t, n) {
|
|
|
1016
1290
|
if (i <= 0) return n === "vi" ? "Hôm nay" : "Today";
|
|
1017
1291
|
if (i === 1) return n === "vi" ? "Hôm qua" : "Yesterday";
|
|
1018
1292
|
let a = new Date(e);
|
|
1019
|
-
return `${
|
|
1293
|
+
return `${U(a.getDate())}/${U(a.getMonth() + 1)}/${a.getFullYear()}`;
|
|
1020
1294
|
}
|
|
1021
1295
|
//#endregion
|
|
1022
1296
|
//#region src/core/views.ts
|
|
1023
|
-
function
|
|
1297
|
+
function G(e) {
|
|
1024
1298
|
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1025
1299
|
}
|
|
1026
|
-
function
|
|
1027
|
-
let
|
|
1028
|
-
return e.length === 0 ? `<div class="msg-list-empty">${
|
|
1029
|
-
let
|
|
1030
|
-
return `<button class="msg-list-item" type="button" data-session="${
|
|
1031
|
-
|
|
1032
|
-
<
|
|
1033
|
-
|
|
1300
|
+
function ge(e, t, n, r = "") {
|
|
1301
|
+
let i = `<button class="msg-list-new" type="button">+ ${G(t.newConversation)}</button>`;
|
|
1302
|
+
return e.length === 0 ? `<div class="msg-list-empty">${G(t.noConversations)}</div>${i}` : `<div class="msg-list">${e.map((e) => {
|
|
1303
|
+
let i = e.lastMessageAt ? Date.parse(e.lastMessageAt) : n, a = Number.isFinite(i) ? W(i, n, "vi") : "", o = e.escalated ? `<span class="msg-list-badge">${G(t.waitingForHuman)}</span>` : "";
|
|
1304
|
+
return `<button class="msg-list-item" type="button" data-session="${G(e.sessionId)}">
|
|
1305
|
+
${r ? `<div class="msg-list-avatar">${r}</div>` : ""}
|
|
1306
|
+
<div class="msg-list-body">
|
|
1307
|
+
<span class="msg-list-title">${G(e.title)}</span>
|
|
1308
|
+
<span class="msg-list-preview">${G(e.preview)}</span>
|
|
1309
|
+
<span class="msg-list-time">${G(a)}</span>${o}
|
|
1310
|
+
</div>
|
|
1034
1311
|
</button>`;
|
|
1035
|
-
}).join("")}</div>${
|
|
1036
|
-
}
|
|
1037
|
-
function
|
|
1038
|
-
let
|
|
1312
|
+
}).join("")}</div>${i}`;
|
|
1313
|
+
}
|
|
1314
|
+
function _e(e, t, n = [], r = "", i = Date.now()) {
|
|
1315
|
+
let a = e.status !== "offline", o = a ? t.statusOnline : t.statusPaused, s = G(e.design.content.greeting || t.homeGreeting), c = "";
|
|
1316
|
+
if (n.length > 0) {
|
|
1317
|
+
let e = n.slice(0, 3).map((e) => {
|
|
1318
|
+
let t = e.lastMessageAt ? Date.parse(e.lastMessageAt) : i, n = Number.isFinite(t) ? W(t, i, "vi") : "";
|
|
1319
|
+
return `<button class="home-recent-item" type="button" data-session="${G(e.sessionId)}">
|
|
1320
|
+
${r ? `<div class="home-recent-avatar">${r}</div>` : ""}
|
|
1321
|
+
<div class="home-recent-body">
|
|
1322
|
+
<div class="home-recent-title">${G(e.title)}</div>
|
|
1323
|
+
<div class="home-recent-preview">${G(e.preview)}</div>
|
|
1324
|
+
</div>
|
|
1325
|
+
<span class="home-recent-time">${G(n)}</span>
|
|
1326
|
+
</button>`;
|
|
1327
|
+
}).join("");
|
|
1328
|
+
c = `<div class="home-recent-label">${G(t.recentMessages)}</div>${e}`;
|
|
1329
|
+
}
|
|
1039
1330
|
return `
|
|
1040
|
-
<div class="home-greeting">${
|
|
1041
|
-
<button class="home-start" type="button">${
|
|
1042
|
-
|
|
1331
|
+
<div class="home-greeting">${s}</div>
|
|
1332
|
+
<button class="home-start" type="button">${G(t.startConversation)} ›</button>
|
|
1333
|
+
${c}
|
|
1334
|
+
<div class="home-status home-status--${a ? "online" : "offline"}">● ${G(o)}</div>
|
|
1043
1335
|
`;
|
|
1044
1336
|
}
|
|
1045
1337
|
//#endregion
|
|
1046
1338
|
//#region src/core/assets.ts
|
|
1047
|
-
var
|
|
1339
|
+
var ve = "data:image/png;base64,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";
|
|
1048
1340
|
//#endregion
|
|
1049
1341
|
//#region src/core/history-pager.ts
|
|
1050
|
-
function
|
|
1342
|
+
function K() {
|
|
1051
1343
|
return {
|
|
1052
1344
|
oldestCursor: null,
|
|
1053
1345
|
hasMore: !1,
|
|
1054
1346
|
cursorReady: !1
|
|
1055
1347
|
};
|
|
1056
1348
|
}
|
|
1057
|
-
function
|
|
1349
|
+
function ye(e) {
|
|
1058
1350
|
return {
|
|
1059
1351
|
oldestCursor: e.messages[0]?.id ?? null,
|
|
1060
1352
|
hasMore: e.hasMore,
|
|
1061
1353
|
cursorReady: e.messages.length > 0
|
|
1062
1354
|
};
|
|
1063
1355
|
}
|
|
1064
|
-
function
|
|
1356
|
+
function be(e, t) {
|
|
1065
1357
|
return {
|
|
1066
1358
|
oldestCursor: t.messages[0]?.id ?? e.oldestCursor,
|
|
1067
1359
|
hasMore: t.hasMore,
|
|
1068
1360
|
cursorReady: e.cursorReady
|
|
1069
1361
|
};
|
|
1070
1362
|
}
|
|
1071
|
-
function
|
|
1363
|
+
function xe(e, t) {
|
|
1072
1364
|
return e.cursorReady && e.hasMore && !t && e.oldestCursor !== null;
|
|
1073
1365
|
}
|
|
1074
|
-
function
|
|
1366
|
+
function Se(e, t, n) {
|
|
1075
1367
|
return e + (n - t);
|
|
1076
1368
|
}
|
|
1077
1369
|
//#endregion
|
|
1078
1370
|
//#region src/core/confirm-dialog.ts
|
|
1079
|
-
function
|
|
1371
|
+
function q(e) {
|
|
1080
1372
|
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1081
1373
|
}
|
|
1082
|
-
function
|
|
1374
|
+
function Ce(e, t) {
|
|
1083
1375
|
let n = t.labels?.confirm ?? "Đồng ý", r = t.labels?.cancel ?? "Huỷ", i = t.labels?.countdownPrefix ?? "Tự động xác nhận sau ", a = t.labels?.countdownSuffix ?? "s…";
|
|
1084
1376
|
return new Promise((o) => {
|
|
1085
1377
|
let s = document.createElement("div");
|
|
1086
1378
|
s.className = "botiq-confirm-overlay", s.innerHTML = `
|
|
1087
1379
|
<div class="botiq-confirm-dialog" role="dialog" aria-modal="true">
|
|
1088
|
-
<div class="botiq-confirm-header">${
|
|
1380
|
+
<div class="botiq-confirm-header">${q(t.title)}</div>
|
|
1089
1381
|
<div class="botiq-confirm-body">
|
|
1090
|
-
<div class="botiq-confirm-reason">${
|
|
1091
|
-
<pre class="botiq-confirm-params">${
|
|
1382
|
+
<div class="botiq-confirm-reason">${q(t.reason)}</div>
|
|
1383
|
+
<pre class="botiq-confirm-params">${q(t.paramsDisplay)}</pre>
|
|
1092
1384
|
</div>
|
|
1093
1385
|
<div class="botiq-confirm-actions">
|
|
1094
|
-
<button class="botiq-confirm-yes" data-risk="${t.riskLevel}" type="button">${
|
|
1095
|
-
<button class="botiq-confirm-no" type="button">${
|
|
1386
|
+
<button class="botiq-confirm-yes" data-risk="${t.riskLevel}" type="button">${q(n)}</button>
|
|
1387
|
+
<button class="botiq-confirm-no" type="button">${q(r)}</button>
|
|
1096
1388
|
</div>
|
|
1097
|
-
${t.autoConfirmAfterSec ? `<div class="botiq-confirm-countdown">${
|
|
1389
|
+
${t.autoConfirmAfterSec ? `<div class="botiq-confirm-countdown">${q(i)}<span class="botiq-confirm-secs">${t.autoConfirmAfterSec}</span>${q(a)}</div>` : ""}
|
|
1098
1390
|
</div>`, e.appendChild(s);
|
|
1099
1391
|
let c = !1, l = null, u = (t) => {
|
|
1100
1392
|
c || (c = !0, l && clearInterval(l), e.removeChild(s), o(t));
|
|
@@ -1109,15 +1401,15 @@ function me(e, t) {
|
|
|
1109
1401
|
}
|
|
1110
1402
|
//#endregion
|
|
1111
1403
|
//#region src/core/emoji.ts
|
|
1112
|
-
function
|
|
1404
|
+
function we(e, t) {
|
|
1113
1405
|
let n = e.selectionStart ?? e.value.length, r = e.selectionEnd ?? e.value.length;
|
|
1114
1406
|
e.value = e.value.slice(0, n) + t + e.value.slice(r), e.selectionStart = e.selectionEnd = n + t.length, e.dispatchEvent(new Event("input", { bubbles: !0 }));
|
|
1115
1407
|
}
|
|
1116
|
-
var
|
|
1117
|
-
async function
|
|
1118
|
-
return
|
|
1408
|
+
var J = null;
|
|
1409
|
+
async function Te() {
|
|
1410
|
+
return J || (J = (await import("./emoji-data-DWiYsBZI.js")).EMOJIS, J);
|
|
1119
1411
|
}
|
|
1120
|
-
function
|
|
1412
|
+
function Ee(e) {
|
|
1121
1413
|
let t = document.createElement("button");
|
|
1122
1414
|
t.type = "button", t.className = "emoji-btn", t.setAttribute("aria-label", "Emoji"), t.textContent = "🙂";
|
|
1123
1415
|
let n = document.createElement("div");
|
|
@@ -1125,7 +1417,7 @@ function _e(e) {
|
|
|
1125
1417
|
let r = !1;
|
|
1126
1418
|
return t.addEventListener("click", async () => {
|
|
1127
1419
|
if (!r) {
|
|
1128
|
-
let t = await
|
|
1420
|
+
let t = await Te();
|
|
1129
1421
|
for (let r of t) {
|
|
1130
1422
|
let t = document.createElement("button");
|
|
1131
1423
|
t.type = "button", t.className = "emoji-item", t.textContent = r, t.addEventListener("click", () => {
|
|
@@ -1141,45 +1433,95 @@ function _e(e) {
|
|
|
1141
1433
|
};
|
|
1142
1434
|
}
|
|
1143
1435
|
//#endregion
|
|
1436
|
+
//#region src/core/blocks-renderer.ts
|
|
1437
|
+
function Y(e) {
|
|
1438
|
+
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1439
|
+
}
|
|
1440
|
+
function X(e) {
|
|
1441
|
+
return /^https?:\/\//i.test(e) ? e : "";
|
|
1442
|
+
}
|
|
1443
|
+
function De(e) {
|
|
1444
|
+
let t = Y(e.label), n = Y(e.value), r = Y(e.action);
|
|
1445
|
+
if (e.action === "url") {
|
|
1446
|
+
let n = X(e.value);
|
|
1447
|
+
return n ? `<a class="biq-btn biq-btn--url" href="${Y(n)}" target="_blank" rel="noopener noreferrer">${t}</a>` : "";
|
|
1448
|
+
}
|
|
1449
|
+
return `<button class="biq-btn biq-btn--${r}" type="button" data-action="${r}" data-value="${n}">${t}</button>`;
|
|
1450
|
+
}
|
|
1451
|
+
function Oe(e) {
|
|
1452
|
+
let t = `${e.imageUrl ? (() => {
|
|
1453
|
+
let t = X(e.imageUrl);
|
|
1454
|
+
return t ? `<img class="biq-card-img" src="${Y(t)}" alt="" loading="lazy" />` : "";
|
|
1455
|
+
})() : ""}${`<div class="biq-card-title">${Y(e.title)}</div>`}${e.subtitle ? `<div class="biq-card-subtitle">${Y(e.subtitle)}</div>` : ""}${e.price ? `<div class="biq-card-price">${Y(e.price)}</div>` : ""}${e.buttons && e.buttons.length > 0 ? `<div class="biq-card-btns">${e.buttons.map(De).join("")}</div>` : ""}`;
|
|
1456
|
+
if (e.url) {
|
|
1457
|
+
let n = X(e.url);
|
|
1458
|
+
if (n) return `<a class="biq-card biq-card--link" href="${Y(n)}" target="_blank" rel="noopener noreferrer">${t}</a>`;
|
|
1459
|
+
}
|
|
1460
|
+
return `<div class="biq-card">${t}</div>`;
|
|
1461
|
+
}
|
|
1462
|
+
function ke(e) {
|
|
1463
|
+
return `<div class="biq-carousel">${e.cards.map(Oe).join("")}</div>`;
|
|
1464
|
+
}
|
|
1465
|
+
function Ae(e) {
|
|
1466
|
+
return `<div class="biq-quick-replies">${e.replies.map((e) => {
|
|
1467
|
+
let t = Y(e.label);
|
|
1468
|
+
return `<button class="biq-qr-pill" type="button" data-qr="1" data-value="${Y(e.value)}">${t}</button>`;
|
|
1469
|
+
}).join("")}</div>`;
|
|
1470
|
+
}
|
|
1471
|
+
function je(e) {
|
|
1472
|
+
return `<div class="biq-buttons">${e.buttons.map(De).join("")}</div>`;
|
|
1473
|
+
}
|
|
1474
|
+
function Me(e) {
|
|
1475
|
+
return !e || e.length === 0 ? "" : e.map((e) => {
|
|
1476
|
+
switch (e.type) {
|
|
1477
|
+
case "card": return Oe(e);
|
|
1478
|
+
case "carousel": return ke(e);
|
|
1479
|
+
case "quick_replies": return Ae(e);
|
|
1480
|
+
case "buttons": return je(e);
|
|
1481
|
+
default: return "";
|
|
1482
|
+
}
|
|
1483
|
+
}).join("");
|
|
1484
|
+
}
|
|
1485
|
+
//#endregion
|
|
1144
1486
|
//#region src/core/ui.ts
|
|
1145
|
-
var
|
|
1146
|
-
function
|
|
1147
|
-
if (!e || e.type === "icon") return
|
|
1148
|
-
if (e.type === "emoji") return `<span style="font-size:22px;line-height:1;display:flex;align-items:center;justify-content:center;width:100%;height:100%">${
|
|
1487
|
+
var Ne = "https://bot-q-frontend.vercel.app/", Pe = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M20 2H4a2 2 0 00-2 2v18l4-4h14a2 2 0 002-2V4a2 2 0 00-2-2z\"/>\n</svg>", Fe = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\n</svg>", Ie = `<img src="${ve}" alt="" style="width:100%;height:100%;object-fit:cover;border-radius:50%" />`, Le = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M2.01 21L23 12 2.01 3 2 10l15 2-15 2z\"/>\n</svg>", Re = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M20 2H4a2 2 0 00-2 2v18l4-4h14a2 2 0 002-2V4a2 2 0 00-2-2zm-2 10H6v-2h12v2zm0-3H6V7h12v2z\"/>\n</svg>", ze = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48\"/>\n</svg>";
|
|
1488
|
+
function Be(e) {
|
|
1489
|
+
if (!e || e.type === "icon") return Ie;
|
|
1490
|
+
if (e.type === "emoji") return `<span style="font-size:22px;line-height:1;display:flex;align-items:center;justify-content:center;width:100%;height:100%">${Z(e.value)}</span>`;
|
|
1149
1491
|
if (e.type === "initials") {
|
|
1150
1492
|
let t = e.bgColor ?? "#F97316";
|
|
1151
|
-
return `<div style="width:100%;height:100%;border-radius:50%;background:${/^#[0-9A-Fa-f]{3,6}$/.test(t) ? t : "#F97316"};display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;color:#fff">${
|
|
1493
|
+
return `<div style="width:100%;height:100%;border-radius:50%;background:${/^#[0-9A-Fa-f]{3,6}$/.test(t) ? t : "#F97316"};display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;color:#fff">${Z(e.value.slice(0, 2).toUpperCase())}</div>`;
|
|
1152
1494
|
}
|
|
1153
|
-
return e.type === "image" ? `<img src="${
|
|
1495
|
+
return e.type === "image" ? `<img src="${Z(e.value)}" style="width:100%;height:100%;object-fit:cover;border-radius:50%" alt="" />` : Ie;
|
|
1154
1496
|
}
|
|
1155
|
-
function
|
|
1497
|
+
function Z(e) {
|
|
1156
1498
|
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1157
1499
|
}
|
|
1158
|
-
function
|
|
1500
|
+
function Q(e) {
|
|
1159
1501
|
let t = [];
|
|
1160
1502
|
return e = e.replace(/`([^`]+)`/g, (e, n) => (t.push(`<code>${n}</code>`), `\x00CODE${t.length - 1}\x00`)), e = e.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>"), e = e.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>"), e = e.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, "<em>$1</em>"), e = e.replace(/~~(.+?)~~/g, "<del>$1</del>"), e = e.replace(/__(.+?)__/g, "<strong>$1</strong>"), e = e.replace(/(^|\s)_(?!_)(.+?)_(?!_)(?=\s|$)/g, "$1<em>$2</em>"), e = e.replace(/\[([^\]]+)\]\(([^()]*(?:\([^()]*\))*[^()]*)\)/g, (e, t, n) => /^https?:\/\//.test(n) ? `<a href="${n}" target="_blank" rel="noopener noreferrer">${t}</a>` : t), e = e.replace(/\x00CODE(\d+)\x00/g, (e, n) => t[Number(n)]), e;
|
|
1161
1503
|
}
|
|
1162
|
-
function
|
|
1504
|
+
function Ve(e) {
|
|
1163
1505
|
return /^\|[\s\-:|]+\|$/.test(e);
|
|
1164
1506
|
}
|
|
1165
|
-
function
|
|
1507
|
+
function He(e) {
|
|
1166
1508
|
return e.replace(/^\|/, "").replace(/\|$/, "").split("|").map((e) => e.trim());
|
|
1167
1509
|
}
|
|
1168
|
-
function
|
|
1169
|
-
return e ? `<div class="handoff-banner">⏳ ${
|
|
1510
|
+
function Ue(e, t) {
|
|
1511
|
+
return e ? `<div class="handoff-banner">⏳ ${Z(t.waitingForHuman)}</div>` : "";
|
|
1170
1512
|
}
|
|
1171
|
-
function
|
|
1513
|
+
function We(e) {
|
|
1172
1514
|
return e <= 0 ? "" : `<span class="unread-badge">${e > 9 ? "9+" : String(e)}</span>`;
|
|
1173
1515
|
}
|
|
1174
|
-
function
|
|
1175
|
-
let t =
|
|
1516
|
+
function Ge(e) {
|
|
1517
|
+
let t = Z(e).replace(/\x00/g, "").split("\n"), n = [], r = 0;
|
|
1176
1518
|
for (; r < t.length;) {
|
|
1177
1519
|
let e = t[r].trim();
|
|
1178
1520
|
if (e.startsWith("|") && e.endsWith("|")) {
|
|
1179
1521
|
let e = [];
|
|
1180
1522
|
for (; r < t.length && t[r].trim().startsWith("|") && t[r].trim().endsWith("|");) e.push(t[r].trim()), r++;
|
|
1181
|
-
let i = e.findIndex(
|
|
1182
|
-
a.length > 0 && (s += "<thead>" + a.map((e) => "<tr>" +
|
|
1523
|
+
let i = e.findIndex(Ve), a = i > 0 ? e.slice(0, i) : [], o = i >= 0 ? e.slice(i + 1) : e, s = "<table>";
|
|
1524
|
+
a.length > 0 && (s += "<thead>" + a.map((e) => "<tr>" + He(e).map((e) => `<th>${Q(e)}</th>`).join("") + "</tr>").join("") + "</thead>"), o.length > 0 && (s += "<tbody>" + o.map((e) => "<tr>" + He(e).map((e) => `<td>${Q(e)}</td>`).join("") + "</tr>").join("") + "</tbody>"), s += "</table>", n.push(s);
|
|
1183
1525
|
continue;
|
|
1184
1526
|
}
|
|
1185
1527
|
if (/^-{3,}$/.test(e)) {
|
|
@@ -1189,67 +1531,67 @@ function De(e) {
|
|
|
1189
1531
|
let i = e.match(/^(#{1,6})\s+(.*)$/);
|
|
1190
1532
|
if (i) {
|
|
1191
1533
|
let e = i[1].length;
|
|
1192
|
-
n.push(`<h${e}>${
|
|
1534
|
+
n.push(`<h${e}>${Q(i[2])}</h${e}>`), r++;
|
|
1193
1535
|
continue;
|
|
1194
1536
|
}
|
|
1195
1537
|
if (/^[-*]\s/.test(e)) {
|
|
1196
1538
|
let e = [];
|
|
1197
1539
|
for (; r < t.length && /^\s*[-*]\s/.test(t[r]);) e.push(t[r].trim().replace(/^[-*]\s+/, "")), r++;
|
|
1198
|
-
n.push("<ul>" + e.map((e) => `<li>${
|
|
1540
|
+
n.push("<ul>" + e.map((e) => `<li>${Q(e)}</li>`).join("") + "</ul>");
|
|
1199
1541
|
continue;
|
|
1200
1542
|
}
|
|
1201
1543
|
if (/^\d+\.\s/.test(e)) {
|
|
1202
1544
|
let e = [];
|
|
1203
1545
|
for (; r < t.length && /^\s*\d+\.\s/.test(t[r]);) e.push(t[r].trim().replace(/^\d+\.\s+/, "")), r++;
|
|
1204
|
-
n.push("<ol>" + e.map((e) => `<li>${
|
|
1546
|
+
n.push("<ol>" + e.map((e) => `<li>${Q(e)}</li>`).join("") + "</ol>");
|
|
1205
1547
|
continue;
|
|
1206
1548
|
}
|
|
1207
1549
|
if (e === "") {
|
|
1208
1550
|
n.push("<br>"), r++;
|
|
1209
1551
|
continue;
|
|
1210
1552
|
}
|
|
1211
|
-
n.push(
|
|
1553
|
+
n.push(Q(e)), n.push("<br>"), r++;
|
|
1212
1554
|
}
|
|
1213
1555
|
for (; n.length > 0 && n[n.length - 1] === "<br>";) n.pop();
|
|
1214
1556
|
return n.join("");
|
|
1215
1557
|
}
|
|
1216
|
-
function
|
|
1217
|
-
let { strings: n, content: r, botName: i, lang: a, now: o, contactInfo: s } = t;
|
|
1558
|
+
function Ke(e, t) {
|
|
1559
|
+
let { strings: n, content: r, botName: i, lang: a, now: o, contactInfo: s, richMessages: c } = t;
|
|
1218
1560
|
if (e.messages.length === 0 && !e.isLoading) {
|
|
1219
|
-
let e = r.suggestionChips.length > 0 ? `<div class="chips">${r.suggestionChips.map((e) => `<button class="chip">${
|
|
1561
|
+
let e = r.suggestionChips.length > 0 ? `<div class="chips">${r.suggestionChips.map((e) => `<button class="chip">${Z(e)}</button>`).join("")}</div>` : "";
|
|
1220
1562
|
return `
|
|
1221
1563
|
<div class="empty-state">
|
|
1222
|
-
${
|
|
1223
|
-
<span class="greeting">${
|
|
1564
|
+
${Re}
|
|
1565
|
+
<span class="greeting">${Z(r.greeting || n.defaultGreeting)}</span>
|
|
1224
1566
|
${e}
|
|
1225
1567
|
</div>
|
|
1226
1568
|
`;
|
|
1227
1569
|
}
|
|
1228
|
-
let
|
|
1229
|
-
let t = e.ts ?? o, r =
|
|
1230
|
-
|
|
1231
|
-
let
|
|
1232
|
-
return `${
|
|
1233
|
-
}).join(""),
|
|
1234
|
-
return
|
|
1235
|
-
}
|
|
1236
|
-
function
|
|
1237
|
-
let { name: i, design: a } = t, o, s, c, l, u, d, f, p, m, h, g, _, { content:
|
|
1238
|
-
function
|
|
1570
|
+
let l = "", u = e.messages.map((e) => {
|
|
1571
|
+
let t = e.ts ?? o, r = he(t, o, a), u = r === l ? "" : `<div class="day-sep"><span>${Z(r)}</span></div>`;
|
|
1572
|
+
l = r;
|
|
1573
|
+
let d = e.role === "assistant" ? Ge(e.content) : Z(e.content), f = e.role === "assistant" && !e.error ? `<div class="msg-meta">${Z(i)} · ${Z(W(t, o, a))}</div>` : "", p = e.error ? `<button class="retry-btn" type="button">↻ ${Z(n.retry)}</button>` : "", m = e.error && s ? `<div class="msg-contact">${Z(s)}</div>` : "", h = c && e.role === "assistant" && !e.error && e.blocks && e.blocks.length > 0 ? `<div class="biq-blocks">${Me(e.blocks)}</div>` : "";
|
|
1574
|
+
return `${u}<div class="${`message ${e.role}${e.error ? " error" : ""}`}"><div class="message-bubble">${d}</div>${p}${m}${f}${h}</div>`;
|
|
1575
|
+
}).join(""), d = e.loadingOlder ? "<div class=\"typing\"><span></span><span></span><span></span></div>" : "", f = e.isLoading ? "<div class=\"typing\"><span></span><span></span><span></span></div>" : "";
|
|
1576
|
+
return d + u + f;
|
|
1577
|
+
}
|
|
1578
|
+
function qe(e, t, n, r) {
|
|
1579
|
+
let { name: i, design: a } = t, o, s, c, l, u, d, f, p, m, h, g, _, v = null, y = null, b = null, { content: x } = a, S = t.imageInput === !0, C = Be(a.avatar), w = null;
|
|
1580
|
+
function T(e) {
|
|
1239
1581
|
e.setAttribute("data-position", a.layout.position), o = e.attachShadow({ mode: "closed" });
|
|
1240
|
-
let
|
|
1241
|
-
|
|
1242
|
-
<span class="icon-chat">${
|
|
1243
|
-
<span class="icon-close">${
|
|
1582
|
+
let w = document.createElement("style");
|
|
1583
|
+
w.textContent = me(a), o.appendChild(w), s = document.createElement("button"), s.className = "bubble", s.setAttribute("aria-label", n.ariaOpenChat), s.innerHTML = `
|
|
1584
|
+
<span class="icon-chat">${Pe}</span>
|
|
1585
|
+
<span class="icon-close">${Fe}</span>
|
|
1244
1586
|
<span class="unread-badge-slot"></span>
|
|
1245
1587
|
`, s.addEventListener("click", () => r.onToggle()), o.appendChild(s), c = document.createElement("div"), c.className = "chat-window", c.setAttribute("role", "dialog"), c.setAttribute("aria-label", `${i} chat`), c.innerHTML = `
|
|
1246
1588
|
<div class="chat-header">
|
|
1247
|
-
<div class="avatar">${
|
|
1589
|
+
<div class="avatar">${Be(a.avatar)}</div>
|
|
1248
1590
|
<div class="header-text">
|
|
1249
|
-
<span class="bot-name">${
|
|
1250
|
-
<span class="bot-status">${
|
|
1591
|
+
<span class="bot-name">${Z(i)}</span>
|
|
1592
|
+
<span class="bot-status">${Z(n.statusOnline)}</span>
|
|
1251
1593
|
</div>
|
|
1252
|
-
<button class="close-btn" aria-label="${
|
|
1594
|
+
<button class="close-btn" aria-label="${Z(n.ariaCloseChat)}">×</button>
|
|
1253
1595
|
</div>
|
|
1254
1596
|
<div class="chat-body">
|
|
1255
1597
|
<div class="panel panel-home"></div>
|
|
@@ -1258,29 +1600,31 @@ function ke(e, t, n, r) {
|
|
|
1258
1600
|
<div class="messages" id="messages-container" role="log" aria-live="polite" aria-atomic="false"></div>
|
|
1259
1601
|
<div class="handoff-slot"></div>
|
|
1260
1602
|
<div class="chat-footer">
|
|
1603
|
+
<div class="attach-preview-slot"></div>
|
|
1261
1604
|
<div class="input-row">
|
|
1605
|
+
${S ? `<button class="attach-btn" type="button" aria-label="${Z(n.imageAttach)}">${ze}</button>` : ""}
|
|
1262
1606
|
<textarea
|
|
1263
1607
|
class="input"
|
|
1264
|
-
placeholder="${
|
|
1608
|
+
placeholder="${Z(x.placeholder || n.inputPlaceholder)}"
|
|
1265
1609
|
rows="1"
|
|
1266
1610
|
maxlength="2000"
|
|
1267
1611
|
aria-label="Message input"
|
|
1268
1612
|
></textarea>
|
|
1269
|
-
<button class="send-btn" aria-label="${
|
|
1270
|
-
${
|
|
1613
|
+
<button class="send-btn" aria-label="${Z(n.ariaSendMessage)}">
|
|
1614
|
+
${Le}
|
|
1271
1615
|
</button>
|
|
1272
1616
|
</div>
|
|
1273
|
-
<a class="botiq-badge" href="${
|
|
1274
|
-
${
|
|
1617
|
+
<a class="botiq-badge" href="${Ne}" target="_blank" rel="noopener noreferrer">
|
|
1618
|
+
${Z(n.poweredBy)} <span class="botiq-badge-name">BotIQ</span>
|
|
1275
1619
|
</a>
|
|
1276
1620
|
</div>
|
|
1277
1621
|
</div>
|
|
1278
1622
|
</div>
|
|
1279
1623
|
<div class="bottom-nav">
|
|
1280
|
-
<button class="nav-btn" data-view="home">⌂ ${
|
|
1281
|
-
<button class="nav-btn" data-view="messages">💬 ${
|
|
1624
|
+
<button class="nav-btn" data-view="home">⌂ ${Z(n.navHome)}</button>
|
|
1625
|
+
<button class="nav-btn" data-view="messages">💬 ${Z(n.navMessages)}</button>
|
|
1282
1626
|
</div>
|
|
1283
|
-
`, c.querySelector(".close-btn").addEventListener("click", () => r.onToggle()), l = c.querySelector(".panel-home"), u = c.querySelector(".panel-messages"), d = c.querySelector(".panel-conversation"), l.innerHTML =
|
|
1627
|
+
`, c.querySelector(".close-btn").addEventListener("click", () => r.onToggle()), l = c.querySelector(".panel-home"), u = c.querySelector(".panel-messages"), d = c.querySelector(".panel-conversation"), l.innerHTML = _e(t, n, [], C), l.querySelector(".home-start")?.addEventListener("click", () => {
|
|
1284
1628
|
r.onNewConversation();
|
|
1285
1629
|
}), f = c.querySelector(".nav-btn[data-view=\"home\"]"), p = c.querySelector(".nav-btn[data-view=\"messages\"]"), c.querySelectorAll(".nav-btn").forEach((e) => {
|
|
1286
1630
|
e.addEventListener("click", () => {
|
|
@@ -1288,44 +1632,105 @@ function ke(e, t, n, r) {
|
|
|
1288
1632
|
r.onNavigate(t);
|
|
1289
1633
|
});
|
|
1290
1634
|
}), m = c.querySelector("#messages-container"), h = c.querySelector(".handoff-slot");
|
|
1291
|
-
let
|
|
1635
|
+
let T = null;
|
|
1292
1636
|
m.addEventListener("scroll", () => {
|
|
1293
|
-
m.scrollTop <= 48 && !
|
|
1294
|
-
|
|
1637
|
+
m.scrollTop <= 48 && !T && (T = setTimeout(() => {
|
|
1638
|
+
T = null;
|
|
1295
1639
|
}, 150), r.onScrollTop());
|
|
1296
1640
|
}), g = c.querySelector(".input"), _ = c.querySelector(".send-btn"), g.addEventListener("input", () => {
|
|
1297
1641
|
g.style.height = "auto", g.style.height = Math.min(g.scrollHeight, 100) + "px";
|
|
1298
1642
|
}), g.addEventListener("keydown", (e) => {
|
|
1299
|
-
e.key === "Enter" && !e.shiftKey && (e.preventDefault(),
|
|
1300
|
-
}), _.addEventListener("click",
|
|
1301
|
-
let
|
|
1302
|
-
|
|
1643
|
+
e.key === "Enter" && !e.shiftKey && (e.preventDefault(), E());
|
|
1644
|
+
}), _.addEventListener("click", E);
|
|
1645
|
+
let D = c.querySelector(".input-row"), { button: O, panel: k } = Ee((e) => {
|
|
1646
|
+
we(g, e), g.focus();
|
|
1303
1647
|
});
|
|
1304
|
-
|
|
1648
|
+
D.insertBefore(O, _), c.querySelector(".chat-footer").appendChild(k), y = c.querySelector(".attach-preview-slot"), S && (v = c.querySelector(".attach-btn"), v && (b = document.createElement("input"), b.type = "file", b.accept = "image/jpeg,image/png,image/webp", b.style.display = "none", b.setAttribute("aria-hidden", "true"), o.appendChild(b), v.addEventListener("click", () => {
|
|
1649
|
+
b?.click();
|
|
1650
|
+
}), b.addEventListener("change", () => {
|
|
1651
|
+
let e = b?.files?.[0];
|
|
1652
|
+
e && r.onAttachImage && (r.onAttachImage(e), b && (b.value = ""));
|
|
1653
|
+
}))), o.appendChild(c);
|
|
1305
1654
|
}
|
|
1306
|
-
function
|
|
1655
|
+
function E() {
|
|
1307
1656
|
let e = g.value.trim();
|
|
1308
|
-
!e || _.disabled || (g.value = "", g.style.height = "auto", r.onSend(e));
|
|
1657
|
+
!e && !y?.querySelector(".attach-preview") || _.disabled || (g.value = "", g.style.height = "auto", r.onSend(e));
|
|
1309
1658
|
}
|
|
1310
|
-
function
|
|
1659
|
+
function D(e) {
|
|
1311
1660
|
let a = m.scrollHeight - m.scrollTop - m.clientHeight < 80, o = m.scrollTop, s = m.scrollHeight;
|
|
1312
|
-
m.innerHTML =
|
|
1661
|
+
m.innerHTML = Ke(e, {
|
|
1313
1662
|
strings: n,
|
|
1314
|
-
content:
|
|
1663
|
+
content: x,
|
|
1315
1664
|
botName: i,
|
|
1316
1665
|
lang: t.widgetLanguage,
|
|
1317
1666
|
now: Date.now(),
|
|
1318
|
-
contactInfo: t.contactInfo
|
|
1667
|
+
contactInfo: t.contactInfo,
|
|
1668
|
+
richMessages: t.richMessages
|
|
1319
1669
|
}), m.querySelectorAll(".chip").forEach((e) => {
|
|
1320
1670
|
e.addEventListener("click", () => r.onSend(e.textContent ?? ""));
|
|
1321
1671
|
}), m.querySelectorAll(".retry-btn").forEach((e) => {
|
|
1322
1672
|
e.addEventListener("click", () => r.onRetry());
|
|
1323
|
-
}),
|
|
1673
|
+
}), m.querySelectorAll(".biq-btn[data-action=\"send\"]").forEach((e) => {
|
|
1674
|
+
e.addEventListener("click", () => {
|
|
1675
|
+
let t = e.dataset.value ?? "";
|
|
1676
|
+
if (t) {
|
|
1677
|
+
r.onSend(t);
|
|
1678
|
+
let n = e.closest(".biq-blocks");
|
|
1679
|
+
n && (n.style.pointerEvents = "none", n.style.opacity = "0.5");
|
|
1680
|
+
}
|
|
1681
|
+
});
|
|
1682
|
+
}), m.querySelectorAll(".biq-btn[data-action=\"page_action\"]").forEach((e) => {
|
|
1683
|
+
e.addEventListener("click", () => {
|
|
1684
|
+
let t = e.dataset.value ?? "";
|
|
1685
|
+
if (t && r.onBlockPageAction) {
|
|
1686
|
+
let n = e.closest(".biq-blocks");
|
|
1687
|
+
n && (n.style.pointerEvents = "none", n.style.opacity = "0.5"), r.onBlockPageAction(t);
|
|
1688
|
+
}
|
|
1689
|
+
});
|
|
1690
|
+
}), m.querySelectorAll(".biq-qr-pill[data-qr=\"1\"]").forEach((e) => {
|
|
1691
|
+
e.addEventListener("click", () => {
|
|
1692
|
+
let t = e.dataset.value ?? "";
|
|
1693
|
+
if (t) {
|
|
1694
|
+
r.onSend(t);
|
|
1695
|
+
let n = e.closest(".biq-quick-replies");
|
|
1696
|
+
n && (n.style.display = "none");
|
|
1697
|
+
}
|
|
1698
|
+
});
|
|
1699
|
+
}), a ? m.scrollTop = m.scrollHeight : m.scrollTop = Se(o, s, m.scrollHeight);
|
|
1324
1700
|
}
|
|
1325
|
-
function
|
|
1701
|
+
function O(e) {
|
|
1326
1702
|
e.isOpen ? (c.classList.add("open"), s.classList.add("open"), s.setAttribute("aria-label", n.ariaCloseChat), e.view === "conversation" && requestAnimationFrame(() => g.focus())) : (c.classList.remove("open"), s.classList.remove("open"), s.setAttribute("aria-label", n.ariaOpenChat));
|
|
1327
|
-
let
|
|
1328
|
-
|
|
1703
|
+
let i = s.querySelector(".unread-badge-slot");
|
|
1704
|
+
if (i && (i.innerHTML = We(e.unreadCount)), _.disabled = e.isLoading || e.isUploading, y && S) if (e.pendingAttachment) {
|
|
1705
|
+
let t = e.pendingAttachment, i = e.isUploading, a = e.uploadError;
|
|
1706
|
+
y.innerHTML = `
|
|
1707
|
+
<div class="attach-preview">
|
|
1708
|
+
<img
|
|
1709
|
+
src="${Z(t.previewUrl)}"
|
|
1710
|
+
alt="Preview"
|
|
1711
|
+
class="attach-preview-img${i ? " attach-preview-img--uploading" : ""}"
|
|
1712
|
+
/>
|
|
1713
|
+
${i ? `<span class="attach-preview-status">${Z(n.imageUploading)}</span>` : ""}
|
|
1714
|
+
${a ? `<span class="attach-preview-error">${Z(a)}</span>` : ""}
|
|
1715
|
+
${i ? "" : `<button class="attach-preview-remove" type="button" aria-label="${Z(n.imageRemove)}">×</button>`}
|
|
1716
|
+
</div>
|
|
1717
|
+
`, y.querySelector(".attach-preview-remove")?.addEventListener("click", () => {
|
|
1718
|
+
r.onRemoveAttachment?.();
|
|
1719
|
+
});
|
|
1720
|
+
} else y.innerHTML = "";
|
|
1721
|
+
if (c.dataset.view = e.view, l.classList.toggle("active", e.view === "home"), u.classList.toggle("active", e.view === "messages"), d.classList.toggle("active", e.view === "conversation"), f.classList.toggle("active", e.view === "home"), p.classList.toggle("active", e.view === "messages"), e.view === "home" && e.conversations !== w) {
|
|
1722
|
+
w = e.conversations;
|
|
1723
|
+
let i = Date.now();
|
|
1724
|
+
l.innerHTML = _e(t, n, e.conversations, C, i), l.querySelector(".home-start")?.addEventListener("click", () => {
|
|
1725
|
+
r.onNewConversation();
|
|
1726
|
+
}), l.querySelectorAll(".home-recent-item").forEach((e) => {
|
|
1727
|
+
e.addEventListener("click", () => {
|
|
1728
|
+
let t = e.dataset.session;
|
|
1729
|
+
t && r.onOpenConversation(t);
|
|
1730
|
+
});
|
|
1731
|
+
});
|
|
1732
|
+
}
|
|
1733
|
+
e.view === "conversation" && (D(e), h.innerHTML = Ue(e.escalated, n)), e.view === "messages" && (u.innerHTML = ge(e.conversations, n, Date.now(), C), u.querySelectorAll(".msg-list-item").forEach((e) => {
|
|
1329
1734
|
e.addEventListener("click", () => {
|
|
1330
1735
|
let t = e.dataset.session;
|
|
1331
1736
|
t && r.onOpenConversation(t);
|
|
@@ -1334,8 +1739,8 @@ function ke(e, t, n, r) {
|
|
|
1334
1739
|
r.onNewConversation();
|
|
1335
1740
|
}));
|
|
1336
1741
|
}
|
|
1337
|
-
function
|
|
1338
|
-
return
|
|
1742
|
+
function k(e) {
|
|
1743
|
+
return Ce(o, {
|
|
1339
1744
|
...e,
|
|
1340
1745
|
labels: {
|
|
1341
1746
|
confirm: n.confirmYes,
|
|
@@ -1346,14 +1751,14 @@ function ke(e, t, n, r) {
|
|
|
1346
1751
|
});
|
|
1347
1752
|
}
|
|
1348
1753
|
return {
|
|
1349
|
-
mount:
|
|
1350
|
-
update:
|
|
1351
|
-
confirmAction:
|
|
1754
|
+
mount: T,
|
|
1755
|
+
update: O,
|
|
1756
|
+
confirmAction: k
|
|
1352
1757
|
};
|
|
1353
1758
|
}
|
|
1354
1759
|
//#endregion
|
|
1355
1760
|
//#region src/i18n/vi.ts
|
|
1356
|
-
var
|
|
1761
|
+
var Je = {
|
|
1357
1762
|
statusOnline: "Trực tuyến",
|
|
1358
1763
|
statusPaused: "Tạm ngừng",
|
|
1359
1764
|
navHome: "Trang chủ",
|
|
@@ -1385,8 +1790,16 @@ var Ae = {
|
|
|
1385
1790
|
confirmNo: "Huỷ",
|
|
1386
1791
|
confirmCountdownPrefix: "Tự động xác nhận sau ",
|
|
1387
1792
|
confirmCountdownSuffix: "s…",
|
|
1388
|
-
retry: "Thử lại"
|
|
1389
|
-
|
|
1793
|
+
retry: "Thử lại",
|
|
1794
|
+
recentMessages: "Tin nhắn gần đây",
|
|
1795
|
+
imageAttach: "Đính kèm ảnh",
|
|
1796
|
+
imageRemove: "Xóa ảnh",
|
|
1797
|
+
imageUploading: "Đang tải ảnh…",
|
|
1798
|
+
imageUploadPlanError: "Gói hiện tại không hỗ trợ gửi ảnh.",
|
|
1799
|
+
imageUploadTooLarge: "Ảnh quá lớn (tối đa 5 MB sau khi nén).",
|
|
1800
|
+
imageUploadRateLimit: "Gửi quá nhanh. Vui lòng thử lại.",
|
|
1801
|
+
imageUploadError: "Tải ảnh thất bại. Vui lòng thử lại."
|
|
1802
|
+
}, Ye = {
|
|
1390
1803
|
statusOnline: "Online",
|
|
1391
1804
|
statusPaused: "Paused",
|
|
1392
1805
|
navHome: "Home",
|
|
@@ -1418,24 +1831,32 @@ var Ae = {
|
|
|
1418
1831
|
confirmNo: "Cancel",
|
|
1419
1832
|
confirmCountdownPrefix: "Auto-confirming in ",
|
|
1420
1833
|
confirmCountdownSuffix: "s…",
|
|
1421
|
-
retry: "Retry"
|
|
1834
|
+
retry: "Retry",
|
|
1835
|
+
recentMessages: "Recent messages",
|
|
1836
|
+
imageAttach: "Attach image",
|
|
1837
|
+
imageRemove: "Remove image",
|
|
1838
|
+
imageUploading: "Uploading image…",
|
|
1839
|
+
imageUploadPlanError: "Your plan does not support image sending.",
|
|
1840
|
+
imageUploadTooLarge: "Image too large (max 5 MB after compression).",
|
|
1841
|
+
imageUploadRateLimit: "Too many requests. Please try again.",
|
|
1842
|
+
imageUploadError: "Image upload failed. Please try again."
|
|
1422
1843
|
};
|
|
1423
1844
|
//#endregion
|
|
1424
1845
|
//#region src/i18n/index.ts
|
|
1425
|
-
function
|
|
1426
|
-
return e === "en" ?
|
|
1846
|
+
function Xe(e) {
|
|
1847
|
+
return e === "en" ? Ye : Je;
|
|
1427
1848
|
}
|
|
1428
1849
|
//#endregion
|
|
1429
1850
|
//#region src/core/declarative-executor.ts
|
|
1430
|
-
var
|
|
1431
|
-
function
|
|
1851
|
+
var Ze = /^[a-zA-Z0-9_-]*$/;
|
|
1852
|
+
function Qe(e, t) {
|
|
1432
1853
|
return e.replace(/\{([a-zA-Z][a-zA-Z0-9_]*)\}/g, (e, n) => {
|
|
1433
1854
|
let r = t[n], i = r == null ? "" : String(r);
|
|
1434
|
-
if (!
|
|
1855
|
+
if (!Ze.test(i)) throw Error(`Unsafe param value for "${n}"`);
|
|
1435
1856
|
return i;
|
|
1436
1857
|
});
|
|
1437
1858
|
}
|
|
1438
|
-
function
|
|
1859
|
+
function $e(e, t) {
|
|
1439
1860
|
let n = typeof location < "u" ? location.origin : "https://placeholder.local", r, i;
|
|
1440
1861
|
try {
|
|
1441
1862
|
r = new URL(e, n), i = new URL(t.replace(/\{[a-zA-Z][a-zA-Z0-9_]*\}/g, "x"), n);
|
|
@@ -1445,10 +1866,10 @@ function Me(e, t) {
|
|
|
1445
1866
|
if (!/^https?:$/.test(r.protocol)) throw Error("Navigation must be http(s)");
|
|
1446
1867
|
if (r.origin !== i.origin) throw Error("Navigation origin not allowed");
|
|
1447
1868
|
}
|
|
1448
|
-
async function
|
|
1869
|
+
async function et(e, t) {
|
|
1449
1870
|
let n = e.config;
|
|
1450
1871
|
if (e.operation === "click") {
|
|
1451
|
-
let e =
|
|
1872
|
+
let e = Qe(String(n.selectorTemplate ?? ""), t), r = document.querySelector(e);
|
|
1452
1873
|
if (!r) throw Error(`No element for selector: ${e}`);
|
|
1453
1874
|
r.click();
|
|
1454
1875
|
return;
|
|
@@ -1463,15 +1884,15 @@ async function Ne(e, t) {
|
|
|
1463
1884
|
return;
|
|
1464
1885
|
}
|
|
1465
1886
|
if (e.operation === "navigate") {
|
|
1466
|
-
let e = String(n.urlTemplate ?? ""), r =
|
|
1467
|
-
|
|
1887
|
+
let e = String(n.urlTemplate ?? ""), r = Qe(e, t);
|
|
1888
|
+
$e(r, e), location.assign(r);
|
|
1468
1889
|
return;
|
|
1469
1890
|
}
|
|
1470
1891
|
throw Error(`Unknown operation: ${String(e.operation)}`);
|
|
1471
1892
|
}
|
|
1472
1893
|
//#endregion
|
|
1473
1894
|
//#region src/core/page-action-executor.ts
|
|
1474
|
-
async function
|
|
1895
|
+
async function tt(e, t) {
|
|
1475
1896
|
let n = t.registry.get(e.actionName);
|
|
1476
1897
|
if (!n) return {
|
|
1477
1898
|
status: "unknown",
|
|
@@ -1496,26 +1917,26 @@ async function Pe(e, t) {
|
|
|
1496
1917
|
//#endregion
|
|
1497
1918
|
//#region src/builds/npm/index.ts
|
|
1498
1919
|
var $ = 10;
|
|
1499
|
-
function
|
|
1500
|
-
if (D.setDeclarativeRunner(
|
|
1920
|
+
function nt(e) {
|
|
1921
|
+
if (D.setDeclarativeRunner(et), typeof window < "u" && (window.botiq = window.botiq ?? {}, window.botiq.registerActions = (e) => D.register(e)), !e.apiKey) return console.warn("[BotIQ] apiKey is required"), () => void 0;
|
|
1501
1922
|
let t = p(e);
|
|
1502
1923
|
y();
|
|
1503
1924
|
let n = t.apiKey.slice(-16), r = C(), i = b(n), a = x(n, i);
|
|
1504
|
-
|
|
1925
|
+
I({
|
|
1505
1926
|
messages: a,
|
|
1506
1927
|
view: "home",
|
|
1507
1928
|
currentSessionId: i
|
|
1508
1929
|
});
|
|
1509
|
-
let o =
|
|
1930
|
+
let o = K(), s = document.createElement("div");
|
|
1510
1931
|
document.body.appendChild(s);
|
|
1511
|
-
let c = () => void 0, l = !1, u =
|
|
1512
|
-
function
|
|
1513
|
-
|
|
1514
|
-
if (
|
|
1515
|
-
let e = await
|
|
1516
|
-
e.messages.length > 0 &&
|
|
1932
|
+
let c = () => void 0, l = !1, u = Xe(void 0), d = null, m = null, h = null, g = null;
|
|
1933
|
+
function _() {
|
|
1934
|
+
g ||= setTimeout(async () => {
|
|
1935
|
+
if (g = null, !(!F().escalated || !F().isOpen)) try {
|
|
1936
|
+
let e = await M(t.apiUrl, t.apiKey, F().currentSessionId, $, r);
|
|
1937
|
+
e.messages.length > 0 && I({ messages: e.messages.map(j) }), I({ escalated: e.escalated === !0 });
|
|
1517
1938
|
} catch {} finally {
|
|
1518
|
-
|
|
1939
|
+
F().escalated && F().isOpen && _();
|
|
1519
1940
|
}
|
|
1520
1941
|
}, 1e4);
|
|
1521
1942
|
}
|
|
@@ -1525,94 +1946,111 @@ function Fe(e) {
|
|
|
1525
1946
|
console.warn("[BotIQ] Widget not authorised on this origin — skipped mount"), s.remove();
|
|
1526
1947
|
return;
|
|
1527
1948
|
}
|
|
1528
|
-
u =
|
|
1529
|
-
let n =
|
|
1530
|
-
onSend:
|
|
1531
|
-
onToggle:
|
|
1532
|
-
onScrollTop:
|
|
1533
|
-
onRetry:
|
|
1534
|
-
onNavigate:
|
|
1535
|
-
onOpenConversation:
|
|
1536
|
-
onNewConversation:
|
|
1949
|
+
h = e, u = Xe(e.widgetLanguage), e.pageActions?.length && D.seed(e.pageActions);
|
|
1950
|
+
let n = qe(t, e, u, {
|
|
1951
|
+
onSend: oe,
|
|
1952
|
+
onToggle: H,
|
|
1953
|
+
onScrollTop: P,
|
|
1954
|
+
onRetry: ce,
|
|
1955
|
+
onNavigate: E,
|
|
1956
|
+
onOpenConversation: te,
|
|
1957
|
+
onNewConversation: A,
|
|
1958
|
+
onAttachImage: ie,
|
|
1959
|
+
onRemoveAttachment: ae,
|
|
1960
|
+
onBlockPageAction: V
|
|
1537
1961
|
});
|
|
1538
|
-
d = n, n.mount(s), c = re((e) => n.update(e)), n.update(
|
|
1539
|
-
if (
|
|
1540
|
-
let t =
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1962
|
+
d = n, n.mount(s), c = re((e) => n.update(e)), n.update(F()), e.proactive?.enabled && (m = setTimeout(() => {
|
|
1963
|
+
if (F().isOpen) return;
|
|
1964
|
+
let t = w();
|
|
1965
|
+
I({
|
|
1966
|
+
messages: [{
|
|
1967
|
+
role: "assistant",
|
|
1968
|
+
content: e.proactive.message,
|
|
1969
|
+
ts: Date.now()
|
|
1970
|
+
}],
|
|
1547
1971
|
view: "conversation",
|
|
1548
|
-
|
|
1972
|
+
currentSessionId: t,
|
|
1973
|
+
unreadCount: F().unreadCount + 1
|
|
1549
1974
|
});
|
|
1550
|
-
}, e.proactive.delayMs ?? 8e3)), a.length > 0 &&
|
|
1975
|
+
}, e.proactive.delayMs ?? 8e3)), a.length > 0 && N(i);
|
|
1551
1976
|
});
|
|
1552
|
-
|
|
1553
|
-
|
|
1977
|
+
let v = !1;
|
|
1978
|
+
async function T() {
|
|
1979
|
+
if (!v) {
|
|
1980
|
+
v = !0;
|
|
1981
|
+
try {
|
|
1982
|
+
I({ conversations: await O(t.apiUrl, t.apiKey, r) });
|
|
1983
|
+
} finally {
|
|
1984
|
+
v = !1;
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1554
1987
|
}
|
|
1555
|
-
function
|
|
1556
|
-
|
|
1988
|
+
function E(e) {
|
|
1989
|
+
I({ view: e }), (e === "home" || e === "messages") && T();
|
|
1557
1990
|
}
|
|
1558
|
-
function
|
|
1559
|
-
|
|
1991
|
+
function A() {
|
|
1992
|
+
I({
|
|
1560
1993
|
view: "conversation",
|
|
1561
1994
|
currentSessionId: w(),
|
|
1562
1995
|
messages: [],
|
|
1563
1996
|
escalated: !1
|
|
1564
|
-
}), o =
|
|
1997
|
+
}), o = K();
|
|
1565
1998
|
}
|
|
1566
|
-
function
|
|
1567
|
-
|
|
1999
|
+
function te(e) {
|
|
2000
|
+
I({
|
|
1568
2001
|
view: "conversation",
|
|
1569
2002
|
currentSessionId: e,
|
|
1570
2003
|
messages: x(n, e)
|
|
1571
|
-
}), o =
|
|
2004
|
+
}), o = K(), N(e);
|
|
1572
2005
|
}
|
|
1573
|
-
function
|
|
2006
|
+
function j(e) {
|
|
1574
2007
|
let t = Date.parse(e.createdAt);
|
|
1575
2008
|
return {
|
|
1576
2009
|
role: e.role,
|
|
1577
2010
|
content: e.content,
|
|
1578
|
-
...Number.isFinite(t) ? { ts: t } : {}
|
|
2011
|
+
...Number.isFinite(t) ? { ts: t } : {},
|
|
2012
|
+
...h?.richMessages && e.blocks?.length ? { blocks: e.blocks } : {}
|
|
1579
2013
|
};
|
|
1580
2014
|
}
|
|
1581
|
-
async function
|
|
1582
|
-
let n = await
|
|
1583
|
-
n.messages.length > 0 && (o =
|
|
2015
|
+
async function N(e) {
|
|
2016
|
+
let n = await M(t.apiUrl, t.apiKey, e, $, r);
|
|
2017
|
+
n.messages.length > 0 && (o = ye(n), I({ messages: n.messages.map(j) })), I({ escalated: n.escalated === !0 }), F().escalated && _();
|
|
1584
2018
|
}
|
|
1585
|
-
async function
|
|
1586
|
-
if (
|
|
1587
|
-
|
|
2019
|
+
async function P() {
|
|
2020
|
+
if (xe(o, F().loadingOlder)) {
|
|
2021
|
+
I({ loadingOlder: !0 });
|
|
1588
2022
|
try {
|
|
1589
|
-
let e =
|
|
1590
|
-
n.messages.length > 0 &&
|
|
2023
|
+
let e = F().currentSessionId, n = await ne(t.apiUrl, t.apiKey, e, o.oldestCursor, $);
|
|
2024
|
+
n.messages.length > 0 && I({ messages: [...n.messages.map(j), ...F().messages] }), o = be(o, n);
|
|
1591
2025
|
} finally {
|
|
1592
|
-
|
|
2026
|
+
I({ loadingOlder: !1 });
|
|
1593
2027
|
}
|
|
1594
2028
|
}
|
|
1595
2029
|
}
|
|
1596
|
-
let
|
|
1597
|
-
async function
|
|
1598
|
-
let
|
|
1599
|
-
|
|
2030
|
+
let L = "", R = null, z = null;
|
|
2031
|
+
async function B(e, i, a) {
|
|
2032
|
+
let o = F().currentSessionId, s = x(n, o).length === 0 && F().messages.filter((e) => e.role === "user").length === 1;
|
|
2033
|
+
I({ isLoading: !0 });
|
|
1600
2034
|
try {
|
|
1601
|
-
let
|
|
2035
|
+
let c = i && a ? [{
|
|
2036
|
+
url: i,
|
|
2037
|
+
mimeType: a
|
|
2038
|
+
}] : void 0, l = await ee(t.apiUrl, t.apiKey, o, e, F().messages.filter((e) => !e.error), u, r, c), f = {
|
|
1602
2039
|
role: "assistant",
|
|
1603
|
-
content:
|
|
2040
|
+
content: l.reply,
|
|
1604
2041
|
ts: Date.now(),
|
|
1605
|
-
...
|
|
2042
|
+
...l.error ? { error: !0 } : {},
|
|
2043
|
+
...h?.richMessages && l.blocks?.length ? { blocks: l.blocks } : {}
|
|
1606
2044
|
};
|
|
1607
|
-
if (
|
|
1608
|
-
messages: [...
|
|
2045
|
+
if (I({
|
|
2046
|
+
messages: [...F().messages, f],
|
|
1609
2047
|
isLoading: !1
|
|
1610
|
-
}),
|
|
1611
|
-
|
|
1612
|
-
}), !
|
|
2048
|
+
}), l.error || S(n, o, [f]), !l.error && s && T(), l.error || M(t.apiUrl, t.apiKey, o, $, r).then((e) => {
|
|
2049
|
+
I({ escalated: e.escalated === !0 }), F().escalated && _();
|
|
2050
|
+
}), !l.error && l.pageAction && d) {
|
|
1613
2051
|
let e = d;
|
|
1614
2052
|
try {
|
|
1615
|
-
let t = await
|
|
2053
|
+
let t = await tt(l.pageAction, {
|
|
1616
2054
|
registry: D,
|
|
1617
2055
|
confirm: (t) => e.confirmAction(t)
|
|
1618
2056
|
});
|
|
@@ -1622,7 +2060,7 @@ function Fe(e) {
|
|
|
1622
2060
|
content: t.status === "executed" ? u.actionDone : t.status === "cancelled" ? u.actionCancelled : t.status === "unknown" ? `⚠ ${t.message ?? u.actionUnavailable}` : `⚠ ${t.message ?? u.actionError}`,
|
|
1623
2061
|
ts: Date.now()
|
|
1624
2062
|
};
|
|
1625
|
-
|
|
2063
|
+
I({ messages: [...F().messages, r] }), S(n, o, [r]);
|
|
1626
2064
|
} catch {
|
|
1627
2065
|
if (!d) return;
|
|
1628
2066
|
let e = {
|
|
@@ -1630,38 +2068,128 @@ function Fe(e) {
|
|
|
1630
2068
|
content: u.actionError,
|
|
1631
2069
|
ts: Date.now()
|
|
1632
2070
|
};
|
|
1633
|
-
|
|
2071
|
+
I({ messages: [...F().messages, e] }), S(n, o, [e]);
|
|
1634
2072
|
}
|
|
1635
2073
|
}
|
|
1636
2074
|
} catch {
|
|
1637
|
-
|
|
2075
|
+
I({ isLoading: !1 });
|
|
1638
2076
|
}
|
|
1639
2077
|
}
|
|
1640
|
-
async function
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
2078
|
+
async function ie(e) {
|
|
2079
|
+
let t = se(e);
|
|
2080
|
+
if (!t.ok) {
|
|
2081
|
+
I({ uploadError: t.error });
|
|
2082
|
+
return;
|
|
2083
|
+
}
|
|
2084
|
+
I({ uploadError: null });
|
|
2085
|
+
try {
|
|
2086
|
+
let { blob: t, mimeType: n } = await le(e), r = F().pendingAttachment;
|
|
2087
|
+
r && URL.revokeObjectURL(r.previewUrl), I({
|
|
2088
|
+
pendingAttachment: {
|
|
2089
|
+
blob: t,
|
|
2090
|
+
previewUrl: URL.createObjectURL(t),
|
|
2091
|
+
mimeType: n
|
|
2092
|
+
},
|
|
2093
|
+
uploadError: null
|
|
2094
|
+
});
|
|
2095
|
+
} catch {
|
|
2096
|
+
I({ uploadError: u.imageUploadError });
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
function ae() {
|
|
2100
|
+
let e = F().pendingAttachment;
|
|
2101
|
+
e && URL.revokeObjectURL(e.previewUrl), I({
|
|
2102
|
+
pendingAttachment: null,
|
|
2103
|
+
uploadError: null
|
|
2104
|
+
});
|
|
2105
|
+
}
|
|
2106
|
+
async function oe(e) {
|
|
2107
|
+
if (F().isLoading || F().isUploading) return;
|
|
2108
|
+
let i = F().pendingAttachment;
|
|
2109
|
+
if (!e && !i) return;
|
|
2110
|
+
I({ uploadError: null }), L = e, R = null, z = null;
|
|
2111
|
+
let a = F().currentSessionId, o = {
|
|
1644
2112
|
role: "user",
|
|
1645
2113
|
content: e,
|
|
1646
2114
|
ts: Date.now()
|
|
1647
2115
|
};
|
|
1648
|
-
|
|
2116
|
+
if (I({ messages: [...F().messages, o] }), S(n, a, [o]), i) {
|
|
2117
|
+
I({
|
|
2118
|
+
isUploading: !0,
|
|
2119
|
+
uploadError: null
|
|
2120
|
+
});
|
|
2121
|
+
let e = await k(t.apiUrl, t.apiKey, i.blob, r, u);
|
|
2122
|
+
if (I({ isUploading: !1 }), !e.ok) {
|
|
2123
|
+
I({ uploadError: e.error });
|
|
2124
|
+
let t = F().messages;
|
|
2125
|
+
I({ messages: t.slice(0, -1) });
|
|
2126
|
+
return;
|
|
2127
|
+
}
|
|
2128
|
+
R = e.url, z = i.mimeType, URL.revokeObjectURL(i.previewUrl), I({
|
|
2129
|
+
pendingAttachment: null,
|
|
2130
|
+
uploadError: null
|
|
2131
|
+
});
|
|
2132
|
+
}
|
|
2133
|
+
await B(e, R ?? void 0, z ?? void 0);
|
|
1649
2134
|
}
|
|
1650
|
-
function
|
|
1651
|
-
if (
|
|
1652
|
-
let e =
|
|
1653
|
-
|
|
2135
|
+
function ce() {
|
|
2136
|
+
if (F().isLoading || !L) return;
|
|
2137
|
+
let e = F().messages;
|
|
2138
|
+
I({ messages: e.length > 0 && e[e.length - 1].error ? e.slice(0, -1) : e }), B(L, R ?? void 0, z ?? void 0);
|
|
1654
2139
|
}
|
|
1655
|
-
function
|
|
1656
|
-
|
|
1657
|
-
|
|
2140
|
+
async function V(e) {
|
|
2141
|
+
if (!d) return;
|
|
2142
|
+
if (!D.has(e)) {
|
|
2143
|
+
let e = {
|
|
2144
|
+
role: "assistant",
|
|
2145
|
+
content: `⚠ ${u.actionUnavailable}`,
|
|
2146
|
+
ts: Date.now()
|
|
2147
|
+
};
|
|
2148
|
+
I({ messages: [...F().messages, e] });
|
|
2149
|
+
return;
|
|
2150
|
+
}
|
|
2151
|
+
let t = d;
|
|
2152
|
+
try {
|
|
2153
|
+
let n = await tt({
|
|
2154
|
+
actionName: e,
|
|
2155
|
+
params: {},
|
|
2156
|
+
reason: ""
|
|
2157
|
+
}, {
|
|
2158
|
+
registry: D,
|
|
2159
|
+
confirm: (e) => t.confirmAction(e)
|
|
2160
|
+
});
|
|
2161
|
+
if (!d) return;
|
|
2162
|
+
let r = {
|
|
2163
|
+
role: "assistant",
|
|
2164
|
+
content: n.status === "executed" ? u.actionDone : n.status === "cancelled" ? u.actionCancelled : n.status === "unknown" ? `⚠ ${n.message ?? u.actionUnavailable}` : `⚠ ${n.message ?? u.actionError}`,
|
|
2165
|
+
ts: Date.now()
|
|
2166
|
+
};
|
|
2167
|
+
I({ messages: [...F().messages, r] });
|
|
2168
|
+
} catch {
|
|
2169
|
+
if (!d) return;
|
|
2170
|
+
let e = {
|
|
2171
|
+
role: "assistant",
|
|
2172
|
+
content: u.actionError,
|
|
2173
|
+
ts: Date.now()
|
|
2174
|
+
};
|
|
2175
|
+
I({ messages: [...F().messages, e] });
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
function H() {
|
|
2179
|
+
let e = !F().isOpen, t = F().view;
|
|
2180
|
+
I({
|
|
1658
2181
|
isOpen: e,
|
|
1659
2182
|
...e ? { unreadCount: 0 } : {}
|
|
1660
|
-
});
|
|
2183
|
+
}), e && t === "home" && T();
|
|
1661
2184
|
}
|
|
1662
2185
|
return () => {
|
|
1663
|
-
l = !0, d = null, c(), m && clearTimeout(m),
|
|
2186
|
+
l = !0, d = null, c(), m && clearTimeout(m), g &&= (clearTimeout(g), null);
|
|
2187
|
+
let e = F().pendingAttachment;
|
|
2188
|
+
e && URL.revokeObjectURL(e.previewUrl), I({
|
|
2189
|
+
pendingAttachment: null,
|
|
2190
|
+
uploadError: null
|
|
2191
|
+
}), s.remove();
|
|
1664
2192
|
};
|
|
1665
2193
|
}
|
|
1666
2194
|
//#endregion
|
|
1667
|
-
export {
|
|
2195
|
+
export { nt as t };
|