@locdo.tech/botiq-chat-sdk 0.5.0 → 0.6.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 CHANGED
@@ -1,2 +1,2 @@
1
- import { t as e } from "./npm-XnNJWLXh.js";
1
+ import { t as e } from "./npm-DbbHOVFV.js";
2
2
  export { e as init };
@@ -90,19 +90,23 @@ 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;
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;
94
94
  return !a.design?.colors || !a.design?.layout || !a.design?.content || !l(a.design) ? {
95
95
  name: o,
96
96
  design: t,
97
97
  widgetLanguage: s,
98
98
  ...c ? { pageActions: c } : {},
99
- ...u ? { contactInfo: u } : {}
99
+ ...u ? { contactInfo: u } : {},
100
+ ...f ? { proactive: f } : {},
101
+ ...p ? { status: p } : {}
100
102
  } : {
101
103
  name: o,
102
104
  design: a.design,
103
105
  widgetLanguage: s,
104
106
  ...c ? { pageActions: c } : {},
105
- ...u ? { contactInfo: u } : {}
107
+ ...u ? { contactInfo: u } : {},
108
+ ...f ? { proactive: f } : {},
109
+ ...p ? { status: p } : {}
106
110
  };
107
111
  }
108
112
  function p(t) {
@@ -113,14 +117,14 @@ function p(t) {
113
117
  }
114
118
  //#endregion
115
119
  //#region src/core/session.ts
116
- var m = "botiq:sessionId", h = "botiq:sessionId:", g = "botiq:history:", _ = 10;
117
- function v() {
120
+ var m = "botiq:sessionId", h = "botiq:sessionId:", g = "botiq:history:", _ = "botiq:visitorId", v = 10;
121
+ function y() {
118
122
  try {
119
123
  let e = localStorage.getItem(m);
120
124
  localStorage.removeItem(m), e && localStorage.removeItem(g + e);
121
125
  } catch {}
122
126
  }
123
- function y(e) {
127
+ function b(e) {
124
128
  try {
125
129
  let t = h + e, n = localStorage.getItem(t);
126
130
  return n || (n = crypto.randomUUID(), localStorage.setItem(t, n)), n;
@@ -128,7 +132,7 @@ function y(e) {
128
132
  return crypto.randomUUID();
129
133
  }
130
134
  }
131
- function b(e, t) {
135
+ function x(e, t) {
132
136
  try {
133
137
  let n = localStorage.getItem(`${g}${e}:${t}`);
134
138
  return n ? JSON.parse(n) : [];
@@ -136,27 +140,38 @@ function b(e, t) {
136
140
  return [];
137
141
  }
138
142
  }
139
- function x(e, t, n) {
143
+ function S(e, t, n) {
140
144
  try {
141
- let r = [...b(e, t), ...n].slice(-_);
145
+ let r = [...x(e, t), ...n].slice(-v);
142
146
  localStorage.setItem(`${g}${e}:${t}`, JSON.stringify(r));
143
147
  } catch {}
144
148
  }
149
+ function C() {
150
+ try {
151
+ let e = localStorage.getItem(_);
152
+ return e || (e = crypto.randomUUID(), localStorage.setItem(_, e)), e;
153
+ } catch {
154
+ return crypto.randomUUID();
155
+ }
156
+ }
157
+ function w() {
158
+ return crypto.randomUUID();
159
+ }
145
160
  //#endregion
146
161
  //#region src/core/action-registry.ts
147
- var S = /^[a-z][a-z0-9_]{2,40}$/, C = new Set([
162
+ var T = /^[a-z][a-z0-9_]{2,40}$/, E = new Set([
148
163
  "low",
149
164
  "medium",
150
165
  "high"
151
- ]), w = new class {
166
+ ]), D = new class {
152
167
  actions = /* @__PURE__ */ new Map();
153
168
  declarativeRunner;
154
169
  constructor(e) {
155
170
  this.declarativeRunner = e;
156
171
  }
157
172
  validate(e) {
158
- if (!S.test(e.name)) throw Error(`Invalid action name: "${e.name}"`);
159
- if (!C.has(e.riskLevel)) throw Error(`Invalid riskLevel: ${e.riskLevel}`);
173
+ if (!T.test(e.name)) throw Error(`Invalid action name: "${e.name}"`);
174
+ if (!E.has(e.riskLevel)) throw Error(`Invalid riskLevel: ${e.riskLevel}`);
160
175
  if (typeof e.description != "string" || e.description.length < 5) throw Error(`description ≥5 chars required for ${e.name}`);
161
176
  }
162
177
  seed(e) {
@@ -208,39 +223,57 @@ var S = /^[a-z][a-z0-9_]{2,40}$/, C = new Set([
208
223
  }();
209
224
  //#endregion
210
225
  //#region src/core/api.ts
211
- async function ee(e, t, n, r, i, a) {
226
+ async function ee(e, t, n) {
212
227
  try {
213
- let o = w.getDefinitions(), s = await fetch(`${e}/widget/chat`, {
228
+ let r = new URLSearchParams({ visitorId: n }), i = await fetch(`${e}/widget/conversations?${r.toString()}`, {
229
+ method: "GET",
230
+ headers: {
231
+ "X-Api-Key": t,
232
+ "X-Visitor-Id": n
233
+ },
234
+ referrerPolicy: "no-referrer-when-downgrade"
235
+ });
236
+ if (!i.ok) return [];
237
+ let a = await i.json();
238
+ return Array.isArray(a.conversations) ? a.conversations : [];
239
+ } catch {
240
+ return [];
241
+ }
242
+ }
243
+ async function te(e, t, n, r, i, a, o) {
244
+ try {
245
+ let s = D.getDefinitions(), c = await fetch(`${e}/widget/chat`, {
214
246
  method: "POST",
215
247
  headers: {
216
248
  "Content-Type": "application/json",
217
- "X-Api-Key": t
249
+ "X-Api-Key": t,
250
+ ...o ? { "X-Visitor-Id": o } : {}
218
251
  },
219
252
  referrerPolicy: "no-referrer-when-downgrade",
220
253
  body: JSON.stringify({
221
254
  sessionId: n,
222
255
  message: r,
223
256
  history: i,
224
- ...o.length > 0 ? { availableActions: o } : {}
257
+ ...s.length > 0 ? { availableActions: s } : {}
225
258
  })
226
259
  });
227
- if (!s.ok) return s.status === 401 ? {
260
+ if (!c.ok) return c.status === 401 ? {
228
261
  reply: a.errorAuth,
229
262
  error: !0
230
- } : s.status === 403 ? {
263
+ } : c.status === 403 ? {
231
264
  reply: a.errorForbidden,
232
265
  error: !0
233
- } : s.status === 429 ? {
266
+ } : c.status === 429 ? {
234
267
  reply: a.errorQuota,
235
268
  error: !0
236
269
  } : {
237
270
  reply: a.errorGeneric,
238
271
  error: !0
239
272
  };
240
- let c = await s.json();
273
+ let l = await c.json();
241
274
  return {
242
- reply: c.reply || a.errorMessage,
243
- pageAction: c.pageAction
275
+ reply: l.reply || a.errorMessage,
276
+ pageAction: l.pageAction
244
277
  };
245
278
  } catch {
246
279
  return {
@@ -249,68 +282,78 @@ async function ee(e, t, n, r, i, a) {
249
282
  };
250
283
  }
251
284
  }
252
- var T = {
285
+ var O = {
253
286
  messages: [],
254
287
  hasMore: !1
255
288
  };
256
- function te(e) {
289
+ function k(e) {
257
290
  if (!e || typeof e != "object") return !1;
258
291
  let t = e;
259
292
  return typeof t.id == "string" && (t.role === "user" || t.role === "assistant") && typeof t.content == "string";
260
293
  }
261
- async function E(e, t, n, r, i) {
294
+ async function A(e, t, n, r, i, a) {
262
295
  try {
263
- let a = new URLSearchParams({
296
+ let o = new URLSearchParams({
264
297
  sessionId: n,
265
298
  limit: String(i)
266
299
  });
267
- r && a.set("before", r);
268
- let o = await fetch(`${e}/widget/messages?${a.toString()}`, {
300
+ r && o.set("before", r);
301
+ let s = await fetch(`${e}/widget/messages?${o.toString()}`, {
269
302
  method: "GET",
270
- headers: { "X-Api-Key": t },
303
+ headers: {
304
+ "X-Api-Key": t,
305
+ ...a ? { "X-Visitor-Id": a } : {}
306
+ },
271
307
  referrerPolicy: "no-referrer-when-downgrade"
272
308
  });
273
- if (!o.ok) return T;
274
- let s = await o.json();
309
+ if (!s.ok) return O;
310
+ let c = await s.json();
275
311
  return {
276
- messages: Array.isArray(s.messages) ? s.messages.filter(te) : [],
277
- hasMore: s.hasMore === !0
312
+ messages: Array.isArray(c.messages) ? c.messages.filter(k) : [],
313
+ hasMore: c.hasMore === !0,
314
+ escalated: c.escalated === !0
278
315
  };
279
316
  } catch {
280
- return T;
317
+ return O;
281
318
  }
282
319
  }
283
- function D(e, t, n, r) {
284
- return E(e, t, n, void 0, r);
320
+ function j(e, t, n, r, i) {
321
+ return A(e, t, n, void 0, r, i);
285
322
  }
286
- function O(e, t, n, r, i) {
287
- return E(e, t, n, r, i);
323
+ function ne(e, t, n, r, i, a) {
324
+ return A(e, t, n, r, i, a);
288
325
  }
289
326
  //#endregion
290
327
  //#region src/core/state.ts
291
- var k = {
328
+ var M = {
292
329
  messages: [],
293
330
  isLoading: !1,
294
331
  isOpen: !1,
295
- loadingOlder: !1
296
- }, A = /* @__PURE__ */ new Set();
297
- function j() {
298
- return k;
299
- }
300
- function M(e) {
301
- Object.assign(k, e);
332
+ loadingOlder: !1,
333
+ view: "home",
334
+ unreadCount: 0,
335
+ conversations: [],
336
+ currentSessionId: "",
337
+ escalated: !1
338
+ }, N = /* @__PURE__ */ new Set();
339
+ function P() {
340
+ return M;
341
+ }
342
+ function F(e) {
343
+ Object.assign(M, e);
302
344
  let t = {
303
- ...k,
304
- messages: [...k.messages]
345
+ ...M,
346
+ messages: [...M.messages],
347
+ conversations: [...M.conversations]
305
348
  };
306
- A.forEach((e) => e(t));
349
+ N.forEach((e) => e(t));
307
350
  }
308
- function N(e) {
309
- return A.add(e), () => A.delete(e);
351
+ function re(e) {
352
+ return N.add(e), () => N.delete(e);
310
353
  }
311
354
  //#endregion
312
355
  //#region src/core/styles.ts
313
- var P = {
356
+ var I = {
314
357
  inter: {
315
358
  url: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap",
316
359
  family: "'Inter', system-ui, -apple-system, sans-serif"
@@ -332,21 +375,21 @@ var P = {
332
375
  family: "'Playfair Display', Georgia, serif"
333
376
  }
334
377
  };
335
- function F(e, t) {
378
+ function L(e, t) {
336
379
  if (!t) return e;
337
380
  let n = t.angle ?? 135;
338
381
  return t.type === "linear" ? `linear-gradient(${n}deg, ${t.from}, ${t.to})` : `radial-gradient(circle, ${t.from}, ${t.to})`;
339
382
  }
340
- function ne(e) {
383
+ function R(e) {
341
384
  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, "");
342
385
  }
343
- function re(e) {
386
+ function ie(e) {
344
387
  let t = e?.bubbleOpen ?? "none", n = e?.typingIndicator ?? "dots-bounce";
345
388
  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");
346
389
  }
347
- var ie = "\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";
348
- function ae(e) {
349
- let { colors: t, layout: n, font: r, gradient: i, animation: a, customCSS: o, whiteLabel: s } = e, c = P[r] ?? P.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 = F(t.primary, i), h = F(t.header, i), g = F(t.userBubble, i), _ = s ? ".botiq-badge { display: none !important; }" : "";
390
+ var ae = "\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";
391
+ function oe(e) {
392
+ let { colors: t, layout: n, font: r, gradient: i, animation: a, customCSS: o, whiteLabel: s } = e, c = I[r] ?? I.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 = L(t.primary, i), h = L(t.header, i), g = L(t.userBubble, i), _ = s ? ".botiq-badge { display: none !important; }" : "";
350
393
  return `
351
394
  @import url('${c.url}');
352
395
 
@@ -393,6 +436,7 @@ function ae(e) {
393
436
  box-shadow: var(--shadow-md);
394
437
  transition: transform .2s ease, box-shadow .2s ease;
395
438
  outline: none;
439
+ position: relative;
396
440
  }
397
441
 
398
442
  .bubble:hover { transform: scale(1.08); box-shadow: var(--shadow-lg); }
@@ -404,6 +448,24 @@ function ae(e) {
404
448
  .bubble.open .icon-chat { opacity: 0; }
405
449
  .bubble.open .icon-close { opacity: 1; }
406
450
 
451
+ .unread-badge {
452
+ position: absolute;
453
+ top: -2px;
454
+ right: -2px;
455
+ min-width: 18px;
456
+ height: 18px;
457
+ padding: 0 5px;
458
+ border-radius: 9px;
459
+ background: #EF4444;
460
+ color: #fff;
461
+ font-size: 11px;
462
+ font-weight: 600;
463
+ display: flex;
464
+ align-items: center;
465
+ justify-content: center;
466
+ pointer-events: none;
467
+ }
468
+
407
469
  /* ── Chat Window ────────────────────────── */
408
470
  .chat-window {
409
471
  position: absolute;
@@ -482,6 +544,120 @@ function ae(e) {
482
544
  }
483
545
  .close-btn:hover { background: rgba(255,255,255,.25); }
484
546
 
547
+ /* ── Chat body + panels ─────────────────── */
548
+ .chat-body { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
549
+
550
+ .panel { display: none; flex: 1; flex-direction: column; overflow: hidden; }
551
+ .panel.active { display: flex; }
552
+
553
+ /* ── Bottom nav ─────────────────────────── */
554
+ .bottom-nav {
555
+ display: flex;
556
+ border-top: 1px solid var(--gray-100);
557
+ flex-shrink: 0;
558
+ background: var(--color-bg);
559
+ }
560
+
561
+ .nav-btn {
562
+ flex: 1;
563
+ background: transparent;
564
+ border: none;
565
+ color: var(--gray-400);
566
+ font: inherit;
567
+ font-size: 12px;
568
+ padding: 10px;
569
+ cursor: pointer;
570
+ transition: color .15s;
571
+ }
572
+
573
+ .nav-btn:hover { color: var(--color-text); }
574
+ .nav-btn.active { color: var(--color-primary); }
575
+
576
+ /* ── Messages list panel ────────────────── */
577
+ .msg-list { flex: 1; overflow-y: auto; }
578
+
579
+ .msg-list-item {
580
+ display: grid;
581
+ width: 100%;
582
+ text-align: left;
583
+ gap: 2px;
584
+ padding: 12px 16px;
585
+ background: transparent;
586
+ border: none;
587
+ border-bottom: 1px solid var(--gray-100);
588
+ cursor: pointer;
589
+ font: inherit;
590
+ }
591
+
592
+ .msg-list-item:hover { background: var(--gray-50); }
593
+
594
+ .msg-list-title {
595
+ color: var(--color-text);
596
+ font-weight: 600;
597
+ font-size: 14px;
598
+ }
599
+
600
+ .msg-list-preview {
601
+ color: var(--gray-400);
602
+ font-size: 12px;
603
+ white-space: nowrap;
604
+ overflow: hidden;
605
+ text-overflow: ellipsis;
606
+ }
607
+
608
+ .msg-list-time { color: var(--gray-400); font-size: 10px; }
609
+
610
+ .msg-list-badge { color: #F97316; font-size: 10px; }
611
+
612
+ .msg-list-empty {
613
+ padding: 24px;
614
+ text-align: center;
615
+ color: var(--gray-400);
616
+ font-size: 13px;
617
+ }
618
+
619
+ .msg-list-new {
620
+ margin: 10px 16px;
621
+ padding: 10px;
622
+ border-radius: 10px;
623
+ border: 1.5px solid var(--color-primary);
624
+ background: transparent;
625
+ color: var(--color-primary);
626
+ cursor: pointer;
627
+ font: inherit;
628
+ width: calc(100% - 32px);
629
+ }
630
+
631
+ .msg-list-new:hover { background: var(--color-primary); color: #fff; }
632
+
633
+ /* ── Home panel ─────────────────────────── */
634
+ .home-greeting {
635
+ font-size: 20px;
636
+ font-weight: 600;
637
+ color: var(--color-text);
638
+ padding: 24px 18px 8px;
639
+ }
640
+
641
+ .home-start {
642
+ margin: 8px 18px;
643
+ padding: 14px;
644
+ border-radius: 12px;
645
+ border: 1px solid var(--gray-200);
646
+ background: var(--gray-50);
647
+ color: var(--color-text);
648
+ text-align: left;
649
+ cursor: pointer;
650
+ font: inherit;
651
+ font-size: 14px;
652
+ transition: background .15s, border-color .15s;
653
+ }
654
+
655
+ .home-start:hover { background: var(--gray-100); border-color: var(--color-primary); }
656
+
657
+ .home-status { margin: 8px 18px; font-size: 12px; }
658
+ .home-status--online { color: #16A34A; }
659
+ .home-status--offline { color: var(--gray-400); }
660
+
485
661
  /* ── Messages ───────────────────────────── */
486
662
  .messages {
487
663
  flex: 1;
@@ -703,6 +879,17 @@ function ae(e) {
703
879
  color: #fff;
704
880
  }
705
881
 
882
+ /* ── Handoff Banner ─────────────────────── */
883
+ .handoff-banner {
884
+ margin: 6px 14px;
885
+ padding: 6px 10px;
886
+ border-radius: 8px;
887
+ background: rgba(249,115,22,.12);
888
+ color: var(--color-primary);
889
+ font-size: 12px;
890
+ text-align: center;
891
+ }
892
+
706
893
  /* ── Footer / Input ─────────────────────── */
707
894
  .chat-footer {
708
895
  border-top: 1px solid var(--gray-100);
@@ -791,9 +978,9 @@ function ae(e) {
791
978
  .emoji-item:hover { background: var(--gray-100); }
792
979
 
793
980
  ${_}
794
- ${re(a)}
795
- ${o ? ne(o) : ""}
796
- ${ie}
981
+ ${ie(a)}
982
+ ${o ? R(o) : ""}
983
+ ${ae}
797
984
  @media (max-width: 480px) {
798
985
  :host { bottom: 0; right: 0; left: 0; }
799
986
  .chat-window {
@@ -809,58 +996,105 @@ ${ie}
809
996
  `;
810
997
  }
811
998
  //#endregion
999
+ //#region src/core/timeago.ts
1000
+ function z(e) {
1001
+ return String(e).padStart(2, "0");
1002
+ }
1003
+ function B(e, t, n) {
1004
+ let r = Math.max(0, Math.floor((t - e) / 1e3));
1005
+ if (r < 60) return n === "vi" ? "vừa xong" : "just now";
1006
+ let i = Math.floor(r / 60);
1007
+ if (i < 60) return n === "vi" ? `${i} phút` : `${i} min`;
1008
+ let a = new Date(e);
1009
+ return `${z(a.getHours())}:${z(a.getMinutes())}`;
1010
+ }
1011
+ function se(e, t, n) {
1012
+ let r = (e) => {
1013
+ let t = new Date(e);
1014
+ return new Date(t.getFullYear(), t.getMonth(), t.getDate()).getTime();
1015
+ }, i = Math.round((r(t) - r(e)) / 864e5);
1016
+ if (i <= 0) return n === "vi" ? "Hôm nay" : "Today";
1017
+ if (i === 1) return n === "vi" ? "Hôm qua" : "Yesterday";
1018
+ let a = new Date(e);
1019
+ return `${z(a.getDate())}/${z(a.getMonth() + 1)}/${a.getFullYear()}`;
1020
+ }
1021
+ //#endregion
1022
+ //#region src/core/views.ts
1023
+ function V(e) {
1024
+ return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1025
+ }
1026
+ function ce(e, t, n) {
1027
+ let r = `<button class="msg-list-new" type="button">+ ${V(t.newConversation)}</button>`;
1028
+ return e.length === 0 ? `<div class="msg-list-empty">${V(t.noConversations)}</div>${r}` : `<div class="msg-list">${e.map((e) => {
1029
+ let r = e.lastMessageAt ? Date.parse(e.lastMessageAt) : n, i = Number.isFinite(r) ? B(r, n, "vi") : "", a = e.escalated ? `<span class="msg-list-badge">${V(t.waitingForHuman)}</span>` : "";
1030
+ return `<button class="msg-list-item" type="button" data-session="${V(e.sessionId)}">
1031
+ <span class="msg-list-title">${V(e.title)}</span>
1032
+ <span class="msg-list-preview">${V(e.preview)}</span>
1033
+ <span class="msg-list-time">${V(i)}</span>${a}
1034
+ </button>`;
1035
+ }).join("")}</div>${r}`;
1036
+ }
1037
+ function le(e, t) {
1038
+ let n = e.status !== "offline", r = n ? t.statusOnline : t.statusPaused;
1039
+ return `
1040
+ <div class="home-greeting">${V(e.design.content.greeting || t.homeGreeting)}</div>
1041
+ <button class="home-start" type="button">${V(t.startConversation)} ›</button>
1042
+ <div class="home-status home-status--${n ? "online" : "offline"}">● ${V(r)}</div>
1043
+ `;
1044
+ }
1045
+ //#endregion
812
1046
  //#region src/core/assets.ts
813
- var oe = "data:image/png;base64,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";
1047
+ var ue = "data:image/png;base64,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";
814
1048
  //#endregion
815
1049
  //#region src/core/history-pager.ts
816
- function se() {
1050
+ function H() {
817
1051
  return {
818
1052
  oldestCursor: null,
819
1053
  hasMore: !1,
820
1054
  cursorReady: !1
821
1055
  };
822
1056
  }
823
- function ce(e) {
1057
+ function U(e) {
824
1058
  return {
825
1059
  oldestCursor: e.messages[0]?.id ?? null,
826
1060
  hasMore: e.hasMore,
827
1061
  cursorReady: e.messages.length > 0
828
1062
  };
829
1063
  }
830
- function I(e, t) {
1064
+ function de(e, t) {
831
1065
  return {
832
1066
  oldestCursor: t.messages[0]?.id ?? e.oldestCursor,
833
1067
  hasMore: t.hasMore,
834
1068
  cursorReady: e.cursorReady
835
1069
  };
836
1070
  }
837
- function L(e, t) {
1071
+ function fe(e, t) {
838
1072
  return e.cursorReady && e.hasMore && !t && e.oldestCursor !== null;
839
1073
  }
840
- function R(e, t, n) {
1074
+ function pe(e, t, n) {
841
1075
  return e + (n - t);
842
1076
  }
843
1077
  //#endregion
844
1078
  //#region src/core/confirm-dialog.ts
845
- function z(e) {
1079
+ function W(e) {
846
1080
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#x27;");
847
1081
  }
848
- function B(e, t) {
1082
+ function me(e, t) {
849
1083
  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…";
850
1084
  return new Promise((o) => {
851
1085
  let s = document.createElement("div");
852
1086
  s.className = "botiq-confirm-overlay", s.innerHTML = `
853
1087
  <div class="botiq-confirm-dialog" role="dialog" aria-modal="true">
854
- <div class="botiq-confirm-header">${z(t.title)}</div>
1088
+ <div class="botiq-confirm-header">${W(t.title)}</div>
855
1089
  <div class="botiq-confirm-body">
856
- <div class="botiq-confirm-reason">${z(t.reason)}</div>
857
- <pre class="botiq-confirm-params">${z(t.paramsDisplay)}</pre>
1090
+ <div class="botiq-confirm-reason">${W(t.reason)}</div>
1091
+ <pre class="botiq-confirm-params">${W(t.paramsDisplay)}</pre>
858
1092
  </div>
859
1093
  <div class="botiq-confirm-actions">
860
- <button class="botiq-confirm-yes" data-risk="${t.riskLevel}" type="button">${z(n)}</button>
861
- <button class="botiq-confirm-no" type="button">${z(r)}</button>
1094
+ <button class="botiq-confirm-yes" data-risk="${t.riskLevel}" type="button">${W(n)}</button>
1095
+ <button class="botiq-confirm-no" type="button">${W(r)}</button>
862
1096
  </div>
863
- ${t.autoConfirmAfterSec ? `<div class="botiq-confirm-countdown">${z(i)}<span class="botiq-confirm-secs">${t.autoConfirmAfterSec}</span>${z(a)}</div>` : ""}
1097
+ ${t.autoConfirmAfterSec ? `<div class="botiq-confirm-countdown">${W(i)}<span class="botiq-confirm-secs">${t.autoConfirmAfterSec}</span>${W(a)}</div>` : ""}
864
1098
  </div>`, e.appendChild(s);
865
1099
  let c = !1, l = null, u = (t) => {
866
1100
  c || (c = !0, l && clearInterval(l), e.removeChild(s), o(t));
@@ -874,39 +1108,16 @@ function B(e, t) {
874
1108
  });
875
1109
  }
876
1110
  //#endregion
877
- //#region src/core/timeago.ts
878
- function V(e) {
879
- return String(e).padStart(2, "0");
880
- }
881
- function H(e, t, n) {
882
- let r = Math.max(0, Math.floor((t - e) / 1e3));
883
- if (r < 60) return n === "vi" ? "vừa xong" : "just now";
884
- let i = Math.floor(r / 60);
885
- if (i < 60) return n === "vi" ? `${i} phút` : `${i} min`;
886
- let a = new Date(e);
887
- return `${V(a.getHours())}:${V(a.getMinutes())}`;
888
- }
889
- function U(e, t, n) {
890
- let r = (e) => {
891
- let t = new Date(e);
892
- return new Date(t.getFullYear(), t.getMonth(), t.getDate()).getTime();
893
- }, i = Math.round((r(t) - r(e)) / 864e5);
894
- if (i <= 0) return n === "vi" ? "Hôm nay" : "Today";
895
- if (i === 1) return n === "vi" ? "Hôm qua" : "Yesterday";
896
- let a = new Date(e);
897
- return `${V(a.getDate())}/${V(a.getMonth() + 1)}/${a.getFullYear()}`;
898
- }
899
- //#endregion
900
1111
  //#region src/core/emoji.ts
901
- function W(e, t) {
1112
+ function he(e, t) {
902
1113
  let n = e.selectionStart ?? e.value.length, r = e.selectionEnd ?? e.value.length;
903
1114
  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 }));
904
1115
  }
905
1116
  var G = null;
906
- async function le() {
1117
+ async function ge() {
907
1118
  return G || (G = (await import("./emoji-data-DWiYsBZI.js")).EMOJIS, G);
908
1119
  }
909
- function ue(e) {
1120
+ function _e(e) {
910
1121
  let t = document.createElement("button");
911
1122
  t.type = "button", t.className = "emoji-btn", t.setAttribute("aria-label", "Emoji"), t.textContent = "🙂";
912
1123
  let n = document.createElement("div");
@@ -914,7 +1125,7 @@ function ue(e) {
914
1125
  let r = !1;
915
1126
  return t.addEventListener("click", async () => {
916
1127
  if (!r) {
917
- let t = await le();
1128
+ let t = await ge();
918
1129
  for (let r of t) {
919
1130
  let t = document.createElement("button");
920
1131
  t.type = "button", t.className = "emoji-item", t.textContent = r, t.addEventListener("click", () => {
@@ -931,8 +1142,8 @@ function ue(e) {
931
1142
  }
932
1143
  //#endregion
933
1144
  //#region src/core/ui.ts
934
- var de = "https://bot-q-frontend.vercel.app/", fe = "<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>", pe = "<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>", K = `<img src="${oe}" alt="" style="width:100%;height:100%;object-fit:cover;border-radius:50%" />`, me = "<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>", he = "<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>";
935
- function ge(e) {
1145
+ var ve = "https://bot-q-frontend.vercel.app/", ye = "<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>", be = "<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>", K = `<img src="${ue}" alt="" style="width:100%;height:100%;object-fit:cover;border-radius:50%" />`, xe = "<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>", Se = "<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>";
1146
+ function Ce(e) {
936
1147
  if (!e || e.type === "icon") return K;
937
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%">${q(e.value)}</span>`;
938
1149
  if (e.type === "initials") {
@@ -948,20 +1159,26 @@ function J(e) {
948
1159
  let t = [];
949
1160
  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;
950
1161
  }
951
- function _e(e) {
1162
+ function we(e) {
952
1163
  return /^\|[\s\-:|]+\|$/.test(e);
953
1164
  }
954
1165
  function Y(e) {
955
1166
  return e.replace(/^\|/, "").replace(/\|$/, "").split("|").map((e) => e.trim());
956
1167
  }
957
- function ve(e) {
1168
+ function Te(e, t) {
1169
+ return e ? `<div class="handoff-banner">⏳ ${q(t.waitingForHuman)}</div>` : "";
1170
+ }
1171
+ function Ee(e) {
1172
+ return e <= 0 ? "" : `<span class="unread-badge">${e > 9 ? "9+" : String(e)}</span>`;
1173
+ }
1174
+ function De(e) {
958
1175
  let t = q(e).replace(/\x00/g, "").split("\n"), n = [], r = 0;
959
1176
  for (; r < t.length;) {
960
1177
  let e = t[r].trim();
961
1178
  if (e.startsWith("|") && e.endsWith("|")) {
962
1179
  let e = [];
963
1180
  for (; r < t.length && t[r].trim().startsWith("|") && t[r].trim().endsWith("|");) e.push(t[r].trim()), r++;
964
- let i = e.findIndex(_e), a = i > 0 ? e.slice(0, i) : [], o = i >= 0 ? e.slice(i + 1) : e, s = "<table>";
1181
+ let i = e.findIndex(we), a = i > 0 ? e.slice(0, i) : [], o = i >= 0 ? e.slice(i + 1) : e, s = "<table>";
965
1182
  a.length > 0 && (s += "<thead>" + a.map((e) => "<tr>" + Y(e).map((e) => `<th>${J(e)}</th>`).join("") + "</tr>").join("") + "</thead>"), o.length > 0 && (s += "<tbody>" + o.map((e) => "<tr>" + Y(e).map((e) => `<td>${J(e)}</td>`).join("") + "</tr>").join("") + "</tbody>"), s += "</table>", n.push(s);
966
1183
  continue;
967
1184
  }
@@ -996,101 +1213,129 @@ function ve(e) {
996
1213
  for (; n.length > 0 && n[n.length - 1] === "<br>";) n.pop();
997
1214
  return n.join("");
998
1215
  }
999
- function ye(e, t) {
1216
+ function Oe(e, t) {
1000
1217
  let { strings: n, content: r, botName: i, lang: a, now: o, contactInfo: s } = t;
1001
1218
  if (e.messages.length === 0 && !e.isLoading) {
1002
1219
  let e = r.suggestionChips.length > 0 ? `<div class="chips">${r.suggestionChips.map((e) => `<button class="chip">${q(e)}</button>`).join("")}</div>` : "";
1003
1220
  return `
1004
1221
  <div class="empty-state">
1005
- ${he}
1222
+ ${Se}
1006
1223
  <span class="greeting">${q(r.greeting || n.defaultGreeting)}</span>
1007
1224
  ${e}
1008
1225
  </div>
1009
1226
  `;
1010
1227
  }
1011
1228
  let c = "", l = e.messages.map((e) => {
1012
- let t = e.ts ?? o, r = U(t, o, a), l = r === c ? "" : `<div class="day-sep"><span>${q(r)}</span></div>`;
1229
+ let t = e.ts ?? o, r = se(t, o, a), l = r === c ? "" : `<div class="day-sep"><span>${q(r)}</span></div>`;
1013
1230
  c = r;
1014
- let u = e.role === "assistant" ? ve(e.content) : q(e.content), d = e.role === "assistant" && !e.error ? `<div class="msg-meta">${q(i)} · ${q(H(t, o, a))}</div>` : "", f = e.error ? `<button class="retry-btn" type="button">↻ ${q(n.retry)}</button>` : "", p = e.error && s ? `<div class="msg-contact">${q(s)}</div>` : "";
1231
+ let u = e.role === "assistant" ? De(e.content) : q(e.content), d = e.role === "assistant" && !e.error ? `<div class="msg-meta">${q(i)} · ${q(B(t, o, a))}</div>` : "", f = e.error ? `<button class="retry-btn" type="button">↻ ${q(n.retry)}</button>` : "", p = e.error && s ? `<div class="msg-contact">${q(s)}</div>` : "";
1015
1232
  return `${l}<div class="${`message ${e.role}${e.error ? " error" : ""}`}"><div class="message-bubble">${u}</div>${f}${p}${d}</div>`;
1016
1233
  }).join(""), u = e.loadingOlder ? "<div class=\"typing\"><span></span><span></span><span></span></div>" : "", d = e.isLoading ? "<div class=\"typing\"><span></span><span></span><span></span></div>" : "";
1017
1234
  return u + l + d;
1018
1235
  }
1019
- function be(e, t, n, r, i, a, o) {
1020
- let { name: s, design: c } = t, l, u, d, f, p, m, { content: h } = c;
1021
- function g(e) {
1022
- e.setAttribute("data-position", c.layout.position), l = e.attachShadow({ mode: "closed" });
1023
- let t = document.createElement("style");
1024
- t.textContent = ae(c), l.appendChild(t), u = document.createElement("button"), u.className = "bubble", u.setAttribute("aria-label", n.ariaOpenChat), u.innerHTML = `
1025
- <span class="icon-chat">${fe}</span>
1026
- <span class="icon-close">${pe}</span>
1027
- `, u.addEventListener("click", i), l.appendChild(u), d = document.createElement("div"), d.className = "chat-window", d.setAttribute("role", "dialog"), d.setAttribute("aria-label", `${s} chat`), d.innerHTML = `
1236
+ function ke(e, t, n, r) {
1237
+ let { name: i, design: a } = t, o, s, c, l, u, d, f, p, m, h, g, _, { content: v } = a;
1238
+ function y(e) {
1239
+ e.setAttribute("data-position", a.layout.position), o = e.attachShadow({ mode: "closed" });
1240
+ let y = document.createElement("style");
1241
+ y.textContent = oe(a), o.appendChild(y), s = document.createElement("button"), s.className = "bubble", s.setAttribute("aria-label", n.ariaOpenChat), s.innerHTML = `
1242
+ <span class="icon-chat">${ye}</span>
1243
+ <span class="icon-close">${be}</span>
1244
+ <span class="unread-badge-slot"></span>
1245
+ `, 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 = `
1028
1246
  <div class="chat-header">
1029
- <div class="avatar">${ge(c.avatar)}</div>
1247
+ <div class="avatar">${Ce(a.avatar)}</div>
1030
1248
  <div class="header-text">
1031
- <span class="bot-name">${q(s)}</span>
1249
+ <span class="bot-name">${q(i)}</span>
1032
1250
  <span class="bot-status">${q(n.statusOnline)}</span>
1033
1251
  </div>
1034
1252
  <button class="close-btn" aria-label="${q(n.ariaCloseChat)}">×</button>
1035
1253
  </div>
1036
- <div class="messages" id="messages-container" role="log" aria-live="polite" aria-atomic="false"></div>
1037
- <div class="chat-footer">
1038
- <div class="input-row">
1039
- <textarea
1040
- class="input"
1041
- placeholder="${q(h.placeholder || n.inputPlaceholder)}"
1042
- rows="1"
1043
- maxlength="2000"
1044
- aria-label="Message input"
1045
- ></textarea>
1046
- <button class="send-btn" aria-label="${q(n.ariaSendMessage)}">
1047
- ${me}
1048
- </button>
1254
+ <div class="chat-body">
1255
+ <div class="panel panel-home"></div>
1256
+ <div class="panel panel-messages"></div>
1257
+ <div class="panel panel-conversation">
1258
+ <div class="messages" id="messages-container" role="log" aria-live="polite" aria-atomic="false"></div>
1259
+ <div class="handoff-slot"></div>
1260
+ <div class="chat-footer">
1261
+ <div class="input-row">
1262
+ <textarea
1263
+ class="input"
1264
+ placeholder="${q(v.placeholder || n.inputPlaceholder)}"
1265
+ rows="1"
1266
+ maxlength="2000"
1267
+ aria-label="Message input"
1268
+ ></textarea>
1269
+ <button class="send-btn" aria-label="${q(n.ariaSendMessage)}">
1270
+ ${xe}
1271
+ </button>
1272
+ </div>
1273
+ <a class="botiq-badge" href="${ve}" target="_blank" rel="noopener noreferrer">
1274
+ ${q(n.poweredBy)} <span class="botiq-badge-name">BotIQ</span>
1275
+ </a>
1276
+ </div>
1049
1277
  </div>
1050
- <a class="botiq-badge" href="${de}" target="_blank" rel="noopener noreferrer">
1051
- ${q(n.poweredBy)} <span class="botiq-badge-name">BotIQ</span>
1052
- </a>
1053
1278
  </div>
1054
- `, d.querySelector(".close-btn").addEventListener("click", i), f = d.querySelector("#messages-container");
1055
- let r = null;
1056
- f.addEventListener("scroll", () => {
1057
- f.scrollTop <= 48 && !r && (r = setTimeout(() => {
1058
- r = null;
1059
- }, 150), a());
1060
- }), p = d.querySelector(".input"), m = d.querySelector(".send-btn"), p.addEventListener("input", () => {
1061
- p.style.height = "auto", p.style.height = Math.min(p.scrollHeight, 100) + "px";
1062
- }), p.addEventListener("keydown", (e) => {
1063
- e.key === "Enter" && !e.shiftKey && (e.preventDefault(), _());
1064
- }), m.addEventListener("click", _);
1065
- let o = d.querySelector(".input-row"), { button: g, panel: v } = ue((e) => {
1066
- W(p, e), p.focus();
1279
+ <div class="bottom-nav">
1280
+ <button class="nav-btn" data-view="home">⌂ ${q(n.navHome)}</button>
1281
+ <button class="nav-btn" data-view="messages">💬 ${q(n.navMessages)}</button>
1282
+ </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 = le(t, n), l.querySelector(".home-start")?.addEventListener("click", () => {
1284
+ r.onNewConversation();
1285
+ }), f = c.querySelector(".nav-btn[data-view=\"home\"]"), p = c.querySelector(".nav-btn[data-view=\"messages\"]"), c.querySelectorAll(".nav-btn").forEach((e) => {
1286
+ e.addEventListener("click", () => {
1287
+ let t = e.dataset.view;
1288
+ r.onNavigate(t);
1289
+ });
1290
+ }), m = c.querySelector("#messages-container"), h = c.querySelector(".handoff-slot");
1291
+ let x = null;
1292
+ m.addEventListener("scroll", () => {
1293
+ m.scrollTop <= 48 && !x && (x = setTimeout(() => {
1294
+ x = null;
1295
+ }, 150), r.onScrollTop());
1296
+ }), g = c.querySelector(".input"), _ = c.querySelector(".send-btn"), g.addEventListener("input", () => {
1297
+ g.style.height = "auto", g.style.height = Math.min(g.scrollHeight, 100) + "px";
1298
+ }), g.addEventListener("keydown", (e) => {
1299
+ e.key === "Enter" && !e.shiftKey && (e.preventDefault(), b());
1300
+ }), _.addEventListener("click", b);
1301
+ let S = c.querySelector(".input-row"), { button: C, panel: w } = _e((e) => {
1302
+ he(g, e), g.focus();
1067
1303
  });
1068
- o.insertBefore(g, m), d.querySelector(".chat-footer").appendChild(v), l.appendChild(d);
1304
+ S.insertBefore(C, _), c.querySelector(".chat-footer").appendChild(w), o.appendChild(c);
1069
1305
  }
1070
- function _() {
1071
- let e = p.value.trim();
1072
- !e || m.disabled || (p.value = "", p.style.height = "auto", r(e));
1306
+ function b() {
1307
+ let e = g.value.trim();
1308
+ !e || _.disabled || (g.value = "", g.style.height = "auto", r.onSend(e));
1073
1309
  }
1074
- function v(e) {
1075
- let i = f.scrollHeight - f.scrollTop - f.clientHeight < 80, a = f.scrollTop, c = f.scrollHeight;
1076
- f.innerHTML = ye(e, {
1310
+ function x(e) {
1311
+ let a = m.scrollHeight - m.scrollTop - m.clientHeight < 80, o = m.scrollTop, s = m.scrollHeight;
1312
+ m.innerHTML = Oe(e, {
1077
1313
  strings: n,
1078
- content: h,
1079
- botName: s,
1314
+ content: v,
1315
+ botName: i,
1080
1316
  lang: t.widgetLanguage,
1081
1317
  now: Date.now(),
1082
1318
  contactInfo: t.contactInfo
1083
- }), f.querySelectorAll(".chip").forEach((e) => {
1084
- e.addEventListener("click", () => r(e.textContent ?? ""));
1085
- }), f.querySelectorAll(".retry-btn").forEach((e) => {
1086
- e.addEventListener("click", () => o());
1087
- }), i ? f.scrollTop = f.scrollHeight : f.scrollTop = R(a, c, f.scrollHeight);
1319
+ }), m.querySelectorAll(".chip").forEach((e) => {
1320
+ e.addEventListener("click", () => r.onSend(e.textContent ?? ""));
1321
+ }), m.querySelectorAll(".retry-btn").forEach((e) => {
1322
+ e.addEventListener("click", () => r.onRetry());
1323
+ }), a ? m.scrollTop = m.scrollHeight : m.scrollTop = pe(o, s, m.scrollHeight);
1088
1324
  }
1089
- function y(e) {
1090
- e.isOpen ? (d.classList.add("open"), u.classList.add("open"), u.setAttribute("aria-label", n.ariaCloseChat), requestAnimationFrame(() => p.focus())) : (d.classList.remove("open"), u.classList.remove("open"), u.setAttribute("aria-label", n.ariaOpenChat)), m.disabled = e.isLoading, v(e);
1325
+ function S(e) {
1326
+ 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 t = s.querySelector(".unread-badge-slot");
1328
+ t && (t.innerHTML = Ee(e.unreadCount)), _.disabled = e.isLoading, 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 === "conversation" && (x(e), h.innerHTML = Te(e.escalated, n)), e.view === "messages" && (u.innerHTML = ce(e.conversations, n, Date.now()), u.querySelectorAll(".msg-list-item").forEach((e) => {
1329
+ e.addEventListener("click", () => {
1330
+ let t = e.dataset.session;
1331
+ t && r.onOpenConversation(t);
1332
+ });
1333
+ }), u.querySelector(".msg-list-new")?.addEventListener("click", () => {
1334
+ r.onNewConversation();
1335
+ }));
1091
1336
  }
1092
- function b(e) {
1093
- return B(l, {
1337
+ function C(e) {
1338
+ return me(o, {
1094
1339
  ...e,
1095
1340
  labels: {
1096
1341
  confirm: n.confirmYes,
@@ -1101,15 +1346,23 @@ function be(e, t, n, r, i, a, o) {
1101
1346
  });
1102
1347
  }
1103
1348
  return {
1104
- mount: g,
1105
- update: y,
1106
- confirmAction: b
1349
+ mount: y,
1350
+ update: S,
1351
+ confirmAction: C
1107
1352
  };
1108
1353
  }
1109
1354
  //#endregion
1110
1355
  //#region src/i18n/vi.ts
1111
- var xe = {
1356
+ var Ae = {
1112
1357
  statusOnline: "Trực tuyến",
1358
+ statusPaused: "Tạm ngừng",
1359
+ navHome: "Trang chủ",
1360
+ navMessages: "Tin nhắn",
1361
+ homeGreeting: "Xin chào 👋",
1362
+ startConversation: "Bắt đầu trò chuyện",
1363
+ newConversation: "Cuộc trò chuyện mới",
1364
+ noConversations: "Chưa có cuộc trò chuyện nào",
1365
+ waitingForHuman: "Đang chờ nhân viên…",
1113
1366
  inputPlaceholder: "Nhắn tin...",
1114
1367
  defaultGreeting: "Xin chào! Tôi có thể giúp gì cho bạn?",
1115
1368
  errorMessage: "Xin lỗi, không thể kết nối. Vui lòng thử lại.",
@@ -1133,8 +1386,16 @@ var xe = {
1133
1386
  confirmCountdownPrefix: "Tự động xác nhận sau ",
1134
1387
  confirmCountdownSuffix: "s…",
1135
1388
  retry: "Thử lại"
1136
- }, Se = {
1389
+ }, X = {
1137
1390
  statusOnline: "Online",
1391
+ statusPaused: "Paused",
1392
+ navHome: "Home",
1393
+ navMessages: "Messages",
1394
+ homeGreeting: "Hi there 👋",
1395
+ startConversation: "Start a conversation",
1396
+ newConversation: "New conversation",
1397
+ noConversations: "No conversations yet",
1398
+ waitingForHuman: "Waiting for a teammate…",
1138
1399
  inputPlaceholder: "Type a message...",
1139
1400
  defaultGreeting: "Hello! How can I help you?",
1140
1401
  errorMessage: "Sorry, something went wrong. Please try again.",
@@ -1161,20 +1422,20 @@ var xe = {
1161
1422
  };
1162
1423
  //#endregion
1163
1424
  //#region src/i18n/index.ts
1164
- function X(e) {
1165
- return e === "en" ? Se : xe;
1425
+ function Z(e) {
1426
+ return e === "en" ? X : Ae;
1166
1427
  }
1167
1428
  //#endregion
1168
1429
  //#region src/core/declarative-executor.ts
1169
- var Z = /^[a-zA-Z0-9_-]*$/;
1430
+ var je = /^[a-zA-Z0-9_-]*$/;
1170
1431
  function Q(e, t) {
1171
1432
  return e.replace(/\{([a-zA-Z][a-zA-Z0-9_]*)\}/g, (e, n) => {
1172
1433
  let r = t[n], i = r == null ? "" : String(r);
1173
- if (!Z.test(i)) throw Error(`Unsafe param value for "${n}"`);
1434
+ if (!je.test(i)) throw Error(`Unsafe param value for "${n}"`);
1174
1435
  return i;
1175
1436
  });
1176
1437
  }
1177
- function Ce(e, t) {
1438
+ function Me(e, t) {
1178
1439
  let n = typeof location < "u" ? location.origin : "https://placeholder.local", r, i;
1179
1440
  try {
1180
1441
  r = new URL(e, n), i = new URL(t.replace(/\{[a-zA-Z][a-zA-Z0-9_]*\}/g, "x"), n);
@@ -1184,7 +1445,7 @@ function Ce(e, t) {
1184
1445
  if (!/^https?:$/.test(r.protocol)) throw Error("Navigation must be http(s)");
1185
1446
  if (r.origin !== i.origin) throw Error("Navigation origin not allowed");
1186
1447
  }
1187
- async function we(e, t) {
1448
+ async function Ne(e, t) {
1188
1449
  let n = e.config;
1189
1450
  if (e.operation === "click") {
1190
1451
  let e = Q(String(n.selectorTemplate ?? ""), t), r = document.querySelector(e);
@@ -1203,14 +1464,14 @@ async function we(e, t) {
1203
1464
  }
1204
1465
  if (e.operation === "navigate") {
1205
1466
  let e = String(n.urlTemplate ?? ""), r = Q(e, t);
1206
- Ce(r, e), location.assign(r);
1467
+ Me(r, e), location.assign(r);
1207
1468
  return;
1208
1469
  }
1209
1470
  throw Error(`Unknown operation: ${String(e.operation)}`);
1210
1471
  }
1211
1472
  //#endregion
1212
1473
  //#region src/core/page-action-executor.ts
1213
- async function Te(e, t) {
1474
+ async function Pe(e, t) {
1214
1475
  let n = t.registry.get(e.actionName);
1215
1476
  if (!n) return {
1216
1477
  status: "unknown",
@@ -1235,26 +1496,81 @@ async function Te(e, t) {
1235
1496
  //#endregion
1236
1497
  //#region src/builds/npm/index.ts
1237
1498
  var $ = 10;
1238
- function Ee(e) {
1239
- if (w.setDeclarativeRunner(we), typeof window < "u" && (window.botiq = window.botiq ?? {}, window.botiq.registerActions = (e) => w.register(e)), !e.apiKey) return console.warn("[BotIQ] apiKey is required"), () => void 0;
1499
+ function Fe(e) {
1500
+ if (D.setDeclarativeRunner(Ne), 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;
1240
1501
  let t = p(e);
1241
- v();
1242
- let n = t.apiKey.slice(-16), r = y(n), i = b(n, r);
1243
- M({ messages: i });
1244
- let a = se(), o = document.createElement("div");
1245
- document.body.appendChild(o);
1246
- let s = () => void 0, c = !1, l = X(void 0), u = null;
1502
+ y();
1503
+ let n = t.apiKey.slice(-16), r = C(), i = b(n), a = x(n, i);
1504
+ F({
1505
+ messages: a,
1506
+ view: "home",
1507
+ currentSessionId: i
1508
+ });
1509
+ let o = H(), s = document.createElement("div");
1510
+ document.body.appendChild(s);
1511
+ let c = () => void 0, l = !1, u = Z(void 0), d = null, m = null, h = null;
1512
+ function g() {
1513
+ h ||= setTimeout(async () => {
1514
+ if (h = null, !(!P().escalated || !P().isOpen)) try {
1515
+ let e = await j(t.apiUrl, t.apiKey, P().currentSessionId, $, r);
1516
+ e.messages.length > 0 && F({ messages: e.messages.map(O) }), F({ escalated: e.escalated === !0 });
1517
+ } catch {} finally {
1518
+ P().escalated && P().isOpen && g();
1519
+ }
1520
+ }, 1e4);
1521
+ }
1247
1522
  f(t.apiKey, t.apiUrl).then((e) => {
1248
- if (c) return;
1523
+ if (l) return;
1249
1524
  if (e === null) {
1250
- console.warn("[BotIQ] Widget not authorised on this origin — skipped mount"), o.remove();
1525
+ console.warn("[BotIQ] Widget not authorised on this origin — skipped mount"), s.remove();
1251
1526
  return;
1252
1527
  }
1253
- l = X(e.widgetLanguage), e.pageActions?.length && w.seed(e.pageActions);
1254
- let n = be(t, e, l, S, T, h, C);
1255
- u = n, n.mount(o), s = N((e) => n.update(e)), n.update(j()), i.length > 0 && m();
1528
+ u = Z(e.widgetLanguage), e.pageActions?.length && D.seed(e.pageActions);
1529
+ let n = ke(t, e, u, {
1530
+ onSend: I,
1531
+ onToggle: R,
1532
+ onScrollTop: A,
1533
+ onRetry: L,
1534
+ onNavigate: v,
1535
+ onOpenConversation: E,
1536
+ onNewConversation: T
1537
+ });
1538
+ d = n, n.mount(s), c = re((e) => n.update(e)), n.update(P()), e.proactive?.enabled && (m = setTimeout(() => {
1539
+ if (P().isOpen) return;
1540
+ let t = {
1541
+ role: "assistant",
1542
+ content: e.proactive.message,
1543
+ ts: Date.now()
1544
+ };
1545
+ F({
1546
+ messages: [...P().messages, t],
1547
+ view: "conversation",
1548
+ unreadCount: P().unreadCount + 1
1549
+ });
1550
+ }, e.proactive.delayMs ?? 8e3)), a.length > 0 && k(i);
1256
1551
  });
1257
- function d(e) {
1552
+ async function _() {
1553
+ F({ conversations: await ee(t.apiUrl, t.apiKey, r) });
1554
+ }
1555
+ function v(e) {
1556
+ F({ view: e }), e === "messages" && _();
1557
+ }
1558
+ function T() {
1559
+ F({
1560
+ view: "conversation",
1561
+ currentSessionId: w(),
1562
+ messages: [],
1563
+ escalated: !1
1564
+ }), o = H();
1565
+ }
1566
+ function E(e) {
1567
+ F({
1568
+ view: "conversation",
1569
+ currentSessionId: e,
1570
+ messages: x(n, e)
1571
+ }), o = H(), k(e);
1572
+ }
1573
+ function O(e) {
1258
1574
  let t = Date.parse(e.createdAt);
1259
1575
  return {
1260
1576
  role: e.role,
@@ -1262,83 +1578,90 @@ function Ee(e) {
1262
1578
  ...Number.isFinite(t) ? { ts: t } : {}
1263
1579
  };
1264
1580
  }
1265
- async function m() {
1266
- let e = await D(t.apiUrl, t.apiKey, r, $);
1267
- e.messages.length > 0 && (a = ce(e), M({ messages: e.messages.map(d) }));
1581
+ async function k(e) {
1582
+ let n = await j(t.apiUrl, t.apiKey, e, $, r);
1583
+ n.messages.length > 0 && (o = U(n), F({ messages: n.messages.map(O) })), F({ escalated: n.escalated === !0 }), P().escalated && g();
1268
1584
  }
1269
- async function h() {
1270
- if (L(a, j().loadingOlder)) {
1271
- M({ loadingOlder: !0 });
1585
+ async function A() {
1586
+ if (fe(o, P().loadingOlder)) {
1587
+ F({ loadingOlder: !0 });
1272
1588
  try {
1273
- let e = await O(t.apiUrl, t.apiKey, r, a.oldestCursor, $);
1274
- e.messages.length > 0 && M({ messages: [...e.messages.map(d), ...j().messages] }), a = I(a, e);
1589
+ let e = P().currentSessionId, n = await ne(t.apiUrl, t.apiKey, e, o.oldestCursor, $);
1590
+ n.messages.length > 0 && F({ messages: [...n.messages.map(O), ...P().messages] }), o = de(o, n);
1275
1591
  } finally {
1276
- M({ loadingOlder: !1 });
1592
+ F({ loadingOlder: !1 });
1277
1593
  }
1278
1594
  }
1279
1595
  }
1280
- let g = "";
1281
- async function _(e) {
1282
- M({ isLoading: !0 });
1596
+ let M = "";
1597
+ async function N(e) {
1598
+ let i = P().currentSessionId, a = x(n, i).length === 0 && P().messages.filter((e) => e.role === "user").length === 1;
1599
+ F({ isLoading: !0 });
1283
1600
  try {
1284
- let i = await ee(t.apiUrl, t.apiKey, r, e, j().messages.filter((e) => !e.error), l), a = {
1601
+ let o = await te(t.apiUrl, t.apiKey, i, e, P().messages.filter((e) => !e.error), u, r), s = {
1285
1602
  role: "assistant",
1286
- content: i.reply,
1603
+ content: o.reply,
1287
1604
  ts: Date.now(),
1288
- ...i.error ? { error: !0 } : {}
1605
+ ...o.error ? { error: !0 } : {}
1289
1606
  };
1290
- if (M({
1291
- messages: [...j().messages, a],
1607
+ if (F({
1608
+ messages: [...P().messages, s],
1292
1609
  isLoading: !1
1293
- }), i.error || x(n, r, [a]), !i.error && i.pageAction && u) {
1294
- let e = u;
1610
+ }), o.error || S(n, i, [s]), !o.error && a && _(), o.error || j(t.apiUrl, t.apiKey, i, $, r).then((e) => {
1611
+ F({ escalated: e.escalated === !0 }), P().escalated && g();
1612
+ }), !o.error && o.pageAction && d) {
1613
+ let e = d;
1295
1614
  try {
1296
- let t = await Te(i.pageAction, {
1297
- registry: w,
1615
+ let t = await Pe(o.pageAction, {
1616
+ registry: D,
1298
1617
  confirm: (t) => e.confirmAction(t)
1299
1618
  });
1300
- if (!u) return;
1301
- let a = {
1619
+ if (!d) return;
1620
+ let r = {
1302
1621
  role: "assistant",
1303
- content: t.status === "executed" ? l.actionDone : t.status === "cancelled" ? l.actionCancelled : t.status === "unknown" ? `⚠ ${t.message ?? l.actionUnavailable}` : `⚠ ${t.message ?? l.actionError}`,
1622
+ content: t.status === "executed" ? u.actionDone : t.status === "cancelled" ? u.actionCancelled : t.status === "unknown" ? `⚠ ${t.message ?? u.actionUnavailable}` : `⚠ ${t.message ?? u.actionError}`,
1304
1623
  ts: Date.now()
1305
1624
  };
1306
- M({ messages: [...j().messages, a] }), x(n, r, [a]);
1625
+ F({ messages: [...P().messages, r] }), S(n, i, [r]);
1307
1626
  } catch {
1308
- if (!u) return;
1627
+ if (!d) return;
1309
1628
  let e = {
1310
1629
  role: "assistant",
1311
- content: l.actionError,
1630
+ content: u.actionError,
1312
1631
  ts: Date.now()
1313
1632
  };
1314
- M({ messages: [...j().messages, e] }), x(n, r, [e]);
1633
+ F({ messages: [...P().messages, e] }), S(n, i, [e]);
1315
1634
  }
1316
1635
  }
1317
1636
  } catch {
1318
- M({ isLoading: !1 });
1637
+ F({ isLoading: !1 });
1319
1638
  }
1320
1639
  }
1321
- async function S(e) {
1322
- if (j().isLoading) return;
1323
- g = e;
1324
- let t = {
1640
+ async function I(e) {
1641
+ if (P().isLoading) return;
1642
+ M = e;
1643
+ let t = P().currentSessionId, r = {
1325
1644
  role: "user",
1326
1645
  content: e,
1327
1646
  ts: Date.now()
1328
1647
  };
1329
- M({ messages: [...j().messages, t] }), x(n, r, [t]), await _(e);
1648
+ F({ messages: [...P().messages, r] }), S(n, t, [r]), await N(e);
1330
1649
  }
1331
- function C() {
1332
- if (j().isLoading || !g) return;
1333
- let e = j().messages;
1334
- M({ messages: e.length > 0 && e[e.length - 1].error ? e.slice(0, -1) : e }), _(g);
1650
+ function L() {
1651
+ if (P().isLoading || !M) return;
1652
+ let e = P().messages;
1653
+ F({ messages: e.length > 0 && e[e.length - 1].error ? e.slice(0, -1) : e }), N(M);
1335
1654
  }
1336
- function T() {
1337
- M({ isOpen: !j().isOpen });
1655
+ function R() {
1656
+ let e = !P().isOpen;
1657
+ F({
1658
+ isOpen: e,
1659
+ ...e ? { unreadCount: 0 } : {}
1660
+ });
1338
1661
  }
1339
1662
  return () => {
1340
- c = !0, u = null, s(), o.remove();
1663
+ l = !0, d = null, c(), m && clearTimeout(m), h &&= (clearTimeout(h), null), s.remove();
1341
1664
  };
1342
1665
  }
1343
1666
  //#endregion
1344
- export { Ee as t };
1667
+ export { Fe as t };
package/dist/sdk/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as e } from "./npm-XnNJWLXh.js";
1
+ import { t as e } from "./npm-DbbHOVFV.js";
2
2
  import { useEffect as t } from "react";
3
3
  //#region src/builds/npm/react.tsx
4
4
  function n(n) {
package/dist/sdk/vue.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as e } from "./npm-XnNJWLXh.js";
1
+ import { t as e } from "./npm-DbbHOVFV.js";
2
2
  import { defineComponent as t, onMounted as n, onUnmounted as r } from "vue";
3
3
  //#region src/builds/npm/vue.ts
4
4
  var i = t({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@locdo.tech/botiq-chat-sdk",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "BotIQ chat widget SDK — embed AI chatbot into any website with vanilla JS, React, or Vue.",
5
5
  "keywords": [
6
6
  "botiq",