@webority/support-react 0.37.0 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1335 +1 @@
1
- import { createContext as e, useCallback as t, useContext as n, useEffect as r, useId as i, useMemo as a, useRef as o, useState as s } from "react";
2
- import { AppAlert as c, AppAvatar as l, AppBadge as u, AppButton as d, AppCard as f, AppCopyButton as p, AppDataTable as m, AppFileAttachment as h, AppIcon as g, AppInfoList as _, AppInput as v, AppLink as y, AppModal as b, AppSearch as x, AppSelect as S, AppSkeleton as C, AppSpinner as w, AppStatusBadge as T, AppTableEmptyState as E, AppTabs as D, AppTextarea as O, useFloatingStack as k } from "@webority/ui-react";
3
- import { toBlob as A } from "html-to-image";
4
- import { createPortal as j } from "react-dom";
5
- import { Fragment as ee, jsx as M, jsxs as N } from "react/jsx-runtime";
6
- //#region src/client.js
7
- var P = "Something went wrong. Please try again.", F = class extends Error {
8
- constructor(e, t, n) {
9
- super(t), this.name = "SupportApiError", this.code = e, this.status = n;
10
- }
11
- };
12
- async function I(e) {
13
- if (e && typeof Blob < "u" && e instanceof Blob) try {
14
- return JSON.parse(await e.text());
15
- } catch {
16
- return null;
17
- }
18
- if (typeof e == "string") try {
19
- return JSON.parse(e);
20
- } catch {
21
- return null;
22
- }
23
- return e ?? null;
24
- }
25
- async function L(e) {
26
- if (e instanceof F) return e;
27
- let t = e?.response;
28
- if (!t) return new F("network", P);
29
- let n = await I(t.data);
30
- return new F(typeof n?.code == "string" && n.code ? n.code : "unknown", typeof n?.message == "string" && n.message ? n.message : P, t.status);
31
- }
32
- async function R(e) {
33
- try {
34
- return (await e()).data;
35
- } catch (e) {
36
- throw await L(e);
37
- }
38
- }
39
- function z(e, t, n) {
40
- n != null && String(n).trim() !== "" && e.append(t, String(n));
41
- }
42
- function B(e, t, n, r) {
43
- (n ?? []).forEach((n, i) => {
44
- let a = n?.name || `${r}-${i + 1}.png`;
45
- e.append(t, n, a);
46
- });
47
- }
48
- function V(e, t = "/api/support") {
49
- let n = (typeof t == "string" ? t : t?.base ?? "/api/support").replace(/\/+$/, ""), r = (e) => `${n}/tickets/${encodeURIComponent(e)}`;
50
- return {
51
- getConfig: () => R(() => e.get(`${n}/settings`)),
52
- listTickets: ({ status: t, search: r, page: i, pageSize: a } = {}) => {
53
- let o = new URLSearchParams();
54
- z(o, "status", t), z(o, "search", r?.trim()), z(o, "page", i), z(o, "pageSize", a);
55
- let s = o.toString();
56
- return R(() => e.get(`${n}/tickets${s ? `?${s}` : ""}`));
57
- },
58
- getTicketCounts: () => R(() => e.get(`${n}/tickets/counts`)),
59
- getTicket: (t) => R(() => e.get(r(t))),
60
- createTicket: ({ category: t, subject: r, body: i, pageUrl: a, userAgent: o, appVersion: s, files: c, screenshots: l }) => {
61
- let u = new FormData();
62
- return u.append("category", t ?? ""), u.append("subject", r ?? ""), u.append("body", i ?? ""), z(u, "pageUrl", a), z(u, "userAgent", o), z(u, "appVersion", s), B(u, "files", c, "file"), B(u, "screenshots", l, "screenshot"), R(() => e.post(`${n}/tickets`, u));
63
- },
64
- reply: (t, { body: n, files: i, screenshots: a }) => {
65
- let o = new FormData();
66
- return o.append("body", n ?? ""), B(o, "files", i, "file"), B(o, "screenshots", a, "screenshot"), R(() => e.post(`${r(t)}/replies`, o));
67
- },
68
- reopen: (t) => R(() => e.post(`${r(t)}/reopen`)),
69
- rate: (t, { satisfaction: n, comment: i }) => {
70
- let a = { satisfaction: n };
71
- return i != null && i.trim() !== "" && (a.comment = i.trim()), R(() => e.post(`${r(t)}/rating`, a));
72
- },
73
- fetchAttachment: (t) => R(() => e.get(`${n}/attachments/${encodeURIComponent(t)}`, { responseType: "blob" })),
74
- confirmAction: (t) => R(() => e.post(`${n}/actions/confirm`, { token: t }))
75
- };
76
- }
77
- //#endregion
78
- //#region src/context.js
79
- var H = e(null);
80
- function U() {
81
- let e = n(H);
82
- if (!e) throw Error("Support components and hooks must be used inside <SupportProvider>.");
83
- return e;
84
- }
85
- function W() {
86
- return U().client;
87
- }
88
- function G(e, n, i = !0) {
89
- let [a, c] = s({
90
- data: null,
91
- loading: i,
92
- error: null
93
- }), [l, u] = s(0), d = o(e);
94
- d.current = e;
95
- let f = o(n);
96
- r(() => {
97
- let e = f.current !== n;
98
- if (f.current = n, !i) {
99
- c({
100
- data: null,
101
- loading: !1,
102
- error: null
103
- });
104
- return;
105
- }
106
- let t = !0;
107
- return c((t) => ({
108
- data: e ? null : t.data,
109
- loading: !0,
110
- error: null
111
- })), d.current(l > 0).then((e) => t && c({
112
- data: e,
113
- loading: !1,
114
- error: null
115
- }), (e) => t && c((t) => ({
116
- ...t,
117
- loading: !1,
118
- error: e
119
- }))), () => {
120
- t = !1;
121
- };
122
- }, [
123
- n,
124
- i,
125
- l
126
- ]);
127
- let p = t(() => u((e) => e + 1), []), m = t((e) => c((t) => ({
128
- ...t,
129
- data: e
130
- })), []);
131
- return {
132
- ...a,
133
- reload: p,
134
- setData: m
135
- };
136
- }
137
- function K() {
138
- let { loadConfig: e } = U(), { data: t, loading: n, error: r, reload: i } = G(e, "config");
139
- return {
140
- config: t,
141
- loading: n,
142
- error: r,
143
- reload: i
144
- };
145
- }
146
- function te(e = {}) {
147
- let t = W(), { status: n, search: r, page: i, pageSize: a } = e, { data: o, loading: s, error: c, reload: l } = G(() => t.listTickets({
148
- status: n,
149
- search: r,
150
- page: i,
151
- pageSize: a
152
- }), JSON.stringify([
153
- "tickets",
154
- n ?? null,
155
- r ?? null,
156
- i ?? null,
157
- a ?? null
158
- ]));
159
- return {
160
- tickets: o?.items ?? [],
161
- totalCount: o?.totalCount ?? 0,
162
- totalPages: o?.totalPages ?? 0,
163
- loading: s,
164
- error: c,
165
- reload: l
166
- };
167
- }
168
- function ne() {
169
- let e = W(), { data: t, loading: n, error: r, reload: i } = G(() => e.getTicketCounts(), "ticket-counts");
170
- return {
171
- counts: t,
172
- loading: n,
173
- error: r,
174
- reload: i
175
- };
176
- }
177
- function q(e) {
178
- let n = W(), { data: r, loading: i, error: a, reload: o, setData: s } = G(() => n.getTicket(e), e ?? "", !!e), c = t(async (e) => {
179
- let t = await e();
180
- return s(t), t;
181
- }, [s]);
182
- return {
183
- ticket: r,
184
- loading: i,
185
- error: a,
186
- reload: o,
187
- reply: t((t) => c(() => n.reply(e, t)), [
188
- c,
189
- n,
190
- e
191
- ]),
192
- reopen: t(() => c(() => n.reopen(e)), [
193
- c,
194
- n,
195
- e
196
- ]),
197
- rate: t((t) => c(() => n.rate(e, t)), [
198
- c,
199
- n,
200
- e
201
- ])
202
- };
203
- }
204
- //#endregion
205
- //#region src/lib/format.js
206
- var re = new Intl.DateTimeFormat("en-IN", {
207
- day: "2-digit",
208
- month: "numeric",
209
- year: "numeric",
210
- hour: "numeric",
211
- minute: "2-digit",
212
- hour12: !0,
213
- timeZoneName: "short"
214
- }), ie = [
215
- "Jan",
216
- "Feb",
217
- "Mar",
218
- "Apr",
219
- "May",
220
- "Jun",
221
- "Jul",
222
- "Aug",
223
- "Sep",
224
- "Oct",
225
- "Nov",
226
- "Dec"
227
- ];
228
- function J(e) {
229
- if (!e) return "-";
230
- let t = new Date(e);
231
- if (Number.isNaN(t.getTime())) return "-";
232
- let n = Object.fromEntries(re.formatToParts(t).map((e) => [e.type, e.value]));
233
- return `${n.day} ${ie[Number(n.month) - 1]} ${n.year}, ${n.hour}:${n.minute} ${n.dayPeriod.toLowerCase()} ${n.timeZoneName}`;
234
- }
235
- function Y(e) {
236
- if (!Number.isFinite(e) || e < 0) return "-";
237
- if (e < 1024) return `${e} B`;
238
- if (e < 1024 * 1024) return `${Math.round(e / 1024)} KB`;
239
- let t = e / (1024 * 1024);
240
- return `${Number.isInteger(t) ? t : t.toFixed(1)} MB`;
241
- }
242
- //#endregion
243
- //#region src/lib/files.js
244
- function ae(e) {
245
- return (e?.allowedContentTypes ?? []).join(",");
246
- }
247
- function oe(e, t) {
248
- if (t.length === 0) return !0;
249
- let n = (e || "").toLowerCase();
250
- return t.some((e) => {
251
- let t = e.toLowerCase();
252
- return t.endsWith("/*") ? n.startsWith(t.slice(0, -1)) : n === t;
253
- });
254
- }
255
- function X(e, t) {
256
- let n = e ?? [], r = t?.maxAttachmentsPerMessage ?? 0, i = t?.maxAttachmentBytes ?? 0, a = t?.allowedContentTypes ?? [];
257
- if (r > 0 && n.length > r) return r === 1 ? "You can attach one file." : `You can attach up to ${r} files.`;
258
- for (let e of n) {
259
- let t = e.name || "This file";
260
- if (!oe(e.type, a)) return `${t} is a file type we cannot accept.`;
261
- if (i > 0 && e.size > i) return `${t} is larger than ${Y(i)}.`;
262
- }
263
- return null;
264
- }
265
- function se(e) {
266
- let t = Array.from(e.clipboardData?.items ?? []), n = Date.now();
267
- return t.filter((e) => e.kind === "file" && e.type.startsWith("image/")).map((e) => e.getAsFile()).filter(Boolean).map((e, t) => {
268
- let r = (e.type.split("/")[1] || "png").replace("jpeg", "jpg");
269
- return new File([e], `pasted-image-${n}-${t + 1}.${r}`, { type: e.type });
270
- });
271
- }
272
- //#endregion
273
- //#region src/components/AttachmentField.jsx
274
- function ce({ id: e, label: t = "Attachments", files: n, onChange: r, config: i, error: a }) {
275
- let o = i?.maxAttachmentBytes ?? 0, s = o > 0 ? Math.max(.1, Math.round(o / (1024 * 1024) * 10) / 10) : 0;
276
- return /* @__PURE__ */ M(h, {
277
- id: e,
278
- label: t,
279
- optional: !0,
280
- multiple: !0,
281
- value: n,
282
- onChange: r,
283
- accept: ae(i),
284
- maxSizeMb: s,
285
- validate: !1,
286
- error: a || void 0
287
- });
288
- }
289
- //#endregion
290
- //#region src/components/TicketForm.jsx
291
- function le(e, t) {
292
- return t && e.includes(t) ? t : e[0] ?? "";
293
- }
294
- function ue({ id: e, config: t, defaultCategory: n, extraFiles: r = [], onSubmit: i, onBusyChange: a, children: o }) {
295
- let l = t?.categories ?? [], [u, d] = s(() => le(l, n)), [f, p] = s(""), [m, h] = s(""), [g, _] = s([]), [y, b] = s({}), [x, C] = s(""), w = (e) => {
296
- _(e), b((n) => ({
297
- ...n,
298
- files: X([...r, ...e], t) ?? void 0
299
- }));
300
- }, T = (e) => {
301
- let t = se(e);
302
- t.length > 0 && w([...g, ...t]);
303
- };
304
- function E() {
305
- let e = {};
306
- u || (e.category = "Choose a category."), f.trim() || (e.subject = "Give your ticket a subject."), m.trim() || (e.body = "Tell us what happened.");
307
- let n = X([...r, ...g], t);
308
- return n && (e.files = n), b(e), Object.keys(e).length === 0;
309
- }
310
- async function D(e) {
311
- if (e.preventDefault(), C(""), E()) {
312
- a?.(!0);
313
- try {
314
- await i({
315
- category: u,
316
- subject: f.trim(),
317
- body: m.trim(),
318
- files: g
319
- });
320
- } catch (e) {
321
- C(e?.message || "Your ticket did not send. Please try again.");
322
- } finally {
323
- a?.(!1);
324
- }
325
- }
326
- }
327
- return /* @__PURE__ */ N("form", {
328
- id: e,
329
- onSubmit: D,
330
- noValidate: !0,
331
- className: "d-flex flex-column gap-3",
332
- children: [
333
- x && /* @__PURE__ */ M(c, {
334
- variant: "danger",
335
- children: x
336
- }),
337
- /* @__PURE__ */ M(S, {
338
- id: `${e}-category`,
339
- label: "Category",
340
- required: !0,
341
- value: u,
342
- onChange: d,
343
- options: l.map((e) => ({
344
- value: e,
345
- label: e
346
- })),
347
- placeholder: "Choose a category",
348
- error: y.category
349
- }),
350
- /* @__PURE__ */ M(v, {
351
- id: `${e}-subject`,
352
- label: "Subject",
353
- required: !0,
354
- maxLength: t?.subjectMaxLength,
355
- placeholder: "A short summary",
356
- value: f,
357
- onChange: (e) => p(e.target.value),
358
- error: y.subject
359
- }),
360
- /* @__PURE__ */ M(O, {
361
- id: `${e}-body`,
362
- label: "Message",
363
- required: !0,
364
- rows: 6,
365
- maxLength: t?.bodyMaxLength,
366
- placeholder: "What happened, and what did you expect to happen?",
367
- value: m,
368
- onChange: (e) => h(e.target.value),
369
- onPaste: T,
370
- hint: "You can paste an image into the message.",
371
- error: y.body
372
- }),
373
- o,
374
- /* @__PURE__ */ M(ce, {
375
- id: `${e}-files`,
376
- files: g,
377
- onChange: w,
378
- config: t,
379
- error: y.files
380
- })
381
- ]
382
- });
383
- }
384
- //#endregion
385
- //#region src/ReportIssue.jsx
386
- var de = "supportCapture", fe = {
387
- zIndex: "var(--wui-z-fixed)",
388
- bottom: 0,
389
- insetInlineEnd: 0
390
- }, pe = (e) => e?.dataset?.[de] !== "exclude";
391
- async function me() {
392
- let e = await A(document.body, {
393
- filter: pe,
394
- pixelRatio: Math.min(window.devicePixelRatio || 1, 2)
395
- });
396
- if (!e) throw Error("The page capture came back empty.");
397
- return new File([e], "screenshot.png", { type: "image/png" });
398
- }
399
- function he({ file: e, onRemove: t }) {
400
- let [n, i] = s(null);
401
- return r(() => {
402
- let t = URL.createObjectURL(e);
403
- return i(t), () => URL.revokeObjectURL(t);
404
- }, [e]), /* @__PURE__ */ N("figure", {
405
- className: "mb-0 d-flex flex-column gap-2",
406
- children: [
407
- /* @__PURE__ */ M("figcaption", {
408
- className: "wui-text-sm fw-semibold",
409
- children: "Screenshot of this page"
410
- }),
411
- n && /* @__PURE__ */ M("img", {
412
- src: n,
413
- alt: "Screenshot of the page you were on",
414
- className: "d-block w-100 border rounded"
415
- }),
416
- /* @__PURE__ */ M(d, {
417
- variant: "ghost",
418
- size: "sm",
419
- leftIcon: "x",
420
- onClick: t,
421
- className: "align-self-start",
422
- children: "Remove screenshot"
423
- })
424
- ]
425
- });
426
- }
427
- function ge({ label: e = "Report an issue", floating: t = !1, compact: n = !1, defaultCategory: r = "Bug report", appVersion: a, getTicketHref: o, onOpenTicket: l, onCreated: u, className: f, style: p }) {
428
- let m = W(), { config: h, error: _ } = K(), v = `support-report-${i().replace(/[^a-zA-Z0-9-]/g, "")}`, [y, x] = s(!1), [S, C] = s(!1), [w, T] = s(null), [E, D] = s(!1), [O, A] = s(!1), [P, F] = s(null), I = k("end", t && n);
429
- async function L() {
430
- C(!0), F(null);
431
- try {
432
- T(await me()), D(!1);
433
- } catch {
434
- T(null), D(!0);
435
- } finally {
436
- C(!1), x(!0);
437
- }
438
- }
439
- let R = () => {
440
- O || (x(!1), T(null), F(null));
441
- };
442
- async function z(e) {
443
- let t = await m.createTicket({
444
- ...e,
445
- pageUrl: window.location.href,
446
- userAgent: navigator.userAgent,
447
- appVersion: a,
448
- screenshots: w ? [w] : []
449
- });
450
- F(t), T(null), u?.(t);
451
- }
452
- let B = P && o ? o(P.id) : void 0, V = P ? /* @__PURE__ */ N("div", {
453
- className: "d-flex justify-content-end gap-2 w-100",
454
- children: [/* @__PURE__ */ M(d, {
455
- variant: "secondary",
456
- onClick: R,
457
- children: "Close"
458
- }), P && (B || l) ? /* @__PURE__ */ M(d, {
459
- href: B,
460
- onClick: B ? void 0 : () => {
461
- x(!1), F(null), l(P);
462
- },
463
- children: "View ticket"
464
- }) : null]
465
- }) : /* @__PURE__ */ N("div", {
466
- className: "d-flex justify-content-end gap-2 w-100",
467
- children: [/* @__PURE__ */ M(d, {
468
- variant: "secondary",
469
- onClick: R,
470
- disabled: O,
471
- children: "Cancel"
472
- }), /* @__PURE__ */ M(d, {
473
- type: "submit",
474
- form: v,
475
- loading: O,
476
- disabled: !h,
477
- children: "Send report"
478
- })]
479
- }), H = n ? /* @__PURE__ */ M(d, {
480
- variant: "secondary",
481
- className: "wui-floating-btn wui-floating-btn--secondary",
482
- loading: S,
483
- onClick: L,
484
- "aria-haspopup": "dialog",
485
- "aria-label": e,
486
- tooltip: e,
487
- tooltipPlacement: "start",
488
- children: /* @__PURE__ */ M(g, {
489
- name: "bug",
490
- size: 22
491
- })
492
- }) : /* @__PURE__ */ M(d, {
493
- leftIcon: "bug",
494
- variant: t ? "primary" : "outline",
495
- loading: S,
496
- onClick: L,
497
- "aria-haspopup": "dialog",
498
- children: e
499
- });
500
- return /* @__PURE__ */ N(ee, { children: [t && n ? I && j(/* @__PURE__ */ M("span", {
501
- className: ["wui-floating-stack-item wui-floating-stack-item--secondary", f].filter(Boolean).join(" "),
502
- style: p,
503
- children: H
504
- }), I) : /* @__PURE__ */ M("span", {
505
- "data-support-capture": "exclude",
506
- className: [t ? "position-fixed m-3" : "d-inline-block", f].filter(Boolean).join(" "),
507
- style: t ? {
508
- ...fe,
509
- ...p
510
- } : p,
511
- children: H
512
- }), /* @__PURE__ */ M(b, {
513
- open: y,
514
- size: "lg",
515
- title: "Report an issue",
516
- subtitle: "Tell us what went wrong. We attach a screenshot of this page to help us see it.",
517
- headerIcon: "bug",
518
- staticBackdrop: !0,
519
- onClose: R,
520
- footer: V,
521
- children: P ? /* @__PURE__ */ M(c, {
522
- variant: "success",
523
- role: "status",
524
- title: `Ticket ${P.number} is with the support team`,
525
- children: "We reply by email. You can follow the ticket on your support page."
526
- }) : h ? /* @__PURE__ */ M(ue, {
527
- id: v,
528
- config: h,
529
- defaultCategory: r,
530
- extraFiles: w ? [w] : [],
531
- onSubmit: z,
532
- onBusyChange: A,
533
- children: w ? /* @__PURE__ */ M(he, {
534
- file: w,
535
- onRemove: () => T(null)
536
- }) : E ? /* @__PURE__ */ M(c, {
537
- variant: "info",
538
- children: "We could not take a screenshot of this page. You can attach an image instead."
539
- }) : null
540
- }) : /* @__PURE__ */ M(c, {
541
- variant: _ ? "danger" : "info",
542
- children: _ ? _.message || "We could not load the support settings." : "Loading the form."
543
- })
544
- })] });
545
- }
546
- //#endregion
547
- //#region src/components/NewTicketModal.jsx
548
- function _e({ open: e, onClose: t, onCreated: n, config: r, defaultCategory: a, appVersion: o }) {
549
- let c = W(), l = `support-new-${i().replace(/[^a-zA-Z0-9-]/g, "")}`, [u, f] = s(!1);
550
- async function p(e) {
551
- n(await c.createTicket({
552
- ...e,
553
- userAgent: typeof navigator > "u" ? void 0 : navigator.userAgent,
554
- appVersion: o
555
- }));
556
- }
557
- return /* @__PURE__ */ M(b, {
558
- open: e,
559
- size: "lg",
560
- title: "New ticket",
561
- subtitle: "Tell us what you need. We reply by email and on this page.",
562
- headerIcon: "message-square",
563
- staticBackdrop: !0,
564
- onClose: () => {
565
- u || t();
566
- },
567
- footer: /* @__PURE__ */ N("div", {
568
- className: "d-flex justify-content-end gap-2 w-100",
569
- children: [/* @__PURE__ */ M(d, {
570
- variant: "secondary",
571
- onClick: t,
572
- disabled: u,
573
- children: "Cancel"
574
- }), /* @__PURE__ */ M(d, {
575
- type: "submit",
576
- form: l,
577
- loading: u,
578
- children: "Send ticket"
579
- })]
580
- }),
581
- children: e && /* @__PURE__ */ M(ue, {
582
- id: l,
583
- config: r,
584
- defaultCategory: a,
585
- onSubmit: p,
586
- onBusyChange: f
587
- })
588
- });
589
- }
590
- //#endregion
591
- //#region src/lib/status.js
592
- var ve = {
593
- Open: "warning",
594
- InProgress: "info",
595
- Resolved: "success",
596
- Closed: "neutral"
597
- };
598
- function ye(e) {
599
- return ve[e] ?? "neutral";
600
- }
601
- //#endregion
602
- //#region src/components/AttachmentThumb.jsx
603
- var be = {
604
- width: 140,
605
- maxWidth: "100%"
606
- }, xe = { height: 84 };
607
- function Se({ attachment: e }) {
608
- let t = W(), n = (e.contentType || "").startsWith("image/"), [i, a] = s(null), [o, c] = s(!1);
609
- r(() => {
610
- let n = !0, r = null;
611
- return a(null), c(!1), t.fetchAttachment(e.id).then((e) => {
612
- r = URL.createObjectURL(e), n ? a(r) : URL.revokeObjectURL(r);
613
- }, () => n && c(!0)), () => {
614
- n = !1, r && URL.revokeObjectURL(r);
615
- };
616
- }, [t, e.id]);
617
- let l = `Open ${e.fileName}`, u = /* @__PURE__ */ N("span", {
618
- className: "d-block text-truncate px-2 py-1 wui-text-xs text-body-secondary",
619
- children: [
620
- e.fileName,
621
- ", ",
622
- Y(e.sizeBytes)
623
- ]
624
- });
625
- return o ? /* @__PURE__ */ N("span", {
626
- className: "d-inline-flex flex-column border rounded overflow-hidden",
627
- style: be,
628
- children: [/* @__PURE__ */ N("span", {
629
- className: "d-flex align-items-center justify-content-center gap-1 p-2 wui-text-xs text-body-secondary",
630
- children: [/* @__PURE__ */ M(g, {
631
- name: "x-circle",
632
- size: 14
633
- }), "Could not load this file."]
634
- }), u]
635
- }) : /* @__PURE__ */ N("a", {
636
- className: "d-inline-flex flex-column border rounded overflow-hidden text-decoration-none",
637
- style: be,
638
- href: i ?? void 0,
639
- target: "_blank",
640
- rel: "noopener noreferrer",
641
- "aria-label": l,
642
- "aria-busy": !i || void 0,
643
- children: [/* @__PURE__ */ M("span", {
644
- className: "d-flex align-items-center justify-content-center bg-body-tertiary",
645
- style: xe,
646
- children: i ? n ? /* @__PURE__ */ M("img", {
647
- src: i,
648
- alt: e.fileName,
649
- className: "d-block w-100 h-100 object-fit-cover"
650
- }) : /* @__PURE__ */ M(g, {
651
- name: "file-text",
652
- size: 28
653
- }) : /* @__PURE__ */ M(w, {
654
- size: "sm",
655
- label: `Loading ${e.fileName}`
656
- })
657
- }), u]
658
- });
659
- }
660
- //#endregion
661
- //#region src/components/MessageThread.jsx
662
- var Ce = {
663
- whiteSpace: "pre-wrap",
664
- overflowWrap: "anywhere"
665
- };
666
- function we({ messages: e }) {
667
- return /* @__PURE__ */ M("ol", {
668
- className: "list-unstyled d-flex flex-column gap-3 mb-0",
669
- "aria-label": "Conversation",
670
- children: e.map((e) => {
671
- let t = /* @__PURE__ */ M("time", {
672
- dateTime: e.createdDateTimeUtc,
673
- className: "wui-text-xs text-body-secondary text-nowrap",
674
- children: J(e.createdDateTimeUtc)
675
- });
676
- if (e.authorKind === "System") return /* @__PURE__ */ N("li", {
677
- className: "text-center wui-text-xs text-body-secondary",
678
- "data-author": "system",
679
- children: [/* @__PURE__ */ M("span", {
680
- className: "d-block",
681
- children: e.body
682
- }), t]
683
- }, e.id);
684
- let n = e.authorKind === "Customer", r = e.authorName || (n ? "You" : "Support team");
685
- return /* @__PURE__ */ N("li", {
686
- className: `d-flex align-items-start gap-2${n ? " flex-row-reverse" : ""}`,
687
- "data-author": n ? "customer" : "agent",
688
- children: [/* @__PURE__ */ M(l, {
689
- name: r,
690
- size: 32,
691
- tone: n ? "neutral" : "primary"
692
- }), /* @__PURE__ */ N(f, {
693
- className: "flex-grow-1 border",
694
- padding: "sm",
695
- variant: n ? "default" : "accent",
696
- style: { minWidth: 0 },
697
- children: [
698
- /* @__PURE__ */ N("div", {
699
- className: "d-flex flex-wrap align-items-center justify-content-between gap-2 mb-2",
700
- children: [/* @__PURE__ */ N("span", {
701
- className: "d-inline-flex flex-wrap align-items-center gap-2 fw-semibold wui-text-sm text-break",
702
- children: [r, !n && /* @__PURE__ */ M(u, {
703
- tone: "primary",
704
- children: "Support"
705
- })]
706
- }), t]
707
- }),
708
- /* @__PURE__ */ M("div", {
709
- className: "wui-text-sm",
710
- style: Ce,
711
- children: e.body
712
- }),
713
- e.attachments?.length > 0 && /* @__PURE__ */ M("div", {
714
- className: "d-flex flex-wrap gap-2 mt-2",
715
- children: e.attachments.map((e) => /* @__PURE__ */ M(Se, { attachment: e }, e.id))
716
- })
717
- ]
718
- })]
719
- }, e.id);
720
- })
721
- });
722
- }
723
- //#endregion
724
- //#region src/components/RatingPanel.jsx
725
- function Te({ satisfaction: e, comment: t, canRate: n = !1, commentMaxLength: r, onRate: a }) {
726
- let o = i(), [l, u] = s(""), [p, m] = s(null), [h, g] = s("");
727
- if (e) return /* @__PURE__ */ N(c, {
728
- variant: e === "Satisfied" ? "success" : "info",
729
- role: "status",
730
- children: [e === "Satisfied" ? "You told us this solved your problem." : "You told us this did not solve your problem.", t ? /* @__PURE__ */ N("span", {
731
- className: "d-block mt-1",
732
- children: ["Your comment: ", t]
733
- }) : null]
734
- });
735
- if (!n) return null;
736
- async function _(e) {
737
- g(""), m(e);
738
- try {
739
- await a({
740
- satisfaction: e,
741
- comment: l
742
- });
743
- } catch (e) {
744
- g(e?.message || "Your rating did not send. Please try again.");
745
- } finally {
746
- m(null);
747
- }
748
- }
749
- return /* @__PURE__ */ M(f, {
750
- padding: "sm",
751
- className: "border",
752
- title: "Did this solve your problem?",
753
- children: /* @__PURE__ */ N("div", {
754
- className: "d-flex flex-column gap-2",
755
- children: [
756
- h && /* @__PURE__ */ M(c, {
757
- variant: "danger",
758
- children: h
759
- }),
760
- /* @__PURE__ */ M(O, {
761
- id: `${o}-comment`,
762
- label: "Anything to add?",
763
- rows: 2,
764
- maxLength: r,
765
- value: l,
766
- onChange: (e) => u(e.target.value),
767
- hint: "Optional. Your comment goes to the support team."
768
- }),
769
- /* @__PURE__ */ N("div", {
770
- className: "d-flex flex-wrap gap-2",
771
- children: [/* @__PURE__ */ M(d, {
772
- variant: "outline",
773
- leftIcon: "check-circle",
774
- loading: p === "Satisfied",
775
- disabled: p !== null,
776
- onClick: () => _("Satisfied"),
777
- children: "Yes, it is solved"
778
- }), /* @__PURE__ */ M(d, {
779
- variant: "outline",
780
- leftIcon: "x-circle",
781
- loading: p === "Unsatisfied",
782
- disabled: p !== null,
783
- onClick: () => _("Unsatisfied"),
784
- children: "No, it is not"
785
- })]
786
- })
787
- ]
788
- })
789
- });
790
- }
791
- //#endregion
792
- //#region src/components/ReplyBox.jsx
793
- function Ee({ onSend: e, config: t, reopens: n = !1 }) {
794
- let r = i(), [a, o] = s(""), [l, u] = s([]), [f, p] = s(""), [m, h] = s(""), [g, _] = s(!1), v = (e) => {
795
- u(e), p(X(e, t) ?? "");
796
- }, y = (e) => {
797
- let t = se(e);
798
- t.length > 0 && v([...l, ...t]);
799
- };
800
- async function b(n) {
801
- n.preventDefault();
802
- let r = a.trim();
803
- if (!r) {
804
- h("Write a message before you send it.");
805
- return;
806
- }
807
- let i = X(l, t);
808
- if (i) {
809
- p(i);
810
- return;
811
- }
812
- h(""), _(!0);
813
- try {
814
- await e({
815
- body: r,
816
- files: l
817
- }), o(""), u([]), p("");
818
- } catch (e) {
819
- h(e?.message || "Your reply did not send. Please try again.");
820
- } finally {
821
- _(!1);
822
- }
823
- }
824
- return /* @__PURE__ */ N("form", {
825
- onSubmit: b,
826
- noValidate: !0,
827
- className: "d-flex flex-column gap-2",
828
- "aria-label": "Reply to this ticket",
829
- children: [
830
- m && /* @__PURE__ */ M(c, {
831
- variant: "danger",
832
- children: m
833
- }),
834
- /* @__PURE__ */ M(O, {
835
- id: `${r}-body`,
836
- label: "Your reply",
837
- rows: 4,
838
- autoGrow: !0,
839
- maxLength: t?.bodyMaxLength,
840
- value: a,
841
- onChange: (e) => o(e.target.value),
842
- onPaste: y,
843
- hint: n ? "Sending a reply reopens this ticket. You can paste an image into the message." : "You can paste an image into the message.",
844
- required: !0
845
- }),
846
- /* @__PURE__ */ M(ce, {
847
- id: `${r}-files`,
848
- files: l,
849
- onChange: v,
850
- config: t,
851
- error: f
852
- }),
853
- /* @__PURE__ */ M("div", {
854
- className: "d-flex justify-content-end",
855
- children: /* @__PURE__ */ M(d, {
856
- type: "submit",
857
- leftIcon: "send",
858
- loading: g,
859
- children: "Send reply"
860
- })
861
- })
862
- ]
863
- });
864
- }
865
- //#endregion
866
- //#region src/components/TicketDetail.jsx
867
- function Z({ label: e, children: t }) {
868
- return /* @__PURE__ */ N("div", {
869
- className: "d-flex flex-column",
870
- children: [/* @__PURE__ */ M("span", {
871
- className: "wui-text-xs fw-semibold text-body-secondary",
872
- children: e
873
- }), /* @__PURE__ */ M("span", {
874
- className: "wui-text-sm",
875
- children: t
876
- })]
877
- });
878
- }
879
- function De({ ticketId: e, onBack: t, onChanged: n }) {
880
- let { config: r } = K(), { ticket: i, loading: a, error: o, reload: l, reply: u, reopen: f, rate: p } = q(e), [m, h] = s(!1), [g, _] = s(""), v = async (e) => {
881
- let t = await e();
882
- return n?.(), t;
883
- };
884
- async function y() {
885
- _(""), h(!0);
886
- try {
887
- await v(f);
888
- } catch (e) {
889
- _(e?.message || "The ticket did not reopen. Please try again.");
890
- } finally {
891
- h(!1);
892
- }
893
- }
894
- let b = /* @__PURE__ */ M(d, {
895
- variant: "ghost",
896
- size: "sm",
897
- leftIcon: "arrow-left",
898
- onClick: t,
899
- className: "align-self-start",
900
- children: "Back to tickets"
901
- });
902
- if (!i) return /* @__PURE__ */ N("section", {
903
- className: "d-flex flex-column gap-3",
904
- "aria-busy": a || void 0,
905
- children: [b, o ? /* @__PURE__ */ N(c, {
906
- variant: "danger",
907
- children: [
908
- o.message || "We could not load this ticket.",
909
- " ",
910
- /* @__PURE__ */ M(d, {
911
- variant: "ghost",
912
- size: "sm",
913
- onClick: l,
914
- children: "Try again"
915
- })
916
- ]
917
- }) : /* @__PURE__ */ M(C, { height: 160 })]
918
- });
919
- let x = i.status === "Resolved" || i.status === "Closed";
920
- return /* @__PURE__ */ N("section", {
921
- className: "d-flex flex-column gap-3",
922
- "aria-labelledby": `support-ticket-${i.id}`,
923
- children: [
924
- b,
925
- /* @__PURE__ */ N("header", {
926
- className: "d-flex flex-column gap-2",
927
- children: [
928
- /* @__PURE__ */ N("div", {
929
- className: "d-flex flex-wrap align-items-center gap-2",
930
- children: [/* @__PURE__ */ M("h2", {
931
- id: `support-ticket-${i.id}`,
932
- className: "h5 mb-0 text-break",
933
- children: i.subject
934
- }), i.statusLabel && /* @__PURE__ */ M(T, {
935
- label: i.statusLabel,
936
- tone: ye(i.status)
937
- })]
938
- }),
939
- /* @__PURE__ */ N("div", {
940
- className: "row row-cols-2 row-cols-md-4 g-3",
941
- children: [
942
- /* @__PURE__ */ M(Z, {
943
- label: "Ticket",
944
- children: i.number
945
- }),
946
- /* @__PURE__ */ M(Z, {
947
- label: "Category",
948
- children: i.category || "-"
949
- }),
950
- /* @__PURE__ */ M(Z, {
951
- label: "Opened",
952
- children: /* @__PURE__ */ M("time", {
953
- dateTime: i.createdDateTimeUtc,
954
- children: J(i.createdDateTimeUtc)
955
- })
956
- }),
957
- /* @__PURE__ */ M(Z, {
958
- label: "Last update",
959
- children: /* @__PURE__ */ M("time", {
960
- dateTime: i.updatedDateTimeUtc,
961
- children: J(i.updatedDateTimeUtc)
962
- })
963
- })
964
- ]
965
- }),
966
- /* @__PURE__ */ M("p", {
967
- className: "wui-text-xs text-body-secondary mb-0",
968
- children: "Times are shown in your time zone."
969
- })
970
- ]
971
- }),
972
- g && /* @__PURE__ */ M(c, {
973
- variant: "danger",
974
- children: g
975
- }),
976
- x && /* @__PURE__ */ M(c, {
977
- variant: "success",
978
- role: "status",
979
- children: "If you still need help, reopen the ticket or send a reply."
980
- }),
981
- i.canReopen && /* @__PURE__ */ M(d, {
982
- variant: "secondary",
983
- leftIcon: "history",
984
- loading: m,
985
- onClick: y,
986
- className: "align-self-start",
987
- children: "Reopen ticket"
988
- }),
989
- /* @__PURE__ */ M(Te, {
990
- satisfaction: i.satisfaction,
991
- comment: i.satisfactionComment,
992
- canRate: i.canRate,
993
- commentMaxLength: r?.satisfactionCommentMaxLength,
994
- onRate: (e) => v(() => p(e))
995
- }),
996
- /* @__PURE__ */ M(we, { messages: i.messages ?? [] }),
997
- /* @__PURE__ */ M(Ee, {
998
- config: r,
999
- reopens: x,
1000
- onSend: (e) => v(() => u(e))
1001
- })
1002
- ]
1003
- });
1004
- }
1005
- //#endregion
1006
- //#region src/lib/url.js
1007
- var Q = "ticket";
1008
- function Oe() {
1009
- return typeof window > "u" ? null : new URLSearchParams(window.location.search).get(Q);
1010
- }
1011
- function ke(e) {
1012
- if (typeof window > "u") return e ? `?${Q}=${encodeURIComponent(e)}` : "?";
1013
- let t = new URL(window.location.href);
1014
- return e ? t.searchParams.set(Q, e) : t.searchParams.delete(Q), `${t.pathname}${t.search}${t.hash}`;
1015
- }
1016
- function Ae(e) {
1017
- if (typeof window > "u") return;
1018
- let t = ke(e);
1019
- t !== `${window.location.pathname}${window.location.search}${window.location.hash}` && window.history.replaceState(window.history.state, "", t);
1020
- }
1021
- //#endregion
1022
- //#region src/components/TicketList.jsx
1023
- var je = [
1024
- {
1025
- key: "all",
1026
- label: "All",
1027
- countKey: "total"
1028
- },
1029
- {
1030
- key: "Open",
1031
- label: "Open",
1032
- countKey: "open"
1033
- },
1034
- {
1035
- key: "InProgress",
1036
- label: "In progress",
1037
- countKey: "inProgress"
1038
- },
1039
- {
1040
- key: "Resolved",
1041
- label: "Resolved",
1042
- countKey: "resolved"
1043
- },
1044
- {
1045
- key: "Closed",
1046
- label: "Closed",
1047
- countKey: "closed"
1048
- }
1049
- ];
1050
- function Me({ tickets: e, loading: t, error: n, onRetry: r, onOpen: i, status: a, onStatusChange: o, counts: s, search: l, onSearchChange: u, pagination: f }) {
1051
- return /* @__PURE__ */ N("div", {
1052
- className: "d-flex flex-column gap-3",
1053
- children: [
1054
- n && /* @__PURE__ */ N(c, {
1055
- variant: "danger",
1056
- children: [
1057
- n.message || "We could not load your tickets.",
1058
- " ",
1059
- /* @__PURE__ */ M(d, {
1060
- variant: "ghost",
1061
- size: "sm",
1062
- onClick: r,
1063
- children: "Try again"
1064
- })
1065
- ]
1066
- }),
1067
- /* @__PURE__ */ N("div", {
1068
- className: "d-flex flex-column flex-md-row gap-2 align-items-md-center justify-content-between",
1069
- children: [/* @__PURE__ */ M(D, {
1070
- tabs: je.map(({ key: e, label: t, countKey: n }) => ({
1071
- key: e,
1072
- label: t,
1073
- count: s?.[n]
1074
- })),
1075
- value: a,
1076
- onChange: o,
1077
- ariaLabel: "Filter tickets by status",
1078
- className: "flex-grow-1"
1079
- }), /* @__PURE__ */ M(x, {
1080
- value: l,
1081
- onChange: u,
1082
- placeholder: "Search tickets",
1083
- ariaLabel: "Search tickets"
1084
- })]
1085
- }),
1086
- /* @__PURE__ */ M(m, {
1087
- columns: [
1088
- {
1089
- key: "subject",
1090
- label: "Subject",
1091
- render: (e) => /* @__PURE__ */ N("div", {
1092
- className: "d-flex flex-column",
1093
- style: { minWidth: 0 },
1094
- children: [/* @__PURE__ */ M(y, {
1095
- href: ke(e.id),
1096
- animation: "none",
1097
- className: "fw-semibold text-break",
1098
- onClick: (t) => {
1099
- t.metaKey || t.ctrlKey || t.shiftKey || t.altKey || (t.preventDefault(), i(e.id));
1100
- },
1101
- children: e.subject
1102
- }), /* @__PURE__ */ N("span", {
1103
- className: "wui-text-xs text-body-secondary",
1104
- children: [
1105
- e.number,
1106
- ", ",
1107
- e.category,
1108
- e.awaitingCustomer ? ". Waiting for your reply" : ""
1109
- ]
1110
- })]
1111
- })
1112
- },
1113
- {
1114
- key: "status",
1115
- label: "Status",
1116
- render: (e) => e.statusLabel ? /* @__PURE__ */ M(T, {
1117
- label: e.statusLabel,
1118
- tone: ye(e.status)
1119
- }) : "-"
1120
- },
1121
- {
1122
- key: "messageCount",
1123
- label: "Messages",
1124
- cellClassName: "wui-text-sm text-body-secondary",
1125
- render: (e) => e.messageCount
1126
- },
1127
- {
1128
- key: "updatedDateTimeUtc",
1129
- label: "Last update",
1130
- cellClassName: "wui-text-sm text-body-secondary text-nowrap",
1131
- render: (e) => /* @__PURE__ */ M("time", {
1132
- dateTime: e.updatedDateTimeUtc,
1133
- children: J(e.updatedDateTimeUtc)
1134
- })
1135
- }
1136
- ],
1137
- rows: e,
1138
- loading: t,
1139
- skeletonRows: 4,
1140
- ariaLabel: "Support tickets",
1141
- sourceCount: s?.total ?? 0,
1142
- pagination: f,
1143
- empty: /* @__PURE__ */ M(E, {
1144
- icon: "message-square",
1145
- title: "No tickets yet",
1146
- text: "When you raise a ticket, it shows here with its status."
1147
- }),
1148
- emptyFiltered: /* @__PURE__ */ M(E, {
1149
- icon: "search",
1150
- title: "No tickets match",
1151
- text: "Try another search or status."
1152
- })
1153
- })
1154
- ]
1155
- });
1156
- }
1157
- //#endregion
1158
- //#region src/lib/useDebouncedValue.js
1159
- function Ne(e, t) {
1160
- let [n, i] = s(e);
1161
- return r(() => {
1162
- let n = setTimeout(() => i(e), t);
1163
- return () => clearTimeout(n);
1164
- }, [e, t]), n;
1165
- }
1166
- //#endregion
1167
- //#region src/SupportCenter.jsx
1168
- var Pe = 300, Fe = 10;
1169
- function Ie({ initialTicketId: e, defaultCategory: t, appVersion: n }) {
1170
- let { config: i, error: a, reload: o } = K(), [l, u] = s("all"), [f, p] = s(""), m = Ne(f.trim(), Pe), [h, g] = s(Fe), _ = `${l}|${m}|${h}`, [v, y] = s({
1171
- key: _,
1172
- page: 1
1173
- }), b = v.key === _ ? v.page : 1, x = (e) => y({
1174
- key: _,
1175
- page: e
1176
- }), S = te({
1177
- status: l === "all" ? void 0 : l,
1178
- search: m || void 0,
1179
- page: b,
1180
- pageSize: h
1181
- }), { counts: C, reload: w } = ne(), [T, E] = s(() => e || Oe()), [D, O] = s(!1), k = S.totalPages;
1182
- r(() => {
1183
- k > 0 && b > k && y({
1184
- key: _,
1185
- page: k
1186
- });
1187
- }, [
1188
- k,
1189
- b,
1190
- _
1191
- ]);
1192
- let A = () => {
1193
- S.reload(), w();
1194
- }, j = (e) => {
1195
- E(e), Ae(e);
1196
- };
1197
- if (T) return /* @__PURE__ */ M(De, {
1198
- ticketId: T,
1199
- onBack: () => j(null),
1200
- onChanged: A
1201
- }, T);
1202
- let ee = {
1203
- page: b,
1204
- totalPages: Math.max(1, S.totalPages),
1205
- pageSize: h,
1206
- total: S.totalCount,
1207
- setPage: x,
1208
- setPageSize: g
1209
- };
1210
- return /* @__PURE__ */ N("section", {
1211
- className: "d-flex flex-column gap-3",
1212
- "aria-labelledby": "support-center-title",
1213
- children: [
1214
- /* @__PURE__ */ N("div", {
1215
- className: "d-flex flex-wrap align-items-center justify-content-between gap-2",
1216
- children: [/* @__PURE__ */ M("h2", {
1217
- id: "support-center-title",
1218
- className: "h5 mb-0",
1219
- children: "Your tickets"
1220
- }), /* @__PURE__ */ M(d, {
1221
- leftIcon: "plus",
1222
- onClick: () => O(!0),
1223
- disabled: !i,
1224
- children: "New ticket"
1225
- })]
1226
- }),
1227
- a && /* @__PURE__ */ N(c, {
1228
- variant: "warning",
1229
- children: [
1230
- a.message || "We could not load the support settings.",
1231
- " ",
1232
- /* @__PURE__ */ M(d, {
1233
- variant: "ghost",
1234
- size: "sm",
1235
- onClick: o,
1236
- children: "Try again"
1237
- })
1238
- ]
1239
- }),
1240
- /* @__PURE__ */ M(Me, {
1241
- tickets: S.tickets,
1242
- loading: S.loading,
1243
- error: S.error,
1244
- onRetry: A,
1245
- onOpen: j,
1246
- status: l,
1247
- onStatusChange: u,
1248
- counts: C,
1249
- search: f,
1250
- onSearchChange: p,
1251
- pagination: ee
1252
- }),
1253
- i && /* @__PURE__ */ M(_e, {
1254
- open: D,
1255
- onClose: () => O(!1),
1256
- config: i,
1257
- defaultCategory: t,
1258
- appVersion: n,
1259
- onCreated: (e) => {
1260
- O(!1), A(), j(e.id);
1261
- }
1262
- })
1263
- ]
1264
- });
1265
- }
1266
- //#endregion
1267
- //#region src/SupportContact.jsx
1268
- var $ = (e) => typeof e == "string" && e.trim() !== "";
1269
- function Le({ className: e }) {
1270
- let { config: t } = K();
1271
- if (!t) return null;
1272
- let n = [];
1273
- return $(t.supportEmail) && n.push({
1274
- key: "email",
1275
- icon: "mail",
1276
- label: "Email",
1277
- value: /* @__PURE__ */ N("span", {
1278
- className: "d-inline-flex flex-wrap align-items-center gap-2",
1279
- children: [/* @__PURE__ */ M("a", {
1280
- href: `mailto:${t.supportEmail}`,
1281
- className: "text-break",
1282
- children: t.supportEmail
1283
- }), /* @__PURE__ */ M(p, {
1284
- text: t.supportEmail,
1285
- size: "sm",
1286
- label: "Copy email",
1287
- copiedLabel: "Email copied"
1288
- })]
1289
- })
1290
- }), $(t.supportPhone) && n.push({
1291
- key: "phone",
1292
- icon: "phone",
1293
- label: "Phone",
1294
- value: t.supportPhone,
1295
- href: `tel:${t.supportPhone.replace(/[^\d+]/g, "")}`
1296
- }), $(t.supportHours) && n.push({
1297
- key: "hours",
1298
- icon: "clock",
1299
- label: "Hours",
1300
- value: t.supportHours
1301
- }), n.length === 0 ? null : /* @__PURE__ */ N("section", {
1302
- className: e,
1303
- "aria-label": $(t.supportName) ? `Contact ${t.supportName}` : "Contact support",
1304
- children: [$(t.supportName) && /* @__PURE__ */ M("p", {
1305
- className: "fw-semibold mb-2",
1306
- children: t.supportName
1307
- }), /* @__PURE__ */ M(_, { items: n })]
1308
- });
1309
- }
1310
- //#endregion
1311
- //#region src/SupportProvider.jsx
1312
- function Re({ client: e, children: n }) {
1313
- let r = o(null), i = t((t = !1) => {
1314
- let n = r.current;
1315
- if (t || !n || n.client !== e) {
1316
- let t = e.getConfig(), n = {
1317
- client: e,
1318
- pending: t
1319
- };
1320
- return r.current = n, t.catch(() => {
1321
- r.current === n && (r.current = null);
1322
- }), t;
1323
- }
1324
- return n.pending;
1325
- }, [e]), s = a(() => ({
1326
- client: e,
1327
- loadConfig: i
1328
- }), [e, i]);
1329
- return /* @__PURE__ */ M(H.Provider, {
1330
- value: s,
1331
- children: n
1332
- });
1333
- }
1334
- //#endregion
1335
- export { ge as ReportIssue, F as SupportApiError, Ie as SupportCenter, Le as SupportContact, Re as SupportProvider, V as createSupportClient, W as useSupportClient, K as useSupportConfig, q as useSupportTicket, ne as useSupportTicketCounts, te as useSupportTickets };
1
+ import{createContext as e,useCallback as t,useContext as n,useEffect as r,useId as i,useMemo as a,useRef as o,useState as s}from"react";import{AppAlert as c,AppAvatar as l,AppBadge as u,AppButton as d,AppCard as f,AppCopyButton as p,AppDataTable as m,AppFileAttachment as h,AppIcon as g,AppInfoList as _,AppInput as v,AppLink as y,AppModal as b,AppSearch as x,AppSelect as S,AppSkeleton as C,AppSpinner as w,AppStatusBadge as T,AppTableEmptyState as E,AppTabs as D,AppTextarea as O,useFloatingStack as k}from"@webority/ui-react";import{toBlob as A}from"html-to-image";import{createPortal as j}from"react-dom";import{Fragment as ee,jsx as M,jsxs as N}from"react/jsx-runtime";var P=`Something went wrong. Please try again.`,F=class extends Error{constructor(e,t,n){super(t),this.name=`SupportApiError`,this.code=e,this.status=n}};async function I(e){if(e&&typeof Blob<`u`&&e instanceof Blob)try{return JSON.parse(await e.text())}catch{return null}if(typeof e==`string`)try{return JSON.parse(e)}catch{return null}return e??null}async function L(e){if(e instanceof F)return e;let t=e?.response;if(!t)return new F(`network`,P);let n=await I(t.data);return new F(typeof n?.code==`string`&&n.code?n.code:`unknown`,typeof n?.message==`string`&&n.message?n.message:P,t.status)}async function R(e){try{return(await e()).data}catch(e){throw await L(e)}}function z(e,t,n){n!=null&&String(n).trim()!==``&&e.append(t,String(n))}function B(e,t,n,r){(n??[]).forEach((n,i)=>{let a=n?.name||`${r}-${i+1}.png`;e.append(t,n,a)})}function te(e,t=`/api/support`){let n=(typeof t==`string`?t:t?.base??`/api/support`).replace(/\/+$/,``),r=e=>`${n}/tickets/${encodeURIComponent(e)}`;return{getConfig:()=>R(()=>e.get(`${n}/settings`)),listTickets:({status:t,search:r,page:i,pageSize:a}={})=>{let o=new URLSearchParams;z(o,`status`,t),z(o,`search`,r?.trim()),z(o,`page`,i),z(o,`pageSize`,a);let s=o.toString();return R(()=>e.get(`${n}/tickets${s?`?${s}`:``}`))},getTicketCounts:()=>R(()=>e.get(`${n}/tickets/counts`)),getTicket:t=>R(()=>e.get(r(t))),createTicket:({category:t,subject:r,body:i,pageUrl:a,userAgent:o,appVersion:s,files:c,screenshots:l})=>{let u=new FormData;return u.append(`category`,t??``),u.append(`subject`,r??``),u.append(`body`,i??``),z(u,`pageUrl`,a),z(u,`userAgent`,o),z(u,`appVersion`,s),B(u,`files`,c,`file`),B(u,`screenshots`,l,`screenshot`),R(()=>e.post(`${n}/tickets`,u))},reply:(t,{body:n,files:i,screenshots:a})=>{let o=new FormData;return o.append(`body`,n??``),B(o,`files`,i,`file`),B(o,`screenshots`,a,`screenshot`),R(()=>e.post(`${r(t)}/replies`,o))},reopen:t=>R(()=>e.post(`${r(t)}/reopen`)),rate:(t,{satisfaction:n,comment:i})=>{let a={satisfaction:n};return i!=null&&i.trim()!==``&&(a.comment=i.trim()),R(()=>e.post(`${r(t)}/rating`,a))},fetchAttachment:t=>R(()=>e.get(`${n}/attachments/${encodeURIComponent(t)}`,{responseType:`blob`})),confirmAction:t=>R(()=>e.post(`${n}/actions/confirm`,{token:t}))}}var V=e(null);function H(){let e=n(V);if(!e)throw Error(`Support components and hooks must be used inside <SupportProvider>.`);return e}function U(){return H().client}function W(){return H().timeZone}function G(e,n,i=!0){let[a,c]=s({data:null,loading:i,error:null}),[l,u]=s(0),d=o(e);d.current=e;let f=o(n);r(()=>{let e=f.current!==n;if(f.current=n,!i){c({data:null,loading:!1,error:null});return}let t=!0;return c(t=>({data:e?null:t.data,loading:!0,error:null})),d.current(l>0).then(e=>t&&c({data:e,loading:!1,error:null}),e=>t&&c(t=>({...t,loading:!1,error:e}))),()=>{t=!1}},[n,i,l]);let p=t(()=>u(e=>e+1),[]),m=t(e=>c(t=>({...t,data:e})),[]);return{...a,reload:p,setData:m}}function K(){let{loadConfig:e}=H(),{data:t,loading:n,error:r,reload:i}=G(e,`config`);return{config:t,loading:n,error:r,reload:i}}function ne(e={}){let t=U(),{status:n,search:r,page:i,pageSize:a}=e,{data:o,loading:s,error:c,reload:l}=G(()=>t.listTickets({status:n,search:r,page:i,pageSize:a}),JSON.stringify([`tickets`,n??null,r??null,i??null,a??null]));return{tickets:o?.items??[],totalCount:o?.totalCount??0,totalPages:o?.totalPages??0,loading:s,error:c,reload:l}}function q(){let e=U(),{data:t,loading:n,error:r,reload:i}=G(()=>e.getTicketCounts(),`ticket-counts`);return{counts:t,loading:n,error:r,reload:i}}function re(e){let n=U(),{data:r,loading:i,error:a,reload:o,setData:s}=G(()=>n.getTicket(e),e??``,!!e),c=t(async e=>{let t=await e();return s(t),t},[s]);return{ticket:r,loading:i,error:a,reload:o,reply:t(t=>c(()=>n.reply(e,t)),[c,n,e]),reopen:t(()=>c(()=>n.reopen(e)),[c,n,e]),rate:t(t=>c(()=>n.rate(e,t)),[c,n,e])}}var J=`Asia/Kolkata`,ie=[`Jan`,`Feb`,`Mar`,`Apr`,`May`,`Jun`,`Jul`,`Aug`,`Sep`,`Oct`,`Nov`,`Dec`],ae=new Map;function oe(e){let t=ae.get(e);return t||(t=new Intl.DateTimeFormat(`en-IN`,{day:`2-digit`,month:`numeric`,year:`numeric`,hour:`numeric`,minute:`2-digit`,hour12:!0,timeZone:e}),ae.set(e,t)),t}function Y(e,t=J){if(!e)return`-`;let n=new Date(e);if(Number.isNaN(n.getTime()))return`-`;let r=Object.fromEntries(oe(t).formatToParts(n).map(e=>[e.type,e.value]));return`${r.day}-${ie[Number(r.month)-1]}-${r.year}, ${r.hour}:${r.minute} ${r.dayPeriod.toUpperCase()}`}function se(e=J){return new Intl.DateTimeFormat(`en-IN`,{timeZone:e,timeZoneName:`short`}).formatToParts(new Date).find(e=>e.type===`timeZoneName`)?.value??e}function ce(e){if(!Number.isFinite(e)||e<0)return`-`;if(e<1024)return`${e} B`;if(e<1024*1024)return`${Math.round(e/1024)} KB`;let t=e/(1024*1024);return`${Number.isInteger(t)?t:t.toFixed(1)} MB`}function le(e){return(e?.allowedContentTypes??[]).join(`,`)}function ue(e,t){if(t.length===0)return!0;let n=(e||``).toLowerCase();return t.some(e=>{let t=e.toLowerCase();return t.endsWith(`/*`)?n.startsWith(t.slice(0,-1)):n===t})}function X(e,t){let n=e??[],r=t?.maxAttachmentsPerMessage??0,i=t?.maxAttachmentBytes??0,a=t?.allowedContentTypes??[];if(r>0&&n.length>r)return r===1?`You can attach one file.`:`You can attach up to ${r} files.`;for(let e of n){let t=e.name||`This file`;if(!ue(e.type,a))return`${t} is a file type we cannot accept.`;if(i>0&&e.size>i)return`${t} is larger than ${ce(i)}.`}return null}function de(e){let t=Array.from(e.clipboardData?.items??[]),n=Date.now();return t.filter(e=>e.kind===`file`&&e.type.startsWith(`image/`)).map(e=>e.getAsFile()).filter(Boolean).map((e,t)=>{let r=(e.type.split(`/`)[1]||`png`).replace(`jpeg`,`jpg`);return new File([e],`pasted-image-${n}-${t+1}.${r}`,{type:e.type})})}function fe({id:e,label:t=`Attachments`,files:n,onChange:r,config:i,error:a}){let o=i?.maxAttachmentBytes??0,s=o>0?Math.max(.1,Math.round(o/(1024*1024)*10)/10):0;return M(h,{id:e,label:t,optional:!0,multiple:!0,value:n,onChange:r,accept:le(i),maxSizeMb:s,validate:!1,error:a||void 0})}function pe(e,t){return t&&e.includes(t)?t:e[0]??``}function me({id:e,config:t,defaultCategory:n,extraFiles:r=[],onSubmit:i,onBusyChange:a,children:o}){let l=t?.categories??[],[u,d]=s(()=>pe(l,n)),[f,p]=s(``),[m,h]=s(``),[g,_]=s([]),[y,b]=s({}),[x,C]=s(``),w=e=>{_(e),b(n=>({...n,files:X([...r,...e],t)??void 0}))},T=e=>{let t=de(e);t.length>0&&w([...g,...t])};function E(){let e={};u||(e.category=`Choose a category.`),f.trim()||(e.subject=`Give your ticket a subject.`),m.trim()||(e.body=`Tell us what happened.`);let n=X([...r,...g],t);return n&&(e.files=n),b(e),Object.keys(e).length===0}async function D(e){if(e.preventDefault(),C(``),E()){a?.(!0);try{await i({category:u,subject:f.trim(),body:m.trim(),files:g})}catch(e){C(e?.message||`Your ticket did not send. Please try again.`)}finally{a?.(!1)}}}return N(`form`,{id:e,onSubmit:D,noValidate:!0,className:`d-flex flex-column gap-3`,children:[x&&M(c,{variant:`danger`,children:x}),M(S,{id:`${e}-category`,label:`Category`,required:!0,value:u,onChange:d,options:l.map(e=>({value:e,label:e})),placeholder:`Choose a category`,error:y.category}),M(v,{id:`${e}-subject`,label:`Subject`,required:!0,maxLength:t?.subjectMaxLength,placeholder:`A short summary`,value:f,onChange:e=>p(e.target.value),error:y.subject}),M(O,{id:`${e}-body`,label:`Message`,required:!0,rows:6,maxLength:t?.bodyMaxLength,placeholder:`What happened, and what did you expect to happen?`,value:m,onChange:e=>h(e.target.value),onPaste:T,hint:`You can paste an image into the message.`,error:y.body}),o,M(fe,{id:`${e}-files`,files:g,onChange:w,config:t,error:y.files})]})}var he=`supportCapture`,ge={zIndex:`var(--wui-z-fixed)`,bottom:0,insetInlineEnd:0},_e=e=>e?.dataset?.[he]!==`exclude`;async function ve(){let e=await A(document.body,{filter:_e,pixelRatio:Math.min(window.devicePixelRatio||1,2)});if(!e)throw Error(`The page capture came back empty.`);return new File([e],`screenshot.png`,{type:`image/png`})}function ye({file:e,onRemove:t}){let[n,i]=s(null);return r(()=>{let t=URL.createObjectURL(e);return i(t),()=>URL.revokeObjectURL(t)},[e]),N(`figure`,{className:`mb-0 d-flex flex-column gap-2`,children:[M(`figcaption`,{className:`wui-text-sm fw-semibold`,children:`Screenshot of this page`}),n&&M(`img`,{src:n,alt:`Screenshot of the page you were on`,className:`d-block w-100 border rounded`}),M(d,{variant:`ghost`,size:`sm`,leftIcon:`x`,onClick:t,className:`align-self-start`,children:`Remove screenshot`})]})}function be({label:e=`Report an issue`,floating:t=!1,compact:n=!1,defaultCategory:r=`Bug report`,appVersion:a,getTicketHref:o,onOpenTicket:l,onCreated:u,className:f,style:p}){let m=U(),{config:h,error:_}=K(),v=`support-report-${i().replace(/[^a-zA-Z0-9-]/g,``)}`,[y,x]=s(!1),[S,C]=s(!1),[w,T]=s(null),[E,D]=s(!1),[O,A]=s(!1),[P,F]=s(null),I=k(`end`,t&&n);async function L(){C(!0),F(null);try{T(await ve()),D(!1)}catch{T(null),D(!0)}finally{C(!1),x(!0)}}let R=()=>{O||(x(!1),T(null),F(null))};async function z(e){let t=await m.createTicket({...e,pageUrl:window.location.href,userAgent:navigator.userAgent,appVersion:a,screenshots:w?[w]:[]});F(t),T(null),u?.(t)}let B=P&&o?o(P.id):void 0,te=P?N(`div`,{className:`d-flex justify-content-end gap-2 w-100`,children:[M(d,{variant:`secondary`,onClick:R,children:`Close`}),P&&(B||l)?M(d,{href:B,onClick:B?void 0:()=>{x(!1),F(null),l(P)},children:`View ticket`}):null]}):N(`div`,{className:`d-flex justify-content-end gap-2 w-100`,children:[M(d,{variant:`secondary`,onClick:R,disabled:O,children:`Cancel`}),M(d,{type:`submit`,form:v,loading:O,disabled:!h,children:`Send report`})]}),V=n?M(d,{variant:`secondary`,className:`wui-floating-btn wui-floating-btn--secondary`,loading:S,onClick:L,"aria-haspopup":`dialog`,"aria-label":e,tooltip:e,tooltipPlacement:`start`,children:M(g,{name:`bug`,size:22})}):M(d,{leftIcon:`bug`,variant:t?`primary`:`outline`,loading:S,onClick:L,"aria-haspopup":`dialog`,children:e});return N(ee,{children:[t&&n?I&&j(M(`span`,{className:[`wui-floating-stack-item wui-floating-stack-item--secondary`,f].filter(Boolean).join(` `),style:p,children:V}),I):M(`span`,{"data-support-capture":`exclude`,className:[t?`position-fixed m-3`:`d-inline-block`,f].filter(Boolean).join(` `),style:t?{...ge,...p}:p,children:V}),M(b,{open:y,size:`lg`,title:`Report an issue`,subtitle:`Tell us what went wrong. We attach a screenshot of this page to help us see it.`,headerIcon:`bug`,staticBackdrop:!0,onClose:R,footer:te,children:P?M(c,{variant:`success`,role:`status`,title:`Ticket ${P.number} is with the support team`,children:`We reply by email. You can follow the ticket on your support page.`}):h?M(me,{id:v,config:h,defaultCategory:r,extraFiles:w?[w]:[],onSubmit:z,onBusyChange:A,children:w?M(ye,{file:w,onRemove:()=>T(null)}):E?M(c,{variant:`info`,children:`We could not take a screenshot of this page. You can attach an image instead.`}):null}):M(c,{variant:_?`danger`:`info`,children:_?_.message||`We could not load the support settings.`:`Loading the form.`})})]})}function xe({open:e,onClose:t,onCreated:n,config:r,defaultCategory:a,appVersion:o}){let c=U(),l=`support-new-${i().replace(/[^a-zA-Z0-9-]/g,``)}`,[u,f]=s(!1);async function p(e){n(await c.createTicket({...e,userAgent:typeof navigator>`u`?void 0:navigator.userAgent,appVersion:o}))}return M(b,{open:e,size:`lg`,title:`New ticket`,subtitle:`Tell us what you need. We reply by email and on this page.`,headerIcon:`message-square`,staticBackdrop:!0,onClose:()=>{u||t()},footer:N(`div`,{className:`d-flex justify-content-end gap-2 w-100`,children:[M(d,{variant:`secondary`,onClick:t,disabled:u,children:`Cancel`}),M(d,{type:`submit`,form:l,loading:u,children:`Send ticket`})]}),children:e&&M(me,{id:l,config:r,defaultCategory:a,onSubmit:p,onBusyChange:f})})}var Se={Open:`warning`,InProgress:`info`,Resolved:`success`,Closed:`neutral`};function Ce(e){return Se[e]??`neutral`}var we={width:140,maxWidth:`100%`},Te={height:84};function Ee({attachment:e}){let t=U(),n=(e.contentType||``).startsWith(`image/`),[i,a]=s(null),[o,c]=s(!1);r(()=>{let n=!0,r=null;return a(null),c(!1),t.fetchAttachment(e.id).then(e=>{r=URL.createObjectURL(e),n?a(r):URL.revokeObjectURL(r)},()=>n&&c(!0)),()=>{n=!1,r&&URL.revokeObjectURL(r)}},[t,e.id]);let l=`Open ${e.fileName}`,u=N(`span`,{className:`d-block text-truncate px-2 py-1 wui-text-xs text-body-secondary`,children:[e.fileName,`, `,ce(e.sizeBytes)]});return o?N(`span`,{className:`d-inline-flex flex-column border rounded overflow-hidden`,style:we,children:[N(`span`,{className:`d-flex align-items-center justify-content-center gap-1 p-2 wui-text-xs text-body-secondary`,children:[M(g,{name:`x-circle`,size:14}),`Could not load this file.`]}),u]}):N(`a`,{className:`d-inline-flex flex-column border rounded overflow-hidden text-decoration-none`,style:we,href:i??void 0,target:`_blank`,rel:`noopener noreferrer`,"aria-label":l,"aria-busy":!i||void 0,children:[M(`span`,{className:`d-flex align-items-center justify-content-center bg-body-tertiary`,style:Te,children:i?n?M(`img`,{src:i,alt:e.fileName,className:`d-block w-100 h-100 object-fit-cover`}):M(g,{name:`file-text`,size:28}):M(w,{size:`sm`,label:`Loading ${e.fileName}`})}),u]})}var De={whiteSpace:`pre-wrap`,overflowWrap:`anywhere`};function Oe({messages:e}){let t=W();return M(`ol`,{className:`list-unstyled d-flex flex-column gap-3 mb-0`,"aria-label":`Conversation`,children:e.map(e=>{let n=M(`time`,{dateTime:e.createdDateTimeUtc,className:`wui-text-xs text-body-secondary text-nowrap`,children:Y(e.createdDateTimeUtc,t)});if(e.authorKind===`System`)return N(`li`,{className:`text-center wui-text-xs text-body-secondary`,"data-author":`system`,children:[M(`span`,{className:`d-block`,children:e.body}),n]},e.id);let r=e.authorKind===`Customer`,i=e.authorName||(r?`You`:`Support team`);return N(`li`,{className:`d-flex align-items-start gap-2${r?` flex-row-reverse`:``}`,"data-author":r?`customer`:`agent`,children:[M(l,{name:i,size:32,tone:r?`neutral`:`primary`}),N(f,{className:`flex-grow-1 border`,padding:`sm`,variant:r?`default`:`accent`,style:{minWidth:0},children:[N(`div`,{className:`d-flex flex-wrap align-items-center justify-content-between gap-2 mb-2`,children:[N(`span`,{className:`d-inline-flex flex-wrap align-items-center gap-2 fw-semibold wui-text-sm text-break`,children:[i,!r&&M(u,{tone:`primary`,children:`Support`})]}),n]}),M(`div`,{className:`wui-text-sm`,style:De,children:e.body}),e.attachments?.length>0&&M(`div`,{className:`d-flex flex-wrap gap-2 mt-2`,children:e.attachments.map(e=>M(Ee,{attachment:e},e.id))})]})]},e.id)})})}function ke({satisfaction:e,comment:t,canRate:n=!1,commentMaxLength:r,onRate:a}){let o=i(),[l,u]=s(``),[p,m]=s(null),[h,g]=s(``);if(e)return N(c,{variant:e===`Satisfied`?`success`:`info`,role:`status`,children:[e===`Satisfied`?`You told us this solved your problem.`:`You told us this did not solve your problem.`,t?N(`span`,{className:`d-block mt-1`,children:[`Your comment: `,t]}):null]});if(!n)return null;async function _(e){g(``),m(e);try{await a({satisfaction:e,comment:l})}catch(e){g(e?.message||`Your rating did not send. Please try again.`)}finally{m(null)}}return M(f,{padding:`sm`,className:`border`,title:`Did this solve your problem?`,children:N(`div`,{className:`d-flex flex-column gap-2`,children:[h&&M(c,{variant:`danger`,children:h}),M(O,{id:`${o}-comment`,label:`Anything to add?`,rows:2,maxLength:r,value:l,onChange:e=>u(e.target.value),hint:`Optional. Your comment goes to the support team.`}),N(`div`,{className:`d-flex flex-wrap gap-2`,children:[M(d,{variant:`outline`,leftIcon:`check-circle`,loading:p===`Satisfied`,disabled:p!==null,onClick:()=>_(`Satisfied`),children:`Yes, it is solved`}),M(d,{variant:`outline`,leftIcon:`x-circle`,loading:p===`Unsatisfied`,disabled:p!==null,onClick:()=>_(`Unsatisfied`),children:`No, it is not`})]})]})})}function Ae({onSend:e,config:t,reopens:n=!1}){let r=i(),[a,o]=s(``),[l,u]=s([]),[f,p]=s(``),[m,h]=s(``),[g,_]=s(!1),v=e=>{u(e),p(X(e,t)??``)},y=e=>{let t=de(e);t.length>0&&v([...l,...t])};async function b(n){n.preventDefault();let r=a.trim();if(!r){h(`Write a message before you send it.`);return}let i=X(l,t);if(i){p(i);return}h(``),_(!0);try{await e({body:r,files:l}),o(``),u([]),p(``)}catch(e){h(e?.message||`Your reply did not send. Please try again.`)}finally{_(!1)}}return N(`form`,{onSubmit:b,noValidate:!0,className:`d-flex flex-column gap-2`,"aria-label":`Reply to this ticket`,children:[m&&M(c,{variant:`danger`,children:m}),M(O,{id:`${r}-body`,label:`Your reply`,rows:4,autoGrow:!0,maxLength:t?.bodyMaxLength,value:a,onChange:e=>o(e.target.value),onPaste:y,hint:n?`Sending a reply reopens this ticket. You can paste an image into the message.`:`You can paste an image into the message.`,required:!0}),M(fe,{id:`${r}-files`,files:l,onChange:v,config:t,error:f}),M(`div`,{className:`d-flex justify-content-end`,children:M(d,{type:`submit`,leftIcon:`send`,loading:g,children:`Send reply`})})]})}function Z({label:e,children:t}){return N(`div`,{className:`d-flex flex-column`,children:[M(`span`,{className:`wui-text-xs fw-semibold text-body-secondary`,children:e}),M(`span`,{className:`wui-text-sm`,children:t})]})}function je({ticketId:e,onBack:t,onChanged:n}){let{config:r}=K(),i=W(),{ticket:a,loading:o,error:l,reload:u,reply:f,reopen:p,rate:m}=re(e),[h,g]=s(!1),[_,v]=s(``),y=async e=>{let t=await e();return n?.(),t};async function b(){v(``),g(!0);try{await y(p)}catch(e){v(e?.message||`The ticket did not reopen. Please try again.`)}finally{g(!1)}}let x=M(d,{variant:`ghost`,size:`sm`,leftIcon:`arrow-left`,onClick:t,className:`align-self-start`,children:`Back to tickets`});if(!a)return N(`section`,{className:`d-flex flex-column gap-3`,"aria-busy":o||void 0,children:[x,l?N(c,{variant:`danger`,children:[l.message||`We could not load this ticket.`,` `,M(d,{variant:`ghost`,size:`sm`,onClick:u,children:`Try again`})]}):M(C,{height:160})]});let S=a.status===`Resolved`||a.status===`Closed`;return N(`section`,{className:`d-flex flex-column gap-3`,"aria-labelledby":`support-ticket-${a.id}`,children:[x,N(`header`,{className:`d-flex flex-column gap-2`,children:[N(`div`,{className:`d-flex flex-wrap align-items-center gap-2`,children:[M(`h2`,{id:`support-ticket-${a.id}`,className:`h5 mb-0 text-break`,children:a.subject}),a.statusLabel&&M(T,{label:a.statusLabel,tone:Ce(a.status)})]}),N(`div`,{className:`row row-cols-2 row-cols-md-4 g-3`,children:[M(Z,{label:`Ticket`,children:a.number}),M(Z,{label:`Category`,children:a.category||`-`}),M(Z,{label:`Opened`,children:M(`time`,{dateTime:a.createdDateTimeUtc,children:Y(a.createdDateTimeUtc,i)})}),M(Z,{label:`Last update`,children:M(`time`,{dateTime:a.updatedDateTimeUtc,children:Y(a.updatedDateTimeUtc,i)})})]}),N(`p`,{className:`wui-text-xs text-body-secondary mb-0`,children:[`Times are shown in `,se(i),`.`]})]}),_&&M(c,{variant:`danger`,children:_}),S&&M(c,{variant:`success`,role:`status`,children:`If you still need help, reopen the ticket or send a reply.`}),a.canReopen&&M(d,{variant:`secondary`,leftIcon:`history`,loading:h,onClick:b,className:`align-self-start`,children:`Reopen ticket`}),M(ke,{satisfaction:a.satisfaction,comment:a.satisfactionComment,canRate:a.canRate,commentMaxLength:r?.satisfactionCommentMaxLength,onRate:e=>y(()=>m(e))}),M(Oe,{messages:a.messages??[]}),M(Ae,{config:r,reopens:S,onSend:e=>y(()=>f(e))})]})}var Q=`ticket`;function Me(){return typeof window>`u`?null:new URLSearchParams(window.location.search).get(Q)}function Ne(e){if(typeof window>`u`)return e?`?${Q}=${encodeURIComponent(e)}`:`?`;let t=new URL(window.location.href);return e?t.searchParams.set(Q,e):t.searchParams.delete(Q),`${t.pathname}${t.search}${t.hash}`}function Pe(e){if(typeof window>`u`)return;let t=Ne(e);t!==`${window.location.pathname}${window.location.search}${window.location.hash}`&&window.history.replaceState(window.history.state,``,t)}var Fe=[{key:`all`,label:`All`,countKey:`total`},{key:`Open`,label:`Open`,countKey:`open`},{key:`InProgress`,label:`In progress`,countKey:`inProgress`},{key:`Resolved`,label:`Resolved`,countKey:`resolved`},{key:`Closed`,label:`Closed`,countKey:`closed`}];function Ie({tickets:e,loading:t,error:n,onRetry:r,onOpen:i,status:a,onStatusChange:o,counts:s,search:l,onSearchChange:u,pagination:f}){let p=W();return N(`div`,{className:`d-flex flex-column gap-3`,children:[n&&N(c,{variant:`danger`,children:[n.message||`We could not load your tickets.`,` `,M(d,{variant:`ghost`,size:`sm`,onClick:r,children:`Try again`})]}),N(`div`,{className:`d-flex flex-column flex-md-row gap-2 align-items-md-center justify-content-between`,children:[M(D,{tabs:Fe.map(({key:e,label:t,countKey:n})=>({key:e,label:t,count:s?.[n]})),value:a,onChange:o,ariaLabel:`Filter tickets by status`,className:`flex-grow-1`}),M(x,{value:l,onChange:u,placeholder:`Search tickets`,ariaLabel:`Search tickets`})]}),M(m,{columns:[{key:`subject`,label:`Subject`,render:e=>N(`div`,{className:`d-flex flex-column`,style:{minWidth:0},children:[M(y,{href:Ne(e.id),animation:`none`,className:`fw-semibold text-break`,onClick:t=>{t.metaKey||t.ctrlKey||t.shiftKey||t.altKey||(t.preventDefault(),i(e.id))},children:e.subject}),N(`span`,{className:`wui-text-xs text-body-secondary`,children:[e.number,`, `,e.category,e.awaitingCustomer?`. Waiting for your reply`:``]})]})},{key:`status`,label:`Status`,render:e=>e.statusLabel?M(T,{label:e.statusLabel,tone:Ce(e.status)}):`-`},{key:`messageCount`,label:`Messages`,cellClassName:`wui-text-sm text-body-secondary`,render:e=>e.messageCount},{key:`updatedDateTimeUtc`,label:`Last update`,cellClassName:`wui-text-sm text-body-secondary text-nowrap`,render:e=>M(`time`,{dateTime:e.updatedDateTimeUtc,children:Y(e.updatedDateTimeUtc,p)})}],rows:e,loading:t,skeletonRows:4,ariaLabel:`Support tickets`,sourceCount:s?.total??0,pagination:f,empty:M(E,{icon:`message-square`,title:`No tickets yet`,text:`When you raise a ticket, it shows here with its status.`}),emptyFiltered:M(E,{icon:`search`,title:`No tickets match`,text:`Try another search or status.`})})]})}function Le(e,t){let[n,i]=s(e);return r(()=>{let n=setTimeout(()=>i(e),t);return()=>clearTimeout(n)},[e,t]),n}var Re=300,ze=10;function Be({initialTicketId:e,defaultCategory:t,appVersion:n}){let{config:i,error:a,reload:o}=K(),[l,u]=s(`all`),[f,p]=s(``),m=Le(f.trim(),Re),[h,g]=s(ze),_=`${l}|${m}|${h}`,[v,y]=s({key:_,page:1}),b=v.key===_?v.page:1,x=e=>y({key:_,page:e}),S=ne({status:l===`all`?void 0:l,search:m||void 0,page:b,pageSize:h}),{counts:C,reload:w}=q(),[T,E]=s(()=>e||Me()),[D,O]=s(!1),k=S.totalPages;r(()=>{k>0&&b>k&&y({key:_,page:k})},[k,b,_]);let A=()=>{S.reload(),w()},j=e=>{E(e),Pe(e)};if(T)return M(je,{ticketId:T,onBack:()=>j(null),onChanged:A},T);let ee={page:b,totalPages:Math.max(1,S.totalPages),pageSize:h,total:S.totalCount,setPage:x,setPageSize:g};return N(`section`,{className:`d-flex flex-column gap-3`,"aria-labelledby":`support-center-title`,children:[N(`div`,{className:`d-flex flex-wrap align-items-center justify-content-between gap-2`,children:[M(`h2`,{id:`support-center-title`,className:`h5 mb-0`,children:`Your tickets`}),M(d,{leftIcon:`plus`,onClick:()=>O(!0),disabled:!i,children:`New ticket`})]}),a&&N(c,{variant:`warning`,children:[a.message||`We could not load the support settings.`,` `,M(d,{variant:`ghost`,size:`sm`,onClick:o,children:`Try again`})]}),M(Ie,{tickets:S.tickets,loading:S.loading,error:S.error,onRetry:A,onOpen:j,status:l,onStatusChange:u,counts:C,search:f,onSearchChange:p,pagination:ee}),i&&M(xe,{open:D,onClose:()=>O(!1),config:i,defaultCategory:t,appVersion:n,onCreated:e=>{O(!1),A(),j(e.id)}})]})}var $=e=>typeof e==`string`&&e.trim()!==``;function Ve({className:e}){let{config:t}=K();if(!t)return null;let n=[];return $(t.supportEmail)&&n.push({key:`email`,icon:`mail`,label:`Email`,value:N(`span`,{className:`d-inline-flex flex-wrap align-items-center gap-2`,children:[M(`a`,{href:`mailto:${t.supportEmail}`,className:`text-break`,children:t.supportEmail}),M(p,{text:t.supportEmail,size:`sm`,label:`Copy email`,copiedLabel:`Email copied`})]})}),$(t.supportPhone)&&n.push({key:`phone`,icon:`phone`,label:`Phone`,value:t.supportPhone,href:`tel:${t.supportPhone.replace(/[^\d+]/g,``)}`}),$(t.supportHours)&&n.push({key:`hours`,icon:`clock`,label:`Hours`,value:t.supportHours}),n.length===0?null:N(`section`,{className:e,"aria-label":$(t.supportName)?`Contact ${t.supportName}`:`Contact support`,children:[$(t.supportName)&&M(`p`,{className:`fw-semibold mb-2`,children:t.supportName}),M(_,{items:n})]})}function He({client:e,timeZone:n=J,children:r}){let i=o(null),s=t((t=!1)=>{let n=i.current;if(t||!n||n.client!==e){let t=e.getConfig(),n={client:e,pending:t};return i.current=n,t.catch(()=>{i.current===n&&(i.current=null)}),t}return n.pending},[e]),c=a(()=>({client:e,loadConfig:s,timeZone:n}),[e,s,n]);return M(V.Provider,{value:c,children:r})}export{be as ReportIssue,F as SupportApiError,Be as SupportCenter,Ve as SupportContact,He as SupportProvider,te as createSupportClient,U as useSupportClient,K as useSupportConfig,re as useSupportTicket,q as useSupportTicketCounts,ne as useSupportTickets};