@lightworkai.official/debug-capture-react 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +14 -12
  2. package/dist/SupportPortalButton.d.ts +20 -0
  3. package/dist/index.d.ts +3 -9
  4. package/dist/index.mjs +48 -1560
  5. package/package.json +2 -2
  6. package/src/SupportPortalButton.tsx +80 -0
  7. package/src/index.ts +12 -11
  8. package/dist/components/ImageAnnotatorDialog.d.ts +0 -11
  9. package/dist/components/MyTicketsPanel.d.ts +0 -11
  10. package/dist/components/ReopenPanel.d.ts +0 -7
  11. package/dist/components/RichReplyEditor.d.ts +0 -29
  12. package/dist/components/StatusHero.d.ts +0 -8
  13. package/dist/components/StatusPill.d.ts +0 -14
  14. package/dist/components/TicketBody.d.ts +0 -5
  15. package/dist/components/TicketConversation.d.ts +0 -13
  16. package/dist/components/TicketDetail.d.ts +0 -23
  17. package/dist/components/TicketScreenshots.d.ts +0 -6
  18. package/dist/components/TicketTable.d.ts +0 -18
  19. package/dist/components/TicketTimeline.d.ts +0 -14
  20. package/dist/components/ToolbarButton.d.ts +0 -18
  21. package/dist/components/icons.d.ts +0 -35
  22. package/src/components/ImageAnnotatorDialog.tsx +0 -160
  23. package/src/components/MyTicketsPanel.tsx +0 -321
  24. package/src/components/ReopenPanel.tsx +0 -52
  25. package/src/components/RichReplyEditor.tsx +0 -264
  26. package/src/components/StatusHero.tsx +0 -92
  27. package/src/components/StatusPill.tsx +0 -14
  28. package/src/components/TicketBody.tsx +0 -50
  29. package/src/components/TicketConversation.tsx +0 -177
  30. package/src/components/TicketDetail.tsx +0 -110
  31. package/src/components/TicketScreenshots.tsx +0 -41
  32. package/src/components/TicketTable.tsx +0 -161
  33. package/src/components/TicketTimeline.tsx +0 -81
  34. package/src/components/ToolbarButton.tsx +0 -37
  35. package/src/components/icons.tsx +0 -79
