@paramms/chat-widget 1.0.33 → 1.0.34
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/README.md +2 -2
- package/dist/chatlist.d.ts +13 -1
- package/dist/chatlist.js +64 -58
- package/dist/chatlist.js.map +1 -1
- package/dist/core.js.map +1 -1
- package/dist/embed.js +15 -4
- package/dist/embed.js.map +1 -1
- package/dist/hooks.d.ts +11 -1
- package/dist/hooks.js +58 -48
- package/dist/hooks.js.map +1 -1
- package/dist/index.js +631 -503
- package/dist/index.js.map +1 -1
- package/dist/outbox.js +2 -1
- package/dist/outbox.js.map +1 -1
- package/dist/protocol/frames.d.ts +10 -0
- package/dist/react.d.ts +35 -8
- package/dist/react.js +308 -270
- package/dist/react.js.map +1 -1
- package/dist/renderer.d.ts +24 -0
- package/dist/store.d.ts +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import { p as
|
|
5
|
-
import { h as
|
|
6
|
-
import { P as
|
|
7
|
-
import { e as
|
|
8
|
-
import { E2ESession as
|
|
9
|
-
const
|
|
10
|
-
class
|
|
1
|
+
var pe = Object.defineProperty;
|
|
2
|
+
var he = (o, e, i) => e in o ? pe(o, e, { enumerable: !0, configurable: !0, writable: !0, value: i }) : o[e] = i;
|
|
3
|
+
var y = (o, e, i) => he(o, typeof e != "symbol" ? e + "" : e, i);
|
|
4
|
+
import { p as fe, r as ue, a as we } from "./uid.js";
|
|
5
|
+
import { h as Me } from "./uid.js";
|
|
6
|
+
import { P as be, C as xe, b as ge } from "./outbox.js";
|
|
7
|
+
import { e as He } from "./outbox.js";
|
|
8
|
+
import { E2ESession as me, extractX3DHInit as ye } from "./e2e.js";
|
|
9
|
+
const te = "http://www.w3.org/2000/svg", ve = 8e3;
|
|
10
|
+
class ke {
|
|
11
11
|
constructor() {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
y(this, "svg", null);
|
|
13
|
+
y(this, "timers", /* @__PURE__ */ new Set());
|
|
14
14
|
}
|
|
15
15
|
/** Feed every server frame; the overlay reacts to annotation frames only. */
|
|
16
16
|
apply(e) {
|
|
17
|
-
var
|
|
17
|
+
var i;
|
|
18
18
|
if (e.type === "annotation") this.draw(e.stroke);
|
|
19
19
|
else if (e.type === "annotation_clear") this.clear();
|
|
20
|
-
else if (e.type === "opened" && ((
|
|
20
|
+
else if (e.type === "opened" && ((i = e.annotations) != null && i.length))
|
|
21
21
|
for (const s of e.annotations) this.draw(s);
|
|
22
22
|
}
|
|
23
23
|
ensureSvg() {
|
|
24
|
-
var
|
|
25
|
-
if ((
|
|
26
|
-
const e = document.createElementNS(
|
|
24
|
+
var i;
|
|
25
|
+
if ((i = this.svg) != null && i.isConnected) return this.svg;
|
|
26
|
+
const e = document.createElementNS(te, "svg");
|
|
27
27
|
return e.setAttribute("data-relay-annotations", ""), e.setAttribute("aria-hidden", "true"), e.setAttribute(
|
|
28
28
|
"style",
|
|
29
29
|
"position:fixed;inset:0;width:100vw;height:100vh;pointer-events:none;z-index:2147483000;"
|
|
30
30
|
), document.body.append(e), this.svg = e, e;
|
|
31
31
|
}
|
|
32
32
|
draw(e) {
|
|
33
|
-
var
|
|
34
|
-
if (typeof document > "u" || !((
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
33
|
+
var b;
|
|
34
|
+
if (typeof document > "u" || !((b = e.points) != null && b.length)) return;
|
|
35
|
+
const i = this.ensureSvg(), s = window.innerWidth, a = window.innerHeight, c = document.createElementNS(te, "polyline");
|
|
36
|
+
c.setAttribute("points", e.points.map((d) => `${(d.x * s).toFixed(1)},${(d.y * a).toFixed(1)}`).join(" ")), c.setAttribute("fill", "none"), c.setAttribute("stroke", e.color || "#ff3b30"), c.setAttribute("stroke-width", String(e.width || 3)), c.setAttribute("stroke-linecap", "round"), c.setAttribute("stroke-linejoin", "round"), c.setAttribute("data-stroke-id", e.id), i.append(c);
|
|
37
|
+
const f = setTimeout(() => {
|
|
38
|
+
c.style.transition = "opacity 600ms", c.style.opacity = "0";
|
|
39
|
+
const d = setTimeout(() => {
|
|
40
|
+
c.remove(), this.timers.delete(d);
|
|
41
41
|
}, 650);
|
|
42
|
-
this.timers.add(
|
|
43
|
-
},
|
|
44
|
-
this.timers.add(
|
|
42
|
+
this.timers.add(d), this.timers.delete(f);
|
|
43
|
+
}, ve);
|
|
44
|
+
this.timers.add(f);
|
|
45
45
|
}
|
|
46
46
|
clear() {
|
|
47
47
|
var e;
|
|
@@ -49,11 +49,11 @@ class me {
|
|
|
49
49
|
}
|
|
50
50
|
destroy() {
|
|
51
51
|
var e;
|
|
52
|
-
for (const
|
|
52
|
+
for (const i of this.timers) clearTimeout(i);
|
|
53
53
|
this.timers.clear(), (e = this.svg) == null || e.remove(), this.svg = null;
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
-
const
|
|
56
|
+
const oe = "objectchat-widget-styles", Ce = ["👍", "❤️", "😂", "😮", "😢", "🙏"], Te = `
|
|
57
57
|
.ocw { --ocw-accent:#4F63F5; --ocw-bg:#f3efe9; --ocw-card:#fff; --ocw-line:#ececec; --ocw-ink:#1c1b1a; --ocw-mut:#9b9690;
|
|
58
58
|
position:relative;
|
|
59
59
|
display:flex; flex-direction:column; height:100%; min-height:320px; background:var(--ocw-bg);
|
|
@@ -150,6 +150,17 @@ const Z = "objectchat-widget-styles", ve = ["👍", "❤️", "😂", "😮", "
|
|
|
150
150
|
.ocw-offline-input:focus { outline:none; border-color:var(--ocw-accent); }
|
|
151
151
|
.ocw-offline-submit { background:var(--ocw-accent); color:#fff; border:none; border-radius:10px; padding:11px; font-size:14px; font-weight:600; cursor:pointer; }
|
|
152
152
|
.ocw-offline-thanks { font-size:14px; color:#15803d; font-weight:600; }
|
|
153
|
+
.ocw-prechat { margin:20px 14px; padding:20px; background:#fff; border:1px solid #e3ded7; border-radius:16px; }
|
|
154
|
+
.ocw-prechat-title { font-weight:700; font-size:15px; margin-bottom:12px; }
|
|
155
|
+
.ocw-prechat select { border:1px solid #e3ded7; border-radius:10px; padding:10px 12px; font:inherit; font-size:13px; background:#fff; }
|
|
156
|
+
.ocw-prechat-cb { display:flex; align-items:center; gap:8px; font-size:13px; color:var(--ocw-ink); }
|
|
157
|
+
.ocw-deflect { margin:0 14px 8px; display:flex; flex-direction:column; gap:6px; }
|
|
158
|
+
.ocw-deflect-card { text-align:left; background:#fff; border:1px solid #e3ded7; border-radius:12px; padding:10px 12px; font:inherit; font-size:13px; cursor:pointer; }
|
|
159
|
+
.ocw-deflect-card:hover { border-color:var(--ocw-accent); }
|
|
160
|
+
.ocw-deflect-q { font-weight:600; margin-bottom:2px; }
|
|
161
|
+
.ocw-deflect-a { color:var(--ocw-mut); font-size:12.5px; display:none; white-space:pre-wrap; }
|
|
162
|
+
.ocw-deflect-card.open .ocw-deflect-a { display:block; }
|
|
163
|
+
.ocw-deflect-hint { font-size:11.5px; color:var(--ocw-mut); text-align:center; }
|
|
153
164
|
.ocw-csat-title { font-size:13px; font-weight:600; margin-bottom:8px; }
|
|
154
165
|
.ocw-csat-stars { display:flex; gap:6px; }
|
|
155
166
|
.ocw-csat-star { background:none; border:none; font-size:22px; cursor:pointer; padding:2px; opacity:.4; transition:opacity .15s; }
|
|
@@ -213,122 +224,129 @@ const Z = "objectchat-widget-styles", ve = ["👍", "❤️", "😂", "😮", "
|
|
|
213
224
|
.ocw-bubble-wrap:hover .ocw-translate-btn { opacity:1; }
|
|
214
225
|
.ocw-translated-tag { font-size:10px; color:var(--ocw-mut); margin-top:2px; }
|
|
215
226
|
`;
|
|
216
|
-
function
|
|
217
|
-
if (typeof document > "u" || document.getElementById(
|
|
218
|
-
const
|
|
219
|
-
|
|
227
|
+
function Ie() {
|
|
228
|
+
if (typeof document > "u" || document.getElementById(oe)) return;
|
|
229
|
+
const o = document.createElement("style");
|
|
230
|
+
o.id = oe, o.textContent = Te, document.head.appendChild(o);
|
|
220
231
|
}
|
|
221
|
-
function o
|
|
222
|
-
const s = document.createElement(
|
|
223
|
-
return e && (s.className = e),
|
|
232
|
+
function t(o, e, i) {
|
|
233
|
+
const s = document.createElement(o);
|
|
234
|
+
return e && (s.className = e), i !== void 0 && (s.textContent = i), s;
|
|
224
235
|
}
|
|
225
|
-
function
|
|
236
|
+
function Se(o) {
|
|
226
237
|
try {
|
|
227
|
-
return new Date(
|
|
238
|
+
return new Date(o).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
228
239
|
} catch {
|
|
229
240
|
return "";
|
|
230
241
|
}
|
|
231
242
|
}
|
|
232
|
-
function
|
|
243
|
+
function W(o) {
|
|
233
244
|
var e;
|
|
234
|
-
switch (
|
|
245
|
+
switch (o.kind) {
|
|
235
246
|
case "text":
|
|
236
|
-
return
|
|
247
|
+
return o.text;
|
|
237
248
|
case "system":
|
|
238
|
-
return typeof ((e =
|
|
249
|
+
return typeof ((e = o.data) == null ? void 0 : e.message) == "string" ? String(o.data.message) : o.event;
|
|
239
250
|
case "card":
|
|
240
|
-
return [
|
|
251
|
+
return [o.title, o.body].filter(Boolean).join(" — ");
|
|
241
252
|
case "attachment":
|
|
242
|
-
return
|
|
253
|
+
return o.name ?? o.url;
|
|
243
254
|
case "form":
|
|
244
|
-
return
|
|
255
|
+
return o.prompt;
|
|
245
256
|
case "appointment":
|
|
246
|
-
return `📅 ${
|
|
257
|
+
return `📅 ${o.title} — ${new Date(o.startIso).toLocaleString()}`;
|
|
247
258
|
}
|
|
248
259
|
}
|
|
249
|
-
class
|
|
260
|
+
class Ee {
|
|
250
261
|
/** Last seq the guest has seen per conversationId — used to compute unread badges. */
|
|
251
|
-
constructor(e,
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
262
|
+
constructor(e, i, s, a = {}) {
|
|
263
|
+
y(this, "scroll");
|
|
264
|
+
y(this, "chips");
|
|
265
|
+
y(this, "typing");
|
|
266
|
+
y(this, "quick");
|
|
267
|
+
y(this, "formHost");
|
|
268
|
+
y(this, "csatPanel");
|
|
269
|
+
y(this, "offlinePanel");
|
|
270
|
+
y(this, "preChatPanel");
|
|
271
|
+
y(this, "deflectPanel");
|
|
272
|
+
y(this, "preChatBuilt", !1);
|
|
273
|
+
y(this, "preChatDone", !1);
|
|
274
|
+
y(this, "footer");
|
|
275
|
+
y(this, "input");
|
|
276
|
+
y(this, "subjectCard");
|
|
277
|
+
y(this, "e2eBadge");
|
|
278
|
+
y(this, "statusBadge");
|
|
279
|
+
y(this, "headerName");
|
|
280
|
+
y(this, "connStatus");
|
|
281
|
+
y(this, "typingTimer", null);
|
|
282
|
+
y(this, "csatSubmitted", !1);
|
|
268
283
|
// ── Co-browsing (shared whiteboard) ─────────────────────────────────────
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
284
|
+
y(this, "cobrowseBtn");
|
|
285
|
+
y(this, "cobrowseCanvas");
|
|
286
|
+
y(this, "cobrowseToolbar");
|
|
287
|
+
y(this, "cobrowseHint");
|
|
288
|
+
y(this, "cobrowseActive", !1);
|
|
289
|
+
y(this, "cobrowseColor", "#f5713c");
|
|
290
|
+
y(this, "lastAnnotationVersion", -1);
|
|
291
|
+
y(this, "storeRef", null);
|
|
292
|
+
y(this, "scrollCleanup", null);
|
|
278
293
|
// ── Live translation ──────────────────────────────────────────────────-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
var
|
|
283
|
-
this.root = e, this.me =
|
|
284
|
-
const
|
|
285
|
-
if ((
|
|
286
|
-
const
|
|
287
|
-
|
|
294
|
+
y(this, "translationCache", /* @__PURE__ */ new Map());
|
|
295
|
+
y(this, "showingTranslation", /* @__PURE__ */ new Set());
|
|
296
|
+
y(this, "subjectBuilt", !1);
|
|
297
|
+
var g, h, I, T, $, A, z, P, k;
|
|
298
|
+
this.root = e, this.me = i, this.h = s, this.cfg = a, Ie(), e.replaceChildren(), e.classList.add("ocw"), a.accent && e.style.setProperty("--ocw-accent", a.accent);
|
|
299
|
+
const c = t("div", "ocw-head"), f = t("div", "ocw-avatar");
|
|
300
|
+
if ((g = a.userInfo) != null && g.avatar) {
|
|
301
|
+
const m = document.createElement("img");
|
|
302
|
+
m.src = a.userInfo.avatar, m.alt = a.userInfo.name ?? "You", m.style.cssText = "width:100%;height:100%;border-radius:50%;object-fit:cover", f.append(m);
|
|
288
303
|
} else
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
const
|
|
292
|
-
this.headerName =
|
|
304
|
+
f.textContent = (h = a.userInfo) != null && h.name ? a.userInfo.name[0].toUpperCase() : "🧑";
|
|
305
|
+
c.append(f);
|
|
306
|
+
const b = t("div", "ocw-head-main");
|
|
307
|
+
this.headerName = t("div", "ocw-head-name", ((I = a.subject) == null ? void 0 : I.ownerLabel) ?? ((T = a.subject) == null ? void 0 : T.title) ?? ""), b.append(this.headerName), ($ = a.subject) != null && $.subtitle && b.append(t("div", "ocw-head-meta", a.subject.subtitle)), c.append(b), this.statusBadge = t("span", "ocw-badge", ((A = a.subject) == null ? void 0 : A.status) ?? ""), (z = a.subject) != null && z.status || (this.statusBadge.style.display = "none"), c.append(this.statusBadge), this.e2eBadge = t("span", "ocw-e2e", "🔒 E2E"), this.e2eBadge.style.display = "none", c.append(this.e2eBadge), this.connStatus = t("span", "ocw-conn-status"), this.connStatus.style.display = "none", c.append(this.connStatus), this.cobrowseBtn = t("button", "ocw-menu ocw-cobrowse-btn", "🖍"), this.cobrowseBtn.title = "Shared whiteboard — draw to point things out together", this.cobrowseBtn.addEventListener("click", () => {
|
|
293
308
|
this.cobrowseActive = !this.cobrowseActive, this.updateCobrowseUI();
|
|
294
|
-
}),
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
for (const
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
this.h.onSend(
|
|
301
|
-
}), this.quick.append(
|
|
309
|
+
}), c.append(this.cobrowseBtn), c.append(t("button", "ocw-menu", "⋯")), this.chips = t("div", "ocw-chiprow"), this.scroll = t("div", "ocw-scroll"), this.subjectCard = t("div", "ocw-subject"), this.typing = t("div", "ocw-typing");
|
|
310
|
+
const d = t("div", "ocw-typing-bubble");
|
|
311
|
+
d.append(t("div", "ocw-typing-dot"), t("div", "ocw-typing-dot"), t("div", "ocw-typing-dot")), this.typing.append(t("div", "ocw-dot", "🧑"), d), this.quick = t("div", "ocw-quick");
|
|
312
|
+
for (const m of a.quickReplies ?? []) {
|
|
313
|
+
const S = t("button", void 0, m);
|
|
314
|
+
S.addEventListener("click", () => {
|
|
315
|
+
this.h.onSend(m), this.quick.style.display = "none";
|
|
316
|
+
}), this.quick.append(S);
|
|
302
317
|
}
|
|
303
|
-
this.formHost =
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
|
|
318
|
+
this.formHost = t("div", "ocw-form-host"), this.csatPanel = t("div", "ocw-csat"), this.csatPanel.style.display = "none", this.offlinePanel = t("div", "ocw-offline"), this.offlinePanel.style.display = "none", this.preChatPanel = t("div", "ocw-prechat"), this.preChatPanel.style.display = "none", this.deflectPanel = t("div", "ocw-deflect"), this.deflectPanel.style.display = "none", this.input = t("textarea", void 0), this.input.rows = 1, this.input.placeholder = "Message…";
|
|
319
|
+
const w = t("button", "ocw-sendbtn", ((P = a.i18n) == null ? void 0 : P.send) ?? "➤");
|
|
320
|
+
w.addEventListener("click", () => this.flushSend()), this.input.addEventListener("input", () => {
|
|
321
|
+
var m, S;
|
|
322
|
+
this.storeRef && !this.storeRef.messages().some((B) => B.senderRole === "guest") ? (S = (m = this.h).onDeflectQuery) == null || S.call(m, this.input.value) : this.hideDeflection();
|
|
323
|
+
}), this.input.addEventListener("keydown", (m) => {
|
|
324
|
+
m.isComposing || m.keyCode === 229 || (m.key === "Enter" && !m.shiftKey ? (m.preventDefault(), this.flushSend()) : this.signalTyping());
|
|
307
325
|
});
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
var
|
|
313
|
-
(
|
|
326
|
+
const v = t("button", "ocw-attach", "📎");
|
|
327
|
+
v.title = "Attach image or file";
|
|
328
|
+
const r = document.createElement("input");
|
|
329
|
+
r.type = "file", r.accept = "image/*,.pdf,.txt,.doc,.docx", r.style.display = "none", v.addEventListener("click", () => r.click()), r.addEventListener("change", () => {
|
|
330
|
+
var m;
|
|
331
|
+
(m = r.files) != null && m[0] && this.h.onAttach && this.h.onAttach(r.files[0]), r.value = "";
|
|
314
332
|
});
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
const
|
|
318
|
-
((
|
|
319
|
-
for (const
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
this.cobrowseColor =
|
|
323
|
-
for (const
|
|
324
|
-
|
|
325
|
-
}), this.cobrowseToolbar.append(
|
|
333
|
+
const u = t("div", "ocw-input");
|
|
334
|
+
u.append(v, r, this.input, w);
|
|
335
|
+
const l = t("div", "ocw-footer");
|
|
336
|
+
((k = a.i18n) == null ? void 0 : k.poweredBy) !== void 0 ? l.textContent = a.i18n.poweredBy : l.innerHTML = 'Powered by <a href="https://relay.paramms.com" target="_blank" rel="noopener">Relay</a>', this.footer = l, e.append(c, this.chips, this.scroll, this.typing, this.quick, this.formHost, this.csatPanel, this.offlinePanel, this.preChatPanel, this.deflectPanel, u, this.footer), this.cobrowseCanvas = t("canvas", "ocw-cobrowse-canvas"), this.cobrowseToolbar = t("div", "ocw-cobrowse-toolbar");
|
|
337
|
+
for (const m of ["#f5713c", "#1c1b1a", "#2563eb", "#16a34a", "#dc2626"]) {
|
|
338
|
+
const S = t("button", "ocw-cobrowse-swatch");
|
|
339
|
+
S.style.background = m, S.type = "button", m === this.cobrowseColor && S.classList.add("sel"), S.addEventListener("click", () => {
|
|
340
|
+
this.cobrowseColor = m;
|
|
341
|
+
for (const B of this.cobrowseToolbar.querySelectorAll(".ocw-cobrowse-swatch")) B.classList.remove("sel");
|
|
342
|
+
S.classList.add("sel");
|
|
343
|
+
}), this.cobrowseToolbar.append(S);
|
|
326
344
|
}
|
|
327
|
-
const C =
|
|
345
|
+
const C = t("button", "ocw-cobrowse-clear", "Clear");
|
|
328
346
|
C.addEventListener("click", () => {
|
|
329
|
-
var
|
|
330
|
-
return (
|
|
331
|
-
}), this.cobrowseToolbar.append(C), this.cobrowseHint =
|
|
347
|
+
var m, S;
|
|
348
|
+
return (S = (m = this.h).onAnnotateClear) == null ? void 0 : S.call(m);
|
|
349
|
+
}), this.cobrowseToolbar.append(C), this.cobrowseHint = t("div", "ocw-cobrowse-hint", "🖍 Draw to point things out — visible to both sides"), e.append(this.cobrowseCanvas, this.cobrowseToolbar, this.cobrowseHint), this.bindCobrowsePointerEvents();
|
|
332
350
|
}
|
|
333
351
|
/** Returns the scroll container so history.ts can attach scroll listeners. */
|
|
334
352
|
getScrollEl() {
|
|
@@ -336,8 +354,8 @@ class Te {
|
|
|
336
354
|
}
|
|
337
355
|
/** Registers a cleanup fn removed on destroy() to prevent listener leaks. */
|
|
338
356
|
setScrollCleanup(e) {
|
|
339
|
-
var
|
|
340
|
-
(
|
|
357
|
+
var i;
|
|
358
|
+
(i = this.scrollCleanup) == null || i.call(this), this.scrollCleanup = e;
|
|
341
359
|
}
|
|
342
360
|
/** Call when the widget is unmounted. Disconnects scroll listeners and clears timers. */
|
|
343
361
|
destroy() {
|
|
@@ -350,6 +368,7 @@ class Te {
|
|
|
350
368
|
/** Navigate to the chat screen (slide list left, slide chat in from right). */
|
|
351
369
|
/** Navigate back to the list screen. */
|
|
352
370
|
flushSend() {
|
|
371
|
+
this.hideDeflection();
|
|
353
372
|
const e = this.input.value.trim();
|
|
354
373
|
e && (this.input.value = "", this.h.onTyping(!1), this.h.onSend(e));
|
|
355
374
|
}
|
|
@@ -358,66 +377,135 @@ class Te {
|
|
|
358
377
|
this.h.onTyping(!0, e), this.typingTimer && clearTimeout(this.typingTimer), this.typingTimer = setTimeout(() => this.h.onTyping(!1), 2e3);
|
|
359
378
|
}
|
|
360
379
|
render(e) {
|
|
361
|
-
var r,
|
|
380
|
+
var r, u, l, C, g;
|
|
362
381
|
if (this.storeRef = e, this.cobrowseBtn.classList.toggle("show", !!e.subject), !e.subject && this.cobrowseActive && (this.cobrowseActive = !1, this.updateCobrowseUI()), this.cobrowseActive && e.annotationVersion !== this.lastAnnotationVersion && (this.lastAnnotationVersion = e.annotationVersion, this.resizeCobrowseCanvas(), this.redrawCobrowse()), e.accent && this.root.style.setProperty("--ocw-accent", e.accent), this.e2eBadge.style.display = e.e2e ? "inline-flex" : "none", this.buildSubjectCard(e), e.subject) {
|
|
363
|
-
const
|
|
364
|
-
|
|
382
|
+
const h = (r = this.cfg.subject) == null ? void 0 : r.ownerLabel;
|
|
383
|
+
h && (this.headerName.textContent = h);
|
|
365
384
|
}
|
|
366
385
|
this.quick.style.display = e.messages().length === 0 ? "flex" : "none", this.chips.replaceChildren();
|
|
367
|
-
const
|
|
368
|
-
this.chips.style.display =
|
|
369
|
-
for (const
|
|
370
|
-
const s = this.scroll.scrollHeight,
|
|
386
|
+
const i = e.visibleActions();
|
|
387
|
+
this.chips.style.display = i.length ? "flex" : "none";
|
|
388
|
+
for (const h of i) this.chips.append(this.chipEl(h));
|
|
389
|
+
const s = this.scroll.scrollHeight, a = this.scroll.scrollTop;
|
|
371
390
|
if (this.scroll.replaceChildren(), this.subjectCard.childNodes.length && this.scroll.append(this.subjectCard), e.hasMoreHistory) {
|
|
372
|
-
const
|
|
373
|
-
|
|
391
|
+
const h = t("div", "ocw-load-more");
|
|
392
|
+
h.textContent = "↑ Loading earlier messages…", h.style.pointerEvents = "none", this.scroll.append(h);
|
|
374
393
|
}
|
|
375
|
-
let
|
|
376
|
-
for (const
|
|
377
|
-
this.scroll.append(this.messageEl(
|
|
378
|
-
|
|
379
|
-
const
|
|
380
|
-
this.typing.classList.toggle("active",
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
394
|
+
let c = 0;
|
|
395
|
+
for (const h of e.messages())
|
|
396
|
+
this.scroll.append(this.messageEl(h, e)), h.senderId !== this.me && h.seq > c && (c = h.seq);
|
|
397
|
+
a > 20 ? this.scroll.scrollTop = this.scroll.scrollHeight - s + a : this.scroll.scrollTop = this.scroll.scrollHeight, c > 0 && this.h.onReadUpTo(c);
|
|
398
|
+
const f = [...e.typing];
|
|
399
|
+
this.typing.classList.toggle("active", f.length > 0);
|
|
400
|
+
const b = this.typing.querySelector(".ocw-typing-bubble");
|
|
401
|
+
b && b.setAttribute("aria-label", f.length ? "typing" : ""), this.footer.style.display = e.whiteLabel ? "none" : "block";
|
|
402
|
+
const d = e.messages().some((h) => h.senderRole === "guest");
|
|
403
|
+
!!((u = e.preChat) != null && u.enabled) && !this.preChatDone && !d && (e.preChat.showWhen !== "offline" || e.offline) ? (this.preChatBuilt || this.buildPreChatPanel(e.preChat), this.preChatPanel.style.display = "block", this.offlinePanel.style.display = "none", (l = this.root.querySelector(".ocw-input")) == null || l.style.setProperty("display", "none")) : (this.preChatPanel.style.display = "none", e.offline ? (this.offlinePanel.style.display === "none" && this.buildOfflinePanel(e.offlineMessage), this.offlinePanel.style.display = "block", (C = this.root.querySelector(".ocw-input")) == null || C.style.setProperty("display", "none")) : (this.offlinePanel.style.display = "none", (g = this.root.querySelector(".ocw-input")) == null || g.style.removeProperty("display")));
|
|
404
|
+
const v = ["resolved", "closed", "sold", "issued", "checked_out"];
|
|
405
|
+
this.h.onCsat && !this.csatSubmitted && v.includes(e.state) && e.messages().length > 0 && (this.csatPanel.style.display === "none" && this.buildCsatPanel(), this.csatPanel.style.display = "block");
|
|
406
|
+
}
|
|
407
|
+
setConnStatus(e, i) {
|
|
387
408
|
if (e === "open") {
|
|
388
409
|
this.connStatus.style.display = "none";
|
|
389
410
|
return;
|
|
390
411
|
}
|
|
391
412
|
this.connStatus.style.display = "";
|
|
392
413
|
const s = e === "error";
|
|
393
|
-
this.connStatus.className = `ocw-conn-status${s ? " err" : e === "reconnecting" ? " warn" : ""}`, this.connStatus.textContent = s ? `⚠ ${
|
|
414
|
+
this.connStatus.className = `ocw-conn-status${s ? " err" : e === "reconnecting" ? " warn" : ""}`, this.connStatus.textContent = s ? `⚠ ${i ?? "Chat unavailable"}` : e === "reconnecting" ? i ?? "↻ reconnecting…" : "● connecting…";
|
|
394
415
|
}
|
|
395
416
|
buildOfflinePanel(e) {
|
|
396
|
-
var
|
|
397
|
-
this.offlinePanel.replaceChildren(), this.offlinePanel.append(
|
|
398
|
-
const
|
|
417
|
+
var b;
|
|
418
|
+
this.offlinePanel.replaceChildren(), this.offlinePanel.append(t("div", "ocw-offline-icon", "🌙")), this.offlinePanel.append(t("div", "ocw-offline-title", ((b = this.cfg.i18n) == null ? void 0 : b.offline) ?? "We're offline right now")), this.offlinePanel.append(t("div", "ocw-offline-msg", e || "Leave your details and we'll get back to you soon."));
|
|
419
|
+
const i = t("div", "ocw-offline-form"), s = t("input", "ocw-offline-input");
|
|
399
420
|
s.placeholder = "Your name", s.type = "text";
|
|
400
|
-
const
|
|
401
|
-
|
|
402
|
-
const
|
|
403
|
-
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
!
|
|
421
|
+
const a = t("input", "ocw-offline-input");
|
|
422
|
+
a.placeholder = "Your email", a.type = "email";
|
|
423
|
+
const c = t("textarea", "ocw-offline-input");
|
|
424
|
+
c.placeholder = "Your message", c.rows = 3;
|
|
425
|
+
const f = t("button", "ocw-offline-submit", "Send message");
|
|
426
|
+
f.addEventListener("click", () => {
|
|
427
|
+
!a.value.trim() || !c.value.trim() || (this.h.onSend(`[Offline form]
|
|
407
428
|
Name: ${s.value || "Anonymous"}
|
|
408
|
-
Email: ${
|
|
409
|
-
Message: ${
|
|
410
|
-
}),
|
|
429
|
+
Email: ${a.value}
|
|
430
|
+
Message: ${c.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-thanks", "✓ Message sent! We'll reply to your email.")));
|
|
431
|
+
}), i.append(s, a, c, f), this.offlinePanel.append(i);
|
|
432
|
+
}
|
|
433
|
+
buildPreChatPanel(e) {
|
|
434
|
+
var d;
|
|
435
|
+
this.preChatBuilt = !0, this.preChatPanel.replaceChildren(), this.preChatPanel.append(t("div", "ocw-prechat-title", e.title ?? "Before we start…"));
|
|
436
|
+
const i = t("div", "ocw-offline-form"), s = {};
|
|
437
|
+
for (const w of e.fields ?? ["name", "email"]) {
|
|
438
|
+
const v = t("input", "ocw-offline-input");
|
|
439
|
+
v.type = w === "email" ? "email" : w === "phone" ? "tel" : "text", v.placeholder = w === "name" ? "Your name" : w === "email" ? "Your email" : "Your phone number", s[w] = v, i.append(v);
|
|
440
|
+
}
|
|
441
|
+
let a = null;
|
|
442
|
+
if ((d = e.topics) != null && d.length) {
|
|
443
|
+
a = t("select", void 0);
|
|
444
|
+
const w = document.createElement("option");
|
|
445
|
+
w.value = "", w.textContent = "What is this about?", a.append(w);
|
|
446
|
+
for (const v of e.topics) {
|
|
447
|
+
const r = document.createElement("option");
|
|
448
|
+
r.value = v, r.textContent = v, a.append(r);
|
|
449
|
+
}
|
|
450
|
+
i.append(a);
|
|
451
|
+
}
|
|
452
|
+
let c = null, f = null;
|
|
453
|
+
if (e.callbackOption) {
|
|
454
|
+
const w = t("label", "ocw-prechat-cb");
|
|
455
|
+
c = document.createElement("input"), c.type = "checkbox", w.append(c, document.createTextNode("📞 Request a call back")), i.append(w), s.phone || (f = t("input", "ocw-offline-input"), f.type = "tel", f.placeholder = "Phone number for the call", f.style.display = "none", c.addEventListener("change", () => f.style.setProperty("display", c.checked ? "block" : "none")), i.append(f));
|
|
456
|
+
}
|
|
457
|
+
const b = t("button", "ocw-offline-submit", "Start chat");
|
|
458
|
+
b.addEventListener("click", () => {
|
|
459
|
+
var u, l, C, g, h, I, T;
|
|
460
|
+
const w = (u = s.email) == null ? void 0 : u.value.trim();
|
|
461
|
+
if (s.email && (!w || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(w))) {
|
|
462
|
+
s.email.focus();
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
const v = !!(c != null && c.checked), r = (((l = s.phone) == null ? void 0 : l.value) ?? (f == null ? void 0 : f.value) ?? "").trim();
|
|
466
|
+
if (v && !r) {
|
|
467
|
+
(C = s.phone ?? f) == null || C.focus();
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
if (a && ((g = e.topics) != null && g.length) && !a.value) {
|
|
471
|
+
a.focus();
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
this.completePreChat(), (T = (I = this.h).onPreChat) == null || T.call(I, {
|
|
475
|
+
...(h = s.name) != null && h.value.trim() ? { name: s.name.value.trim() } : {},
|
|
476
|
+
...w ? { email: w } : {},
|
|
477
|
+
...r ? { phone: r } : {},
|
|
478
|
+
...a != null && a.value ? { topic: a.value } : {},
|
|
479
|
+
...v ? { callback: !0 } : {}
|
|
480
|
+
});
|
|
481
|
+
}), i.append(b), this.preChatPanel.append(i);
|
|
482
|
+
}
|
|
483
|
+
/** Mark pre-chat complete (submitted now or in a previous session). */
|
|
484
|
+
completePreChat() {
|
|
485
|
+
this.preChatDone = !0, this.preChatPanel.style.display = "none", this.storeRef && this.render(this.storeRef);
|
|
486
|
+
}
|
|
487
|
+
/** KB deflection results ("was this your question?") above the composer. */
|
|
488
|
+
showDeflection(e) {
|
|
489
|
+
if (!e.length) return this.hideDeflection();
|
|
490
|
+
this.deflectPanel.replaceChildren(), this.deflectPanel.append(t("div", "ocw-deflect-hint", "Instant answers — tap to expand"));
|
|
491
|
+
for (const i of e.slice(0, 3)) {
|
|
492
|
+
const s = t("button", "ocw-deflect-card");
|
|
493
|
+
s.append(t("div", "ocw-deflect-q", i.title), t("div", "ocw-deflect-a", i.answer)), s.addEventListener("click", () => s.classList.toggle("open")), this.deflectPanel.append(s);
|
|
494
|
+
}
|
|
495
|
+
this.deflectPanel.style.display = "flex";
|
|
496
|
+
}
|
|
497
|
+
hideDeflection() {
|
|
498
|
+
this.deflectPanel.style.display = "none", this.deflectPanel.replaceChildren();
|
|
411
499
|
}
|
|
412
500
|
buildCsatPanel() {
|
|
413
|
-
this.csatPanel.replaceChildren(), this.csatPanel.append(
|
|
414
|
-
const e =
|
|
501
|
+
this.csatPanel.replaceChildren(), this.csatPanel.append(t("div", "ocw-csat-title", "How did we do?"));
|
|
502
|
+
const e = t("div", "ocw-csat-stars"), i = [];
|
|
415
503
|
for (let s = 1; s <= 5; s++) {
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
var
|
|
419
|
-
this.csatSubmitted = !0, this.csatPanel.replaceChildren(
|
|
420
|
-
}),
|
|
504
|
+
const a = t("button", "ocw-csat-star", "★");
|
|
505
|
+
a.dataset.score = String(s), a.addEventListener("mouseenter", () => i.forEach((c, f) => c.classList.toggle("lit", f < s))), a.addEventListener("mouseleave", () => i.forEach((c) => c.classList.remove("lit"))), a.addEventListener("click", () => {
|
|
506
|
+
var c, f;
|
|
507
|
+
this.csatSubmitted = !0, this.csatPanel.replaceChildren(t("div", "ocw-csat-done", `Thanks for your ${s}★ rating!`)), (f = (c = this.h).onCsat) == null || f.call(c, s);
|
|
508
|
+
}), i.push(a), e.append(a);
|
|
421
509
|
}
|
|
422
510
|
this.csatPanel.append(e);
|
|
423
511
|
}
|
|
@@ -433,242 +521,242 @@ Message: ${d.value}`), this.offlinePanel.replaceChildren(o("div", "ocw-offline-t
|
|
|
433
521
|
/** Draw a stroke whose points are normalized to 0..1, scaled to the current
|
|
434
522
|
* canvas size — so strokes line up across different viewport sizes. */
|
|
435
523
|
drawStroke(e) {
|
|
436
|
-
const
|
|
437
|
-
if (!
|
|
438
|
-
const s = this.cobrowseCanvas.width,
|
|
439
|
-
|
|
440
|
-
for (const
|
|
441
|
-
|
|
524
|
+
const i = this.cobrowseCanvas.getContext("2d");
|
|
525
|
+
if (!i || e.points.length < 2) return;
|
|
526
|
+
const s = this.cobrowseCanvas.width, a = this.cobrowseCanvas.height;
|
|
527
|
+
i.strokeStyle = e.color, i.lineWidth = Math.max(1, e.width * Math.min(s, a)), i.lineJoin = "round", i.lineCap = "round", i.beginPath(), i.moveTo(e.points[0].x * s, e.points[0].y * a);
|
|
528
|
+
for (const c of e.points.slice(1)) i.lineTo(c.x * s, c.y * a);
|
|
529
|
+
i.stroke();
|
|
442
530
|
}
|
|
443
531
|
redrawCobrowse() {
|
|
444
|
-
var
|
|
532
|
+
var i;
|
|
445
533
|
const e = this.cobrowseCanvas.getContext("2d");
|
|
446
534
|
if (e) {
|
|
447
535
|
e.clearRect(0, 0, this.cobrowseCanvas.width, this.cobrowseCanvas.height);
|
|
448
|
-
for (const s of ((
|
|
536
|
+
for (const s of ((i = this.storeRef) == null ? void 0 : i.annotations) ?? []) this.drawStroke(s);
|
|
449
537
|
}
|
|
450
538
|
}
|
|
451
539
|
bindCobrowsePointerEvents() {
|
|
452
|
-
let e = !1,
|
|
453
|
-
const s = (
|
|
454
|
-
const
|
|
455
|
-
return { x: Math.min(1, Math.max(0,
|
|
456
|
-
},
|
|
457
|
-
this.cobrowseCanvas.addEventListener("pointerdown", (
|
|
458
|
-
this.cobrowseActive && (e = !0,
|
|
459
|
-
}), this.cobrowseCanvas.addEventListener("pointermove", (
|
|
460
|
-
e && (
|
|
540
|
+
let e = !1, i = [];
|
|
541
|
+
const s = (f) => {
|
|
542
|
+
const b = this.cobrowseCanvas.getBoundingClientRect(), d = b.width > 0 ? (f.clientX - b.left) / b.width : 0, w = b.height > 0 ? (f.clientY - b.top) / b.height : 0;
|
|
543
|
+
return { x: Math.min(1, Math.max(0, d)), y: Math.min(1, Math.max(0, w)) };
|
|
544
|
+
}, a = 6e-3;
|
|
545
|
+
this.cobrowseCanvas.addEventListener("pointerdown", (f) => {
|
|
546
|
+
this.cobrowseActive && (e = !0, i = [s(f)], this.cobrowseCanvas.setPointerCapture(f.pointerId));
|
|
547
|
+
}), this.cobrowseCanvas.addEventListener("pointermove", (f) => {
|
|
548
|
+
e && (i.push(s(f)), this.redrawCobrowse(), this.drawStroke({ points: i, color: this.cobrowseColor, width: a }));
|
|
461
549
|
});
|
|
462
|
-
const
|
|
463
|
-
var
|
|
550
|
+
const c = (f) => {
|
|
551
|
+
var b, d;
|
|
464
552
|
if (e) {
|
|
465
|
-
e = !1,
|
|
553
|
+
e = !1, i.length > 1 && ((d = (b = this.h).onAnnotate) == null || d.call(b, { id: `an_${Date.now()}_${Math.random().toString(36).slice(2)}`, points: i, color: this.cobrowseColor, width: a })), i = [];
|
|
466
554
|
try {
|
|
467
|
-
this.cobrowseCanvas.releasePointerCapture(
|
|
555
|
+
this.cobrowseCanvas.releasePointerCapture(f.pointerId);
|
|
468
556
|
} catch {
|
|
469
557
|
}
|
|
470
558
|
}
|
|
471
559
|
};
|
|
472
|
-
this.cobrowseCanvas.addEventListener("pointerup",
|
|
560
|
+
this.cobrowseCanvas.addEventListener("pointerup", c), this.cobrowseCanvas.addEventListener("pointercancel", c);
|
|
473
561
|
}
|
|
474
562
|
buildSubjectCard(e) {
|
|
475
563
|
if (this.subjectBuilt) return;
|
|
476
|
-
const
|
|
477
|
-
if (!
|
|
478
|
-
this.subjectBuilt = !0, this.subjectCard.replaceChildren(), this.subjectCard.append(
|
|
479
|
-
const
|
|
480
|
-
if (
|
|
481
|
-
else for (const
|
|
482
|
-
|
|
483
|
-
const
|
|
484
|
-
|
|
564
|
+
const i = e.subject, s = this.cfg.subject, a = (i == null ? void 0 : i.title) ?? (s == null ? void 0 : s.title);
|
|
565
|
+
if (!a) return;
|
|
566
|
+
this.subjectBuilt = !0, this.subjectCard.replaceChildren(), this.subjectCard.append(t("div", "ocw-subject-title", a)), s != null && s.subtitle && this.subjectCard.append(t("div", "ocw-subject-sub", s.subtitle));
|
|
567
|
+
const c = t("div", "ocw-tags");
|
|
568
|
+
if (i) for (const [b, d] of Object.entries(i.fields)) c.append(t("span", "ocw-tag", `${b}: ${d}`));
|
|
569
|
+
else for (const b of (s == null ? void 0 : s.tags) ?? []) c.append(t("span", "ocw-tag", b));
|
|
570
|
+
c.childNodes.length && this.subjectCard.append(c);
|
|
571
|
+
const f = (i == null ? void 0 : i.state) ?? (s == null ? void 0 : s.status);
|
|
572
|
+
f && (this.statusBadge.textContent = f, this.statusBadge.style.display = "inline-flex");
|
|
485
573
|
}
|
|
486
574
|
chipEl(e) {
|
|
487
|
-
const
|
|
488
|
-
return
|
|
575
|
+
const i = t("button", "ocw-chip", e.icon ? `${e.icon} ${e.label}` : e.label);
|
|
576
|
+
return i.dataset.actionId = e.id, i.addEventListener("click", async () => {
|
|
489
577
|
var s;
|
|
490
578
|
e.confirm && !await this.confirm(e.label) || ((s = e.input) != null && s.length ? this.openForm(e) : this.h.onInvoke(e.id));
|
|
491
|
-
}),
|
|
579
|
+
}), i;
|
|
492
580
|
}
|
|
493
581
|
/** In-widget confirmation modal (replaces window.confirm). */
|
|
494
582
|
confirm(e) {
|
|
495
|
-
return new Promise((
|
|
496
|
-
const s =
|
|
497
|
-
|
|
498
|
-
const
|
|
499
|
-
s.remove(),
|
|
583
|
+
return new Promise((i) => {
|
|
584
|
+
const s = t("div", "ocw-modal"), a = t("div", "ocw-modal-card");
|
|
585
|
+
a.append(t("div", "ocw-modal-title", e)), a.append(t("div", "ocw-modal-body", `Confirm “${e}”?`));
|
|
586
|
+
const c = t("div", "ocw-modal-actions"), f = t("button", "ocw-modal-cancel", "Cancel"), b = t("button", "ocw-modal-ok", "Confirm"), d = (w) => {
|
|
587
|
+
s.remove(), i(w);
|
|
500
588
|
};
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
}),
|
|
589
|
+
f.addEventListener("click", () => d(!1)), b.addEventListener("click", () => d(!0)), s.addEventListener("click", (w) => {
|
|
590
|
+
w.target === s && d(!1);
|
|
591
|
+
}), c.append(f, b), a.append(c), s.append(a), this.root.append(s), b.focus();
|
|
504
592
|
});
|
|
505
593
|
}
|
|
506
594
|
/** Inline form for a form-effect action: typed inputs (date picker, number,
|
|
507
595
|
* text) rendered above the composer — no browser prompts. */
|
|
508
596
|
openForm(e) {
|
|
509
|
-
var
|
|
597
|
+
var b, d;
|
|
510
598
|
this.formHost.replaceChildren();
|
|
511
|
-
const
|
|
512
|
-
|
|
599
|
+
const i = t("div", "ocw-form");
|
|
600
|
+
i.append(t("div", "ocw-form-title", e.icon ? `${e.icon} ${e.label}` : e.label));
|
|
513
601
|
const s = /* @__PURE__ */ new Map();
|
|
514
|
-
for (const
|
|
515
|
-
const
|
|
516
|
-
if (
|
|
517
|
-
const
|
|
518
|
-
|
|
519
|
-
for (const
|
|
520
|
-
const
|
|
521
|
-
|
|
602
|
+
for (const w of e.input ?? []) {
|
|
603
|
+
const v = t("label", "ocw-form-row");
|
|
604
|
+
if (v.append(t("span", "ocw-form-lbl", w.label)), w.type === "select" && ((b = w.options) != null && b.length)) {
|
|
605
|
+
const r = t("select", "ocw-form-input");
|
|
606
|
+
w.required || r.append(t("option", void 0, "— select —"));
|
|
607
|
+
for (const u of w.options) {
|
|
608
|
+
const l = t("option");
|
|
609
|
+
l.value = u, l.textContent = u, r.append(l);
|
|
522
610
|
}
|
|
523
|
-
|
|
611
|
+
w.required && (r.required = !0), v.append(r), s.set(w.name, r);
|
|
524
612
|
} else {
|
|
525
|
-
const
|
|
526
|
-
|
|
613
|
+
const r = t("input", "ocw-form-input");
|
|
614
|
+
r.type = w.type === "number" ? "number" : w.type === "date" ? "datetime-local" : "text", w.required && (r.required = !0), v.append(r), s.set(w.name, r);
|
|
527
615
|
}
|
|
528
|
-
|
|
616
|
+
i.append(v);
|
|
529
617
|
}
|
|
530
|
-
const
|
|
531
|
-
|
|
532
|
-
const
|
|
533
|
-
for (const [
|
|
534
|
-
if (
|
|
535
|
-
|
|
618
|
+
const a = t("div", "ocw-form-actions"), c = t("button", "ocw-form-cancel", "Cancel"), f = t("button", "ocw-form-submit", "Send");
|
|
619
|
+
c.addEventListener("click", () => this.formHost.replaceChildren()), f.addEventListener("click", () => {
|
|
620
|
+
const w = {};
|
|
621
|
+
for (const [v, r] of s) {
|
|
622
|
+
if (r.required && !r.value) {
|
|
623
|
+
r.style.borderColor = "#e5484d";
|
|
536
624
|
return;
|
|
537
625
|
}
|
|
538
|
-
|
|
626
|
+
w[v] = r.type === "number" ? Number(r.value) : r.value;
|
|
539
627
|
}
|
|
540
|
-
this.formHost.replaceChildren(), this.h.onInvoke(e.id,
|
|
541
|
-
}),
|
|
628
|
+
this.formHost.replaceChildren(), this.h.onInvoke(e.id, w);
|
|
629
|
+
}), a.append(c, f), i.append(a), this.formHost.append(i), (d = s.values().next().value) == null || d.focus();
|
|
542
630
|
}
|
|
543
|
-
messageEl(e,
|
|
544
|
-
var
|
|
631
|
+
messageEl(e, i) {
|
|
632
|
+
var r;
|
|
545
633
|
if (e.senderRole === "system") {
|
|
546
|
-
const
|
|
547
|
-
return
|
|
634
|
+
const u = t("div", "ocw-sys");
|
|
635
|
+
return u.textContent = e.deletedAt ? "message deleted" : W(e.content), u;
|
|
548
636
|
}
|
|
549
|
-
const s = e.senderId === this.me,
|
|
550
|
-
!s && !
|
|
551
|
-
const
|
|
637
|
+
const s = e.senderId === this.me, a = !!e.internal, c = t("div", `ocw-row ${a ? "ocw-note mine" : s ? "mine" : "theirs"} ${e.senderRole === "bot" ? "ocw-bot" : ""}`);
|
|
638
|
+
!s && !a && c.append(t("div", "ocw-dot", e.senderRole === "bot" ? "🤖" : "🧑"));
|
|
639
|
+
const f = t("div"), b = t("div", "ocw-bubble-wrap");
|
|
552
640
|
if (e.replyToId) {
|
|
553
|
-
const
|
|
554
|
-
|
|
641
|
+
const u = t("div", "ocw-reply-to", "↩ replying to a message");
|
|
642
|
+
u.style.cssText = "font-size:11px;color:var(--ocw-mut);margin-bottom:2px;font-style:italic", f.append(u);
|
|
555
643
|
}
|
|
556
|
-
const
|
|
557
|
-
let
|
|
558
|
-
if (e.deletedAt)
|
|
644
|
+
const d = t("div", "ocw-bubble");
|
|
645
|
+
let w = null;
|
|
646
|
+
if (e.deletedAt) d.append(t("span", "ocw-deleted", "message deleted"));
|
|
559
647
|
else if (e.content.kind === "attachment") {
|
|
560
|
-
const
|
|
561
|
-
if ((
|
|
562
|
-
const
|
|
563
|
-
|
|
648
|
+
const u = e.content;
|
|
649
|
+
if ((r = u.mime) != null && r.startsWith("image/")) {
|
|
650
|
+
const l = document.createElement("img");
|
|
651
|
+
l.src = u.url, l.alt = u.name ?? "image", l.style.cssText = "max-width:220px;max-height:160px;border-radius:10px;display:block;cursor:pointer", l.addEventListener("click", () => window.open(u.url, "_blank")), d.append(l);
|
|
564
652
|
} else {
|
|
565
|
-
const
|
|
566
|
-
|
|
653
|
+
const l = document.createElement("a");
|
|
654
|
+
l.href = u.url, l.target = "_blank", l.rel = "noopener", l.style.cssText = "display:flex;align-items:center;gap:8px;color:inherit;text-decoration:none", l.append(t("span", void 0, "📄"), t("span", void 0, u.name ?? "file")), d.append(l);
|
|
567
655
|
}
|
|
568
656
|
} else if (e.content.kind === "appointment") {
|
|
569
|
-
const
|
|
570
|
-
|
|
571
|
-
const C =
|
|
572
|
-
|
|
573
|
-
const
|
|
574
|
-
|
|
657
|
+
const u = e.content, l = t("div", "ocw-appt");
|
|
658
|
+
l.append(t("div", "ocw-appt-title", `📅 ${u.title}`)), l.append(t("div", "ocw-appt-time", new Date(u.startIso).toLocaleString() + " – " + new Date(u.endIso).toLocaleTimeString())), u.location && l.append(t("div", "ocw-appt-loc", `📍 ${u.location}`)), u.description && l.append(t("div", "ocw-appt-desc", u.description));
|
|
659
|
+
const C = t("div", "ocw-appt-links"), g = document.createElement("a");
|
|
660
|
+
g.href = u.googleUrl, g.target = "_blank", g.rel = "noopener", g.className = "ocw-appt-btn", g.textContent = "📅 Add to Google Calendar";
|
|
661
|
+
const h = document.createElement("a");
|
|
662
|
+
h.href = u.icalUrl, h.download = `${u.title}.ics`, h.className = "ocw-appt-btn ocw-appt-btn-sec", h.textContent = "🍎 Apple / iCal", C.append(g, h), l.append(C), d.append(l);
|
|
575
663
|
} else
|
|
576
|
-
|
|
577
|
-
if (
|
|
578
|
-
const
|
|
579
|
-
if (
|
|
580
|
-
const
|
|
581
|
-
|
|
664
|
+
w = document.createTextNode(W(e.content)), d.append(w), e.editedAt && d.append(t("span", "ocw-edited", "(edited)"));
|
|
665
|
+
if (b.append(d), !s && !a && this.h.onTranslate && e.content.kind === "text" && !e.deletedAt && e.seq > 0 && w) {
|
|
666
|
+
const u = e.content.text;
|
|
667
|
+
if (u.trim()) {
|
|
668
|
+
const l = t("button", "ocw-translate-btn", "🌐");
|
|
669
|
+
l.type = "button", l.title = "Translate", l.addEventListener("click", (C) => {
|
|
582
670
|
if (C.stopPropagation(), this.showingTranslation.has(e.id)) {
|
|
583
|
-
this.showingTranslation.delete(e.id),
|
|
671
|
+
this.showingTranslation.delete(e.id), w.textContent = u, l.textContent = "🌐", l.title = "Translate";
|
|
584
672
|
return;
|
|
585
673
|
}
|
|
586
|
-
const
|
|
587
|
-
if (
|
|
588
|
-
this.showingTranslation.add(e.id),
|
|
674
|
+
const g = this.translationCache.get(e.id);
|
|
675
|
+
if (g !== void 0) {
|
|
676
|
+
this.showingTranslation.add(e.id), w.textContent = g, l.textContent = "↩", l.title = "Show original";
|
|
589
677
|
return;
|
|
590
678
|
}
|
|
591
|
-
|
|
592
|
-
if (
|
|
593
|
-
|
|
594
|
-
|
|
679
|
+
l.textContent = "⏳", this.h.onTranslate(u).then((h) => {
|
|
680
|
+
if (h === null) {
|
|
681
|
+
l.textContent = "⚠️", l.title = "Translation unavailable", setTimeout(() => {
|
|
682
|
+
l.textContent = "🌐", l.title = "Translate";
|
|
595
683
|
}, 1500);
|
|
596
684
|
return;
|
|
597
685
|
}
|
|
598
|
-
this.translationCache.set(e.id,
|
|
686
|
+
this.translationCache.set(e.id, h), this.showingTranslation.add(e.id), w.textContent = h, l.textContent = "↩", l.title = "Show original";
|
|
599
687
|
});
|
|
600
|
-
}),
|
|
688
|
+
}), b.append(l);
|
|
601
689
|
}
|
|
602
690
|
}
|
|
603
691
|
if (s && !e.deletedAt && e.seq > 0 && (this.h.onEdit ?? this.h.onDelete)) {
|
|
604
|
-
const
|
|
692
|
+
const u = t("div", "ocw-msg-menu");
|
|
605
693
|
if (this.h.onEdit) {
|
|
606
|
-
const
|
|
607
|
-
|
|
694
|
+
const l = t("button", void 0, "✏️");
|
|
695
|
+
l.title = "Edit", l.addEventListener("click", (C) => {
|
|
608
696
|
C.stopPropagation();
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
const
|
|
612
|
-
|
|
613
|
-
const
|
|
614
|
-
|
|
615
|
-
const
|
|
616
|
-
|
|
617
|
-
const A =
|
|
618
|
-
A.append(
|
|
619
|
-
const
|
|
620
|
-
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
}),
|
|
624
|
-
|
|
697
|
+
const g = W(e.content), h = document.createElement("textarea");
|
|
698
|
+
h.value = g, h.rows = Math.min(4, Math.ceil(g.length / 40) + 1), h.style.cssText = "width:100%;resize:vertical;border:1px solid var(--ocw-accent);border-radius:8px;padding:6px 10px;font:inherit;font-size:14px;background:#fff;color:#1c1b1a;box-sizing:border-box";
|
|
699
|
+
const I = t("button", "ocw-form-submit", "Save");
|
|
700
|
+
I.style.cssText = "margin-top:6px;padding:5px 14px;font-size:13px";
|
|
701
|
+
const T = t("button", "ocw-form-cancel", "Cancel");
|
|
702
|
+
T.style.cssText = "margin-top:6px;padding:5px 10px;font-size:13px";
|
|
703
|
+
const $ = t("div");
|
|
704
|
+
$.style.cssText = "display:flex;gap:6px;justify-content:flex-end", $.append(T, I);
|
|
705
|
+
const A = t("div");
|
|
706
|
+
A.append(h, $), d.replaceChildren(A), h.focus(), h.select();
|
|
707
|
+
const z = () => d.replaceChildren(w ?? document.createTextNode(g));
|
|
708
|
+
T.addEventListener("click", z), I.addEventListener("click", () => {
|
|
709
|
+
const P = h.value.trim();
|
|
710
|
+
P && P !== g && this.h.onEdit(e.id, P), z();
|
|
711
|
+
}), h.addEventListener("keydown", (P) => {
|
|
712
|
+
P.key === "Enter" && !P.shiftKey && (P.preventDefault(), I.click()), P.key === "Escape" && z();
|
|
625
713
|
});
|
|
626
|
-
}),
|
|
714
|
+
}), u.append(l);
|
|
627
715
|
}
|
|
628
716
|
if (this.h.onDelete) {
|
|
629
|
-
const
|
|
630
|
-
|
|
717
|
+
const l = t("button", "del", "🗑");
|
|
718
|
+
l.title = "Delete", l.addEventListener("click", (C) => {
|
|
631
719
|
C.stopPropagation(), this.h.onDelete(e.id);
|
|
632
|
-
}),
|
|
720
|
+
}), u.append(l);
|
|
633
721
|
}
|
|
634
|
-
|
|
722
|
+
b.append(u);
|
|
635
723
|
}
|
|
636
|
-
if (
|
|
637
|
-
const
|
|
724
|
+
if (f.append(b), this.h.onReact && !e.deletedAt && e.seq > 0) {
|
|
725
|
+
const u = t("div", "ocw-react-wrap"), l = t("div", "ocw-react");
|
|
638
726
|
if (e.reactions && Object.keys(e.reactions).length)
|
|
639
|
-
for (const [
|
|
640
|
-
const
|
|
641
|
-
|
|
642
|
-
var
|
|
643
|
-
return (A = (
|
|
644
|
-
}),
|
|
727
|
+
for (const [h, I] of Object.entries(e.reactions)) {
|
|
728
|
+
const T = t("button", `ocw-react-pill${I.includes(this.me) ? " mine" : ""}`, `${h} ${I.length}`);
|
|
729
|
+
T.addEventListener("click", () => {
|
|
730
|
+
var $, A;
|
|
731
|
+
return (A = ($ = this.h).onReact) == null ? void 0 : A.call($, e.id, h, I.includes(this.me));
|
|
732
|
+
}), l.append(T);
|
|
645
733
|
}
|
|
646
|
-
const C =
|
|
647
|
-
for (const
|
|
648
|
-
const
|
|
649
|
-
|
|
650
|
-
var A,
|
|
651
|
-
|
|
652
|
-
const
|
|
653
|
-
(
|
|
654
|
-
}),
|
|
734
|
+
const C = t("button", "ocw-react-btn", "+"), g = t("div", "ocw-react-picker");
|
|
735
|
+
for (const h of Ce) {
|
|
736
|
+
const I = t("button", void 0, h);
|
|
737
|
+
I.addEventListener("click", (T) => {
|
|
738
|
+
var A, z, P, k;
|
|
739
|
+
T.stopPropagation();
|
|
740
|
+
const $ = (z = (A = e.reactions) == null ? void 0 : A[h]) == null ? void 0 : z.includes(this.me);
|
|
741
|
+
(k = (P = this.h).onReact) == null || k.call(P, e.id, h, !!$), g.style.display = "none";
|
|
742
|
+
}), g.append(I);
|
|
655
743
|
}
|
|
656
|
-
|
|
657
|
-
|
|
744
|
+
g.style.display = "none", C.addEventListener("click", (h) => {
|
|
745
|
+
h.stopPropagation(), g.style.display = g.style.display === "none" ? "flex" : "none";
|
|
658
746
|
}), document.addEventListener("click", () => {
|
|
659
|
-
|
|
660
|
-
}, { once: !0 }),
|
|
661
|
-
} else e.reactions && Object.keys(e.reactions).length &&
|
|
662
|
-
const
|
|
747
|
+
g.style.display = "none";
|
|
748
|
+
}, { once: !0 }), l.append(C), u.append(l, g), f.append(u);
|
|
749
|
+
} else e.reactions && Object.keys(e.reactions).length && f.append(t("div", "ocw-react", Object.entries(e.reactions).map(([u, l]) => `${u}${l.length}`).join(" ")));
|
|
750
|
+
const v = t("div", "ocw-time ocw-meta", Se(e.ts));
|
|
663
751
|
if (s && e.status) {
|
|
664
|
-
const
|
|
665
|
-
|
|
752
|
+
const u = t("span", `ocw-tick${e.status === "read" ? " read" : e.status === "delivered" ? " delivered" : ""}`, Pe(e.status));
|
|
753
|
+
v.append(u);
|
|
666
754
|
}
|
|
667
|
-
return s && e.seq > 0 &&
|
|
755
|
+
return s && e.seq > 0 && i.lastReadByOthers >= e.seq && v.append(t("span", "ocw-seen", " · Seen")), f.append(v), c.append(f), c;
|
|
668
756
|
}
|
|
669
757
|
}
|
|
670
|
-
function
|
|
671
|
-
switch (
|
|
758
|
+
function Pe(o) {
|
|
759
|
+
switch (o) {
|
|
672
760
|
case "read":
|
|
673
761
|
return "✓✓";
|
|
674
762
|
case "delivered":
|
|
@@ -679,29 +767,31 @@ function Se(t) {
|
|
|
679
767
|
return "🕓";
|
|
680
768
|
}
|
|
681
769
|
}
|
|
682
|
-
const
|
|
683
|
-
function
|
|
684
|
-
return `relay-launcher::${
|
|
770
|
+
const R = /* @__PURE__ */ new WeakMap(), U = /* @__PURE__ */ new Map();
|
|
771
|
+
function ne(o) {
|
|
772
|
+
return `relay-launcher::${o.profileId}::${o.subjectId ?? ""}`;
|
|
685
773
|
}
|
|
686
|
-
function
|
|
774
|
+
function Ae(o) {
|
|
687
775
|
var e;
|
|
688
|
-
(e =
|
|
776
|
+
(e = R.get(o)) == null || e.close(), R.delete(o);
|
|
689
777
|
}
|
|
690
|
-
function
|
|
691
|
-
var
|
|
692
|
-
|
|
693
|
-
const e =
|
|
694
|
-
let
|
|
695
|
-
const
|
|
696
|
-
let
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
const
|
|
704
|
-
|
|
778
|
+
function Be(o) {
|
|
779
|
+
var J, Q, G, Z, ee;
|
|
780
|
+
R.has(o.el) && (R.get(o.el).close(), R.delete(o.el)), o.launcher && ((J = U.get(ne(o))) == null || J.close());
|
|
781
|
+
const e = fe();
|
|
782
|
+
let i, s = !1;
|
|
783
|
+
const a = o.token ?? o.userId ?? e, c = a !== e ? e : void 0, { wsUrl: f, httpBase: b } = ue(o.url, o.apiUrl);
|
|
784
|
+
let d = new xe(a);
|
|
785
|
+
const w = o.subjectId ? `${a}::${o.subjectId}` : a, v = new be(w);
|
|
786
|
+
let r, u = !1, l = null, C = null;
|
|
787
|
+
!o.launcher && !o.el.style.height && o.el.clientHeight === 0 && (o.el.style.width = o.el.style.width || "100%", o.el.style.height = "600px");
|
|
788
|
+
for (const n of v.load()) d.addOptimistic(n.clientMsgId, n.content);
|
|
789
|
+
let g = null, h = null, I = 0, T = !o.launcher;
|
|
790
|
+
if (o.launcher) {
|
|
791
|
+
const p = (o.position ?? "bottom-right").includes("right");
|
|
792
|
+
g = document.createElement("div"), g.style.cssText = `position:fixed;${p ? "right:20px" : "left:20px"};bottom:20px;z-index:9999;display:flex;flex-direction:column;align-items:${p ? "flex-end" : "flex-start"};gap:12px`;
|
|
793
|
+
const x = document.createElement("div"), E = typeof window < "u" ? window.matchMedia("(max-width: 479px)") : null, O = (q) => {
|
|
794
|
+
x.style.cssText = q ? [
|
|
705
795
|
"position:fixed",
|
|
706
796
|
"inset:0",
|
|
707
797
|
"width:100%",
|
|
@@ -724,150 +814,183 @@ function Ae(t) {
|
|
|
724
814
|
"display:none",
|
|
725
815
|
"flex-direction:column",
|
|
726
816
|
"background:#fff",
|
|
727
|
-
"transform-origin:bottom " + (
|
|
817
|
+
"transform-origin:bottom " + (p ? "right" : "left"),
|
|
728
818
|
"transition:opacity .18s,transform .18s",
|
|
729
819
|
"opacity:0",
|
|
730
820
|
"transform:scale(.95)"
|
|
731
821
|
].join(";");
|
|
732
822
|
};
|
|
733
|
-
O((
|
|
734
|
-
const N = (
|
|
735
|
-
|
|
736
|
-
const
|
|
737
|
-
|
|
823
|
+
O((E == null ? void 0 : E.matches) ?? !1);
|
|
824
|
+
const N = (q) => O(q.matches);
|
|
825
|
+
E == null || E.addEventListener("change", N), l = E, C = N, o.el.style.cssText = "width:100%;height:100%;overflow:hidden", x.append(o.el);
|
|
826
|
+
const L = document.createElement("button");
|
|
827
|
+
L.style.cssText = [
|
|
738
828
|
"width:56px;height:56px;border-radius:50%",
|
|
739
|
-
`background:${
|
|
829
|
+
`background:${o.accent ?? "#4F63F5"}`,
|
|
740
830
|
"color:#fff;border:none;font-size:24px;cursor:pointer",
|
|
741
831
|
"box-shadow:0 4px 16px rgba(0,0,0,.25)",
|
|
742
832
|
"position:relative;flex:none",
|
|
743
833
|
"transition:transform .15s"
|
|
744
|
-
].join(";"),
|
|
745
|
-
|
|
746
|
-
},
|
|
747
|
-
|
|
748
|
-
},
|
|
749
|
-
const
|
|
750
|
-
|
|
834
|
+
].join(";"), L.textContent = "💬", L.onmouseenter = () => {
|
|
835
|
+
L.style.transform = "scale(1.08)";
|
|
836
|
+
}, L.onmouseleave = () => {
|
|
837
|
+
L.style.transform = "scale(1)";
|
|
838
|
+
}, h = document.createElement("span"), h.style.cssText = "position:absolute;top:-4px;right:-4px;background:#ef4444;color:#fff;border-radius:50%;width:20px;height:20px;font-size:11px;font-weight:700;display:none;align-items:center;justify-content:center", L.append(h), g.append(x, L), document.body.append(g);
|
|
839
|
+
const _ = (q) => {
|
|
840
|
+
q ? (x.style.display = "flex", requestAnimationFrame(() => {
|
|
751
841
|
x.style.opacity = "1", x.style.transform = "scale(1)";
|
|
752
842
|
})) : (x.style.opacity = "0", x.style.transform = "scale(.95)", setTimeout(() => {
|
|
753
|
-
|
|
843
|
+
T || (x.style.display = "none");
|
|
754
844
|
}, 180));
|
|
755
845
|
};
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
}), document.addEventListener("keydown", (
|
|
759
|
-
|
|
846
|
+
L.addEventListener("click", () => {
|
|
847
|
+
T = !T, _(T), L.textContent = T ? "✕" : "💬", L.append(h), T && (I = 0, h && (h.style.display = "none"));
|
|
848
|
+
}), document.addEventListener("keydown", (q) => {
|
|
849
|
+
q.key === "Escape" && T && (T = !1, _(!1), L.textContent = "💬", L.append(h));
|
|
760
850
|
});
|
|
761
851
|
}
|
|
762
|
-
const
|
|
763
|
-
|
|
764
|
-
},
|
|
852
|
+
const $ = () => {
|
|
853
|
+
T || (I++, h && (h.textContent = String(I), h.style.display = "flex"));
|
|
854
|
+
}, A = () => {
|
|
765
855
|
try {
|
|
766
|
-
const
|
|
767
|
-
|
|
856
|
+
const n = new AudioContext(), p = n.createOscillator(), x = n.createGain();
|
|
857
|
+
p.connect(x), x.connect(n.destination), p.frequency.setValueAtTime(880, n.currentTime), p.frequency.exponentialRampToValueAtTime(440, n.currentTime + 0.15), x.gain.setValueAtTime(0.3, n.currentTime), x.gain.exponentialRampToValueAtTime(1e-3, n.currentTime + 0.3), p.start(), p.stop(n.currentTime + 0.3);
|
|
768
858
|
} catch {
|
|
769
859
|
}
|
|
770
|
-
},
|
|
771
|
-
for (;
|
|
772
|
-
const
|
|
773
|
-
|
|
860
|
+
}, z = [], P = (n) => {
|
|
861
|
+
for (; z.length; ) {
|
|
862
|
+
const p = z.shift();
|
|
863
|
+
v.add({ clientMsgId: p.clientMsgId, content: p.content, ts: Date.now() }), k.send({ type: "send", conversationId: n, clientMsgId: p.clientMsgId, content: p.content });
|
|
774
864
|
}
|
|
775
865
|
};
|
|
776
|
-
let
|
|
777
|
-
const
|
|
778
|
-
let
|
|
779
|
-
const
|
|
780
|
-
let
|
|
781
|
-
const
|
|
782
|
-
|
|
783
|
-
r &&
|
|
866
|
+
let k;
|
|
867
|
+
const m = new me(`ocw-e2e-${o.profileId}`);
|
|
868
|
+
let S = !1;
|
|
869
|
+
const B = [], D = [];
|
|
870
|
+
let Y = !1;
|
|
871
|
+
const F = (n, p) => {
|
|
872
|
+
m.sealText(p).then((x) => {
|
|
873
|
+
r && k.send({ type: "send", conversationId: r, clientMsgId: n, content: x });
|
|
784
874
|
});
|
|
785
|
-
},
|
|
786
|
-
|
|
787
|
-
r &&
|
|
875
|
+
}, ie = (n, p, x) => {
|
|
876
|
+
m.sealText(p, x).then((E) => {
|
|
877
|
+
r && k.send({ type: "send", conversationId: r, clientMsgId: n, content: E });
|
|
788
878
|
});
|
|
789
|
-
},
|
|
790
|
-
for (;
|
|
791
|
-
const
|
|
792
|
-
|
|
879
|
+
}, se = () => {
|
|
880
|
+
for (; B.length; ) {
|
|
881
|
+
const n = B.shift();
|
|
882
|
+
F(n.clientMsgId, n.text);
|
|
793
883
|
}
|
|
794
|
-
for (;
|
|
795
|
-
const
|
|
796
|
-
|
|
884
|
+
for (; D.length; ) {
|
|
885
|
+
const n = D.shift();
|
|
886
|
+
F(n.clientMsgId, n.text);
|
|
797
887
|
}
|
|
798
|
-
},
|
|
799
|
-
|
|
800
|
-
},
|
|
801
|
-
|
|
802
|
-
const
|
|
803
|
-
onSend(
|
|
804
|
-
const
|
|
805
|
-
|
|
888
|
+
}, ae = (n) => {
|
|
889
|
+
k.send({ type: "fetchPrekey", targetUserId: n });
|
|
890
|
+
}, re = o.i18n ?? {}, ce = ["ar", "he", "fa", "ur"], le = typeof navigator < "u" ? (navigator.language ?? "").slice(0, 2).toLowerCase() : "";
|
|
891
|
+
ce.includes(le) && !o.el.dir && (o.el.dir = "rtl", o.el.style.fontFamily = o.el.style.fontFamily || "Tahoma,Arial,system-ui,sans-serif");
|
|
892
|
+
const K = new ke(), V = `oc_prechat_${o.profileId}_${a.slice(-8)}`, j = new Ee(o.el, a, {
|
|
893
|
+
onSend(n) {
|
|
894
|
+
const p = `cm_${Math.random().toString(36).slice(2)}`, x = { kind: "text", text: n };
|
|
895
|
+
d.addOptimistic(p, x), j.render(d), d.e2e ? m.ready ? F(p, n) : Y ? D.push({ clientMsgId: p, text: n }) : (B.push({ clientMsgId: p, text: n }), d.assignedAgentId && ae(d.assignedAgentId)) : r ? (v.add({ clientMsgId: p, content: x, ts: Date.now() }), k.send({ type: "send", conversationId: r, clientMsgId: p, content: x })) : z.push({ clientMsgId: p, content: x });
|
|
806
896
|
},
|
|
807
|
-
async onAttach(
|
|
897
|
+
async onAttach(n) {
|
|
808
898
|
if (!r) return;
|
|
809
|
-
const
|
|
810
|
-
|
|
899
|
+
const p = `${b}/upload?name=${encodeURIComponent(n.name)}`, x = `cm_${Math.random().toString(36).slice(2)}`;
|
|
900
|
+
d.addOptimistic(x, { kind: "text", text: `📎 Uploading ${n.name}…` }), j.render(d);
|
|
811
901
|
try {
|
|
812
|
-
const
|
|
902
|
+
const E = await fetch(p, {
|
|
813
903
|
method: "POST",
|
|
814
|
-
headers: { "content-type":
|
|
815
|
-
body:
|
|
904
|
+
headers: { "content-type": n.type, ...o.token ? { authorization: `Bearer ${o.token}` } : {} },
|
|
905
|
+
body: n
|
|
816
906
|
});
|
|
817
|
-
if (!
|
|
818
|
-
const { url: O, name: N, mime:
|
|
819
|
-
|
|
820
|
-
} catch (
|
|
821
|
-
|
|
907
|
+
if (!E.ok) throw new Error(`Upload failed: ${E.status}`);
|
|
908
|
+
const { url: O, name: N, mime: L, size: _ } = await E.json();
|
|
909
|
+
k.send({ type: "send", conversationId: r, clientMsgId: x, content: { kind: "attachment", url: O, name: N, mime: L, size: _ } });
|
|
910
|
+
} catch (E) {
|
|
911
|
+
d.addOptimistic(x, { kind: "text", text: `⚠️ Upload failed: ${E.message}` }), j.render(d);
|
|
822
912
|
}
|
|
823
913
|
},
|
|
824
|
-
onInvoke(
|
|
825
|
-
r &&
|
|
914
|
+
onInvoke(n, p) {
|
|
915
|
+
r && k.send({ type: "invoke", conversationId: r, actionId: n, clientInvokeId: `iv_${Math.random().toString(36).slice(2)}`, ...p ? { inputs: p } : {} });
|
|
826
916
|
},
|
|
827
|
-
onTyping(
|
|
828
|
-
r &&
|
|
917
|
+
onTyping(n, p) {
|
|
918
|
+
r && k.send({ type: "typing", conversationId: r, isTyping: n, ...p ? { preview: p } : {} });
|
|
829
919
|
},
|
|
830
|
-
|
|
831
|
-
|
|
920
|
+
onPreChat(n) {
|
|
921
|
+
try {
|
|
922
|
+
localStorage.setItem(V, "1");
|
|
923
|
+
} catch {
|
|
924
|
+
}
|
|
925
|
+
k.send({
|
|
926
|
+
type: "open",
|
|
927
|
+
profileId: o.profileId,
|
|
928
|
+
...o.subjectId ? { subjectId: o.subjectId } : {},
|
|
929
|
+
userInfo: {
|
|
930
|
+
...n.name ? { name: n.name } : {},
|
|
931
|
+
...n.email ? { email: n.email } : {},
|
|
932
|
+
...n.phone || n.topic ? { meta: {
|
|
933
|
+
...n.phone ? { phone: n.phone } : {},
|
|
934
|
+
...n.topic ? { topic: n.topic } : {}
|
|
935
|
+
} } : {}
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
const p = n.callback ? `📞 Call-back requested${n.phone ? `: ${n.phone}` : ""}${n.topic ? ` — ${n.topic}` : ""}` : n.topic ? `Topic: ${n.topic}` : "";
|
|
939
|
+
p && r && !d.e2e && k.send({ type: "send", conversationId: r, clientMsgId: `pc_${Math.random().toString(36).slice(2, 12)}`, content: { kind: "text", text: p } });
|
|
940
|
+
},
|
|
941
|
+
onDeflectQuery(n) {
|
|
942
|
+
if (s) return;
|
|
943
|
+
clearTimeout(i);
|
|
944
|
+
const p = n.trim();
|
|
945
|
+
if (p.length < 3) {
|
|
946
|
+
j.hideDeflection();
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
i = setTimeout(() => {
|
|
950
|
+
fetch(`${b}/kb/search?profileId=${encodeURIComponent(o.profileId)}&q=${encodeURIComponent(p.slice(0, 200))}`).then((x) => x.ok ? x.json() : { articles: [] }).then((x) => j.showDeflection(x.articles ?? [])).catch(() => j.hideDeflection());
|
|
951
|
+
}, 350);
|
|
952
|
+
},
|
|
953
|
+
onReadUpTo(n) {
|
|
954
|
+
r && k.send({ type: "read", conversationId: r, seq: n });
|
|
832
955
|
},
|
|
833
956
|
onLoadMore() {
|
|
834
|
-
if (!r || !
|
|
835
|
-
const
|
|
836
|
-
|
|
957
|
+
if (!r || !d.e2e) return;
|
|
958
|
+
const n = d.messages()[0];
|
|
959
|
+
n && k.send({ type: "history", conversationId: r, beforeSeq: n.seq, limit: 20 });
|
|
837
960
|
},
|
|
838
|
-
onEdit(
|
|
839
|
-
r &&
|
|
961
|
+
onEdit(n, p) {
|
|
962
|
+
r && k.send({ type: "edit", conversationId: r, messageId: n, content: { kind: "text", text: p } });
|
|
840
963
|
},
|
|
841
|
-
onDelete(
|
|
842
|
-
r &&
|
|
964
|
+
onDelete(n) {
|
|
965
|
+
r && k.send({ type: "delete", conversationId: r, messageId: n });
|
|
843
966
|
},
|
|
844
|
-
onReact(
|
|
845
|
-
r &&
|
|
967
|
+
onReact(n, p, x) {
|
|
968
|
+
r && k.send({ type: "react", conversationId: r, messageId: n, emoji: p, remove: x });
|
|
846
969
|
},
|
|
847
|
-
onCsat(
|
|
848
|
-
r && fetch(`${
|
|
970
|
+
onCsat(n) {
|
|
971
|
+
r && fetch(`${b}/conversations/${r}/csat`, {
|
|
849
972
|
method: "POST",
|
|
850
|
-
headers: { "Content-Type": "application/json", Authorization: `Bearer ${
|
|
851
|
-
body: JSON.stringify({ score:
|
|
973
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${a}` },
|
|
974
|
+
body: JSON.stringify({ score: n })
|
|
852
975
|
}).catch(() => {
|
|
853
976
|
});
|
|
854
977
|
},
|
|
855
|
-
onAnnotate(
|
|
856
|
-
r &&
|
|
978
|
+
onAnnotate(n) {
|
|
979
|
+
r && k.send({ type: "annotate", conversationId: r, stroke: n });
|
|
857
980
|
},
|
|
858
981
|
onAnnotateClear() {
|
|
859
|
-
r &&
|
|
982
|
+
r && k.send({ type: "annotate_clear", conversationId: r });
|
|
860
983
|
},
|
|
861
|
-
...
|
|
862
|
-
async onTranslate(
|
|
984
|
+
...o.translateLang ? {
|
|
985
|
+
async onTranslate(n) {
|
|
863
986
|
try {
|
|
864
|
-
const
|
|
987
|
+
const p = await fetch(`${b}/translate`, {
|
|
865
988
|
method: "POST",
|
|
866
|
-
headers: { "content-type": "application/json", authorization: `Bearer ${
|
|
867
|
-
body: JSON.stringify({ text:
|
|
989
|
+
headers: { "content-type": "application/json", authorization: `Bearer ${a}` },
|
|
990
|
+
body: JSON.stringify({ text: n, targetLang: o.translateLang })
|
|
868
991
|
});
|
|
869
|
-
if (!
|
|
870
|
-
const { translated: x } = await
|
|
992
|
+
if (!p.ok) return null;
|
|
993
|
+
const { translated: x } = await p.json();
|
|
871
994
|
return x;
|
|
872
995
|
} catch {
|
|
873
996
|
return null;
|
|
@@ -875,100 +998,105 @@ function Ae(t) {
|
|
|
875
998
|
}
|
|
876
999
|
} : {}
|
|
877
1000
|
}, {
|
|
878
|
-
...
|
|
879
|
-
...
|
|
880
|
-
...
|
|
881
|
-
...(
|
|
882
|
-
i18n:
|
|
883
|
-
})
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
1001
|
+
...o.subject ? { subject: o.subject } : {},
|
|
1002
|
+
...o.quickReplies ? { quickReplies: o.quickReplies } : {},
|
|
1003
|
+
...o.accent ? { accent: o.accent } : {},
|
|
1004
|
+
...(Q = o.user) != null && Q.name || (G = o.user) != null && G.avatar ? { userInfo: { ...o.user.name ? { name: o.user.name } : {}, ...o.user.avatar ? { avatar: o.user.avatar } : {} } } : {},
|
|
1005
|
+
i18n: re
|
|
1006
|
+
});
|
|
1007
|
+
try {
|
|
1008
|
+
localStorage.getItem(V) && j.completePreChat();
|
|
1009
|
+
} catch {
|
|
1010
|
+
}
|
|
1011
|
+
const X = o.user && (o.user.name || o.user.email || o.user.avatar || o.user.meta) ? {
|
|
1012
|
+
...o.user.name ? { name: o.user.name } : {},
|
|
1013
|
+
...o.user.email ? { email: o.user.email } : {},
|
|
1014
|
+
...o.user.avatar ? { avatar: o.user.avatar } : {},
|
|
1015
|
+
...o.user.meta ? { meta: o.user.meta } : {}
|
|
1016
|
+
} : void 0, de = {
|
|
889
1017
|
type: "open",
|
|
890
|
-
profileId:
|
|
1018
|
+
profileId: o.profileId,
|
|
891
1019
|
// Direct conversations use the kind/peerId pair; the dm:… subject key is
|
|
892
1020
|
// server-derived and owner-keyed, so passing it as subjectId from the
|
|
893
1021
|
// NON-owner side would find-or-create a junk duplicate thread.
|
|
894
|
-
...
|
|
895
|
-
...
|
|
896
|
-
...
|
|
1022
|
+
...o.kind === "direct" && o.peerId ? { kind: "direct", peerId: o.peerId } : o.subjectId ? { subjectId: o.subjectId } : {},
|
|
1023
|
+
...c ? { linkFrom: c } : {},
|
|
1024
|
+
...X ? { userInfo: X } : {},
|
|
897
1025
|
...typeof location < "u" ? { pageUrl: location.href } : {},
|
|
898
1026
|
...typeof document < "u" && document.title ? { pageTitle: document.title } : {},
|
|
899
1027
|
// Pass subject display info so the server can persist it to the Subject record.
|
|
900
1028
|
// This is how listingTitle and listingMeta get saved without a separate API call.
|
|
901
|
-
...(
|
|
902
|
-
...(
|
|
1029
|
+
...(Z = o.subject) != null && Z.title ? { subjectTitle: o.subject.title } : {},
|
|
1030
|
+
...(ee = o.subject) != null && ee.subtitle ? { subjectMeta: o.subject.subtitle } : {}
|
|
903
1031
|
};
|
|
904
|
-
|
|
905
|
-
...
|
|
906
|
-
url:
|
|
907
|
-
token:
|
|
908
|
-
open:
|
|
909
|
-
getCursor: () =>
|
|
910
|
-
onStatusChange: (
|
|
911
|
-
onFrame(
|
|
912
|
-
if (
|
|
913
|
-
if (r =
|
|
914
|
-
|
|
915
|
-
for (const
|
|
916
|
-
|
|
1032
|
+
k = new ge({
|
|
1033
|
+
...o.refreshToken ? { refreshToken: o.refreshToken } : {},
|
|
1034
|
+
url: f,
|
|
1035
|
+
token: a,
|
|
1036
|
+
open: de,
|
|
1037
|
+
getCursor: () => d.highestSeq(),
|
|
1038
|
+
onStatusChange: (n, p) => j.setConnStatus(n, p),
|
|
1039
|
+
onFrame(n) {
|
|
1040
|
+
if (K.apply(n), n.type === "opened") {
|
|
1041
|
+
if (r = n.conversation.id, !u) {
|
|
1042
|
+
u = !0;
|
|
1043
|
+
for (const p of v.load())
|
|
1044
|
+
k.send({ type: "send", conversationId: r, clientMsgId: p.clientMsgId, content: p.content });
|
|
917
1045
|
}
|
|
918
|
-
|
|
1046
|
+
we(f, a, r, d, j, b), z.length && P(r);
|
|
919
1047
|
}
|
|
920
|
-
if (
|
|
921
|
-
|
|
922
|
-
const x = [...
|
|
923
|
-
for (const
|
|
924
|
-
|
|
1048
|
+
if (n.type === "ack" && v.remove(n.clientMsgId), n.type === "prekeyBundle") {
|
|
1049
|
+
n.bundle && (Y = !0, m.x3dhSendTo(n.bundle).then((p) => {
|
|
1050
|
+
const x = [...B.splice(0), ...D.splice(0)];
|
|
1051
|
+
for (const E of x) ie(E.clientMsgId, E.text, p);
|
|
1052
|
+
j.render(d);
|
|
925
1053
|
}));
|
|
926
1054
|
return;
|
|
927
1055
|
}
|
|
928
|
-
if (
|
|
929
|
-
const
|
|
930
|
-
if (
|
|
931
|
-
|
|
932
|
-
await
|
|
1056
|
+
if (n.type === "message" && d.e2e) {
|
|
1057
|
+
const p = ye(n.message.content);
|
|
1058
|
+
if (p && !m.ready) {
|
|
1059
|
+
m.x3dhReceiveFrom(p.x3dhIK, p.x3dhEK, p.x3dhSPK).then(async () => {
|
|
1060
|
+
await m.openFrame(n), d.apply(n), j.render(d);
|
|
933
1061
|
});
|
|
934
1062
|
return;
|
|
935
1063
|
}
|
|
936
1064
|
}
|
|
937
|
-
if (
|
|
938
|
-
|
|
939
|
-
|
|
1065
|
+
if (n.type === "peerkey") {
|
|
1066
|
+
m.onPeerKey(n.key).then(() => {
|
|
1067
|
+
se(), j.render(d);
|
|
940
1068
|
});
|
|
941
1069
|
return;
|
|
942
1070
|
}
|
|
943
1071
|
(async () => {
|
|
944
|
-
if (
|
|
945
|
-
|
|
946
|
-
const
|
|
947
|
-
|
|
948
|
-
const x = await
|
|
949
|
-
|
|
1072
|
+
if (d.e2e && await m.openFrame(n), d.apply(n), n.type === "message" && n.message.senderId !== a && !n.message.internal && ($(), A()), d.e2e && r && !S) {
|
|
1073
|
+
S = !0;
|
|
1074
|
+
const p = await m.initX3DH();
|
|
1075
|
+
k.send({ type: "uploadPrekeys", ...p });
|
|
1076
|
+
const x = await m.begin();
|
|
1077
|
+
k.send({ type: "pubkey", conversationId: r, key: x });
|
|
950
1078
|
}
|
|
951
|
-
|
|
1079
|
+
j.render(d);
|
|
952
1080
|
})();
|
|
953
1081
|
}
|
|
954
|
-
}),
|
|
955
|
-
const
|
|
956
|
-
|
|
1082
|
+
}), k.connect(), j.render(d);
|
|
1083
|
+
const M = o.launcher ? ne(o) : null, H = { close: () => {
|
|
1084
|
+
s = !0, clearTimeout(i), k.close(), g == null || g.remove(), j.destroy(), K.destroy(), l && C && l.removeEventListener("change", C), R.delete(o.el), M && U.get(M) === H && U.delete(M);
|
|
957
1085
|
} };
|
|
958
|
-
return
|
|
1086
|
+
return R.set(o.el, H), M && U.set(M, H), H;
|
|
959
1087
|
}
|
|
960
1088
|
export {
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1089
|
+
xe as ChatStore,
|
|
1090
|
+
ge as ConnectionManager,
|
|
1091
|
+
me as E2ESession,
|
|
1092
|
+
be as PersistentOutbox,
|
|
1093
|
+
Ee as Renderer,
|
|
1094
|
+
He as asConversationId,
|
|
1095
|
+
ye as extractX3DHInit,
|
|
1096
|
+
Me as httpBaseFromWsUrl,
|
|
1097
|
+
Be as mount,
|
|
1098
|
+
ue as resolveRelayUrls,
|
|
1099
|
+
we as restoreHistory,
|
|
1100
|
+
Ae as unmount
|
|
973
1101
|
};
|
|
974
1102
|
//# sourceMappingURL=index.js.map
|