@docgenlab.com/chat-widget 0.1.3 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,301 +1,546 @@
1
- import { createRoot as he } from "react-dom/client";
1
+ import { createRoot as $e } from "react-dom/client";
2
2
  import * as e from "react";
3
- import { useRef as $, useState as E, useEffect as F, useCallback as ae, createElement as re } from "react";
4
- const j = "/api/v1/public/kb", le = "dgl-visitor-id";
5
- function ie() {
3
+ import { useRef as j, useState as f, useEffect as T, useCallback as be, createElement as Ee } from "react";
4
+ const S = "/api/v1/public/kb", ye = "dgl-visitor-id";
5
+ function ve() {
6
6
  const t = globalThis.crypto;
7
- return t && typeof t.randomUUID == "function" ? t.randomUUID() : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (a) => {
8
- const r = Math.random() * 16 | 0;
9
- return (a === "x" ? r : r & 3 | 8).toString(16);
7
+ return t && typeof t.randomUUID == "function" ? t.randomUUID() : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (n) => {
8
+ const i = Math.random() * 16 | 0;
9
+ return (n === "x" ? i : i & 3 | 8).toString(16);
10
10
  });
11
11
  }
12
- function fe() {
12
+ function Se() {
13
13
  try {
14
- let t = localStorage.getItem(le);
15
- return t || (t = ie(), localStorage.setItem(le, t)), t;
14
+ let t = localStorage.getItem(ye);
15
+ return t || (t = ve(), localStorage.setItem(ye, t)), t;
16
16
  } catch (t) {
17
- return ie();
17
+ return ve();
18
18
  }
19
19
  }
20
- class ye {
21
- constructor(a) {
22
- this.agentKey = a.agentKey, this.baseUrl = a.apiBaseUrl.replace(/\/+$/, ""), this.visitorId = fe();
20
+ class Te {
21
+ constructor(n) {
22
+ this.agentKey = n.agentKey, this.baseUrl = n.apiBaseUrl.replace(/\/+$/, ""), this.visitorId = n.endUserId ? `user:${n.endUserId}` : Se(), this.endUserHash = n.endUserHash;
23
23
  }
24
- headers(a) {
25
- return {
24
+ headers(n) {
25
+ const i = {
26
26
  "X-DocGenLab-Key": this.agentKey,
27
27
  "X-DocGenLab-Visitor-Id": this.visitorId,
28
- ...a || {}
28
+ ...n || {}
29
29
  };
30
+ return this.endUserHash && (i["X-DocGenLab-User-Hash"] = this.endUserHash), i;
30
31
  }
31
32
  async getAgent() {
32
- const a = await fetch(`${this.baseUrl}${j}/agent`, {
33
+ const n = await fetch(`${this.baseUrl}${S}/agent`, {
33
34
  method: "GET",
34
35
  headers: this.headers()
35
36
  });
36
- if (!a.ok) throw new Error(`getAgent failed: ${a.status}`);
37
- return a.json();
37
+ if (!n.ok) throw new Error(`getAgent failed: ${n.status}`);
38
+ return n.json();
39
+ }
40
+ /** Load a previous conversation's messages so the widget can show
41
+ * history after a refresh / re-open. The visitor-id header is the
42
+ * authorization — the backend only returns conversations owned by
43
+ * the requesting visitor on this agent. */
44
+ async getConversation(n) {
45
+ const i = `${this.baseUrl}${S}/conversations/${encodeURIComponent(n)}`, l = await fetch(i, { headers: this.headers() });
46
+ if (!l.ok) throw new Error(`getConversation failed: ${l.status}`);
47
+ return l.json();
38
48
  }
39
- async uploadImage(a) {
40
- const r = new FormData();
41
- r.append("file", a);
42
- const n = await fetch(`${this.baseUrl}${j}/chat-image`, {
49
+ /** Reconstruct the ticket card that SHOULD currently be on the
50
+ * conversation, based on persisted state. Lets the widget restore
51
+ * raise-ticket / "already on it" / created cards after refresh.
52
+ * Returns kind=null when nothing should show. */
53
+ async getTicketCardState(n) {
54
+ const i = `${this.baseUrl}${S}/conversations/${encodeURIComponent(n)}/ticket-card`, l = await fetch(i, { headers: this.headers() });
55
+ if (!l.ok) throw new Error(`getTicketCardState failed: ${l.status}`);
56
+ return l.json();
57
+ }
58
+ async uploadImage(n) {
59
+ const i = new FormData();
60
+ i.append("file", n);
61
+ const l = await fetch(`${this.baseUrl}${S}/chat-image`, {
43
62
  method: "POST",
44
63
  headers: this.headers(),
45
64
  // browser sets Content-Type for FormData
46
- body: r
65
+ body: i
47
66
  });
48
- if (!n.ok) {
49
- let o = `${n.status} ${n.statusText}`;
67
+ if (!l.ok) {
68
+ let o = `${l.status} ${l.statusText}`;
50
69
  try {
51
- const s = await n.json();
70
+ const s = await l.json();
52
71
  o = (s == null ? void 0 : s.detail) || o;
53
72
  } catch (s) {
54
73
  }
55
74
  throw new Error(o);
56
75
  }
57
- return (await n.json()).image_path;
76
+ return (await l.json()).image_path;
58
77
  }
59
78
  /** Fetch a previously-uploaded image as a blob URL. Caller must
60
79
  * URL.revokeObjectURL() when done to avoid memory leaks. */
61
- async fetchImage(a) {
62
- const r = `${this.baseUrl}${j}/chat-image?path=${encodeURIComponent(a)}&key=${encodeURIComponent(this.agentKey)}`, n = await fetch(r, {
80
+ async fetchImage(n) {
81
+ const i = `${this.baseUrl}${S}/chat-image?path=${encodeURIComponent(n)}&key=${encodeURIComponent(this.agentKey)}`, l = await fetch(i, {
63
82
  method: "GET",
64
83
  headers: { "X-DocGenLab-Visitor-Id": this.visitorId }
65
84
  });
66
- if (!n.ok) throw new Error(`fetchImage failed: ${n.status}`);
67
- const l = await n.blob();
68
- return URL.createObjectURL(l);
85
+ if (!l.ok) throw new Error(`fetchImage failed: ${l.status}`);
86
+ const a = await l.blob();
87
+ return URL.createObjectURL(a);
88
+ }
89
+ /** Raise a support ticket from a conversation. Requires explicit user
90
+ * consent — the widget only calls this after the user clicks the
91
+ * in-chat "Raise a ticket" chip. */
92
+ async raiseTicket(n, i) {
93
+ const l = `${this.baseUrl}${S}/conversations/${encodeURIComponent(n)}/raise-ticket`, a = await fetch(l, {
94
+ method: "POST",
95
+ headers: {
96
+ "Content-Type": "application/json",
97
+ "X-DocGenLab-Key": this.agentKey,
98
+ "X-DocGenLab-Visitor-Id": this.visitorId,
99
+ ...this.endUserHash ? { "X-DocGenLab-User-Hash": this.endUserHash } : {}
100
+ },
101
+ body: JSON.stringify(i)
102
+ });
103
+ if (!a.ok) {
104
+ let o = `raiseTicket failed: ${a.status}`;
105
+ try {
106
+ o = (await a.json()).detail || o;
107
+ } catch (s) {
108
+ }
109
+ throw new Error(o);
110
+ }
111
+ return a.json();
112
+ }
113
+ /** List all tickets for THIS visitor on THIS agent. Used by the widget
114
+ * to hydrate ticket cards on conversation reload and to power the
115
+ * "Manage tickets" modal. Optionally filtered by conversation. */
116
+ async listTickets(n) {
117
+ const i = n ? `?conversation_id=${encodeURIComponent(n)}` : "", l = `${this.baseUrl}${S}/tickets${i}`, a = await fetch(l, {
118
+ headers: {
119
+ "X-DocGenLab-Key": this.agentKey,
120
+ "X-DocGenLab-Visitor-Id": this.visitorId
121
+ }
122
+ });
123
+ if (!a.ok) throw new Error(`listTickets failed: ${a.status}`);
124
+ return a.json();
125
+ }
126
+ /** Fetch the latest status of a ticket the user raised. */
127
+ async getTicket(n, i = !1) {
128
+ const l = `${this.baseUrl}${S}/tickets/${encodeURIComponent(n)}${i ? "?refresh=1" : ""}`, a = await fetch(l, {
129
+ headers: {
130
+ "X-DocGenLab-Key": this.agentKey,
131
+ "X-DocGenLab-Visitor-Id": this.visitorId
132
+ }
133
+ });
134
+ if (!a.ok) throw new Error(`getTicket failed: ${a.status}`);
135
+ return a.json();
136
+ }
137
+ /** Fetch a video-source frame attached to a citation chunk.
138
+ * Same auth pattern as fetchImage. */
139
+ async fetchSourceFrame(n, i) {
140
+ const l = `${this.baseUrl}${S}/sources/${encodeURIComponent(n)}/frame?path=${encodeURIComponent(i)}&key=${encodeURIComponent(this.agentKey)}`, a = await fetch(l, {
141
+ method: "GET",
142
+ headers: { "X-DocGenLab-Visitor-Id": this.visitorId }
143
+ });
144
+ if (!a.ok) throw new Error(`fetchSourceFrame failed: ${a.status}`);
145
+ const o = await a.blob();
146
+ return URL.createObjectURL(o);
69
147
  }
70
148
  /** Stream a chat response via SSE. Returns an abort fn the caller invokes
71
149
  * to cancel the stream. */
72
- streamChat(a, r) {
73
- const n = new AbortController();
150
+ streamChat(n, i) {
151
+ const l = new AbortController();
74
152
  return (async () => {
75
153
  try {
76
- const l = await fetch(`${this.baseUrl}${j}/chat`, {
154
+ const a = await fetch(`${this.baseUrl}${S}/chat`, {
77
155
  method: "POST",
78
- signal: n.signal,
156
+ signal: l.signal,
79
157
  headers: this.headers({ "Content-Type": "application/json", Accept: "text/event-stream" }),
80
- body: JSON.stringify(a)
158
+ body: JSON.stringify(n)
81
159
  });
82
- if (!l.ok || !l.body) {
83
- let y = `${l.status} ${l.statusText}`;
160
+ if (!a.ok || !a.body) {
161
+ let d = `${a.status} ${a.statusText}`;
84
162
  try {
85
- const u = await l.json();
86
- y = (u == null ? void 0 : u.detail) || y;
87
- } catch (u) {
163
+ const h = await a.json();
164
+ d = (h == null ? void 0 : h.detail) || d;
165
+ } catch (h) {
88
166
  }
89
- r({ type: "error", error: y });
167
+ i({ type: "error", error: d });
90
168
  return;
91
169
  }
92
- const o = l.body.getReader(), s = new TextDecoder();
93
- let m = "";
170
+ const o = a.body.getReader(), s = new TextDecoder();
171
+ let r = "";
94
172
  for (; ; ) {
95
- const { value: y, done: u } = await o.read();
96
- if (u) break;
97
- m += s.decode(y, { stream: !0 });
98
- let k;
99
- for (; (k = m.indexOf(`
173
+ const { value: d, done: h } = await o.read();
174
+ if (h) break;
175
+ r += s.decode(d, { stream: !0 });
176
+ let w;
177
+ for (; (w = r.indexOf(`
100
178
 
101
179
  `)) !== -1; ) {
102
- const h = m.slice(0, k);
103
- m = m.slice(k + 2);
104
- const R = h.trim();
105
- if (R.startsWith("data:"))
180
+ const y = r.slice(0, w);
181
+ r = r.slice(w + 2);
182
+ const k = y.trim();
183
+ if (k.startsWith("data:"))
106
184
  try {
107
- const U = JSON.parse(R.slice(5).trim());
108
- r(U);
109
- } catch (U) {
185
+ const L = JSON.parse(k.slice(5).trim());
186
+ i(L);
187
+ } catch (L) {
110
188
  }
111
189
  }
112
190
  }
113
- } catch (l) {
114
- (l == null ? void 0 : l.name) !== "AbortError" && r({ type: "error", error: (l == null ? void 0 : l.message) || String(l) });
191
+ } catch (a) {
192
+ (a == null ? void 0 : a.name) !== "AbortError" && i({ type: "error", error: (a == null ? void 0 : a.message) || String(a) });
115
193
  }
116
- })(), () => n.abort();
194
+ })(), () => l.abort();
117
195
  }
118
196
  }
119
- const N = {
197
+ const F = {
120
198
  apiBaseUrl: "https://api.docgenlab.com",
121
199
  position: "bottom-right",
122
200
  primary: "#4F46E5",
123
201
  primaryText: "#FFFFFF",
124
202
  radius: "14px",
125
203
  fontFamily: 'system-ui, -apple-system, "Segoe UI", Roboto, sans-serif',
126
- greeting: "Hi — how can I help?"
204
+ greeting: "How can I help you today?",
205
+ greetingSub: "Ask anything about your uploaded documents. I'll only answer from what's in the knowledge base."
127
206
  };
128
- function V(t) {
129
- var Y, Q, Z, ee;
130
- const a = t.apiBaseUrl || N.apiBaseUrl, r = t.position || N.position, n = t.enableImageUpload !== !1, l = {
131
- "--dgl-primary": ((Y = t.theme) == null ? void 0 : Y.primary) || N.primary,
132
- "--dgl-primary-text": ((Q = t.theme) == null ? void 0 : Q.primaryText) || N.primaryText,
133
- "--dgl-radius": ((Z = t.theme) == null ? void 0 : Z.radius) || N.radius,
134
- "--dgl-font": ((ee = t.theme) == null ? void 0 : ee.fontFamily) || N.fontFamily
135
- }, o = $(null);
136
- o.current || (o.current = new ye({ agentKey: t.agentKey, apiBaseUrl: a }));
137
- const s = o.current, [m, y] = E(!!t.openOnLoad), [u, k] = E(!1), [h, R] = E(null), [U, ce] = E(null), [S, x] = E([]), [A, O] = E(""), [I, T] = E(!1), [B, P] = E(null), [X, K] = E(null), [v, M] = E(null), [D, G] = E(!1), H = $(null), z = $(null), _ = $(""), W = $(null);
138
- F(() => {
139
- !m || h || s.getAgent().then((i) => {
140
- var c;
141
- R(i), (c = t.onReady) == null || c.call(t, i);
142
- }).catch((i) => {
143
- var c;
144
- ce(i.message), (c = t.onError) == null || c.call(t, i.message);
207
+ function le(t) {
208
+ var de, me, ge, ue, he, fe, pe, ke;
209
+ const n = t.apiBaseUrl || F.apiBaseUrl, i = t.enableImageUpload !== !1, l = j(null), a = `${t.agentKey}::${t.endUserId || ""}::${t.endUserHash || ""}`, o = j("");
210
+ (!l.current || o.current !== a) && (l.current = new Te({
211
+ agentKey: t.agentKey,
212
+ apiBaseUrl: n,
213
+ endUserId: t.endUserId,
214
+ endUserHash: t.endUserHash
215
+ }), o.current = a);
216
+ const s = l.current, [r, d] = f(null), [h, w] = f(null), y = (r == null ? void 0 : r.widget_config) || {}, k = {
217
+ position: t.position || y.position || F.position,
218
+ primary: ((de = t.theme) == null ? void 0 : de.primary) || y.primary_color || F.primary,
219
+ primaryText: ((me = t.theme) == null ? void 0 : me.primaryText) || y.primary_text_color || F.primaryText,
220
+ radius: ((ge = t.theme) == null ? void 0 : ge.radius) || y.radius || F.radius,
221
+ fontFamily: ((ue = t.theme) == null ? void 0 : ue.fontFamily) || F.fontFamily,
222
+ greeting: t.greeting || y.greeting || F.greeting,
223
+ agentName: t.agentName || y.agent_name || (r == null ? void 0 : r.name) || "Assistant",
224
+ agentAvatarUrl: t.agentAvatarUrl || y.agent_avatar_url || void 0,
225
+ launcherAvatarUrl: y.launcher_avatar_url || void 0,
226
+ hideBranding: (fe = (he = t.hideBranding) != null ? he : y.hide_branding) != null ? fe : !1,
227
+ openOnLoad: (ke = (pe = t.openOnLoad) != null ? pe : y.open_on_load) != null ? ke : !1
228
+ }, L = {
229
+ "--dgl-primary": k.primary,
230
+ "--dgl-primary-text": k.primaryText,
231
+ "--dgl-radius": k.radius,
232
+ "--dgl-font": k.fontFamily
233
+ }, [_, R] = f(k.openOnLoad), [C, P] = f(!1), [E, I] = f([]), [W, q] = f(""), [D, G] = f(!1), [K, J] = f(null), [re, Q] = f(null), [$, Z] = f(null), [H, ee] = f(!1), ie = j(null), te = j(null), X = j(""), V = j(null), [ae, ne] = f([]), [Ue, se] = f(!1);
234
+ T(() => {
235
+ !_ || r || s.getAgent().then((m) => {
236
+ var b;
237
+ d(m), (b = t.onReady) == null || b.call(t, m);
238
+ }).catch((m) => {
239
+ var b;
240
+ w(m.message), (b = t.onError) == null || b.call(t, m.message);
145
241
  });
146
- }, [m, h, s, t]), F(() => {
147
- const i = `dgl-chat:${t.agentKey}`, c = localStorage.getItem(i);
148
- c && P(c);
149
- }, [t.agentKey]), F(() => {
150
- B && localStorage.setItem(`dgl-chat:${t.agentKey}`, B);
151
- }, [B, t.agentKey]), F(() => {
152
- W.current && (W.current.scrollTop = W.current.scrollHeight);
153
- }, [S]);
154
- const q = ae(() => {
155
- v && URL.revokeObjectURL(v), K(null), M(null);
156
- }, [v]), J = ae((i) => {
157
- if (!i.type.startsWith("image/")) return;
158
- const c = 10 * 1024 * 1024;
159
- i.size > c || (v && URL.revokeObjectURL(v), K(i), M(URL.createObjectURL(i)));
160
- }, [v]), de = async (i) => {
161
- var te;
162
- if (i.preventDefault(), !A.trim() || I || D) return;
163
- const c = A.trim();
164
- let p, w;
165
- if (X) {
242
+ }, [_, r, s, t]), T(() => {
243
+ if (!_ || t.disableTicketing) return;
244
+ let m = !1;
245
+ return s.listTickets().then((b) => {
246
+ m || ne(b);
247
+ }).catch(() => {
248
+ }), () => {
249
+ m = !0;
250
+ };
251
+ }, [_, s, t.disableTicketing]), T(() => {
252
+ if (!_) return;
253
+ const m = `dgl-chat:${t.agentKey}`, b = localStorage.getItem(m);
254
+ if (!b) return;
255
+ let x = !1;
256
+ return (async () => {
166
257
  try {
167
- G(!0), p = await s.uploadImage(X);
168
- } catch (d) {
169
- (te = t.onError) == null || te.call(t, (d == null ? void 0 : d.message) || "Image upload failed"), G(!1);
258
+ const [v, p] = await Promise.all([
259
+ s.getConversation(b),
260
+ s.getTicketCardState(b).catch(() => null)
261
+ ]);
262
+ if (x) return;
263
+ const c = [];
264
+ for (const U of v.messages || [])
265
+ U.role === "user" ? c.push({
266
+ id: U.id,
267
+ role: "user",
268
+ content: U.content || "",
269
+ imagePath: U.image_path || void 0
270
+ }) : U.role === "assistant" && c.push({
271
+ id: U.id,
272
+ role: "assistant",
273
+ content: U.content || "",
274
+ citations: U.retrieved_chunks || void 0
275
+ });
276
+ if (p && p.kind && c.length) {
277
+ let U = -1;
278
+ for (let g = c.length - 1; g >= 0; g--)
279
+ if (c[g].role === "assistant") {
280
+ U = g;
281
+ break;
282
+ }
283
+ if (U >= 0) {
284
+ const g = c[U];
285
+ p.kind === "offer" && p.conversation_id && p.connector_type && p.connector_name ? g.ticketOffer = {
286
+ conversationId: p.conversation_id,
287
+ connectorType: p.connector_type,
288
+ connectorName: p.connector_name
289
+ } : p.kind === "existing" && p.ticket_id && p.status ? g.ticketExisting = {
290
+ ticketId: p.ticket_id,
291
+ externalNumber: p.external_ticket_number || null,
292
+ externalUrl: p.external_url || null,
293
+ status: p.status
294
+ } : p.kind === "created" && p.ticket_id && (g.ticketCreated = {
295
+ id: p.ticket_id,
296
+ externalNumber: p.external_ticket_number || null,
297
+ externalUrl: p.external_url || null
298
+ });
299
+ }
300
+ }
301
+ J(b), I(c);
302
+ } catch (v) {
303
+ localStorage.removeItem(m);
304
+ }
305
+ })(), () => {
306
+ x = !0;
307
+ };
308
+ }, [t.agentKey, s, _]), T(() => {
309
+ K && localStorage.setItem(`dgl-chat:${t.agentKey}`, K);
310
+ }, [K, t.agentKey]), T(() => {
311
+ V.current && (V.current.scrollTop = V.current.scrollHeight);
312
+ }, [E]);
313
+ const ce = be(() => {
314
+ $ && URL.revokeObjectURL($), Q(null), Z(null);
315
+ }, [$]), oe = be((m) => {
316
+ if (!m.type.startsWith("image/")) return;
317
+ const b = 10 * 1024 * 1024;
318
+ m.size > b || ($ && URL.revokeObjectURL($), Q(m), Z(URL.createObjectURL(m)));
319
+ }, [$]), Ce = async (m) => {
320
+ var p;
321
+ if (m.preventDefault(), !W.trim() || D || H) return;
322
+ const b = W.trim();
323
+ let x, v;
324
+ if (re) {
325
+ try {
326
+ ee(!0), x = await s.uploadImage(re);
327
+ } catch (c) {
328
+ (p = t.onError) == null || p.call(t, (c == null ? void 0 : c.message) || "Image upload failed"), ee(!1);
170
329
  return;
171
330
  }
172
- G(!1), w = v || void 0;
331
+ ee(!1), v = $ || void 0;
173
332
  }
174
- O(""), _.current = "", x((d) => [
175
- ...d,
176
- { role: "user", content: c, imagePath: p, imagePreviewUrl: w },
333
+ q(""), X.current = "", I((c) => [
334
+ ...c,
335
+ { role: "user", content: b, imagePath: x, imagePreviewUrl: v },
177
336
  { role: "assistant", content: "", streaming: !0 }
178
- ]), T(!0), K(null), M(null), z.current = s.streamChat(
179
- { message: c, conversation_id: B || void 0, image_path: p },
180
- (d) => {
181
- var ne;
182
- if (d.type === "conversation")
183
- P(d.conversation_id);
184
- else if (d.type === "token") {
185
- _.current += d.content;
186
- const f = _.current;
187
- x((g) => g.map(
188
- (b, ue) => ue === g.length - 1 && b.role === "assistant" ? { ...b, content: f } : b
337
+ ]), G(!0), Q(null), Z(null), te.current = s.streamChat(
338
+ { message: b, conversation_id: K || void 0, image_path: x },
339
+ (c) => {
340
+ var U;
341
+ if (c.type === "conversation")
342
+ J(c.conversation_id);
343
+ else if (c.type === "token") {
344
+ X.current += c.content;
345
+ const g = X.current;
346
+ I((u) => u.map(
347
+ (N, Ie) => Ie === u.length - 1 && N.role === "assistant" ? { ...N, content: g } : N
348
+ ));
349
+ } else if (c.type === "citations")
350
+ I((g) => g.map(
351
+ (u, N) => N === g.length - 1 && u.role === "assistant" ? { ...u, citations: c.citations } : u
352
+ ));
353
+ else if (c.type === "refused")
354
+ X.current = c.content, I((g) => g.map(
355
+ (u, N) => N === g.length - 1 && u.role === "assistant" ? { ...u, content: c.content, refused: !0 } : u
356
+ ));
357
+ else if (c.type === "ticket_offer") {
358
+ if (t.disableTicketing) return;
359
+ I((g) => g.map(
360
+ (u, N) => N === g.length - 1 && u.role === "assistant" ? {
361
+ ...u,
362
+ ticketOffer: {
363
+ conversationId: c.conversation_id,
364
+ connectorType: c.connector_type,
365
+ connectorName: c.connector_name
366
+ }
367
+ } : u
368
+ ));
369
+ } else if (c.type === "ticket_existing") {
370
+ if (t.disableTicketing) return;
371
+ I((g) => g.map(
372
+ (u, N) => N === g.length - 1 && u.role === "assistant" ? {
373
+ ...u,
374
+ ticketExisting: {
375
+ ticketId: c.ticket_id,
376
+ externalNumber: c.external_ticket_number,
377
+ externalUrl: c.external_url,
378
+ status: c.status
379
+ }
380
+ } : u
189
381
  ));
190
- } else d.type === "citations" ? x((f) => f.map(
191
- (g, b) => b === f.length - 1 && g.role === "assistant" ? { ...g, citations: d.citations } : g
192
- )) : d.type === "refused" ? (_.current = d.content, x((f) => f.map(
193
- (g, b) => b === f.length - 1 && g.role === "assistant" ? { ...g, content: d.content, refused: !0 } : g
194
- ))) : d.type === "done" ? (x((f) => f.map(
195
- (g, b) => b === f.length - 1 && g.role === "assistant" ? { ...g, streaming: !1, id: d.message_id, cacheHit: d.cache_hit } : g
196
- )), T(!1)) : d.type === "error" && (x((f) => f.map(
197
- (g, b) => b === f.length - 1 && g.role === "assistant" ? { ...g, content: `Error: ${d.error}`, streaming: !1, refused: !0 } : g
198
- )), T(!1), (ne = t.onError) == null || ne.call(t, d.error));
382
+ } else c.type === "ticket_status_card" ? I((g) => g.map(
383
+ (u, N) => N === g.length - 1 && u.role === "assistant" ? {
384
+ ...u,
385
+ ticketStatus: {
386
+ ticketId: c.ticket_id,
387
+ externalNumber: c.external_number,
388
+ externalUrl: c.external_url,
389
+ status: c.status,
390
+ title: c.title,
391
+ priority: c.priority,
392
+ lastUpdate: c.last_update,
393
+ assignedTo: c.assigned_to,
394
+ createdAt: c.created_at
395
+ }
396
+ } : u
397
+ )) : c.type === "done" ? (I((g) => g.map(
398
+ (u, N) => N === g.length - 1 && u.role === "assistant" ? { ...u, streaming: !1, id: c.message_id, cacheHit: c.cache_hit } : u
399
+ )), G(!1)) : c.type === "error" && (I((g) => g.map(
400
+ (u, N) => N === g.length - 1 && u.role === "assistant" ? { ...u, content: `Error: ${c.error}`, streaming: !1, refused: !0 } : u
401
+ )), G(!1), (U = t.onError) == null || U.call(t, c.error));
199
402
  }
200
403
  );
201
- }, me = () => {
202
- z.current && z.current(), x([]), P(null), T(!1), localStorage.removeItem(`dgl-chat:${t.agentKey}`), q();
203
- }, ge = t.agentName || (h == null ? void 0 : h.name) || "Assistant";
204
- return /* @__PURE__ */ e.createElement("div", { className: `dgl-root dgl-pos-${r}`, style: l }, m && /* @__PURE__ */ e.createElement("div", { className: `dgl-panel ${u ? "dgl-panel-expanded" : ""}` }, /* @__PURE__ */ e.createElement("div", { className: "dgl-header" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-header-info" }, t.agentAvatarUrl && /* @__PURE__ */ e.createElement("img", { src: t.agentAvatarUrl, alt: "", className: "dgl-avatar" }), /* @__PURE__ */ e.createElement("div", { className: "dgl-header-text" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-title" }, ge), (h == null ? void 0 : h.org_name) && /* @__PURE__ */ e.createElement("div", { className: "dgl-subtitle" }, h.org_name))), /* @__PURE__ */ e.createElement("div", { className: "dgl-header-actions" }, /* @__PURE__ */ e.createElement(
404
+ }, Le = () => {
405
+ te.current && te.current(), I([]), J(null), G(!1), localStorage.removeItem(`dgl-chat:${t.agentKey}`), ce();
406
+ };
407
+ return /* @__PURE__ */ e.createElement("div", { className: `dgl-root dgl-pos-${k.position}`, style: L }, _ && /* @__PURE__ */ e.createElement("div", { className: `dgl-panel ${C ? "dgl-panel-expanded" : ""}` }, /* @__PURE__ */ e.createElement("div", { className: "dgl-header" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-header-info" }, k.agentAvatarUrl ? /* @__PURE__ */ e.createElement("img", { src: k.agentAvatarUrl, alt: "", className: "dgl-avatar" }) : /* @__PURE__ */ e.createElement("div", { className: "dgl-avatar dgl-avatar-fallback dgl-avatar-fallback-light" }, k.agentName.slice(0, 1).toUpperCase()), /* @__PURE__ */ e.createElement("div", { className: "dgl-header-text" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-title" }, k.agentName), (r == null ? void 0 : r.org_name) && /* @__PURE__ */ e.createElement("div", { className: "dgl-subtitle" }, r.org_name))), /* @__PURE__ */ e.createElement("div", { className: "dgl-header-actions" }, !t.disableTicketing && ae.length > 0 && /* @__PURE__ */ e.createElement(
205
408
  "button",
206
409
  {
207
410
  type: "button",
208
- onClick: me,
411
+ onClick: () => se(!0),
412
+ className: "dgl-tix-btn",
413
+ title: "Your tickets",
414
+ "aria-label": "Your tickets"
415
+ },
416
+ M(),
417
+ /* @__PURE__ */ e.createElement("span", null, "Tickets"),
418
+ /* @__PURE__ */ e.createElement("span", { className: "dgl-tix-btn-badge" }, ae.length)
419
+ ), /* @__PURE__ */ e.createElement(
420
+ "button",
421
+ {
422
+ type: "button",
423
+ onClick: Le,
209
424
  className: "dgl-icon-btn",
210
425
  title: "New chat",
211
426
  "aria-label": "New chat"
212
427
  },
213
- Ue()
428
+ Je()
214
429
  ), /* @__PURE__ */ e.createElement(
215
430
  "button",
216
431
  {
217
432
  type: "button",
218
- onClick: () => k((i) => !i),
433
+ onClick: () => P((m) => !m),
219
434
  className: "dgl-icon-btn dgl-hide-on-mobile",
220
- title: u ? "Restore size" : "Expand view",
221
- "aria-label": u ? "Restore size" : "Expand view"
435
+ title: C ? "Restore size" : "Expand view",
436
+ "aria-label": C ? "Restore size" : "Expand view"
222
437
  },
223
- u ? Se() : Re()
438
+ C ? tt() : et()
224
439
  ), /* @__PURE__ */ e.createElement(
225
440
  "button",
226
441
  {
227
442
  type: "button",
228
- onClick: () => y(!1),
443
+ onClick: () => R(!1),
229
444
  className: "dgl-icon-btn",
230
445
  title: "Close",
231
446
  "aria-label": "Close"
232
447
  },
233
- oe()
234
- ))), /* @__PURE__ */ e.createElement("div", { className: "dgl-messages", ref: W }, S.length === 0 && !U && /* @__PURE__ */ e.createElement("div", { className: "dgl-empty" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-empty-text" }, t.greeting || N.greeting), (h == null ? void 0 : h.description) && /* @__PURE__ */ e.createElement("div", { className: "dgl-empty-sub" }, h.description)), U && /* @__PURE__ */ e.createElement("div", { className: "dgl-error" }, "Couldn't load the assistant: ", U), S.map((i, c) => /* @__PURE__ */ e.createElement(
235
- Ee,
448
+ Y()
449
+ ))), Ue && /* @__PURE__ */ e.createElement(
450
+ Ve,
236
451
  {
237
- key: c,
238
- message: i,
452
+ tickets: ae,
453
+ onClose: () => se(!1),
454
+ onRefresh: async () => {
455
+ try {
456
+ const m = await s.listTickets();
457
+ ne(m);
458
+ } catch (m) {
459
+ }
460
+ }
461
+ }
462
+ ), /* @__PURE__ */ e.createElement("div", { className: "dgl-messages", ref: V }, E.length === 0 && !h && /* @__PURE__ */ e.createElement("div", { className: "dgl-empty" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-empty-icon" }, _e()), /* @__PURE__ */ e.createElement("div", { className: "dgl-empty-text" }, k.greeting), /* @__PURE__ */ e.createElement("div", { className: "dgl-empty-sub" }, (r == null ? void 0 : r.description) || F.greetingSub)), h && /* @__PURE__ */ e.createElement("div", { className: "dgl-error" }, "Couldn't load the assistant: ", h), E.map((m, b) => /* @__PURE__ */ e.createElement(
463
+ Re,
464
+ {
465
+ key: b,
466
+ message: m,
239
467
  client: s,
240
- isLast: c === S.length - 1,
241
- agentAvatarUrl: t.agentAvatarUrl,
242
- onPickFollowup: (p) => {
243
- O(p);
468
+ isLast: b === E.length - 1,
469
+ agentAvatarUrl: k.agentAvatarUrl,
470
+ onPickFollowup: (x) => {
471
+ q(x);
472
+ },
473
+ defaultEmail: t.endUserEmail,
474
+ defaultPhone: t.endUserPhone,
475
+ conversationId: K || void 0,
476
+ onTicketCreated: (x, v) => {
477
+ I((p) => p.map((c) => c === x ? {
478
+ ...c,
479
+ // Either an existing-issue card OR a fresh offer
480
+ // can land here — clear both, render created.
481
+ ticketOffer: void 0,
482
+ ticketExisting: void 0,
483
+ ticketCreated: {
484
+ id: v.id,
485
+ externalNumber: v.external_ticket_number,
486
+ externalUrl: v.external_url
487
+ }
488
+ } : c)), ne((p) => [v, ...p.filter((c) => c.id !== v.id)]);
244
489
  }
245
490
  }
246
- ))), /* @__PURE__ */ e.createElement("form", { className: "dgl-composer", onSubmit: de }, v && /* @__PURE__ */ e.createElement("div", { className: "dgl-staged-image" }, /* @__PURE__ */ e.createElement("img", { src: v, alt: "attachment" }), /* @__PURE__ */ e.createElement(
491
+ ))), /* @__PURE__ */ e.createElement("form", { className: "dgl-composer", onSubmit: Ce }, $ && /* @__PURE__ */ e.createElement("div", { className: "dgl-staged-image" }, /* @__PURE__ */ e.createElement("img", { src: $, alt: "attachment" }), /* @__PURE__ */ e.createElement(
247
492
  "button",
248
493
  {
249
494
  type: "button",
250
- onClick: q,
495
+ onClick: ce,
251
496
  className: "dgl-staged-remove",
252
497
  "aria-label": "Remove image"
253
498
  },
254
- oe()
255
- )), /* @__PURE__ */ e.createElement("div", { className: "dgl-composer-row" }, n && /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement(
499
+ Y()
500
+ )), /* @__PURE__ */ e.createElement("div", { className: "dgl-composer-row" }, i && /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement(
256
501
  "button",
257
502
  {
258
503
  type: "button",
259
504
  className: "dgl-icon-btn",
260
505
  onClick: () => {
261
- var i;
262
- return (i = H.current) == null ? void 0 : i.click();
506
+ var m;
507
+ return (m = ie.current) == null ? void 0 : m.click();
263
508
  },
264
- disabled: I || D,
509
+ disabled: D || H,
265
510
  title: "Attach image",
266
511
  "aria-label": "Attach image"
267
512
  },
268
- $e()
513
+ Ze()
269
514
  ), /* @__PURE__ */ e.createElement(
270
515
  "input",
271
516
  {
272
- ref: H,
517
+ ref: ie,
273
518
  type: "file",
274
519
  accept: "image/png,image/jpeg,image/webp,image/gif",
275
520
  style: { display: "none" },
276
- onChange: (i) => {
277
- var p;
278
- const c = (p = i.target.files) == null ? void 0 : p[0];
279
- c && J(c), i.target && (i.target.value = "");
521
+ onChange: (m) => {
522
+ var x;
523
+ const b = (x = m.target.files) == null ? void 0 : x[0];
524
+ b && oe(b), m.target && (m.target.value = "");
280
525
  }
281
526
  }
282
527
  )), /* @__PURE__ */ e.createElement(
283
528
  "input",
284
529
  {
285
530
  className: "dgl-input",
286
- value: A,
287
- onChange: (i) => O(i.target.value),
288
- placeholder: I ? "Thinking…" : v ? "Describe what to know about this image…" : "Type your question…",
289
- disabled: I,
290
- onPaste: (i) => {
291
- var p;
292
- if (!n) return;
293
- const c = Array.from(((p = i.clipboardData) == null ? void 0 : p.items) || []).find(
294
- (w) => w.kind === "file" && w.type.startsWith("image/")
531
+ value: W,
532
+ onChange: (m) => q(m.target.value),
533
+ placeholder: D ? "Thinking…" : $ ? "Describe what to know about this image…" : "Type your question…",
534
+ disabled: D,
535
+ onPaste: (m) => {
536
+ var x;
537
+ if (!i) return;
538
+ const b = Array.from(((x = m.clipboardData) == null ? void 0 : x.items) || []).find(
539
+ (v) => v.kind === "file" && v.type.startsWith("image/")
295
540
  );
296
- if (c) {
297
- const w = c.getAsFile();
298
- w && (i.preventDefault(), J(w));
541
+ if (b) {
542
+ const v = b.getAsFile();
543
+ v && (m.preventDefault(), oe(v));
299
544
  }
300
545
  }
301
546
  }
@@ -304,155 +549,556 @@ function V(t) {
304
549
  {
305
550
  type: "submit",
306
551
  className: "dgl-send-btn",
307
- disabled: !A.trim() || I || D,
552
+ disabled: !W.trim() || D || H,
308
553
  "aria-label": "Send"
309
554
  },
310
- I || D ? Fe() : Ie()
311
- )), !t.hideBranding && /* @__PURE__ */ e.createElement("div", { className: "dgl-branding" }, "Powered by ", /* @__PURE__ */ e.createElement("a", { href: "https://docgenlab.com", target: "_blank", rel: "noopener noreferrer" }, "DocGenLab")))), /* @__PURE__ */ e.createElement(
555
+ D || H ? z() : Qe()
556
+ )), !k.hideBranding && /* @__PURE__ */ e.createElement("div", { className: "dgl-branding" }, "Powered by ", /* @__PURE__ */ e.createElement("a", { href: "https://docgenlab.com", target: "_blank", rel: "noopener noreferrer" }, "DocGenLab")))), /* @__PURE__ */ e.createElement(
312
557
  "button",
313
558
  {
314
559
  type: "button",
315
560
  className: "dgl-launcher",
316
- onClick: () => y((i) => !i),
317
- "aria-label": m ? "Close chat" : "Open chat"
561
+ onClick: () => R((m) => !m),
562
+ "aria-label": _ ? "Close chat" : "Open chat"
318
563
  },
319
- m ? Le() : Ce()
564
+ _ ? qe() : k.launcherAvatarUrl ? /* @__PURE__ */ e.createElement("img", { src: k.launcherAvatarUrl, alt: "", className: "dgl-launcher-avatar" }) : ze()
320
565
  ));
321
566
  }
322
- function Ee({
567
+ function Re({
323
568
  message: t,
324
- client: a,
325
- isLast: r,
326
- agentAvatarUrl: n,
327
- onPickFollowup: l
569
+ client: n,
570
+ isLast: i,
571
+ agentAvatarUrl: l,
572
+ onPickFollowup: a,
573
+ defaultEmail: o,
574
+ defaultPhone: s,
575
+ conversationId: r,
576
+ onTicketCreated: d
328
577
  }) {
329
- var m;
578
+ var y;
330
579
  if (t.role === "user")
331
- return /* @__PURE__ */ e.createElement("div", { className: "dgl-msg dgl-msg-user" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-bubble dgl-bubble-user" }, (t.imagePath || t.imagePreviewUrl) && /* @__PURE__ */ e.createElement(be, { client: a, imagePath: t.imagePath, previewUrl: t.imagePreviewUrl }), t.content));
332
- const o = ke(t.content), s = t.streaming ? [] : we(t.content);
333
- return /* @__PURE__ */ e.createElement("div", { className: "dgl-msg dgl-msg-assistant" }, n ? /* @__PURE__ */ e.createElement("img", { src: n, className: "dgl-avatar", alt: "" }) : /* @__PURE__ */ e.createElement("div", { className: "dgl-avatar dgl-avatar-fallback" }, Ae()), /* @__PURE__ */ e.createElement("div", { className: "dgl-msg-body" }, t.refused ? /* @__PURE__ */ e.createElement("div", { className: "dgl-refused" }, o) : /* @__PURE__ */ e.createElement("div", { className: "dgl-assistant-text" }, t.streaming && !o ? /* @__PURE__ */ e.createElement(Ne, null) : /* @__PURE__ */ e.createElement(e.Fragment, null, xe(o), t.streaming && /* @__PURE__ */ e.createElement("span", { className: "dgl-typing-cursor" }, "▍"))), !t.streaming && !!((m = t.citations) != null && m.length) && /* @__PURE__ */ e.createElement(ve, { citations: t.citations }), s.length > 0 && /* @__PURE__ */ e.createElement(pe, { suggestions: s, onPick: l })));
580
+ return /* @__PURE__ */ e.createElement("div", { className: "dgl-msg dgl-msg-user" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-bubble dgl-bubble-user" }, (t.imagePath || t.imagePreviewUrl) && /* @__PURE__ */ e.createElement(Be, { client: n, imagePath: t.imagePath, previewUrl: t.imagePreviewUrl }), t.content));
581
+ const h = Me(t.content), w = t.streaming ? [] : je(t.content);
582
+ return /* @__PURE__ */ e.createElement("div", { className: "dgl-msg dgl-msg-assistant" }, l ? /* @__PURE__ */ e.createElement("img", { src: l, className: "dgl-avatar", alt: "" }) : /* @__PURE__ */ e.createElement("div", { className: "dgl-avatar dgl-avatar-fallback" }, _e()), /* @__PURE__ */ e.createElement("div", { className: "dgl-msg-body" }, t.refused ? /* @__PURE__ */ e.createElement("div", { className: "dgl-refused" }, h) : t.ticketStatus ? (
583
+ /* Status query — suppress the markdown body and render
584
+ the rich Jira-style card on its own. */
585
+ /* @__PURE__ */ e.createElement(Xe, { ticket: t.ticketStatus })
586
+ ) : /* @__PURE__ */ e.createElement("div", { className: "dgl-assistant-text" }, t.streaming && !h ? /* @__PURE__ */ e.createElement(Ke, null) : /* @__PURE__ */ e.createElement(e.Fragment, null, Pe(h), t.streaming && /* @__PURE__ */ e.createElement("span", { className: "dgl-typing-cursor" }, "▍"))), !t.streaming && !t.refused && !!((y = t.citations) != null && y.length) && !t.ticketStatus && /* @__PURE__ */ e.createElement(Oe, { citations: t.citations, client: n }), !t.streaming && !t.ticketStatus && t.ticketCreated ? /* @__PURE__ */ e.createElement(Ge, { created: t.ticketCreated }) : !t.streaming && !t.ticketStatus && t.ticketExisting ? /* @__PURE__ */ e.createElement(
587
+ He,
588
+ {
589
+ existing: t.ticketExisting,
590
+ client: n,
591
+ conversationId: r,
592
+ defaultEmail: o,
593
+ defaultPhone: s,
594
+ onNewTicketRaised: (k) => d == null ? void 0 : d(t, k)
595
+ }
596
+ ) : !t.streaming && !t.ticketStatus && t.ticketOffer ? /* @__PURE__ */ e.createElement(
597
+ We,
598
+ {
599
+ client: n,
600
+ offer: t.ticketOffer,
601
+ defaultEmail: o,
602
+ defaultPhone: s,
603
+ onCreated: (k) => d == null ? void 0 : d(t, k)
604
+ }
605
+ ) : null, w.length > 0 && /* @__PURE__ */ e.createElement(Fe, { suggestions: w, onPick: a })));
334
606
  }
335
- function pe({
607
+ function Fe({
336
608
  suggestions: t,
337
- onPick: a
609
+ onPick: n
338
610
  }) {
339
- return /* @__PURE__ */ e.createElement("div", { className: "dgl-followups" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-followups-label" }, "Continue exploring"), /* @__PURE__ */ e.createElement("div", { className: "dgl-followups-list" }, t.map((r, n) => /* @__PURE__ */ e.createElement(
611
+ return /* @__PURE__ */ e.createElement("div", { className: "dgl-followups" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-followups-label" }, "Continue exploring"), /* @__PURE__ */ e.createElement("div", { className: "dgl-followups-list" }, t.map((i, l) => /* @__PURE__ */ e.createElement(
340
612
  "button",
341
613
  {
342
- key: n,
614
+ key: l,
343
615
  type: "button",
344
616
  className: "dgl-followup-chip",
345
- onClick: () => a(r)
617
+ onClick: () => n(i)
346
618
  },
347
- r
619
+ i
348
620
  ))));
349
621
  }
350
- function be({
622
+ function Be({
351
623
  client: t,
352
- imagePath: a,
353
- previewUrl: r
624
+ imagePath: n,
625
+ previewUrl: i
626
+ }) {
627
+ const [l, a] = f(i || null), [o, s] = f(!1);
628
+ return T(() => {
629
+ if (i || !n) return;
630
+ let r = null;
631
+ return t.fetchImage(n).then((d) => {
632
+ r = d, a(d);
633
+ }).catch(() => a(null)), () => {
634
+ r && URL.revokeObjectURL(r);
635
+ };
636
+ }, [t, n, i]), T(() => {
637
+ if (!o) return;
638
+ const r = (h) => {
639
+ h.key === "Escape" && s(!1);
640
+ };
641
+ window.addEventListener("keydown", r);
642
+ const d = document.body.style.overflow;
643
+ return document.body.style.overflow = "hidden", () => {
644
+ window.removeEventListener("keydown", r), document.body.style.overflow = d;
645
+ };
646
+ }, [o]), l ? /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement(
647
+ "button",
648
+ {
649
+ type: "button",
650
+ onClick: () => s(!0),
651
+ className: "dgl-user-image-btn",
652
+ "aria-label": "View image"
653
+ },
654
+ /* @__PURE__ */ e.createElement("img", { src: l, className: "dgl-user-image", alt: "attached" })
655
+ ), o && /* @__PURE__ */ e.createElement(
656
+ "div",
657
+ {
658
+ className: "dgl-lightbox",
659
+ role: "dialog",
660
+ "aria-modal": "true",
661
+ onClick: () => s(!1)
662
+ },
663
+ /* @__PURE__ */ e.createElement(
664
+ "button",
665
+ {
666
+ type: "button",
667
+ className: "dgl-lightbox-close",
668
+ onClick: (r) => {
669
+ r.stopPropagation(), s(!1);
670
+ },
671
+ "aria-label": "Close image"
672
+ },
673
+ Y()
674
+ ),
675
+ /* @__PURE__ */ e.createElement(
676
+ "img",
677
+ {
678
+ src: l,
679
+ className: "dgl-lightbox-img",
680
+ alt: "attached",
681
+ onClick: (r) => r.stopPropagation()
682
+ }
683
+ )
684
+ )) : null;
685
+ }
686
+ function Oe({ citations: t, client: n }) {
687
+ const i = {};
688
+ for (const r of t) {
689
+ const d = i[r.source_id];
690
+ (!d || r.score > d.score) && (i[r.source_id] = r);
691
+ }
692
+ const l = Object.values(i).sort((r, d) => d.score - r.score).slice(0, 3), a = Object.keys(i).length - l.length;
693
+ if (!l.length) return null;
694
+ const [o, s] = f(null);
695
+ return /* @__PURE__ */ e.createElement("div", { className: "dgl-citations" }, l.map((r) => /* @__PURE__ */ e.createElement(
696
+ Ae,
697
+ {
698
+ key: r.chunk_id,
699
+ citation: r,
700
+ client: n,
701
+ isOpen: o === r.chunk_id,
702
+ onToggle: () => s(o === r.chunk_id ? null : r.chunk_id)
703
+ }
704
+ )), a > 0 && /* @__PURE__ */ e.createElement("span", { className: "dgl-citation-more" }, "+", a, " more"));
705
+ }
706
+ function Ae({
707
+ citation: t,
708
+ client: n,
709
+ isOpen: i,
710
+ onToggle: l
354
711
  }) {
355
- const [n, l] = E(r || null);
356
- return F(() => {
357
- if (r || !a) return;
712
+ const a = t, o = !!a.frame_path, s = a.heading ? `${a.heading}${a.subheading ? " › " + a.subheading : ""}` : null, r = a.start_seconds != null ? `${Math.floor(a.start_seconds / 60)}:${String(a.start_seconds % 60).padStart(2, "0")}` : null;
713
+ return /* @__PURE__ */ e.createElement("span", { className: "dgl-citation-wrap" }, /* @__PURE__ */ e.createElement(
714
+ "button",
715
+ {
716
+ type: "button",
717
+ className: `dgl-citation ${i ? "dgl-citation-open" : ""}`,
718
+ onClick: l,
719
+ title: a.snippet || ""
720
+ },
721
+ o && /* @__PURE__ */ e.createElement("span", { className: "dgl-citation-icon" }, "▶"),
722
+ a.source_name,
723
+ r && /* @__PURE__ */ e.createElement("span", { className: "dgl-citation-stamp" }, " · ", r),
724
+ a.page && /* @__PURE__ */ e.createElement("span", { className: "dgl-citation-stamp" }, " · p", a.page)
725
+ ), i && /* @__PURE__ */ e.createElement("div", { className: "dgl-citation-popover" }, a.frame_path && /* @__PURE__ */ e.createElement(
726
+ De,
727
+ {
728
+ client: n,
729
+ sourceId: a.source_id,
730
+ framePath: a.frame_path
731
+ }
732
+ ), s && /* @__PURE__ */ e.createElement("div", { className: "dgl-citation-breadcrumb" }, s), a.snippet && /* @__PURE__ */ e.createElement("div", { className: "dgl-citation-snippet" }, a.snippet)));
733
+ }
734
+ function De({
735
+ client: t,
736
+ sourceId: n,
737
+ framePath: i
738
+ }) {
739
+ const [l, a] = f(null);
740
+ return T(() => {
358
741
  let o = null;
359
- return t.fetchImage(a).then((s) => {
360
- o = s, l(s);
361
- }).catch(() => l(null)), () => {
742
+ return t.fetchSourceFrame(n, i).then((s) => {
743
+ o = s, a(s);
744
+ }).catch(() => a(null)), () => {
362
745
  o && URL.revokeObjectURL(o);
363
746
  };
364
- }, [t, a, r]), n ? /* @__PURE__ */ e.createElement("a", { href: n, target: "_blank", rel: "noopener noreferrer", className: "dgl-user-image-link" }, /* @__PURE__ */ e.createElement("img", { src: n, className: "dgl-user-image", alt: "attached" })) : null;
747
+ }, [t, n, i]), l ? /* @__PURE__ */ e.createElement("a", { href: l, target: "_blank", rel: "noopener noreferrer", className: "dgl-citation-frame-link" }, /* @__PURE__ */ e.createElement("img", { src: l, alt: "", className: "dgl-citation-frame" })) : /* @__PURE__ */ e.createElement("div", { className: "dgl-citation-frame-loading" });
365
748
  }
366
- function ve({ citations: t }) {
367
- const a = /* @__PURE__ */ new Set(), r = t.filter((n) => a.has(n.source_id) ? !1 : (a.add(n.source_id), !0));
368
- return r.length ? /* @__PURE__ */ e.createElement("div", { className: "dgl-citations" }, r.map((n) => /* @__PURE__ */ e.createElement("span", { key: n.chunk_id, className: "dgl-citation", title: n.snippet }, n.source_name, n.page ? ` · p${n.page}` : ""))) : null;
749
+ function je(t) {
750
+ const n = t.match(/<followups>([\s\S]*?)<\/followups>/i);
751
+ return n ? n[1].split(`
752
+ `).map((i) => i.trim()).map((i) => i.replace(/^[-*•\d.)\s"']+|["']$/g, "").trim()).filter((i) => i.length >= 4 && i.length <= 120).slice(0, 3) : [];
369
753
  }
370
- function we(t) {
371
- const a = t.match(/<followups>([\s\S]*?)<\/followups>/i);
372
- return a ? a[1].split(`
373
- `).map((r) => r.trim()).map((r) => r.replace(/^[-*•\d.)\s"']+|["']$/g, "").trim()).filter((r) => r.length >= 4 && r.length <= 120).slice(0, 3) : [];
374
- }
375
- function ke(t) {
376
- return t.replace(/\n*<followups>[\s\S]*?(<\/followups>|$)/gi, "").replace(/\s*\[\s*Section:[^\]]*\]?/gi, "").replace(/\s*\[\s*doc:[^\]]*\]?/gi, "").replace(/\s*\[\s*(?:document|doc|source|ref|reference)[^\]]*\]?/gi, "").replace(/\s*\[\s*(?:p\.?\s*)?\d+(?:\s*[,–-]\s*\d+)*\s*\]/gi, "").replace(/[,;]?\s*doc:\s*[0-9a-fA-F][0-9a-fA-F-]{6,}\]?/gi, "").replace(/[,;]\s*(?:\d+|doc:?\s*[0-9a-fA-F-]+)\s*\]?/gi, "").replace(/([\w%])\s*\]/g, "$1").replace(/\s+([,.;:!?])/g, "$1").replace(/[ \t]+/g, " ").replace(/\n{3,}/g, `
754
+ function Me(t) {
755
+ const n = /\s*I\s+(don'?t|do not)\s+have\s+(?:specific|enough|that|the|any)?\s*information\s+on\s+(?:this|that)[^.]*?\.(?:\s*Please\s+(?:contact|reach\s*out\s+to)\s+(?:your\s+)?(?:support|admin)[^.]*?\.)?/gi, i = /\n*<followups>[\s\S]*?(<\/followups>|$)/gi, l = t.replace(i, ""), a = l.replace(n, "").trim();
756
+ return (l.trim().length > 0 && a.length < 20 ? t : t.replace(n, "")).replace(/\n*<followups>[\s\S]*?(<\/followups>|$)/gi, "").replace(/\s*\[\s*Section:[^\]]*\]?/gi, "").replace(/\s*\[\s*doc:[^\]]*\]?/gi, "").replace(/\s*\[\s*(?:document|doc|source|ref|reference)[^\]]*\]?/gi, "").replace(/\s*\[\s*(?:p\.?\s*)?\d+(?:\s*[,–-]\s*\d+)*\s*\]/gi, "").replace(/[,;]?\s*doc:\s*[0-9a-fA-F][0-9a-fA-F-]{6,}\]?/gi, "").replace(/[,;]\s*(?:\d+|doc:?\s*[0-9a-fA-F-]+)\s*\]?/gi, "").replace(/([\w%])\s*\]/g, "$1").replace(/\s+([,.;:!?])/g, "$1").replace(/[ \t]+/g, " ").replace(/\n{3,}/g, `
377
757
 
378
758
  `).trim();
379
759
  }
380
- function xe(t) {
381
- return t.split(/\n{2,}/).map((r, n) => {
382
- const l = r.split(`
760
+ function Pe(t) {
761
+ return t.split(/\n{2,}/).map((i, l) => {
762
+ const a = i.split(`
383
763
  `);
384
- if (l.every((s) => /^(\s*)([-*]|\d+\.)\s/.test(s)) && l.length > 0) {
385
- const s = /^\d+\./.test(l[0].trim()), m = l.map((u) => u.replace(/^\s*(?:[-*]|\d+\.)\s+/, "")), y = s ? "ol" : "ul";
386
- return /* @__PURE__ */ e.createElement(y, { key: n, className: `dgl-md-list ${s ? "dgl-md-ol" : "dgl-md-ul"}` }, m.map((u, k) => /* @__PURE__ */ e.createElement("li", { key: k }, se(u))));
764
+ if (a.every((s) => /^(\s*)([-*]|\d+\.)\s/.test(s)) && a.length > 0) {
765
+ const s = /^\d+\./.test(a[0].trim()), r = a.map((h) => h.replace(/^\s*(?:[-*]|\d+\.)\s+/, "")), d = s ? "ol" : "ul";
766
+ return /* @__PURE__ */ e.createElement(d, { key: l, className: `dgl-md-list ${s ? "dgl-md-ol" : "dgl-md-ul"}` }, r.map((h, w) => /* @__PURE__ */ e.createElement("li", { key: w }, Ne(h))));
387
767
  }
388
- return /* @__PURE__ */ e.createElement("p", { key: n, className: "dgl-md-p" }, r.split(`
389
- `).map((s, m, y) => /* @__PURE__ */ e.createElement(e.Fragment, { key: m }, se(s), m < y.length - 1 && /* @__PURE__ */ e.createElement("br", null))));
768
+ return /* @__PURE__ */ e.createElement("p", { key: l, className: "dgl-md-p" }, i.split(`
769
+ `).map((s, r, d) => /* @__PURE__ */ e.createElement(e.Fragment, { key: r }, Ne(s), r < d.length - 1 && /* @__PURE__ */ e.createElement("br", null))));
390
770
  });
391
771
  }
392
- function se(t) {
393
- const a = /(`[^`]+`|\*\*[^*\n]+\*\*|\*[^*\n]+\*|\[[^\]]+\]\([^)]+\))/g;
394
- return t.split(a).map((n, l) => {
395
- if (!n) return null;
396
- if (n.startsWith("`") && n.endsWith("`"))
397
- return /* @__PURE__ */ e.createElement("code", { key: l, className: "dgl-md-code" }, n.slice(1, -1));
398
- if (n.startsWith("**") && n.endsWith("**"))
399
- return /* @__PURE__ */ e.createElement("strong", { key: l }, n.slice(2, -2));
400
- if (n.startsWith("*") && n.endsWith("*") && n.length > 2)
401
- return /* @__PURE__ */ e.createElement("em", { key: l }, n.slice(1, -1));
402
- const o = n.match(/^\[([^\]]+)\]\(([^)]+)\)$/);
403
- return o ? /* @__PURE__ */ e.createElement("a", { key: l, href: o[2], target: "_blank", rel: "noopener noreferrer", className: "dgl-md-link" }, o[1]) : /* @__PURE__ */ e.createElement(e.Fragment, { key: l }, n);
772
+ function Ne(t) {
773
+ const n = /(`[^`]+`|\*\*[^*\n]+\*\*|\*[^*\n]+\*|\[[^\]]+\]\([^)]+\))/g;
774
+ return t.split(n).map((l, a) => {
775
+ if (!l) return null;
776
+ if (l.startsWith("`") && l.endsWith("`"))
777
+ return /* @__PURE__ */ e.createElement("code", { key: a, className: "dgl-md-code" }, l.slice(1, -1));
778
+ if (l.startsWith("**") && l.endsWith("**"))
779
+ return /* @__PURE__ */ e.createElement("strong", { key: a }, l.slice(2, -2));
780
+ if (l.startsWith("*") && l.endsWith("*") && l.length > 2)
781
+ return /* @__PURE__ */ e.createElement("em", { key: a }, l.slice(1, -1));
782
+ const o = l.match(/^\[([^\]]+)\]\(([^)]+)\)$/);
783
+ return o ? /* @__PURE__ */ e.createElement("a", { key: a, href: o[2], target: "_blank", rel: "noopener noreferrer", className: "dgl-md-link" }, o[1]) : /* @__PURE__ */ e.createElement(e.Fragment, { key: a }, l);
404
784
  });
405
785
  }
406
- function Ne() {
786
+ function Ke() {
407
787
  return /* @__PURE__ */ e.createElement("span", { className: "dgl-thinking" }, /* @__PURE__ */ e.createElement("span", { className: "dgl-thinking-dot" }), /* @__PURE__ */ e.createElement("span", { className: "dgl-thinking-dot" }), /* @__PURE__ */ e.createElement("span", { className: "dgl-thinking-dot" }));
408
788
  }
409
- function Ce() {
789
+ const A = {
790
+ open: { label: "Open", stripe: "linear-gradient(90deg,#3b82f6,#6366f1)", iconBg: "#3b82f6", pillBg: "#dbeafe", pillFg: "#1e40af" },
791
+ in_progress: { label: "In progress", stripe: "linear-gradient(90deg,#8b5cf6,#d946ef)", iconBg: "#8b5cf6", pillBg: "#ede9fe", pillFg: "#5b21b6" },
792
+ on_hold: { label: "On hold", stripe: "linear-gradient(90deg,#f59e0b,#f97316)", iconBg: "#f59e0b", pillBg: "#fef3c7", pillFg: "#92400e" },
793
+ resolved: { label: "Resolved", stripe: "linear-gradient(90deg,#10b981,#14b8a6)", iconBg: "#10b981", pillBg: "#d1fae5", pillFg: "#065f46" },
794
+ closed: { label: "Closed", stripe: "linear-gradient(90deg,#94a3b8,#64748b)", iconBg: "#64748b", pillBg: "#f1f5f9", pillFg: "#334155" },
795
+ cancelled: { label: "Cancelled", stripe: "linear-gradient(90deg,#ef4444,#f43f5e)", iconBg: "#ef4444", pillBg: "#fee2e2", pillFg: "#991b1b" }
796
+ }, we = {
797
+ low: { bg: "#f1f5f9", fg: "#475569" },
798
+ medium: { bg: "#dbeafe", fg: "#1e40af" },
799
+ high: { bg: "#fef3c7", fg: "#92400e" },
800
+ urgent: { bg: "#fee2e2", fg: "#991b1b" }
801
+ };
802
+ function xe(t) {
803
+ if (!t) return "—";
804
+ const n = new Date(t), i = Date.now() - n.getTime();
805
+ if (Number.isNaN(i)) return t;
806
+ const l = Math.floor(i / 6e4);
807
+ if (l < 1) return "just now";
808
+ if (l < 60) return `${l}m ago`;
809
+ const a = Math.floor(l / 60);
810
+ if (a < 24) return `${a}h ago`;
811
+ const o = Math.floor(a / 24);
812
+ return o < 7 ? `${o}d ago` : n.toLocaleDateString();
813
+ }
814
+ function We({
815
+ client: t,
816
+ offer: n,
817
+ defaultEmail: i,
818
+ defaultPhone: l,
819
+ onCreated: a
820
+ }) {
821
+ const [o, s] = f(i || ""), [r, d] = f(l || ""), [h, w] = f(!i), [y, k] = f("medium"), [L, _] = f(!1), [R, C] = f(null), P = async () => {
822
+ if (!o.trim()) {
823
+ C("Email is required so the team can follow up.");
824
+ return;
825
+ }
826
+ _(!0), C(null);
827
+ try {
828
+ const E = await t.raiseTicket(n.conversationId, {
829
+ consent: !0,
830
+ end_user_email: o.trim(),
831
+ end_user_phone: r.trim() || void 0,
832
+ priority: y
833
+ });
834
+ a(E);
835
+ } catch (E) {
836
+ C((E == null ? void 0 : E.message) || "Could not create ticket. Try again.");
837
+ } finally {
838
+ _(!1);
839
+ }
840
+ };
841
+ return /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-stripe", style: { background: "linear-gradient(90deg,#6366f1,#8b5cf6)" } }), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-body" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-head" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-icon", style: { background: "linear-gradient(135deg,#6366f1,#8b5cf6,#ec4899)" } }, M()), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-titles" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-eyebrow" }, "Support escalation"), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-title" }, "Need a human to look at this?"))), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-desc" }, "We'll summarise this chat and raise a ticket. Our team will follow up on the email below."), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-form-grid" }, /* @__PURE__ */ e.createElement("div", null, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-field-label" }, "Reply to"), h ? /* @__PURE__ */ e.createElement(
842
+ "input",
843
+ {
844
+ type: "email",
845
+ className: "dgl-ticket-input",
846
+ value: o,
847
+ onChange: (E) => s(E.target.value),
848
+ onBlur: () => o && w(!1),
849
+ placeholder: "you@example.com",
850
+ autoFocus: !0
851
+ }
852
+ ) : /* @__PURE__ */ e.createElement(
853
+ "button",
854
+ {
855
+ type: "button",
856
+ className: "dgl-ticket-email-link",
857
+ onClick: () => w(!0),
858
+ title: "Click to change"
859
+ },
860
+ o || "Set email",
861
+ " ",
862
+ /* @__PURE__ */ e.createElement("span", { className: "dgl-ticket-email-change" }, "(change)")
863
+ )), /* @__PURE__ */ e.createElement("div", null, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-field-label" }, "Priority"), /* @__PURE__ */ e.createElement(
864
+ "select",
865
+ {
866
+ className: "dgl-ticket-input",
867
+ value: y,
868
+ onChange: (E) => k(E.target.value)
869
+ },
870
+ /* @__PURE__ */ e.createElement("option", { value: "low" }, "Low"),
871
+ /* @__PURE__ */ e.createElement("option", { value: "medium" }, "Medium"),
872
+ /* @__PURE__ */ e.createElement("option", { value: "high" }, "High"),
873
+ /* @__PURE__ */ e.createElement("option", { value: "urgent" }, "Urgent")
874
+ ))), R && /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-error" }, R), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-footer" }, /* @__PURE__ */ e.createElement("span", { className: "dgl-ticket-hint" }, "The bot writes the title + description from this chat."), /* @__PURE__ */ e.createElement(
875
+ "button",
876
+ {
877
+ type: "button",
878
+ className: "dgl-ticket-submit",
879
+ onClick: P,
880
+ disabled: L || !o.trim()
881
+ },
882
+ L ? z() : M(),
883
+ /* @__PURE__ */ e.createElement("span", null, L ? "Submitting…" : "Submit ticket")
884
+ ))));
885
+ }
886
+ function Ge({ created: t }) {
887
+ const n = A.open;
888
+ return /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-stripe", style: { background: "linear-gradient(90deg,#10b981,#14b8a6)" } }), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-body" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-head" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-icon", style: { background: "linear-gradient(135deg,#10b981,#14b8a6)" } }, Ye()), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-titles" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-eyebrow", style: { color: "#059669" } }, "Ticket created"), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-title" }, "#", t.externalNumber || t.id.slice(0, 8))), t.externalUrl && /* @__PURE__ */ e.createElement("a", { className: "dgl-ticket-open-btn", href: t.externalUrl, target: "_blank", rel: "noopener noreferrer" }, "Open")), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-pills" }, /* @__PURE__ */ e.createElement("span", { className: "dgl-ticket-pill", style: { background: n.pillBg, color: n.pillFg } }, /* @__PURE__ */ e.createElement("span", { className: "dgl-ticket-pill-dot", style: { background: n.iconBg } }), " Open")), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-desc" }, "Support team has been notified — they'll follow up directly on your email.")));
889
+ }
890
+ function He({
891
+ existing: t,
892
+ client: n,
893
+ conversationId: i,
894
+ defaultEmail: l,
895
+ defaultPhone: a,
896
+ onNewTicketRaised: o
897
+ }) {
898
+ const s = A[t.status] || A.open, [r, d] = f(!1), [h, w] = f(l || ""), [y, k] = f("medium"), [L, _] = f(!1), [R, C] = f(null), P = async () => {
899
+ if (!h.trim()) {
900
+ C("Email is required so the team can follow up.");
901
+ return;
902
+ }
903
+ if (!i) {
904
+ C("Conversation not available yet.");
905
+ return;
906
+ }
907
+ _(!0), C(null);
908
+ try {
909
+ const E = await n.raiseTicket(i, {
910
+ consent: !0,
911
+ end_user_email: h.trim(),
912
+ end_user_phone: a || void 0,
913
+ priority: y,
914
+ force_new: !0
915
+ });
916
+ o == null || o(E);
917
+ } catch (E) {
918
+ C((E == null ? void 0 : E.message) || "Could not create ticket. Try again.");
919
+ } finally {
920
+ _(!1);
921
+ }
922
+ };
923
+ return /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-stripe", style: { background: s.stripe } }), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-body" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-head" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-icon", style: { background: s.iconBg } }, M()), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-titles" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-eyebrow" }, "We're already on it"), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-title" }, "#", t.externalNumber || t.ticketId.slice(0, 8))), t.externalUrl && /* @__PURE__ */ e.createElement("a", { className: "dgl-ticket-open-btn", href: t.externalUrl, target: "_blank", rel: "noopener noreferrer" }, "Open")), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-pills" }, /* @__PURE__ */ e.createElement("span", { className: "dgl-ticket-pill", style: { background: s.pillBg, color: s.pillFg } }, /* @__PURE__ */ e.createElement("span", { className: "dgl-ticket-pill-dot", style: { background: s.iconBg } }), " ", s.label)), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-desc" }, "A ticket has already been raised for this conversation. Our team will follow up — no need to file another."), r ? /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-diff-form" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-field-label", style: { marginTop: 4 } }, "File a separate ticket for a new issue"), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-form-grid" }, /* @__PURE__ */ e.createElement("div", null, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-field-label" }, "Reply to"), /* @__PURE__ */ e.createElement(
924
+ "input",
925
+ {
926
+ type: "email",
927
+ className: "dgl-ticket-input",
928
+ value: h,
929
+ onChange: (E) => w(E.target.value),
930
+ placeholder: "you@example.com"
931
+ }
932
+ )), /* @__PURE__ */ e.createElement("div", null, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-field-label" }, "Priority"), /* @__PURE__ */ e.createElement(
933
+ "select",
934
+ {
935
+ className: "dgl-ticket-input",
936
+ value: y,
937
+ onChange: (E) => k(E.target.value)
938
+ },
939
+ /* @__PURE__ */ e.createElement("option", { value: "low" }, "Low"),
940
+ /* @__PURE__ */ e.createElement("option", { value: "medium" }, "Medium"),
941
+ /* @__PURE__ */ e.createElement("option", { value: "high" }, "High"),
942
+ /* @__PURE__ */ e.createElement("option", { value: "urgent" }, "Urgent")
943
+ ))), R && /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-error" }, R), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-footer" }, /* @__PURE__ */ e.createElement(
944
+ "button",
945
+ {
946
+ type: "button",
947
+ className: "dgl-ticket-diff-cancel",
948
+ onClick: () => d(!1)
949
+ },
950
+ "Cancel"
951
+ ), /* @__PURE__ */ e.createElement(
952
+ "button",
953
+ {
954
+ type: "button",
955
+ className: "dgl-ticket-submit",
956
+ onClick: P,
957
+ disabled: L || !h.trim()
958
+ },
959
+ L ? z() : M(),
960
+ /* @__PURE__ */ e.createElement("span", null, L ? "Submitting…" : "Submit new ticket")
961
+ ))) : /* @__PURE__ */ e.createElement(
962
+ "button",
963
+ {
964
+ type: "button",
965
+ className: "dgl-ticket-diff-link",
966
+ onClick: () => d(!0)
967
+ },
968
+ "Different issue? Raise new ticket →"
969
+ )));
970
+ }
971
+ function Xe({
972
+ ticket: t
973
+ }) {
974
+ const n = A[t.status] || A.open, i = we[(t.priority || "medium").toLowerCase()] || we.medium;
975
+ return /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-stripe", style: { background: n.stripe } }), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-body" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-head" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-icon", style: { background: n.iconBg } }, M()), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-titles" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-eyebrow" }, "Support ticket"), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-title" }, "#", t.externalNumber || t.ticketId.slice(0, 8))), t.externalUrl && /* @__PURE__ */ e.createElement("a", { className: "dgl-ticket-open-btn", href: t.externalUrl, target: "_blank", rel: "noopener noreferrer" }, "Open")), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-pills" }, /* @__PURE__ */ e.createElement("span", { className: "dgl-ticket-pill", style: { background: n.pillBg, color: n.pillFg } }, /* @__PURE__ */ e.createElement("span", { className: "dgl-ticket-pill-dot", style: { background: n.iconBg } }), " ", n.label), /* @__PURE__ */ e.createElement("span", { className: "dgl-ticket-pill", style: { background: i.bg, color: i.fg } }, t.priority || "medium", " priority")), t.title && /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-card-body-title" }, t.title), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-meta-grid" }, /* @__PURE__ */ e.createElement("div", null, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-meta-label" }, "Last update"), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-meta-value" }, xe(t.lastUpdate))), /* @__PURE__ */ e.createElement("div", null, /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-meta-label" }, "Assigned to"), /* @__PURE__ */ e.createElement("div", { className: "dgl-ticket-meta-value" }, t.assignedTo || "Unassigned")))));
976
+ }
977
+ function Ve({
978
+ tickets: t,
979
+ onClose: n,
980
+ onRefresh: i
981
+ }) {
982
+ const [l, a] = f(!1);
983
+ T(() => {
984
+ const r = (d) => {
985
+ d.key === "Escape" && n();
986
+ };
987
+ return window.addEventListener("keydown", r), () => window.removeEventListener("keydown", r);
988
+ }, [n]);
989
+ const o = async () => {
990
+ a(!0);
991
+ try {
992
+ await i();
993
+ } finally {
994
+ a(!1);
995
+ }
996
+ }, s = [...t].sort((r, d) => {
997
+ const h = r.created_at ? new Date(r.created_at).getTime() : 0;
998
+ return (d.created_at ? new Date(d.created_at).getTime() : 0) - h;
999
+ });
1000
+ return /* @__PURE__ */ e.createElement("div", { className: "dgl-tix-modal-backdrop", onClick: n }, /* @__PURE__ */ e.createElement("div", { className: "dgl-tix-modal", onClick: (r) => r.stopPropagation() }, /* @__PURE__ */ e.createElement("div", { className: "dgl-tix-modal-header" }, /* @__PURE__ */ e.createElement("div", null, /* @__PURE__ */ e.createElement("div", { className: "dgl-tix-modal-title" }, "Your tickets"), /* @__PURE__ */ e.createElement("div", { className: "dgl-tix-modal-sub" }, t.length === 0 ? "No tickets yet" : `${t.length} ticket${t.length === 1 ? "" : "s"} on this assistant`)), /* @__PURE__ */ e.createElement("div", { style: { display: "flex", gap: 4 } }, /* @__PURE__ */ e.createElement(
1001
+ "button",
1002
+ {
1003
+ type: "button",
1004
+ onClick: o,
1005
+ className: "dgl-icon-btn",
1006
+ title: "Refresh",
1007
+ "aria-label": "Refresh tickets",
1008
+ disabled: l,
1009
+ style: { color: "#475569" }
1010
+ },
1011
+ l ? z() : at()
1012
+ ), /* @__PURE__ */ e.createElement(
1013
+ "button",
1014
+ {
1015
+ type: "button",
1016
+ onClick: n,
1017
+ className: "dgl-icon-btn",
1018
+ title: "Close",
1019
+ "aria-label": "Close",
1020
+ style: { color: "#475569" }
1021
+ },
1022
+ Y()
1023
+ ))), /* @__PURE__ */ e.createElement("div", { className: "dgl-tix-modal-list" }, s.length === 0 ? /* @__PURE__ */ e.createElement("div", { className: "dgl-tix-empty" }, "You haven't raised any support tickets here yet. They'll show up here once you do.") : s.map((r) => {
1024
+ const d = A[r.status] || A.open;
1025
+ return /* @__PURE__ */ e.createElement("div", { key: r.id, className: "dgl-tix-row" }, /* @__PURE__ */ e.createElement("div", { className: "dgl-tix-row-head" }, /* @__PURE__ */ e.createElement("span", { className: "dgl-tix-row-num" }, "#", r.external_ticket_number || r.id.slice(0, 8)), /* @__PURE__ */ e.createElement(
1026
+ "span",
1027
+ {
1028
+ className: "dgl-ticket-pill",
1029
+ style: { background: d.pillBg, color: d.pillFg }
1030
+ },
1031
+ /* @__PURE__ */ e.createElement("span", { className: "dgl-ticket-pill-dot", style: { background: d.iconBg } }),
1032
+ d.label
1033
+ ), r.external_url && /* @__PURE__ */ e.createElement(
1034
+ "a",
1035
+ {
1036
+ href: r.external_url,
1037
+ target: "_blank",
1038
+ rel: "noopener noreferrer",
1039
+ className: "dgl-ticket-open-btn",
1040
+ style: { marginLeft: "auto" }
1041
+ },
1042
+ "Open"
1043
+ )), r.title && /* @__PURE__ */ e.createElement("div", { className: "dgl-tix-row-title" }, r.title), /* @__PURE__ */ e.createElement("div", { className: "dgl-tix-row-meta" }, r.priority || "medium", " priority · raised ", xe(r.created_at)));
1044
+ }))));
1045
+ }
1046
+ function M() {
1047
+ return /* @__PURE__ */ e.createElement("svg", { viewBox: "0 0 24 24", width: "16", height: "16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ e.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ e.createElement("circle", { cx: "12", cy: "12", r: "4" }), /* @__PURE__ */ e.createElement("path", { d: "M4.93 4.93l4.24 4.24M14.83 14.83l4.24 4.24M14.83 9.17l4.24-4.24M14.83 9.17l3.53-3.53M4.93 19.07l4.24-4.24" }));
1048
+ }
1049
+ function Ye() {
1050
+ return /* @__PURE__ */ e.createElement("svg", { viewBox: "0 0 24 24", width: "16", height: "16", fill: "none", stroke: "white", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ e.createElement("path", { d: "M20 6L9 17l-5-5" }));
1051
+ }
1052
+ function ze() {
410
1053
  return /* @__PURE__ */ e.createElement("svg", { viewBox: "0 0 24 24", width: "22", height: "22", fill: "currentColor" }, /* @__PURE__ */ e.createElement("path", { d: "M4 4h16a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H8l-4 4V6a2 2 0 0 1 2-2z" }));
411
1054
  }
412
- function Le() {
1055
+ function qe() {
413
1056
  return /* @__PURE__ */ e.createElement("svg", { viewBox: "0 0 24 24", width: "22", height: "22", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ e.createElement("polyline", { points: "6 9 12 15 18 9" }));
414
1057
  }
415
- function oe() {
1058
+ function Y() {
416
1059
  return /* @__PURE__ */ e.createElement("svg", { viewBox: "0 0 24 24", width: "16", height: "16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ e.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), /* @__PURE__ */ e.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" }));
417
1060
  }
418
- function Ue() {
1061
+ function Je() {
419
1062
  return /* @__PURE__ */ e.createElement("svg", { viewBox: "0 0 24 24", width: "16", height: "16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ e.createElement("line", { x1: "12", y1: "5", x2: "12", y2: "19" }), /* @__PURE__ */ e.createElement("line", { x1: "5", y1: "12", x2: "19", y2: "12" }));
420
1063
  }
421
- function Ie() {
1064
+ function Qe() {
422
1065
  return /* @__PURE__ */ e.createElement("svg", { viewBox: "0 0 24 24", width: "16", height: "16", fill: "currentColor" }, /* @__PURE__ */ e.createElement("path", { d: "M2 21l21-9L2 3v7l15 2-15 2z" }));
423
1066
  }
424
- function $e() {
1067
+ function Ze() {
425
1068
  return /* @__PURE__ */ e.createElement("svg", { viewBox: "0 0 24 24", width: "18", height: "18", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ e.createElement("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }), /* @__PURE__ */ e.createElement("circle", { cx: "8.5", cy: "8.5", r: "1.5" }), /* @__PURE__ */ e.createElement("polyline", { points: "21 15 16 10 5 21" }));
426
1069
  }
427
- function Fe() {
1070
+ function z() {
428
1071
  return /* @__PURE__ */ e.createElement("svg", { viewBox: "0 0 24 24", width: "16", height: "16", className: "dgl-spin", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round" }, /* @__PURE__ */ e.createElement("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }));
429
1072
  }
430
- function Re() {
1073
+ function et() {
431
1074
  return /* @__PURE__ */ e.createElement("svg", { viewBox: "0 0 24 24", width: "14", height: "14", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ e.createElement("polyline", { points: "15 3 21 3 21 9" }), /* @__PURE__ */ e.createElement("polyline", { points: "9 21 3 21 3 15" }), /* @__PURE__ */ e.createElement("line", { x1: "21", y1: "3", x2: "14", y2: "10" }), /* @__PURE__ */ e.createElement("line", { x1: "3", y1: "21", x2: "10", y2: "14" }));
432
1075
  }
433
- function Se() {
1076
+ function tt() {
434
1077
  return /* @__PURE__ */ e.createElement("svg", { viewBox: "0 0 24 24", width: "14", height: "14", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ e.createElement("polyline", { points: "4 14 10 14 10 20" }), /* @__PURE__ */ e.createElement("polyline", { points: "20 10 14 10 14 4" }), /* @__PURE__ */ e.createElement("line", { x1: "14", y1: "10", x2: "21", y2: "3" }), /* @__PURE__ */ e.createElement("line", { x1: "3", y1: "21", x2: "10", y2: "14" }));
435
1078
  }
436
- function Ae() {
1079
+ function at() {
1080
+ return /* @__PURE__ */ e.createElement("svg", { viewBox: "0 0 24 24", width: "14", height: "14", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ e.createElement("polyline", { points: "23 4 23 10 17 10" }), /* @__PURE__ */ e.createElement("polyline", { points: "1 20 1 14 7 14" }), /* @__PURE__ */ e.createElement("path", { d: "M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15" }));
1081
+ }
1082
+ function _e() {
437
1083
  return /* @__PURE__ */ e.createElement("svg", { viewBox: "0 0 24 24", width: "14", height: "14", fill: "currentColor" }, /* @__PURE__ */ e.createElement("path", { d: "M12 2l2.39 6.95L21 11l-6.61 2.05L12 20l-2.39-6.95L3 11l6.61-2.05L12 2z" }));
438
1084
  }
439
- let C = null, L = null;
440
- function Te(t) {
1085
+ let B = null, O = null;
1086
+ function nt(t) {
441
1087
  if (typeof document == "undefined")
442
1088
  throw new Error("DocGenLab.init() requires a browser environment.");
443
- if (C) {
444
- C.render(re(V, t));
1089
+ if (B) {
1090
+ B.render(Ee(le, t));
445
1091
  return;
446
1092
  }
447
- L = document.createElement("div"), L.id = "docgenlab-chat-widget-root", document.body.appendChild(L), C = he(L), C.render(re(V, t));
1093
+ O = document.createElement("div"), O.id = "docgenlab-chat-widget-root", document.body.appendChild(O), B = $e(O), B.render(Ee(le, t));
448
1094
  }
449
- function Be() {
450
- C && (C.unmount(), C = null), L && (L.remove(), L = null);
1095
+ function lt() {
1096
+ B && (B.unmount(), B = null), O && (O.remove(), O = null);
451
1097
  }
452
- typeof window != "undefined" && (window.DocGenLab = { init: Te, destroy: Be, DocGenLabChat: V });
1098
+ typeof window != "undefined" && (window.DocGenLab = { init: nt, destroy: lt, DocGenLabChat: le });
453
1099
  export {
454
- V as DocGenLabChat,
455
- Be as destroy,
456
- Te as init
1100
+ le as DocGenLabChat,
1101
+ lt as destroy,
1102
+ nt as init
457
1103
  };
458
1104
  //# sourceMappingURL=index.js.map