package/dist/index.mjs CHANGED
@@ -124,1566 +124,60 @@ class DebugErrorBoundary extends Component {
124
124
  function reportBoundaryError(error) {
125
125
  import("@lightworkai.official/debug-capture").then(({ launch: launch2 }) => launch2({ type: "framework-error", message: error.message, stack: error.stack }));
126
126
  }
127
- // src/components/MyTicketsPanel.tsx
128
- import { useCallback as useCallback2, useEffect as useEffect6, useMemo as useMemo2, useRef as useRef5, useState as useState7 } from "react";
129
- import {
130
- NoIdentityError,
131
- fetchRealmConfig,
132
- getAttachmentUrl,
133
- getConfig,
134
- getMyTicket,
135
- getMyTicketHistory,
136
- listMyTickets,
137
- reopenMyTicket,
138
- replyToTicket,
139
- statusMaps,
140
- ticketStrings,
141
- uploadInlineImage
142
- } from "@lightworkai.official/debug-capture";
143
-
144
- // src/components/TicketTable.tsx
145
- import { useMemo } from "react";
146
- import {
147
- compareBy,
148
- formatDateTime,
149
- hasSolution,
150
- hasTeamReply,
151
- matchesKeyword,
152
- pageCount,
153
- pageOf,
154
- statusTone,
155
- ticketKey
156
- } from "@lightworkai.official/debug-capture";
157
-
158
- // src/components/StatusPill.tsx
127
+ // src/SupportPortalButton.tsx
128
+ import { useState } from "react";
129
+ import { openSupportPortal, showToast } from "@lightworkai.official/debug-capture";
159
130
  import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
160
- function StatusPill({ label, tone }) {
161
- return /* @__PURE__ */ jsxDEV2("span", {
162
- className: "lw-status",
163
- style: { background: tone.bg, color: tone.fg },
164
- children: label
165
- }, undefined, false, undefined, this);
166
- }
167
-
168
- // src/components/icons.tsx
169
- import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
170
- function glyph(paths, size = 15) {
171
- return function Icon(props) {
172
- return /* @__PURE__ */ jsxDEV3("svg", {
173
- width: size,
174
- height: size,
175
- viewBox: "0 0 24 24",
176
- fill: "none",
177
- stroke: "currentColor",
178
- strokeWidth: 2,
179
- strokeLinecap: "round",
180
- strokeLinejoin: "round",
181
- "aria-hidden": "true",
182
- ...props,
183
- children: paths.map((d) => /* @__PURE__ */ jsxDEV3("path", {
184
- d
185
- }, d, false, undefined, this))
186
- }, undefined, false, undefined, this);
187
- };
188
- }
189
- var BoldIcon = glyph(["M6 4h8a4 4 0 0 1 0 8H6z", "M6 12h9a4 4 0 0 1 0 8H6z"]);
190
- var ItalicIcon = glyph(["M19 4h-9", "M14 20H5", "M15 4L9 20"]);
191
- var UnderlineIcon = glyph(["M6 4v6a6 6 0 0 0 12 0V4", "M4 20h16"]);
192
- var BulletListIcon = glyph(["M8 6h13", "M8 12h13", "M8 18h13", "M3 6h.01", "M3 12h.01", "M3 18h.01"]);
193
- var OrderedListIcon = glyph(["M10 6h11", "M10 12h11", "M10 18h11", "M4 6h1v4", "M4 10h2", "M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"]);
194
- var LinkIcon = glyph([
195
- "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71",
196
- "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"
197
- ]);
198
- var ImageIcon = glyph([
199
- "M19 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z",
200
- "M8.5 10a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z",
201
- "M21 15l-5-5L5 21"
202
- ]);
203
- var SendIcon = glyph(["M22 2L11 13", "M22 2l-7 20-4-9-9-4 20-7z"]);
204
- var SearchIcon = glyph(["M21 21l-4.34-4.34", "M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16z"], 16);
205
- var ArrowLeftIcon = glyph(["M19 12H5", "M12 19l-7-7 7-7"], 14);
206
- var CheckIcon = glyph(["M20 6L9 17l-5-5"], 12);
207
- var MessageIcon = glyph(["M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"], 12);
208
- var RotateIcon = glyph(["M3 12a9 9 0 1 0 3-6.7L3 8", "M3 3v5h5"], 14);
209
- var AlertIcon = glyph(["M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20z", "M12 8v4", "M12 16h.01"], 16);
210
- var InboxIcon = glyph([
211
- "M22 12h-6l-2 3h-4l-2-3H2",
212
- "M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"
213
- ], 22);
214
- var ClockIcon = glyph(["M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20z", "M12 6v6l4 2"], 22);
215
- var CheckCircleIcon = glyph(["M22 11.08V12a10 10 0 1 1-5.93-9.14", "M22 4L12 14.01l-3-3"], 22);
216
- var BanIcon = glyph(["M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20z", "M4.93 4.93l14.14 14.14"], 22);
217
- var WrenchIcon = glyph([
218
- "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"
219
- ], 16);
220
- var SquareIcon = glyph(["M19 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z"], 14);
221
- var ArrowUpRightIcon = glyph(["M7 17L17 7", "M7 7h10v10"], 14);
222
- var HighlighterIcon = glyph([
223
- "M9 11l-6 6v3h9l3-3",
224
- "M22 12l-4.6 4.6a2 2 0 0 1-2.8 0l-5.2-5.2a2 2 0 0 1 0-2.8L14 4"
225
- ], 14);
226
- var TypeIcon = glyph(["M4 7V4h16v3", "M9 20h6", "M12 4v16"], 14);
227
- var TrashIcon = glyph([
228
- "M3 6h18",
229
- "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"
230
- ], 14);
231
- var PencilIcon = glyph(["M12 20h9", "M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"], 11);
232
- var CheckSmallIcon = glyph(["M20 6L9 17l-5-5"], 12);
233
- var XSmallIcon = glyph(["M18 6L6 18", "M6 6l12 12"], 12);
234
-
235
- // src/components/TicketTable.tsx
236
- import { jsxDEV as jsxDEV4, Fragment } from "react/jsx-dev-runtime";
237
- var COLUMNS = [
238
- { key: "number", label: "colNumber", width: "120px" },
239
- { key: "title", label: "colTitle" },
240
- { key: "module", label: "colModule", width: "160px" },
241
- { key: "status", label: "colStatus", width: "130px" },
242
- { key: "response", label: "colResponse", width: "150px" },
243
- { key: "createdAt", label: "colCreated", width: "170px" },
244
- { key: "updatedAt", label: "colUpdated", width: "170px" }
245
- ];
246
- function TicketTable(props) {
247
- const { items, maps, t, slug, timezone, locale, keyword, statusFilter, sort, page } = props;
248
- const visible = useMemo(() => items.filter((item) => statusFilter ? item.status === statusFilter : true).filter((item) => matchesKeyword(item, keyword, slug, maps.labelOf)).sort(compareBy(sort, maps, slug)), [items, statusFilter, keyword, slug, maps, sort]);
249
- const pages = pageCount(visible.length);
250
- const current = Math.min(page, pages);
251
- const rows = pageOf(visible, current);
252
- props.onCount?.(visible.length);
253
- const when = (iso) => formatDateTime(iso, timezone, locale);
254
- return /* @__PURE__ */ jsxDEV4(Fragment, {
255
- children: [
256
- /* @__PURE__ */ jsxDEV4("div", {
257
- className: "lw-tablewrap",
258
- children: /* @__PURE__ */ jsxDEV4("table", {
259
- className: "lw-table",
260
- children: [
261
- /* @__PURE__ */ jsxDEV4("thead", {
262
- children: /* @__PURE__ */ jsxDEV4("tr", {
263
- children: COLUMNS.map((column) => /* @__PURE__ */ jsxDEV4("th", {
264
- scope: "col",
265
- className: "lw-th",
266
- style: column.width ? { width: column.width } : undefined,
267
- "aria-sort": sort.key === column.key ? sort.direction === "asc" ? "ascending" : "descending" : undefined,
268
- onClick: () => props.onSort(column.key),
269
- children: [
270
- t[column.label],
271
- " ",
272
- /* @__PURE__ */ jsxDEV4("span", {
273
- className: "lw-arrow",
274
- children: sort.key === column.key ? sort.direction === "asc" ? "▲" : "▼" : "⇅"
275
- }, undefined, false, undefined, this)
276
- ]
277
- }, column.key, true, undefined, this))
278
- }, undefined, false, undefined, this)
279
- }, undefined, false, undefined, this),
280
- /* @__PURE__ */ jsxDEV4("tbody", {
281
- children: rows.length === 0 ? /* @__PURE__ */ jsxDEV4("tr", {
282
- children: /* @__PURE__ */ jsxDEV4("td", {
283
- colSpan: COLUMNS.length,
284
- className: "lw-empty",
285
- children: items.length === 0 ? t.empty : t.emptyFiltered
286
- }, undefined, false, undefined, this)
287
- }, undefined, false, undefined, this) : rows.map((row) => /* @__PURE__ */ jsxDEV4("tr", {
288
- className: "lw-row",
289
- tabIndex: 0,
290
- onClick: () => props.onOpen(row.id),
291
- onKeyDown: (event) => {
292
- if (event.key === "Enter" || event.key === " ") {
293
- event.preventDefault();
294
- props.onOpen(row.id);
295
- }
296
- },
297
- children: [
298
- /* @__PURE__ */ jsxDEV4("td", {
299
- className: "lw-num",
300
- children: ticketKey(slug, row.number)
301
- }, undefined, false, undefined, this),
302
- /* @__PURE__ */ jsxDEV4("td", {
303
- className: "lw-title",
304
- children: row.title
305
- }, undefined, false, undefined, this),
306
- /* @__PURE__ */ jsxDEV4("td", {
307
- children: row.category ? /* @__PURE__ */ jsxDEV4("span", {
308
- className: "lw-chip",
309
- children: row.category
310
- }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV4("span", {
311
- className: "lw-dash",
312
- children: "—"
313
- }, undefined, false, undefined, this)
314
- }, undefined, false, undefined, this),
315
- /* @__PURE__ */ jsxDEV4("td", {
316
- children: maps.isAwaitingReply(row.status) ? /* @__PURE__ */ jsxDEV4("span", {
317
- className: "lw-pill lw-pill--awaiting",
318
- children: [
319
- /* @__PURE__ */ jsxDEV4(MessageIcon, {}, undefined, false, undefined, this),
320
- " ",
321
- t.awaitingReply
322
- ]
323
- }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV4(StatusPill, {
324
- label: maps.labelOf(row.status),
325
- tone: statusTone(maps.columnOf(row.status)?.color)
326
- }, undefined, false, undefined, this)
327
- }, undefined, false, undefined, this),
328
- /* @__PURE__ */ jsxDEV4("td", {
329
- children: hasSolution(row) ? /* @__PURE__ */ jsxDEV4("span", {
330
- className: "lw-pill lw-pill--solution",
331
- children: [
332
- /* @__PURE__ */ jsxDEV4(CheckIcon, {}, undefined, false, undefined, this),
333
- " ",
334
- t.hasSolution
335
- ]
336
- }, undefined, true, undefined, this) : hasTeamReply(row) ? /* @__PURE__ */ jsxDEV4("span", {
337
- className: "lw-pill lw-pill--replied",
338
- children: [
339
- /* @__PURE__ */ jsxDEV4(MessageIcon, {}, undefined, false, undefined, this),
340
- " ",
341
- t.hasReply
342
- ]
343
- }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV4("span", {
344
- className: "lw-muted",
345
- children: t.noReply
346
- }, undefined, false, undefined, this)
347
- }, undefined, false, undefined, this),
348
- /* @__PURE__ */ jsxDEV4("td", {
349
- className: "lw-dim",
350
- children: when(row.createdAt)
351
- }, undefined, false, undefined, this),
352
- /* @__PURE__ */ jsxDEV4("td", {
353
- className: "lw-dim",
354
- children: when(row.updatedAt)
355
- }, undefined, false, undefined, this)
356
- ]
357
- }, row.id, true, undefined, this))
358
- }, undefined, false, undefined, this)
359
- ]
360
- }, undefined, true, undefined, this)
361
- }, undefined, false, undefined, this),
362
- (visible.length > rows.length || current > 1) && /* @__PURE__ */ jsxDEV4("div", {
363
- className: "lw-pager",
364
- children: [
365
- /* @__PURE__ */ jsxDEV4("span", {
366
- children: t.of(current, pages)
367
- }, undefined, false, undefined, this),
368
- /* @__PURE__ */ jsxDEV4("button", {
369
- type: "button",
370
- className: "lw-btn",
371
- disabled: current <= 1,
372
- onClick: () => props.onPage(current - 1),
373
- children: t.prev
374
- }, undefined, false, undefined, this),
375
- /* @__PURE__ */ jsxDEV4("button", {
376
- type: "button",
377
- className: "lw-btn",
378
- disabled: current >= pages,
379
- onClick: () => props.onPage(current + 1),
380
- children: t.next
381
- }, undefined, false, undefined, this)
382
- ]
383
- }, undefined, true, undefined, this)
384
- ]
385
- }, undefined, true, undefined, this);
386
- }
387
-
388
- // src/components/TicketDetail.tsx
389
- import {
390
- formatDateTime as formatDateTime4,
391
- ticketKey as ticketKey2
392
- } from "@lightworkai.official/debug-capture";
393
-
394
- // src/components/TicketBody.tsx
395
- import { useEffect as useEffect2, useRef, useState } from "react";
396
- import { renderBody } from "@lightworkai.official/debug-capture";
397
- import { jsxDEV as jsxDEV5, Fragment as Fragment2 } from "react/jsx-dev-runtime";
398
- function TicketBody({ html, host, className }) {
399
- const target = useRef(null);
400
- const [zoomed, setZoomed] = useState(null);
401
- useEffect2(() => {
402
- if (target.current)
403
- renderBody(target.current, html, host);
404
- }, [html, host]);
405
- return /* @__PURE__ */ jsxDEV5(Fragment2, {
406
- children: [
407
- /* @__PURE__ */ jsxDEV5("div", {
408
- ref: target,
409
- className: className ? `lw-body ${className}` : "lw-body",
410
- onClick: (event) => {
411
- const node = event.target;
412
- if (node.tagName !== "IMG")
413
- return;
414
- const src = node.getAttribute("src");
415
- if (src)
416
- setZoomed(src);
417
- }
418
- }, undefined, false, undefined, this),
419
- zoomed && /* @__PURE__ */ jsxDEV5("div", {
420
- className: "lw-zoom",
421
- role: "dialog",
422
- "aria-modal": "true",
423
- onClick: () => setZoomed(null),
424
- children: [
425
- /* @__PURE__ */ jsxDEV5("button", {
426
- type: "button",
427
- className: "lw-zoom__close",
428
- "aria-label": "close",
429
- children: "✕"
430
- }, undefined, false, undefined, this),
431
- /* @__PURE__ */ jsxDEV5("img", {
432
- src: zoomed,
433
- alt: ""
434
- }, undefined, false, undefined, this)
435
- ]
436
- }, undefined, true, undefined, this)
437
- ]
438
- }, undefined, true, undefined, this);
439
- }
440
-
441
- // src/components/StatusHero.tsx
442
- import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
443
- var TONES = {
444
- OPEN: { Icon: InboxIcon, border: "#bfdbfe", bg: "#eff6ff", fg: "#1e3a8a", accent: "#3b82f6" },
445
- IN_PROGRESS: { Icon: ClockIcon, border: "#fde68a", bg: "#fffbeb", fg: "#78350f", accent: "#f59e0b" },
446
- RESOLVED: { Icon: CheckCircleIcon, border: "#a7f3d0", bg: "#ecfdf5", fg: "#064e3b", accent: "#10b981" },
447
- CLOSED: { Icon: CheckCircleIcon, border: "#e5e7eb", bg: "#f9fafb", fg: "#1f2937", accent: "#9ca3af" },
448
- WONT_FIX: { Icon: BanIcon, border: "#e5e7eb", bg: "#f9fafb", fg: "#374151", accent: "#9ca3af" }
449
- };
450
- var AWAITING = { Icon: MessageIcon, border: "#fcd34d", bg: "#fffbeb", fg: "#78350f", accent: "#f59e0b" };
451
- var MESSAGES = {
452
- OPEN: { th: "รับเรื่องแล้ว — รอทีมงานตรวจสอบ", en: "Received — waiting for the team to look" },
453
- IN_PROGRESS: { th: "ทีมงานกำลังดำเนินการแก้ไข", en: "The team is working on it" },
454
- RESOLVED: { th: "แก้ไขเรียบร้อยแล้ว", en: "Fixed" },
455
- CLOSED: { th: "ปิดเรื่องแล้ว", en: "Closed" },
456
- WONT_FIX: { th: "พิจารณาแล้ว — ยังไม่ได้ดำเนินการในขณะนี้", en: "Reviewed — not being worked on for now" }
131
+ var DEFAULT_STYLE2 = {
132
+ display: "inline-flex",
133
+ alignItems: "center",
134
+ justifyContent: "center",
135
+ gap: 6,
136
+ height: 38,
137
+ padding: "0 12px",
138
+ border: "none",
139
+ borderRadius: 8,
140
+ background: "transparent",
141
+ color: "currentColor",
142
+ font: "inherit",
143
+ cursor: "pointer"
457
144
  };
458
- function StatusHero({
459
- ticket,
460
- maps,
461
- locale,
462
- host
463
- }) {
464
- const awaiting = maps.isAwaitingReply(ticket.status);
465
- const tone = awaiting ? AWAITING : TONES[ticket.status] ?? TONES.OPEN;
466
- const { Icon } = tone;
467
- const headline = awaiting ? locale === "en" ? "The team needs more information from you" : "ทีมงานขอข้อมูลเพิ่มเติม — รอการตอบกลับจากคุณ" : maps.columnOf(ticket.status)?.description?.trim() || MESSAGES[ticket.status]?.[locale] || maps.labelOf(ticket.status);
468
- const showNote = !awaiting && !ticket.messages.some((m) => m.authorRole === "AGENT") && maps.isClosed(ticket.status) && Boolean(ticket.resolutionNote?.trim());
469
- return /* @__PURE__ */ jsxDEV6("section", {
470
- className: "lw-hero",
471
- style: { borderColor: tone.border, background: tone.bg },
472
- children: [
473
- /* @__PURE__ */ jsxDEV6(Icon, {
474
- className: "lw-hero__icon",
475
- style: { color: tone.accent }
476
- }, undefined, false, undefined, this),
477
- /* @__PURE__ */ jsxDEV6("div", {
478
- className: "lw-hero__body",
479
- children: [
480
- /* @__PURE__ */ jsxDEV6("p", {
481
- className: "lw-hero__kicker",
482
- children: awaiting ? locale === "en" ? "AWAITING YOUR REPLY" : "รอการตอบกลับจากคุณ" : locale === "en" ? "LATEST STATUS" : "สถานะล่าสุด"
483
- }, undefined, false, undefined, this),
484
- /* @__PURE__ */ jsxDEV6("p", {
485
- className: "lw-hero__headline",
486
- style: { color: tone.fg },
487
- children: headline
488
- }, undefined, false, undefined, this),
489
- awaiting && /* @__PURE__ */ jsxDEV6("p", {
490
- className: "lw-hero__nudge",
491
- children: locale === "en" ? "Please reply to the team in the conversation below" : "กรุณาตอบกลับให้ทีมงานในช่องแชทด้านล่าง"
492
- }, undefined, false, undefined, this),
493
- showNote && /* @__PURE__ */ jsxDEV6("div", {
494
- className: "lw-hero__note",
495
- children: [
496
- /* @__PURE__ */ jsxDEV6(WrenchIcon, {
497
- className: "lw-hero__wrench"
498
- }, undefined, false, undefined, this),
499
- /* @__PURE__ */ jsxDEV6(TicketBody, {
500
- html: ticket.resolutionNote ?? "",
501
- host
502
- }, undefined, false, undefined, this)
503
- ]
504
- }, undefined, true, undefined, this)
505
- ]
506
- }, undefined, true, undefined, this)
507
- ]
508
- }, undefined, true, undefined, this);
509
- }
510
-
511
- // src/components/ReopenPanel.tsx
512
- import { useState as useState2 } from "react";
513
- import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
514
- function ReopenPanel({
515
- t,
516
- locale,
517
- busy,
518
- onReopen
519
- }) {
520
- const [open, setOpen] = useState2(false);
521
- const [note, setNote] = useState2("");
522
- if (!open) {
523
- return /* @__PURE__ */ jsxDEV7("section", {
524
- className: "lw-reopen",
525
- children: /* @__PURE__ */ jsxDEV7("div", {
526
- className: "lw-reopen__row",
527
- children: [
528
- /* @__PURE__ */ jsxDEV7("span", {
529
- className: "lw-reopen__hint",
530
- children: locale === "en" ? "Problem not fixed?" : "ปัญหายังไม่หาย?"
531
- }, undefined, false, undefined, this),
532
- /* @__PURE__ */ jsxDEV7("button", {
533
- type: "button",
534
- className: "lw-reopen__open",
535
- onClick: () => setOpen(true),
536
- children: [
537
- /* @__PURE__ */ jsxDEV7(RotateIcon, {}, undefined, false, undefined, this),
538
- " ",
539
- t.reopen
540
- ]
541
- }, undefined, true, undefined, this)
542
- ]
543
- }, undefined, true, undefined, this)
544
- }, undefined, false, undefined, this);
545
- }
546
- return /* @__PURE__ */ jsxDEV7("section", {
547
- className: "lw-reopen",
548
- children: [
549
- /* @__PURE__ */ jsxDEV7("p", {
550
- className: "lw-reopen__title",
551
- children: t.reopen
552
- }, undefined, false, undefined, this),
553
- /* @__PURE__ */ jsxDEV7("textarea", {
554
- className: "lw-reopen__note",
555
- rows: 2,
556
- value: note,
557
- onChange: (event) => setNote(event.target.value),
558
- placeholder: locale === "en" ? "Tell us what is still happening (optional)…" : "บอกเราหน่อยว่ายังพบปัญหาอะไร (ไม่ระบุก็ได้)…"
559
- }, undefined, false, undefined, this),
560
- /* @__PURE__ */ jsxDEV7("div", {
561
- className: "lw-reopen__actions",
562
- children: [
563
- /* @__PURE__ */ jsxDEV7("button", {
564
- type: "button",
565
- className: "lw-reopen__cancel",
566
- onClick: () => {
567
- setOpen(false);
568
- setNote("");
569
- },
570
- children: locale === "en" ? "Cancel" : "ยกเลิก"
571
- }, undefined, false, undefined, this),
572
- /* @__PURE__ */ jsxDEV7("button", {
573
- type: "button",
574
- className: "lw-reopen__confirm",
575
- disabled: busy,
576
- onClick: () => onReopen(note.trim()),
577
- children: [
578
- /* @__PURE__ */ jsxDEV7(RotateIcon, {}, undefined, false, undefined, this),
579
- " ",
580
- busy ? t.reopening : t.reopen
581
- ]
582
- }, undefined, true, undefined, this)
583
- ]
584
- }, undefined, true, undefined, this)
585
- ]
586
- }, undefined, true, undefined, this);
587
- }
588
-
589
- // src/components/TicketTimeline.tsx
590
- import { formatDateTime as formatDateTime2 } from "@lightworkai.official/debug-capture";
591
- import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
592
- var HAPPY = ["OPEN", "IN_PROGRESS", "RESOLVED", "CLOSED"];
593
- function TicketTimeline({
594
- history,
595
- status,
596
- createdAt,
597
- maps,
598
- timezone,
599
- locale
145
+ function SupportPortalButton({
146
+ children,
147
+ label = "ดูปัญหาที่แจ้ง",
148
+ newTab = false,
149
+ onError,
150
+ className,
151
+ style,
152
+ onClick,
153
+ disabled,
154
+ ...rest
600
155
  }) {
601
- const events = history.length ? history.map((h) => ({ status: h.toStatus, at: h.createdAt })) : [{ status: "OPEN", at: createdAt }];
602
- const nodes = events.map((event, i) => {
603
- const previous = events[i - 1];
604
- return {
605
- label: i === 0 ? locale === "en" ? "Reported" : "รายงานปัญหา" : maps.labelOf(event.status),
606
- time: formatDateTime2(event.at, timezone, locale),
607
- state: i === events.length - 1 ? "current" : "done",
608
- reopened: Boolean(previous && maps.isClosed(previous.status) && !maps.isClosed(event.status))
609
- };
610
- });
611
- const index = HAPPY.indexOf(status);
612
- const upcoming = maps.isClosed(status) || index < 0 ? [] : HAPPY.slice(index + 1);
613
- for (const next of upcoming) {
614
- nodes.push({
615
- label: maps.labelOf(next),
616
- time: locale === "en" ? "Pending" : "รอดำเนินการ",
617
- state: "pending",
618
- reopened: false
619
- });
620
- }
621
- return /* @__PURE__ */ jsxDEV8("ol", {
622
- className: "lw-timeline",
623
- children: nodes.map((node, i) => /* @__PURE__ */ jsxDEV8("li", {
624
- className: "lw-node",
625
- children: [
626
- /* @__PURE__ */ jsxDEV8("div", {
627
- className: "lw-rail",
628
- children: [
629
- i < nodes.length - 1 && /* @__PURE__ */ jsxDEV8("span", {
630
- className: `lw-line${node.state === "pending" ? " lw-line--pending" : ""}`
631
- }, undefined, false, undefined, this),
632
- /* @__PURE__ */ jsxDEV8("span", {
633
- className: `lw-dot lw-dot--${node.state}${node.reopened ? " lw-dot--reopened" : ""}`,
634
- children: node.state === "current" && !node.reopened && /* @__PURE__ */ jsxDEV8("span", {
635
- className: "lw-pip"
636
- }, undefined, false, undefined, this)
637
- }, undefined, false, undefined, this)
638
- ]
639
- }, undefined, true, undefined, this),
640
- /* @__PURE__ */ jsxDEV8("div", {
641
- className: `lw-node__text${i === nodes.length - 1 ? " lw-node__text--last" : ""}`,
642
- children: [
643
- /* @__PURE__ */ jsxDEV8("div", {
644
- className: `lw-node__label lw-node__label--${node.state}${node.reopened ? " lw-node__label--reopened" : ""}`,
645
- children: [
646
- node.reopened && /* @__PURE__ */ jsxDEV8(RotateIcon, {
647
- className: "lw-node__icon"
648
- }, undefined, false, undefined, this),
649
- node.reopened ? `${locale === "en" ? "Reopened" : "เปิดใหม่"} · ${node.label}` : node.label
650
- ]
651
- }, undefined, true, undefined, this),
652
- /* @__PURE__ */ jsxDEV8("div", {
653
- className: "lw-node__time",
654
- children: node.time
655
- }, undefined, false, undefined, this)
656
- ]
657
- }, undefined, true, undefined, this)
658
- ]
659
- }, `${node.label}-${i}`, true, undefined, this))
660
- }, undefined, false, undefined, this);
661
- }
662
-
663
- // src/components/TicketConversation.tsx
664
- import { useEffect as useEffect4, useRef as useRef4, useState as useState5 } from "react";
665
- import { editMyMessage, formatDateTime as formatDateTime3 } from "@lightworkai.official/debug-capture";
666
-
667
- // src/components/RichReplyEditor.tsx
668
- import { forwardRef, useCallback, useImperativeHandle, useRef as useRef3, useState as useState4 } from "react";
669
- import { EditorContent, useEditor } from "@tiptap/react";
670
- import StarterKit from "@tiptap/starter-kit";
671
- import Image2 from "@tiptap/extension-image";
672
- import Placeholder from "@tiptap/extension-placeholder";
673
- import { cleanHtml, htmlIsEmpty } from "@lightworkai.official/debug-capture";
674
-
675
- // src/components/ToolbarButton.tsx
676
- import { jsxDEV as jsxDEV9 } from "react/jsx-dev-runtime";
677
- function ToolbarButton({ label, active, disabled, onActivate, children }) {
678
- return /* @__PURE__ */ jsxDEV9("button", {
156
+ const [pending, setPending] = useState(false);
157
+ return /* @__PURE__ */ jsxDEV2("button", {
679
158
  type: "button",
680
- className: `lw-tool${active ? " lw-tool--on" : ""}`,
681
- title: label,
682
159
  "aria-label": label,
683
- "aria-pressed": active ? "true" : "false",
684
- disabled,
685
- onMouseDown: (event) => {
686
- event.preventDefault();
687
- onActivate();
688
- },
689
- children
690
- }, undefined, false, undefined, this);
691
- }
692
-
693
- // src/components/ImageAnnotatorDialog.tsx
694
- import { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
695
- import {
696
- createAnnotator,
697
- reporterStrings
698
- } from "@lightworkai.official/debug-capture";
699
- import { jsxDEV as jsxDEV10 } from "react/jsx-dev-runtime";
700
- var TOOLS = [
701
- { tool: "rect", key: "toolRect", Icon: SquareIcon },
702
- { tool: "arrow", key: "toolArrow", Icon: ArrowUpRightIcon },
703
- { tool: "highlight", key: "toolHighlight", Icon: HighlighterIcon },
704
- { tool: "text", key: "toolText", Icon: TypeIcon }
705
- ];
706
- function ImageAnnotatorDialog({ src, filename, locale, onConfirm, onCancel }) {
707
- const t = reporterStrings(locale);
708
- const canvas = useRef2(null);
709
- const annotator = useRef2(null);
710
- const [active, setActive] = useState3(null);
711
- const [loading, setLoading] = useState3(true);
712
- useEffect3(() => {
713
- const node = canvas.current;
714
- if (!node)
715
- return;
716
- const image = new Image;
717
- image.addEventListener("load", () => {
718
- node.width = image.naturalWidth;
719
- node.height = image.naturalHeight;
720
- annotator.current = createAnnotator(node, image, () => {
721
- setActive(null);
722
- });
723
- setLoading(false);
724
- });
725
- image.src = src;
726
- return () => {
727
- annotator.current?.destroy();
728
- annotator.current = null;
729
- };
730
- }, [src]);
731
- function pick(tool) {
732
- const next = active === tool ? null : tool;
733
- setActive(next);
734
- annotator.current?.setTool(next);
735
- }
736
- return /* @__PURE__ */ jsxDEV10("div", {
737
- className: "lw-annotator",
738
- role: "dialog",
739
- "aria-modal": "true",
740
- onClick: (event) => {
741
- if (event.target === event.currentTarget)
742
- onCancel();
743
- },
744
- children: /* @__PURE__ */ jsxDEV10("div", {
745
- className: "lw-annotator__panel",
746
- children: [
747
- /* @__PURE__ */ jsxDEV10("div", {
748
- className: "lw-annotator__head",
749
- children: [
750
- /* @__PURE__ */ jsxDEV10("div", {
751
- className: "lw-grow",
752
- children: [
753
- /* @__PURE__ */ jsxDEV10("h2", {
754
- className: "lw-annotator__title",
755
- children: t.annotateTitle
756
- }, undefined, false, undefined, this),
757
- /* @__PURE__ */ jsxDEV10("p", {
758
- className: "lw-annotator__desc",
759
- children: [
760
- t.annotateHint,
761
- filename ? ` · ${filename}` : ""
762
- ]
763
- }, undefined, true, undefined, this)
764
- ]
765
- }, undefined, true, undefined, this),
766
- /* @__PURE__ */ jsxDEV10("button", {
767
- type: "button",
768
- className: "lw-annotator__close",
769
- "aria-label": t.cancel,
770
- onClick: onCancel,
771
- children: "✕"
772
- }, undefined, false, undefined, this)
773
- ]
774
- }, undefined, true, undefined, this),
775
- /* @__PURE__ */ jsxDEV10("div", {
776
- className: "lw-annotator__tools",
777
- children: [
778
- TOOLS.map(({ tool, key, Icon }) => /* @__PURE__ */ jsxDEV10("button", {
779
- type: "button",
780
- className: "lw-atool",
781
- "aria-pressed": active === tool,
782
- disabled: loading,
783
- onClick: () => pick(tool),
784
- children: [
785
- /* @__PURE__ */ jsxDEV10(Icon, {}, undefined, false, undefined, this),
786
- " ",
787
- t[key]
788
- ]
789
- }, tool, true, undefined, this)),
790
- /* @__PURE__ */ jsxDEV10("span", {
791
- className: "lw-grow"
792
- }, undefined, false, undefined, this),
793
- /* @__PURE__ */ jsxDEV10("button", {
794
- type: "button",
795
- className: "lw-atool lw-atool--plain",
796
- disabled: loading,
797
- onClick: () => {
798
- annotator.current?.clear();
799
- setActive(null);
800
- },
801
- children: [
802
- /* @__PURE__ */ jsxDEV10(TrashIcon, {}, undefined, false, undefined, this),
803
- " ",
804
- t.clearAll
805
- ]
806
- }, undefined, true, undefined, this)
807
- ]
808
- }, undefined, true, undefined, this),
809
- /* @__PURE__ */ jsxDEV10("div", {
810
- className: "lw-annotator__canvas",
811
- children: /* @__PURE__ */ jsxDEV10("div", {
812
- className: "lw-annotator__canvasbox",
813
- children: /* @__PURE__ */ jsxDEV10("canvas", {
814
- ref: canvas
815
- }, undefined, false, undefined, this)
816
- }, undefined, false, undefined, this)
817
- }, undefined, false, undefined, this),
818
- /* @__PURE__ */ jsxDEV10("p", {
819
- className: "lw-annotator__hint",
820
- children: t.annotateHelp
821
- }, undefined, false, undefined, this),
822
- /* @__PURE__ */ jsxDEV10("div", {
823
- className: "lw-annotator__actions",
824
- children: [
825
- /* @__PURE__ */ jsxDEV10("span", {
826
- className: "lw-grow"
827
- }, undefined, false, undefined, this),
828
- /* @__PURE__ */ jsxDEV10("button", {
829
- type: "button",
830
- className: "lw-btn",
831
- onClick: onCancel,
832
- children: t.cancel
833
- }, undefined, false, undefined, this),
834
- /* @__PURE__ */ jsxDEV10("button", {
835
- type: "button",
836
- className: "lw-send",
837
- disabled: loading,
838
- onClick: () => onConfirm(annotator.current?.toDataUrl() ?? src),
839
- children: t.annotateApply
840
- }, undefined, false, undefined, this)
841
- ]
842
- }, undefined, true, undefined, this)
843
- ]
844
- }, undefined, true, undefined, this)
845
- }, undefined, false, undefined, this);
846
- }
847
-
848
- // src/components/RichReplyEditor.tsx
849
- import { jsxDEV as jsxDEV11 } from "react/jsx-dev-runtime";
850
- var RichReplyEditor = forwardRef(function RichReplyEditor2({ placeholder, host, disabled, labels, uploadImage, onError, locale, initial }, ref) {
851
- const [uploading, setUploading] = useState4(false);
852
- const fileInput = useRef3(null);
853
- const [pending, setPending] = useState4(null);
854
- const pendingRef = useRef3(pending);
855
- pendingRef.current = pending;
856
- const uploadRef = useRef3(uploadImage);
857
- uploadRef.current = uploadImage;
858
- const errorRef = useRef3(onError);
859
- errorRef.current = onError;
860
- const editor = useEditor({
861
- extensions: [
862
- StarterKit,
863
- Image2.configure({ inline: false, allowBase64: false }),
864
- Placeholder.configure({ placeholder })
865
- ],
866
- content: initial ?? "",
867
- editable: !disabled,
868
- immediatelyRender: false,
869
- editorProps: {
870
- attributes: { class: "lw-editor-body" },
871
- handlePaste: (_view, event) => {
872
- const file = Array.from(event.clipboardData?.files ?? []).find((f) => f.type.startsWith("image/"));
873
- if (!file)
874
- return false;
875
- event.preventDefault();
876
- addImage(file);
877
- return true;
878
- },
879
- handleDrop: (_view, event) => {
880
- const dropped = event;
881
- const file = Array.from(dropped.dataTransfer?.files ?? []).find((f) => f.type.startsWith("image/"));
882
- if (!file)
883
- return false;
884
- dropped.preventDefault();
885
- addImage(file);
886
- return true;
160
+ title: label,
161
+ className,
162
+ style: className ? style : { ...DEFAULT_STYLE2, ...style },
163
+ disabled: disabled ?? pending,
164
+ ...rest,
165
+ onClick: async (event) => {
166
+ onClick?.(event);
167
+ if (event.defaultPrevented || pending)
168
+ return;
169
+ setPending(true);
170
+ try {
171
+ await openSupportPortal(newTab ? { target: "_blank" } : {});
172
+ } catch (err) {
173
+ onError?.(err);
174
+ showToast("เปิดรายการปัญหาไม่สำเร็จ", "error");
175
+ } finally {
176
+ setPending(false);
887
177
  }
888
- }
889
- });
890
- const addImage = useCallback(async (file) => {
891
- if (pendingRef.current)
892
- return;
893
- try {
894
- setPending({ src: await readDataUri(file), name: file.name || "screenshot.png" });
895
- } catch (e) {
896
- errorRef.current(e instanceof Error ? e.message : "unreadable file");
897
- }
898
- }, []);
899
- const commitImage = useCallback(async (dataUri) => {
900
- const name = pendingRef.current?.name ?? "screenshot.png";
901
- setPending(null);
902
- setUploading(true);
903
- try {
904
- const src = await uploadRef.current(dataUriToFile(dataUri, name));
905
- editor?.chain().focus().setImage({ src }).run();
906
- } catch (e) {
907
- errorRef.current(e instanceof Error ? e.message : "upload failed");
908
- } finally {
909
- setUploading(false);
910
- }
911
- }, [editor]);
912
- useImperativeHandle(ref, () => ({
913
- value: () => {
914
- const html = cleanHtml(editor?.getHTML() ?? "", host);
915
- return htmlIsEmpty(html) ? "" : html;
916
178
  },
917
- clear: () => editor?.commands.clearContent(true),
918
- focus: () => editor?.commands.focus()
919
- }));
920
- function toggleLink() {
921
- if (!editor)
922
- return;
923
- if (editor.getAttributes("link").href) {
924
- editor.chain().focus().unsetLink().run();
925
- return;
926
- }
927
- const href = window.prompt(labels.linkPrompt, "https://");
928
- if (!href)
929
- return;
930
- if (!/^https?:\/\//i.test(href)) {
931
- onError(`${labels.link}: http(s) only`);
932
- return;
933
- }
934
- editor.chain().focus().extendMarkRange("link").setLink({ href }).run();
935
- }
936
- return /* @__PURE__ */ jsxDEV11("div", {
937
- className: `lw-editor${disabled ? " lw-editor--disabled" : ""}`,
938
- children: [
939
- /* @__PURE__ */ jsxDEV11("div", {
940
- className: "lw-editor__tools",
941
- children: [
942
- /* @__PURE__ */ jsxDEV11(ToolbarButton, {
943
- label: labels.bold ?? "",
944
- active: editor?.isActive("bold"),
945
- disabled,
946
- onActivate: () => editor?.chain().focus().toggleBold().run(),
947
- children: /* @__PURE__ */ jsxDEV11(BoldIcon, {}, undefined, false, undefined, this)
948
- }, undefined, false, undefined, this),
949
- /* @__PURE__ */ jsxDEV11(ToolbarButton, {
950
- label: labels.italic ?? "",
951
- active: editor?.isActive("italic"),
952
- disabled,
953
- onActivate: () => editor?.chain().focus().toggleItalic().run(),
954
- children: /* @__PURE__ */ jsxDEV11(ItalicIcon, {}, undefined, false, undefined, this)
955
- }, undefined, false, undefined, this),
956
- /* @__PURE__ */ jsxDEV11(ToolbarButton, {
957
- label: labels.underline ?? "",
958
- active: editor?.isActive("underline"),
959
- disabled,
960
- onActivate: () => editor?.chain().focus().toggleUnderline().run(),
961
- children: /* @__PURE__ */ jsxDEV11(UnderlineIcon, {}, undefined, false, undefined, this)
962
- }, undefined, false, undefined, this),
963
- /* @__PURE__ */ jsxDEV11("span", {
964
- className: "lw-editor__sep"
965
- }, undefined, false, undefined, this),
966
- /* @__PURE__ */ jsxDEV11(ToolbarButton, {
967
- label: labels.bulletList ?? "",
968
- active: editor?.isActive("bulletList"),
969
- disabled,
970
- onActivate: () => editor?.chain().focus().toggleBulletList().run(),
971
- children: /* @__PURE__ */ jsxDEV11(BulletListIcon, {}, undefined, false, undefined, this)
972
- }, undefined, false, undefined, this),
973
- /* @__PURE__ */ jsxDEV11(ToolbarButton, {
974
- label: labels.orderedList ?? "",
975
- active: editor?.isActive("orderedList"),
976
- disabled,
977
- onActivate: () => editor?.chain().focus().toggleOrderedList().run(),
978
- children: /* @__PURE__ */ jsxDEV11(OrderedListIcon, {}, undefined, false, undefined, this)
979
- }, undefined, false, undefined, this),
980
- /* @__PURE__ */ jsxDEV11(ToolbarButton, {
981
- label: labels.link ?? "",
982
- active: editor?.isActive("link"),
983
- disabled,
984
- onActivate: toggleLink,
985
- children: /* @__PURE__ */ jsxDEV11(LinkIcon, {}, undefined, false, undefined, this)
986
- }, undefined, false, undefined, this),
987
- /* @__PURE__ */ jsxDEV11("span", {
988
- className: "lw-editor__sep"
989
- }, undefined, false, undefined, this),
990
- /* @__PURE__ */ jsxDEV11(ToolbarButton, {
991
- label: labels.attachImage ?? "",
992
- disabled: disabled || uploading,
993
- onActivate: () => fileInput.current?.click(),
994
- children: /* @__PURE__ */ jsxDEV11(ImageIcon, {}, undefined, false, undefined, this)
995
- }, undefined, false, undefined, this)
996
- ]
997
- }, undefined, true, undefined, this),
998
- /* @__PURE__ */ jsxDEV11(EditorContent, {
999
- editor,
1000
- className: "lw-editor__content"
1001
- }, undefined, false, undefined, this),
1002
- /* @__PURE__ */ jsxDEV11("input", {
1003
- ref: fileInput,
1004
- type: "file",
1005
- accept: "image/*",
1006
- hidden: true,
1007
- onChange: (event) => {
1008
- const file = event.target.files?.[0];
1009
- event.target.value = "";
1010
- if (file)
1011
- addImage(file);
1012
- }
1013
- }, undefined, false, undefined, this),
1014
- pending && /* @__PURE__ */ jsxDEV11(ImageAnnotatorDialog, {
1015
- src: pending.src,
1016
- filename: pending.name,
1017
- locale,
1018
- onConfirm: (dataUri) => void commitImage(dataUri),
1019
- onCancel: () => setPending(null)
1020
- }, undefined, false, undefined, this)
1021
- ]
1022
- }, undefined, true, undefined, this);
1023
- });
1024
- function readDataUri(file) {
1025
- return new Promise((resolve, reject) => {
1026
- const reader = new FileReader;
1027
- reader.addEventListener("load", () => typeof reader.result === "string" ? resolve(reader.result) : reject(new Error("unreadable file")));
1028
- reader.addEventListener("error", () => reject(new Error("unreadable file")));
1029
- reader.readAsDataURL(file);
1030
- });
1031
- }
1032
- function dataUriToFile(dataUri, name) {
1033
- const [header, encoded] = dataUri.split(",");
1034
- const type = /data:([^;]+)/.exec(header ?? "")?.[1] ?? "image/png";
1035
- const binary = atob(encoded ?? "");
1036
- const bytes = new Uint8Array(binary.length);
1037
- for (let i = 0;i < binary.length; i += 1)
1038
- bytes[i] = binary.charCodeAt(i);
1039
- return new File([bytes], name, { type });
1040
- }
1041
-
1042
- // src/components/TicketConversation.tsx
1043
- import { jsxDEV as jsxDEV12, Fragment as Fragment3 } from "react/jsx-dev-runtime";
1044
- function TicketConversation({
1045
- ticket,
1046
- t,
1047
- host,
1048
- timezone,
1049
- locale,
1050
- sending,
1051
- uploadImage,
1052
- onSend,
1053
- onEdited,
1054
- onError
1055
- }) {
1056
- const editor = useRef4(null);
1057
- const [editingId, setEditingId] = useState5(null);
1058
- const [savingEdit, setSavingEdit] = useState5(false);
1059
- const draft = useRef4(null);
1060
- const LABELS = {
1061
- bold: t.bold,
1062
- italic: t.italic,
1063
- underline: t.underline,
1064
- bulletList: t.bulletList,
1065
- orderedList: t.orderedList,
1066
- link: t.link,
1067
- linkPrompt: t.linkPrompt,
1068
- attachImage: t.attachImage,
1069
- uploading: t.uploading
1070
- };
1071
- async function saveEdit(messageId) {
1072
- const body = draft.current?.value() ?? "";
1073
- if (!body || savingEdit)
1074
- return;
1075
- setSavingEdit(true);
1076
- try {
1077
- await editMyMessage(ticket.id, messageId, body);
1078
- setEditingId(null);
1079
- onEdited();
1080
- } catch (e) {
1081
- onError(e instanceof Error ? e.message : t.sendFailed);
1082
- } finally {
1083
- setSavingEdit(false);
1084
- }
1085
- }
1086
- const thread = useRef4(null);
1087
- const seen = useRef4(-1);
1088
- useEffect4(() => {
1089
- const box = thread.current;
1090
- if (!box)
1091
- return;
1092
- const first = seen.current < 0;
1093
- if (first || ticket.messages.length > seen.current) {
1094
- box.scrollTop = box.scrollHeight;
1095
- if (!first)
1096
- box.lastElementChild?.scrollIntoView({ block: "nearest", behavior: "smooth" });
1097
- }
1098
- seen.current = ticket.messages.length;
1099
- }, [ticket.id, ticket.messages.length]);
1100
- function send() {
1101
- const body = editor.current?.value() ?? "";
1102
- if (!body || sending)
1103
- return;
1104
- onSend(body);
1105
- editor.current?.clear();
1106
- }
1107
- return /* @__PURE__ */ jsxDEV12("section", {
1108
- className: "lw-card",
1109
- children: [
1110
- /* @__PURE__ */ jsxDEV12("h3", {
1111
- className: "lw-card__title",
1112
- children: t.conversation
1113
- }, undefined, false, undefined, this),
1114
- /* @__PURE__ */ jsxDEV12("div", {
1115
- ref: thread,
1116
- className: "lw-thread",
1117
- children: [
1118
- ticket.messages.length === 0 && /* @__PURE__ */ jsxDEV12("p", {
1119
- className: "lw-thread__empty",
1120
- children: t.noMessages
1121
- }, undefined, false, undefined, this),
1122
- ticket.messages.map((message) => /* @__PURE__ */ jsxDEV12("article", {
1123
- className: `lw-msg${message.authorRole === "REPORTER" ? " lw-msg--mine" : ""}`,
1124
- children: /* @__PURE__ */ jsxDEV12("div", {
1125
- className: "lw-msg__bubble",
1126
- children: [
1127
- /* @__PURE__ */ jsxDEV12("p", {
1128
- className: "lw-msg__meta",
1129
- children: [
1130
- message.authorRole === "AGENT" ? /* @__PURE__ */ jsxDEV12("span", {
1131
- className: "lw-msg__who",
1132
- children: t.team
1133
- }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV12(Fragment3, {
1134
- children: [
1135
- /* @__PURE__ */ jsxDEV12("span", {
1136
- className: "lw-msg__who",
1137
- children: message.authorName || t.you
1138
- }, undefined, false, undefined, this),
1139
- /* @__PURE__ */ jsxDEV12("span", {
1140
- className: "lw-msg__role",
1141
- children: t.reporterRole
1142
- }, undefined, false, undefined, this)
1143
- ]
1144
- }, undefined, true, undefined, this),
1145
- /* @__PURE__ */ jsxDEV12("span", {
1146
- children: [
1147
- "· ",
1148
- formatDateTime3(message.createdAt, timezone, locale)
1149
- ]
1150
- }, undefined, true, undefined, this),
1151
- message.editedAt && /* @__PURE__ */ jsxDEV12("span", {
1152
- className: "lw-msg__edited",
1153
- children: [
1154
- "· ",
1155
- t.edited
1156
- ]
1157
- }, undefined, true, undefined, this),
1158
- message.authorRole === "REPORTER" && editingId !== message.id && /* @__PURE__ */ jsxDEV12("button", {
1159
- type: "button",
1160
- className: "lw-msg__edit",
1161
- onClick: () => setEditingId(message.id),
1162
- children: [
1163
- /* @__PURE__ */ jsxDEV12(PencilIcon, {}, undefined, false, undefined, this),
1164
- " ",
1165
- t.edit
1166
- ]
1167
- }, undefined, true, undefined, this)
1168
- ]
1169
- }, undefined, true, undefined, this),
1170
- editingId === message.id ? /* @__PURE__ */ jsxDEV12("div", {
1171
- className: "lw-msg__editing",
1172
- children: [
1173
- /* @__PURE__ */ jsxDEV12(RichReplyEditor, {
1174
- ref: draft,
1175
- placeholder: t.replyPlaceholder,
1176
- host,
1177
- locale,
1178
- disabled: savingEdit,
1179
- uploadImage,
1180
- onError,
1181
- labels: LABELS,
1182
- initial: message.body
1183
- }, undefined, false, undefined, this),
1184
- /* @__PURE__ */ jsxDEV12("div", {
1185
- className: "lw-msg__editActions",
1186
- children: [
1187
- /* @__PURE__ */ jsxDEV12("button", {
1188
- type: "button",
1189
- className: "lw-btn",
1190
- disabled: savingEdit,
1191
- onClick: () => setEditingId(null),
1192
- children: [
1193
- /* @__PURE__ */ jsxDEV12(XSmallIcon, {}, undefined, false, undefined, this),
1194
- " ",
1195
- t.cancel
1196
- ]
1197
- }, undefined, true, undefined, this),
1198
- /* @__PURE__ */ jsxDEV12("button", {
1199
- type: "button",
1200
- className: "lw-send",
1201
- disabled: savingEdit,
1202
- onClick: () => void saveEdit(message.id),
1203
- children: [
1204
- /* @__PURE__ */ jsxDEV12(CheckSmallIcon, {}, undefined, false, undefined, this),
1205
- " ",
1206
- t.saveEdit
1207
- ]
1208
- }, undefined, true, undefined, this)
1209
- ]
1210
- }, undefined, true, undefined, this)
1211
- ]
1212
- }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV12(TicketBody, {
1213
- html: message.body,
1214
- host
1215
- }, undefined, false, undefined, this)
1216
- ]
1217
- }, undefined, true, undefined, this)
1218
- }, message.id, false, undefined, this))
1219
- ]
1220
- }, undefined, true, undefined, this),
1221
- /* @__PURE__ */ jsxDEV12("div", {
1222
- className: "lw-composer",
1223
- children: [
1224
- /* @__PURE__ */ jsxDEV12(RichReplyEditor, {
1225
- ref: editor,
1226
- placeholder: t.replyPlaceholder,
1227
- host,
1228
- locale,
1229
- disabled: sending,
1230
- uploadImage,
1231
- onError,
1232
- labels: LABELS
1233
- }, undefined, false, undefined, this),
1234
- /* @__PURE__ */ jsxDEV12("div", {
1235
- className: "lw-composer__actions",
1236
- children: /* @__PURE__ */ jsxDEV12("button", {
1237
- type: "button",
1238
- className: "lw-send",
1239
- disabled: sending,
1240
- onClick: send,
1241
- children: [
1242
- /* @__PURE__ */ jsxDEV12(SendIcon, {}, undefined, false, undefined, this),
1243
- " ",
1244
- sending ? t.sending : t.send
1245
- ]
1246
- }, undefined, true, undefined, this)
1247
- }, undefined, false, undefined, this)
1248
- ]
1249
- }, undefined, true, undefined, this)
1250
- ]
1251
- }, undefined, true, undefined, this);
1252
- }
1253
-
1254
- // src/components/TicketScreenshots.tsx
1255
- import { useEffect as useEffect5, useState as useState6 } from "react";
1256
- import { jsxDEV as jsxDEV13 } from "react/jsx-dev-runtime";
1257
- function TicketScreenshots({
1258
- images,
1259
- title,
1260
- attachmentUrl
1261
- }) {
1262
- const [urls, setUrls] = useState6({});
1263
- useEffect5(() => {
1264
- let live = true;
1265
- for (const image of images) {
1266
- attachmentUrl(image.id).then((url) => live && setUrls((prev) => ({ ...prev, [image.id]: url })), () => {
1267
- return;
1268
- });
1269
- }
1270
- return () => {
1271
- live = false;
1272
- };
1273
- }, [images, attachmentUrl]);
1274
- return /* @__PURE__ */ jsxDEV13("section", {
1275
- className: "lw-card",
1276
- children: [
1277
- /* @__PURE__ */ jsxDEV13("h3", {
1278
- className: "lw-card__title",
1279
- children: title
1280
- }, undefined, false, undefined, this),
1281
- images.map((image) => urls[image.id] ? /* @__PURE__ */ jsxDEV13("img", {
1282
- className: "lw-shot",
1283
- src: urls[image.id],
1284
- alt: image.filename ?? ""
1285
- }, image.id, false, undefined, this) : null)
1286
- ]
1287
- }, undefined, true, undefined, this);
1288
- }
1289
-
1290
- // src/components/TicketDetail.tsx
1291
- import { jsxDEV as jsxDEV14 } from "react/jsx-dev-runtime";
1292
- function TicketDetail(props) {
1293
- const { ticket, config, maps, t, host, locale } = props;
1294
- const lang = locale === "en" ? "en" : "th";
1295
- const canReopen = maps.isClosed(ticket.status) && config.featureFlags.selfServiceReopen === true;
1296
- const updated = ticket.updatedAt && ticket.updatedAt !== ticket.createdAt;
1297
- const when = (iso) => formatDateTime4(iso, config.timezone, locale);
1298
- const screenshots = ticket.attachments.filter((a) => (a.contentType ?? "").startsWith("image/"));
1299
- return /* @__PURE__ */ jsxDEV14("div", {
1300
- className: "lw-detail",
1301
- children: [
1302
- /* @__PURE__ */ jsxDEV14("button", {
1303
- type: "button",
1304
- className: "lw-back",
1305
- onClick: props.onBack,
1306
- children: [
1307
- /* @__PURE__ */ jsxDEV14(ArrowLeftIcon, {}, undefined, false, undefined, this),
1308
- " ",
1309
- t.back
1310
- ]
1311
- }, undefined, true, undefined, this),
1312
- /* @__PURE__ */ jsxDEV14("section", {
1313
- className: "lw-card",
1314
- children: [
1315
- /* @__PURE__ */ jsxDEV14("h3", {
1316
- className: "lw-card__heading",
1317
- children: ticket.title
1318
- }, undefined, false, undefined, this),
1319
- /* @__PURE__ */ jsxDEV14("div", {
1320
- className: "lw-facts",
1321
- children: [
1322
- /* @__PURE__ */ jsxDEV14("span", {
1323
- className: "lw-key",
1324
- children: ticketKey2(config.realm.slug, ticket.number)
1325
- }, undefined, false, undefined, this),
1326
- ticket.category && /* @__PURE__ */ jsxDEV14("span", {
1327
- className: "lw-chip",
1328
- children: ticket.category
1329
- }, undefined, false, undefined, this),
1330
- /* @__PURE__ */ jsxDEV14("span", {
1331
- children: [
1332
- t.colCreated,
1333
- " ",
1334
- when(ticket.createdAt)
1335
- ]
1336
- }, undefined, true, undefined, this),
1337
- updated && /* @__PURE__ */ jsxDEV14("span", {
1338
- children: [
1339
- t.colUpdated,
1340
- " ",
1341
- when(ticket.updatedAt)
1342
- ]
1343
- }, undefined, true, undefined, this)
1344
- ]
1345
- }, undefined, true, undefined, this),
1346
- ticket.description && /* @__PURE__ */ jsxDEV14(TicketBody, {
1347
- className: "lw-intro",
1348
- html: ticket.description,
1349
- host
1350
- }, undefined, false, undefined, this),
1351
- ticket.routeUrl && /* @__PURE__ */ jsxDEV14("p", {
1352
- className: "lw-route",
1353
- children: [
1354
- t.page,
1355
- ":",
1356
- " ",
1357
- /* @__PURE__ */ jsxDEV14("a", {
1358
- href: ticket.routeUrl,
1359
- target: "_blank",
1360
- rel: "noopener noreferrer",
1361
- children: ticket.routeUrl
1362
- }, undefined, false, undefined, this)
1363
- ]
1364
- }, undefined, true, undefined, this)
1365
- ]
1366
- }, undefined, true, undefined, this),
1367
- /* @__PURE__ */ jsxDEV14(StatusHero, {
1368
- ticket,
1369
- maps,
1370
- t,
1371
- locale: lang,
1372
- host
1373
- }, undefined, false, undefined, this),
1374
- canReopen && /* @__PURE__ */ jsxDEV14(ReopenPanel, {
1375
- t,
1376
- locale: lang,
1377
- busy: props.reopening,
1378
- onReopen: props.onReopen
1379
- }, undefined, false, undefined, this),
1380
- /* @__PURE__ */ jsxDEV14("section", {
1381
- className: "lw-card",
1382
- children: [
1383
- /* @__PURE__ */ jsxDEV14("h3", {
1384
- className: "lw-card__title",
1385
- children: lang === "en" ? "Progress" : "ความคืบหน้า"
1386
- }, undefined, false, undefined, this),
1387
- /* @__PURE__ */ jsxDEV14(TicketTimeline, {
1388
- history: props.history,
1389
- status: ticket.status,
1390
- createdAt: ticket.createdAt,
1391
- maps,
1392
- timezone: config.timezone,
1393
- locale: lang
1394
- }, undefined, false, undefined, this)
1395
- ]
1396
- }, undefined, true, undefined, this),
1397
- /* @__PURE__ */ jsxDEV14(TicketConversation, {
1398
- ticket,
1399
- t,
1400
- host,
1401
- timezone: config.timezone,
1402
- locale,
1403
- sending: props.sending,
1404
- uploadImage: props.uploadImage,
1405
- onSend: props.onSend,
1406
- onEdited: props.onEdited,
1407
- onError: props.onError
1408
- }, undefined, false, undefined, this),
1409
- screenshots.length > 0 && /* @__PURE__ */ jsxDEV14(TicketScreenshots, {
1410
- images: screenshots,
1411
- title: lang === "en" ? "Screenshots you sent" : "ภาพหน้าจอที่คุณแจ้ง",
1412
- attachmentUrl: props.attachmentUrl
1413
- }, undefined, false, undefined, this)
1414
- ]
1415
- }, undefined, true, undefined, this);
1416
- }
1417
-
1418
- // src/components/MyTicketsPanel.tsx
1419
- import { jsxDEV as jsxDEV15 } from "react/jsx-dev-runtime";
1420
- function safeConfig(read, fallback) {
1421
- try {
1422
- return read();
1423
- } catch {
1424
- return fallback;
1425
- }
1426
- }
1427
- function MyTicketsPanel({ refreshKey, hideTitle, onReplied, onReopened, onError }) {
1428
- const locale = safeConfig(() => getConfig().locale, undefined);
1429
- const host = safeConfig(() => getConfig().host, "");
1430
- const t = useMemo2(() => ticketStrings(locale), [locale]);
1431
- const [items, setItems] = useState7([]);
1432
- const [config, setConfig] = useState7(null);
1433
- const [loading, setLoading] = useState7(true);
1434
- const [error, setError] = useState7(null);
1435
- const [noIdentity, setNoIdentity] = useState7(false);
1436
- const [keyword, setKeyword] = useState7("");
1437
- const [applied, setApplied] = useState7("");
1438
- const [statusFilter, setStatusFilter] = useState7("");
1439
- const [sort, setSort] = useState7({ key: "createdAt", direction: "desc" });
1440
- const [page, setPage] = useState7(1);
1441
- const [shown, setShown] = useState7(0);
1442
- const [detail, setDetail] = useState7(null);
1443
- const [history, setHistory] = useState7([]);
1444
- const [detailError, setDetailError] = useState7(null);
1445
- const [detailLoading, setDetailLoading] = useState7(false);
1446
- const [sending, setSending] = useState7(false);
1447
- const [reopening, setReopening] = useState7(false);
1448
- const maps = useMemo2(() => statusMaps(config?.statusColumns ?? [], t.allStatuses), [config, t]);
1449
- const report = useRef5(onError);
1450
- report.current = onError;
1451
- const load = useCallback2(async () => {
1452
- setLoading(true);
1453
- setError(null);
1454
- setNoIdentity(false);
1455
- try {
1456
- const [realm, list] = await Promise.all([fetchRealmConfig(), listMyTickets()]);
1457
- setConfig(realm);
1458
- setItems(list);
1459
- } catch (e) {
1460
- if (e instanceof NoIdentityError)
1461
- setNoIdentity(true);
1462
- else
1463
- setError(e instanceof Error ? e.message : t.listFailed);
1464
- } finally {
1465
- setLoading(false);
1466
- }
1467
- }, [t]);
1468
- useEffect6(() => {
1469
- load();
1470
- }, [load, refreshKey]);
1471
- useEffect6(() => {
1472
- const timer = setTimeout(() => {
1473
- setApplied(keyword);
1474
- setPage(1);
1475
- }, 300);
1476
- return () => clearTimeout(timer);
1477
- }, [keyword]);
1478
- const reload = useCallback2(async (id) => {
1479
- try {
1480
- const [found, events] = await Promise.all([
1481
- getMyTicket(id),
1482
- getMyTicketHistory(id).catch(() => [])
1483
- ]);
1484
- setDetail(found);
1485
- setHistory(events);
1486
- return found;
1487
- } catch (e) {
1488
- setDetailError(e instanceof Error ? e.message : t.detailFailed);
1489
- return null;
1490
- }
1491
- }, [t]);
1492
- const open = useCallback2(async (id) => {
1493
- setDetail(null);
1494
- setHistory([]);
1495
- setDetailError(null);
1496
- setDetailLoading(true);
1497
- try {
1498
- return await reload(id);
1499
- } finally {
1500
- setDetailLoading(false);
1501
- }
1502
- }, [reload]);
1503
- function back() {
1504
- setDetail(null);
1505
- load();
1506
- }
1507
- function toggleSort(key) {
1508
- setSort((current) => current.key === key ? { key, direction: current.direction === "asc" ? "desc" : "asc" } : { key, direction: key === "createdAt" || key === "updatedAt" ? "desc" : "asc" });
1509
- }
1510
- async function send(body) {
1511
- if (!detail || sending)
1512
- return;
1513
- setSending(true);
1514
- try {
1515
- await replyToTicket(detail.id, body);
1516
- const fresh = await reload(detail.id);
1517
- if (fresh)
1518
- onReplied?.(fresh);
1519
- } catch (e) {
1520
- report.current?.(e instanceof Error ? e.message : t.sendFailed);
1521
- } finally {
1522
- setSending(false);
1523
- }
1524
- }
1525
- async function reopen(note) {
1526
- if (!detail || reopening)
1527
- return;
1528
- setReopening(true);
1529
- try {
1530
- await reopenMyTicket(detail.id, note);
1531
- const fresh = await reload(detail.id);
1532
- if (fresh)
1533
- onReopened?.(fresh);
1534
- } catch (e) {
1535
- report.current?.(e instanceof Error ? e.message : t.reopenFailed);
1536
- } finally {
1537
- setReopening(false);
1538
- }
1539
- }
1540
- const uploadImage = useCallback2(async (file) => {
1541
- if (!detail)
1542
- throw new Error("no ticket");
1543
- const dataUri = await readDataUri2(file);
1544
- const stored = await uploadInlineImage(detail.id, dataUri, file.name);
1545
- return stored.url;
1546
- }, [detail]);
1547
- const attachmentUrl = useCallback2((id) => getAttachmentUrl(id).then((found) => found.url), []);
1548
- if (detailLoading) {
1549
- return /* @__PURE__ */ jsxDEV15("div", {
1550
- className: "lw-panel",
1551
- children: [
1552
- /* @__PURE__ */ jsxDEV15("div", {
1553
- className: "lw-skeleton"
1554
- }, undefined, false, undefined, this),
1555
- /* @__PURE__ */ jsxDEV15("div", {
1556
- className: "lw-skeleton"
1557
- }, undefined, false, undefined, this)
1558
- ]
1559
- }, undefined, true, undefined, this);
1560
- }
1561
- if (detailError) {
1562
- return /* @__PURE__ */ jsxDEV15("div", {
1563
- className: "lw-panel",
1564
- children: /* @__PURE__ */ jsxDEV15("p", {
1565
- className: "lw-state lw-state--error",
1566
- children: detailError
1567
- }, undefined, false, undefined, this)
1568
- }, undefined, false, undefined, this);
1569
- }
1570
- if (detail && config) {
1571
- return /* @__PURE__ */ jsxDEV15("div", {
1572
- className: "lw-panel",
1573
- children: /* @__PURE__ */ jsxDEV15(TicketDetail, {
1574
- ticket: detail,
1575
- history,
1576
- config,
1577
- maps,
1578
- t,
1579
- host,
1580
- locale,
1581
- sending,
1582
- reopening,
1583
- uploadImage,
1584
- attachmentUrl,
1585
- onBack: back,
1586
- onSend: send,
1587
- onEdited: () => void reload(detail.id),
1588
- onReopen: reopen,
1589
- onError: (message) => report.current?.(message)
1590
- }, undefined, false, undefined, this)
1591
- }, undefined, false, undefined, this);
1592
- }
1593
- return /* @__PURE__ */ jsxDEV15("div", {
1594
- className: "lw-panel",
1595
- children: [
1596
- !hideTitle && /* @__PURE__ */ jsxDEV15("h2", {
1597
- className: "lw-panel__title",
1598
- children: t.title
1599
- }, undefined, false, undefined, this),
1600
- /* @__PURE__ */ jsxDEV15("p", {
1601
- className: "lw-panel__intro",
1602
- children: t.intro
1603
- }, undefined, false, undefined, this),
1604
- /* @__PURE__ */ jsxDEV15("div", {
1605
- className: "lw-controls",
1606
- children: [
1607
- /* @__PURE__ */ jsxDEV15("div", {
1608
- className: "lw-search",
1609
- children: [
1610
- /* @__PURE__ */ jsxDEV15(SearchIcon, {
1611
- className: "lw-search__icon"
1612
- }, undefined, false, undefined, this),
1613
- /* @__PURE__ */ jsxDEV15("input", {
1614
- type: "search",
1615
- className: "lw-input lw-search__field",
1616
- placeholder: t.searchPlaceholder,
1617
- "aria-label": t.searchLabel,
1618
- value: keyword,
1619
- onChange: (event) => setKeyword(event.target.value)
1620
- }, undefined, false, undefined, this)
1621
- ]
1622
- }, undefined, true, undefined, this),
1623
- /* @__PURE__ */ jsxDEV15("select", {
1624
- className: "lw-input",
1625
- value: statusFilter,
1626
- onChange: (event) => {
1627
- setStatusFilter(event.target.value);
1628
- setPage(1);
1629
- },
1630
- children: maps.options.map((option) => /* @__PURE__ */ jsxDEV15("option", {
1631
- value: option.value,
1632
- children: option.label
1633
- }, option.value, false, undefined, this))
1634
- }, undefined, false, undefined, this),
1635
- /* @__PURE__ */ jsxDEV15("span", {
1636
- className: "lw-count",
1637
- children: t.count(shown)
1638
- }, undefined, false, undefined, this)
1639
- ]
1640
- }, undefined, true, undefined, this),
1641
- noIdentity ? /* @__PURE__ */ jsxDEV15("p", {
1642
- className: "lw-state",
1643
- children: t.signedOut
1644
- }, undefined, false, undefined, this) : loading ? /* @__PURE__ */ jsxDEV15("div", {
1645
- children: [0, 1, 2, 3].map((n) => /* @__PURE__ */ jsxDEV15("div", {
1646
- className: "lw-skeleton"
1647
- }, n, false, undefined, this))
1648
- }, undefined, false, undefined, this) : error ? /* @__PURE__ */ jsxDEV15("p", {
1649
- className: "lw-state lw-state--error",
1650
- children: [
1651
- /* @__PURE__ */ jsxDEV15(AlertIcon, {}, undefined, false, undefined, this),
1652
- " ",
1653
- error,
1654
- /* @__PURE__ */ jsxDEV15("button", {
1655
- type: "button",
1656
- className: "lw-retry",
1657
- onClick: () => void load(),
1658
- children: t.retry
1659
- }, undefined, false, undefined, this)
1660
- ]
1661
- }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV15(TicketTable, {
1662
- items,
1663
- maps,
1664
- t,
1665
- slug: config?.realm.slug,
1666
- timezone: config?.timezone ?? "Asia/Bangkok",
1667
- locale,
1668
- keyword: applied,
1669
- statusFilter,
1670
- sort,
1671
- page,
1672
- onOpen: (id) => void open(id),
1673
- onSort: toggleSort,
1674
- onPage: setPage,
1675
- onCount: setShown
1676
- }, undefined, false, undefined, this)
1677
- ]
1678
- }, undefined, true, undefined, this);
1679
- }
1680
- function readDataUri2(file) {
1681
- return new Promise((resolve, reject) => {
1682
- const reader = new FileReader;
1683
- reader.addEventListener("load", () => typeof reader.result === "string" ? resolve(reader.result) : reject(new Error("unreadable file")));
1684
- reader.addEventListener("error", () => reject(new Error("unreadable file")));
1685
- reader.readAsDataURL(file);
1686
- });
179
+ children: typeof children === "function" ? children({ pending }) : children ?? label
180
+ }, undefined, false, undefined, this);
1687
181
  }
1688
182
 
1689
183
  // src/index.ts
@@ -1692,14 +186,8 @@ export {
1692
186
  onCrash,
1693
187
  launch2 as launch,
1694
188
  configureDebugCapture2 as configureDebugCapture,
1695
- TicketTable,
1696
- TicketDetail,
1697
- TicketConversation,
1698
- TicketBody,
1699
- RichReplyEditor,
189
+ SupportPortalButton,
1700
190
  ReportProblemButton,
1701
- MyTicketsPanel,
1702
- ImageAnnotatorDialog,
1703
191
  DebugErrorBoundary,
1704
192
  DebugCaptureInit
1705
193
  };