@flamingo-stack/openframe-frontend-core 0.0.216 → 0.0.217
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-SMCG2CCC.cjs → chunk-6DCKL73F.cjs} +24 -24
- package/dist/{chunk-SMCG2CCC.cjs.map → chunk-6DCKL73F.cjs.map} +1 -1
- package/dist/{chunk-QTKU6ULP.js → chunk-BVFRD34B.js} +2 -2
- package/dist/{chunk-CDLYRFDE.js → chunk-ENBGG2K2.js} +3767 -3610
- package/dist/chunk-ENBGG2K2.js.map +1 -0
- package/dist/{chunk-K4DFAVSO.cjs → chunk-G2HHSZ3S.cjs} +9 -9
- package/dist/{chunk-K4DFAVSO.cjs.map → chunk-G2HHSZ3S.cjs.map} +1 -1
- package/dist/{chunk-2V4SACHE.js → chunk-L6IBKPVM.js} +2 -2
- package/dist/{chunk-572WQWIX.cjs → chunk-MVQ3OODK.cjs} +9 -9
- package/dist/{chunk-572WQWIX.cjs.map → chunk-MVQ3OODK.cjs.map} +1 -1
- package/dist/{chunk-GVNQAGXB.js → chunk-N5IKPYRL.js} +3 -81
- package/dist/chunk-N5IKPYRL.js.map +1 -0
- package/dist/{chunk-VC3ND5RB.js → chunk-SWZUZYWR.js} +2 -2
- package/dist/{chunk-IH76P5R6.cjs → chunk-TYIBMDUZ.cjs} +8 -86
- package/dist/chunk-TYIBMDUZ.cjs.map +1 -0
- package/dist/{chunk-ZGTDUPTW.cjs → chunk-YWDC5BXM.cjs} +382 -225
- package/dist/chunk-YWDC5BXM.cjs.map +1 -0
- package/dist/components/chat/chat-attachment-bar.d.ts +13 -2
- package/dist/components/chat/chat-attachment-bar.d.ts.map +1 -1
- package/dist/components/chat/chat-input.d.ts.map +1 -1
- package/dist/components/chat/chat-message-row.d.ts +25 -0
- package/dist/components/chat/chat-message-row.d.ts.map +1 -0
- package/dist/components/chat/index.cjs +6 -2
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.d.ts +1 -0
- package/dist/components/chat/index.d.ts.map +1 -1
- package/dist/components/chat/index.js +5 -1
- package/dist/components/chat/types/component.types.d.ts +8 -1
- package/dist/components/chat/types/component.types.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +3 -3
- package/dist/components/contact/index.js +2 -2
- package/dist/components/features/index.cjs +2 -2
- package/dist/components/features/index.js +1 -1
- package/dist/components/form.d.ts +1 -1
- package/dist/components/form.d.ts.map +1 -1
- package/dist/components/index.cjs +56 -52
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +9 -5
- package/dist/components/index.js.map +1 -1
- package/dist/components/navigation/index.cjs +2 -2
- package/dist/components/navigation/index.js +1 -1
- package/dist/components/onboarding-guides/index.cjs +18 -18
- package/dist/components/onboarding-guides/index.js +3 -3
- package/dist/components/shared/dev-section/dev-card-row.d.ts +5 -45
- package/dist/components/shared/dev-section/dev-card-row.d.ts.map +1 -1
- package/dist/components/shared/legal-document/use-legal-docs.d.ts.map +1 -1
- package/dist/components/tickets/help-center-card.d.ts.map +1 -1
- package/dist/components/tickets/help-center-list.d.ts.map +1 -1
- package/dist/components/tickets/hooks/use-ticket-engagements.d.ts +9 -1
- package/dist/components/tickets/hooks/use-ticket-engagements.d.ts.map +1 -1
- package/dist/components/tickets/hooks/use-tickets-list.d.ts +7 -0
- package/dist/components/tickets/hooks/use-tickets-list.d.ts.map +1 -1
- package/dist/components/tickets/index.cjs +294 -255
- package/dist/components/tickets/index.cjs.map +1 -1
- package/dist/components/tickets/index.d.ts +1 -0
- package/dist/components/tickets/index.d.ts.map +1 -1
- package/dist/components/tickets/index.js +360 -321
- package/dist/components/tickets/index.js.map +1 -1
- package/dist/components/tickets/ticket-detail-drawer.d.ts.map +1 -1
- package/dist/components/tickets/ticket-reply-composer.d.ts +33 -0
- package/dist/components/tickets/ticket-reply-composer.d.ts.map +1 -0
- package/dist/components/tickets/types.d.ts +13 -0
- package/dist/components/tickets/types.d.ts.map +1 -1
- package/dist/components/ui/index.cjs +6 -2
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.js +5 -1
- package/dist/components/ui/ticket-attachments-list.d.ts +5 -1
- package/dist/components/ui/ticket-attachments-list.d.ts.map +1 -1
- package/dist/index.cjs +6 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -1
- package/dist/utils/index.cjs +59 -4
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.js +59 -4
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/scroll-into-view.d.ts +43 -48
- package/dist/utils/scroll-into-view.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/chat/chat-attachment-bar.tsx +58 -22
- package/src/components/chat/chat-input.tsx +68 -29
- package/src/components/chat/chat-message-row.tsx +124 -0
- package/src/components/chat/index.ts +1 -0
- package/src/components/chat/types/component.types.ts +8 -1
- package/src/components/shared/dev-section/dev-card-row.tsx +5 -183
- package/src/components/shared/legal-document/use-legal-docs.ts +5 -1
- package/src/components/tickets/help-center-card.tsx +26 -29
- package/src/components/tickets/help-center-list.tsx +57 -10
- package/src/components/tickets/hooks/use-ticket-engagements.ts +17 -1
- package/src/components/tickets/hooks/use-tickets-list.ts +13 -0
- package/src/components/tickets/index.ts +4 -0
- package/src/components/tickets/ticket-detail-drawer.tsx +144 -200
- package/src/components/tickets/ticket-reply-composer.tsx +195 -0
- package/src/components/tickets/types.ts +14 -0
- package/src/components/ui/ticket-attachments-list.tsx +26 -8
- package/src/styles/app-globals.css +13 -0
- package/src/utils/scroll-into-view.ts +127 -53
- package/dist/chunk-CDLYRFDE.js.map +0 -1
- package/dist/chunk-GVNQAGXB.js.map +0 -1
- package/dist/chunk-IH76P5R6.cjs.map +0 -1
- package/dist/chunk-ZGTDUPTW.cjs.map +0 -1
- /package/dist/{chunk-QTKU6ULP.js.map → chunk-BVFRD34B.js.map} +0 -0
- /package/dist/{chunk-2V4SACHE.js.map → chunk-L6IBKPVM.js.map} +0 -0
- /package/dist/{chunk-VC3ND5RB.js.map → chunk-SWZUZYWR.js.map} +0 -0
|
@@ -4,18 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
var
|
|
7
|
+
var _chunkG2HHSZ3Scjs = require('../../chunk-G2HHSZ3S.cjs');
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
var _chunkTYIBMDUZcjs = require('../../chunk-TYIBMDUZ.cjs');
|
|
13
|
+
require('../../chunk-OB45JHDY.cjs');
|
|
12
14
|
|
|
13
15
|
|
|
14
|
-
var
|
|
15
|
-
|
|
16
|
+
var _chunk6DCKL73Fcjs = require('../../chunk-6DCKL73F.cjs');
|
|
17
|
+
|
|
16
18
|
|
|
17
19
|
|
|
18
|
-
var _chunkSMCG2CCCcjs = require('../../chunk-SMCG2CCC.cjs');
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
|
|
@@ -39,7 +40,8 @@ var _chunkSMCG2CCCcjs = require('../../chunk-SMCG2CCC.cjs');
|
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
|
|
44
|
+
var _chunkYWDC5BXMcjs = require('../../chunk-YWDC5BXM.cjs');
|
|
43
45
|
require('../../chunk-XL4V2PYG.cjs');
|
|
44
46
|
require('../../chunk-BZFW3FOF.cjs');
|
|
45
47
|
|
|
@@ -82,6 +84,7 @@ function isOptimistic(t) {
|
|
|
82
84
|
return t._optimistic === true;
|
|
83
85
|
}
|
|
84
86
|
var TICKET_TEXT_MAX_CHARS = 5e3;
|
|
87
|
+
var TICKET_LIVE_POLL_MS = 8e3;
|
|
85
88
|
var TOAST_COPY = {
|
|
86
89
|
open_success: { title: "Ticket opened", description: "We received your message and will follow up shortly." },
|
|
87
90
|
open_mirror_pending: { title: "Ticket opened", description: "Syncing \u2014 your ticket will appear momentarily." },
|
|
@@ -102,7 +105,7 @@ function TicketOpenForm({
|
|
|
102
105
|
}) {
|
|
103
106
|
const [subject, setSubject] = _react.useState.call(void 0, "");
|
|
104
107
|
const [content, setContent] = _react.useState.call(void 0, "");
|
|
105
|
-
const { attachments, readyAttachments, hasInflightUploads, addFiles, removeAttachment, clear } =
|
|
108
|
+
const { attachments, readyAttachments, hasInflightUploads, addFiles, removeAttachment, clear } = _chunkYWDC5BXMcjs.useChatAttachments.call(void 0, );
|
|
106
109
|
const trimmedSubject = subject.trim();
|
|
107
110
|
const trimmedContent = content.trim();
|
|
108
111
|
const overCap = content.length > TICKET_TEXT_MAX_CHARS;
|
|
@@ -122,7 +125,7 @@ function TicketOpenForm({
|
|
|
122
125
|
clear();
|
|
123
126
|
}
|
|
124
127
|
};
|
|
125
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
128
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYWDC5BXMcjs.Card, { className: "p-6", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { onSubmit: handleSubmit, className: "flex flex-col md:flex-row gap-6", children: [
|
|
126
129
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex-1 min-w-0 md:max-w-md", children: [
|
|
127
130
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "text-2xl font-semibold text-ods-text-primary mb-2", children: "Need Support?" }),
|
|
128
131
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-sm", children: "Can't find what you're looking for? Submit a support ticket below \u2014 we'll follow up shortly." }),
|
|
@@ -161,7 +164,7 @@ function TicketOpenForm({
|
|
|
161
164
|
}
|
|
162
165
|
),
|
|
163
166
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
164
|
-
|
|
167
|
+
_chunkYWDC5BXMcjs.Textarea,
|
|
165
168
|
{
|
|
166
169
|
id: "ticket-content",
|
|
167
170
|
placeholder: "Describe your issue or question in detail...",
|
|
@@ -185,7 +188,7 @@ function TicketOpenForm({
|
|
|
185
188
|
)
|
|
186
189
|
] }),
|
|
187
190
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
188
|
-
|
|
191
|
+
_chunkYWDC5BXMcjs.ChatAttachmentChipStrip,
|
|
189
192
|
{
|
|
190
193
|
attachments,
|
|
191
194
|
onRemove: removeAttachment,
|
|
@@ -194,7 +197,7 @@ function TicketOpenForm({
|
|
|
194
197
|
),
|
|
195
198
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center justify-between gap-3", children: [
|
|
196
199
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
197
|
-
|
|
200
|
+
_chunkYWDC5BXMcjs.ChatAttachmentAddButton,
|
|
198
201
|
{
|
|
199
202
|
attachmentsEnabled: !supportSystemDown,
|
|
200
203
|
attachmentsCount: attachments.length,
|
|
@@ -226,15 +229,15 @@ var CollapsibleContent2 = CollapsiblePrimitive.CollapsibleContent;
|
|
|
226
229
|
|
|
227
230
|
// src/components/tickets/ticket-detail-drawer.tsx
|
|
228
231
|
_chunkXDPSSE4Ocjs.init_button2.call(void 0, );
|
|
229
|
-
|
|
232
|
+
var _usesticktobottom = require('use-stick-to-bottom');
|
|
230
233
|
|
|
231
234
|
// src/components/tickets/hooks/use-ticket-engagements.ts
|
|
232
235
|
|
|
233
236
|
var LIST_ENGAGEMENTS_ENDPOINT = "/api/chat/agent/list-engagements";
|
|
234
|
-
function useTicketEngagements(externalTicketId, enabled = true) {
|
|
235
|
-
const identity =
|
|
236
|
-
const identityKey = _nullishCoalesce(_optionalChain([identity, 'access',
|
|
237
|
-
const queryEnabled = enabled && identity.authTier !== "anon" && !!_optionalChain([identity, 'access',
|
|
237
|
+
function useTicketEngagements(externalTicketId, enabled = true, refetchInterval = false) {
|
|
238
|
+
const identity = _chunkYWDC5BXMcjs.useChatIdentity.call(void 0, );
|
|
239
|
+
const identityKey = _nullishCoalesce(_optionalChain([identity, 'access', _2 => _2.user, 'optionalAccess', _3 => _3.email]), () => ( "anon"));
|
|
240
|
+
const queryEnabled = enabled && identity.authTier !== "anon" && !!_optionalChain([identity, 'access', _4 => _4.user, 'optionalAccess', _5 => _5.email]) && !!externalTicketId && !externalTicketId.startsWith("temp-");
|
|
238
241
|
const query = _reactquery.useQuery.call(void 0, {
|
|
239
242
|
queryKey: ["ticket-engagements", externalTicketId, identityKey],
|
|
240
243
|
enabled: queryEnabled,
|
|
@@ -245,8 +248,13 @@ function useTicketEngagements(externalTicketId, enabled = true) {
|
|
|
245
248
|
gcTime: 0,
|
|
246
249
|
refetchOnMount: "always",
|
|
247
250
|
refetchOnWindowFocus: true,
|
|
251
|
+
// Live conversation: poll while the caller opts in (drawer open). New
|
|
252
|
+
// agent replies + attachments appear within one interval without a
|
|
253
|
+
// manual refresh. `refetchIntervalInBackground` stays false (default)
|
|
254
|
+
// so polling pauses on a hidden tab.
|
|
255
|
+
refetchInterval,
|
|
248
256
|
queryFn: async () => {
|
|
249
|
-
const response = await
|
|
257
|
+
const response = await _chunkYWDC5BXMcjs.embedAuthedFetch.call(void 0, LIST_ENGAGEMENTS_ENDPOINT, {
|
|
250
258
|
method: "POST",
|
|
251
259
|
body: JSON.stringify({ ticket_id: externalTicketId })
|
|
252
260
|
});
|
|
@@ -294,7 +302,7 @@ function TicketLinkedDeliveryCard({
|
|
|
294
302
|
{
|
|
295
303
|
className: `rounded-md border border-ods-border bg-ods-bg overflow-hidden ${_nullishCoalesce(className, () => ( ""))}`,
|
|
296
304
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
297
|
-
|
|
305
|
+
_chunkG2HHSZ3Scjs.DeliveryRow,
|
|
298
306
|
{
|
|
299
307
|
item,
|
|
300
308
|
href: clickup.delivery_href,
|
|
@@ -305,6 +313,132 @@ function TicketLinkedDeliveryCard({
|
|
|
305
313
|
);
|
|
306
314
|
}
|
|
307
315
|
|
|
316
|
+
// src/components/tickets/ticket-reply-composer.tsx
|
|
317
|
+
_chunkXDPSSE4Ocjs.init_button2.call(void 0, );
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
function TicketReplyComposer({
|
|
321
|
+
ticket,
|
|
322
|
+
busy,
|
|
323
|
+
supportSystemDown,
|
|
324
|
+
onSendMessage,
|
|
325
|
+
onClose
|
|
326
|
+
}) {
|
|
327
|
+
const [resolution, setResolution] = _react.useState.call(void 0, "");
|
|
328
|
+
const [closeDialogOpen, setCloseDialogOpen] = _react.useState.call(void 0, false);
|
|
329
|
+
const attachments = _chunkYWDC5BXMcjs.useChatAttachments.call(void 0, );
|
|
330
|
+
const ticketRef = { id: ticket.id, external_id: ticket.external_id };
|
|
331
|
+
const hasReadyFiles = attachments.readyAttachments.length > 0;
|
|
332
|
+
const handleSend = _react.useCallback.call(void 0,
|
|
333
|
+
async (text) => {
|
|
334
|
+
const ref = { id: ticket.id, external_id: ticket.external_id };
|
|
335
|
+
const ok = await onSendMessage(ref, text.trim(), attachments.readyAttachments);
|
|
336
|
+
if (ok) attachments.clear();
|
|
337
|
+
return ok;
|
|
338
|
+
},
|
|
339
|
+
// Depend on the reactive projections, not the whole bag (a fresh object each
|
|
340
|
+
// render). `readyAttachments` is memo-stable; `clear` is callback-stable.
|
|
341
|
+
[
|
|
342
|
+
onSendMessage,
|
|
343
|
+
ticket.id,
|
|
344
|
+
ticket.external_id,
|
|
345
|
+
attachments.readyAttachments,
|
|
346
|
+
attachments.clear
|
|
347
|
+
]
|
|
348
|
+
);
|
|
349
|
+
const confirmClose = async () => {
|
|
350
|
+
setCloseDialogOpen(false);
|
|
351
|
+
await onClose(ticketRef, resolution.trim() || void 0);
|
|
352
|
+
setResolution("");
|
|
353
|
+
};
|
|
354
|
+
const disabled = busy || supportSystemDown;
|
|
355
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-2", children: [
|
|
356
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
357
|
+
_chunkYWDC5BXMcjs.ChatAttachmentChipStrip,
|
|
358
|
+
{
|
|
359
|
+
attachments: attachments.attachments,
|
|
360
|
+
onRemove: attachments.removeAttachment,
|
|
361
|
+
disabled,
|
|
362
|
+
size: "compact"
|
|
363
|
+
}
|
|
364
|
+
),
|
|
365
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
366
|
+
_chunkYWDC5BXMcjs.ChatInput,
|
|
367
|
+
{
|
|
368
|
+
fullWidth: true,
|
|
369
|
+
autoFocus: true,
|
|
370
|
+
placeholder: "Type a reply\u2026",
|
|
371
|
+
sending: busy || attachments.hasInflightUploads,
|
|
372
|
+
disabled: supportSystemDown,
|
|
373
|
+
allowEmptySend: hasReadyFiles,
|
|
374
|
+
maxLength: TICKET_TEXT_MAX_CHARS,
|
|
375
|
+
onSend: handleSend
|
|
376
|
+
}
|
|
377
|
+
),
|
|
378
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2 w-full", children: [
|
|
379
|
+
!supportSystemDown && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
380
|
+
_chunkYWDC5BXMcjs.ChatAttachmentAddButton,
|
|
381
|
+
{
|
|
382
|
+
attachmentsEnabled: true,
|
|
383
|
+
attachmentsCount: attachments.attachments.length,
|
|
384
|
+
onAddFiles: attachments.addFiles,
|
|
385
|
+
disabled,
|
|
386
|
+
size: "compact"
|
|
387
|
+
}
|
|
388
|
+
),
|
|
389
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1 min-w-0" }),
|
|
390
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
391
|
+
_chunkXDPSSE4Ocjs.Button,
|
|
392
|
+
{
|
|
393
|
+
type: "button",
|
|
394
|
+
variant: "transparent",
|
|
395
|
+
size: "small",
|
|
396
|
+
onClick: () => setCloseDialogOpen(true),
|
|
397
|
+
disabled,
|
|
398
|
+
className: "text-ods-text-secondary hover:text-ods-text-primary",
|
|
399
|
+
children: "Close ticket"
|
|
400
|
+
}
|
|
401
|
+
)
|
|
402
|
+
] }),
|
|
403
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYWDC5BXMcjs.AlertDialog, { open: closeDialogOpen, onOpenChange: setCloseDialogOpen, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkYWDC5BXMcjs.AlertDialogContent, { className: "bg-ods-card border-ods-border", children: [
|
|
404
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkYWDC5BXMcjs.AlertDialogHeader, { children: [
|
|
405
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYWDC5BXMcjs.AlertDialogTitle, { className: "text-ods-text-primary", children: "Close this ticket?" }),
|
|
406
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYWDC5BXMcjs.AlertDialogDescription, { className: "text-ods-text-secondary", children: "Add an optional resolution note below. You can reopen the ticket later if needed." })
|
|
407
|
+
] }),
|
|
408
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
409
|
+
_chunkYWDC5BXMcjs.Textarea,
|
|
410
|
+
{
|
|
411
|
+
value: resolution,
|
|
412
|
+
onChange: (e) => setResolution(e.target.value),
|
|
413
|
+
placeholder: "Resolution (optional)",
|
|
414
|
+
rows: 3,
|
|
415
|
+
maxLength: TICKET_TEXT_MAX_CHARS,
|
|
416
|
+
className: "mt-2"
|
|
417
|
+
}
|
|
418
|
+
),
|
|
419
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkYWDC5BXMcjs.AlertDialogFooter, { children: [
|
|
420
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
421
|
+
_chunkYWDC5BXMcjs.AlertDialogCancel,
|
|
422
|
+
{
|
|
423
|
+
disabled: busy,
|
|
424
|
+
className: "bg-transparent border-ods-border text-ods-text-primary hover:bg-ods-border",
|
|
425
|
+
children: "Cancel"
|
|
426
|
+
}
|
|
427
|
+
),
|
|
428
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
429
|
+
_chunkYWDC5BXMcjs.AlertDialogAction,
|
|
430
|
+
{
|
|
431
|
+
onClick: () => void confirmClose(),
|
|
432
|
+
disabled: busy,
|
|
433
|
+
className: "bg-ods-accent text-ods-text-on-accent hover:bg-ods-accent-hover",
|
|
434
|
+
children: "Close ticket"
|
|
435
|
+
}
|
|
436
|
+
)
|
|
437
|
+
] })
|
|
438
|
+
] }) })
|
|
439
|
+
] });
|
|
440
|
+
}
|
|
441
|
+
|
|
308
442
|
// src/components/tickets/ticket-detail-drawer.tsx
|
|
309
443
|
|
|
310
444
|
function TicketDetailDrawer({
|
|
@@ -344,37 +478,49 @@ function TicketDetailDrawer({
|
|
|
344
478
|
onActionCollapsed
|
|
345
479
|
}
|
|
346
480
|
) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
347
|
-
|
|
481
|
+
TicketReplyComposer,
|
|
348
482
|
{
|
|
349
483
|
ticket,
|
|
350
484
|
busy,
|
|
351
485
|
supportSystemDown,
|
|
352
486
|
onSendMessage,
|
|
353
|
-
onClose
|
|
354
|
-
onActionCollapsed
|
|
487
|
+
onClose
|
|
355
488
|
}
|
|
356
489
|
)
|
|
357
490
|
] })
|
|
358
491
|
] });
|
|
359
492
|
}
|
|
360
493
|
var TURN_SEPARATOR_RE = /[\s]{1,16}---[\s]{1,16}/g;
|
|
494
|
+
var TICKET_FEED_FRAME = "bg-ods-card border border-ods-border rounded-[6px] overflow-y-auto w-full";
|
|
495
|
+
var TICKET_FEED_HEIGHT = "h-[60vh] md:h-[420px]";
|
|
496
|
+
var TICKET_FEED_INNER = "flex flex-col gap-4 md:gap-6 px-4 md:px-6 py-4 md:py-6";
|
|
497
|
+
var TICKET_FEED_SKELETON_ROWS = 6;
|
|
361
498
|
function TicketTimelinePanel({ ticket }) {
|
|
362
|
-
const identity =
|
|
499
|
+
const identity = _chunkYWDC5BXMcjs.useChatIdentity.call(void 0, );
|
|
363
500
|
const externalId = isOptimistic(ticket) ? null : ticket.external_id;
|
|
364
|
-
const { engagements, isLoading } = useTicketEngagements(
|
|
501
|
+
const { engagements, isLoading } = useTicketEngagements(
|
|
502
|
+
externalId,
|
|
503
|
+
!!externalId,
|
|
504
|
+
TICKET_LIVE_POLL_MS
|
|
505
|
+
);
|
|
506
|
+
const { scrollRef, contentRef } = _usesticktobottom.useStickToBottom.call(void 0, { initial: "instant", resize: "smooth" });
|
|
365
507
|
const bodyTurns = ticket.body ? ticket.body.split(TURN_SEPARATOR_RE).map((t) => t.trim()).filter(Boolean) : [];
|
|
366
|
-
const
|
|
508
|
+
const customerEngagementBodies = new Set(
|
|
509
|
+
engagements.filter((e) => e.authorRole === "customer").map((e) => (_nullishCoalesce(e.body, () => ( ""))).trim()).filter(Boolean)
|
|
510
|
+
);
|
|
511
|
+
const suppressBodyTurnZero = bodyTurns.length > 0 && customerEngagementBodies.has(bodyTurns[0]);
|
|
512
|
+
const sessionEmailLower = _nullishCoalesce(_optionalChain([identity, 'access', _6 => _6.user, 'optionalAccess', _7 => _7.email, 'optionalAccess', _8 => _8.trim, 'call', _9 => _9(), 'access', _10 => _10.toLowerCase, 'call', _11 => _11()]), () => ( null));
|
|
367
513
|
const isViewerTheCustomer = !!sessionEmailLower && ticket.customer_emails.some((e) => e.trim().toLowerCase() === sessionEmailLower);
|
|
368
|
-
const viewerName = _optionalChain([identity, 'access',
|
|
369
|
-
const ticketCustomerName = _optionalChain([ticket, 'access',
|
|
370
|
-
const customerName = (isViewerTheCustomer ? viewerName : null) || ticketCustomerName || viewerName || _optionalChain([identity, 'access',
|
|
371
|
-
const customerAvatar = isViewerTheCustomer ? _nullishCoalesce(_optionalChain([identity, 'access',
|
|
514
|
+
const viewerName = _optionalChain([identity, 'access', _12 => _12.user, 'optionalAccess', _13 => _13.name, 'optionalAccess', _14 => _14.trim, 'call', _15 => _15()]) || null;
|
|
515
|
+
const ticketCustomerName = _optionalChain([ticket, 'access', _16 => _16.customer_name, 'optionalAccess', _17 => _17.trim, 'call', _18 => _18()]) || null;
|
|
516
|
+
const customerName = (isViewerTheCustomer ? viewerName : null) || ticketCustomerName || viewerName || _optionalChain([identity, 'access', _19 => _19.user, 'optionalAccess', _20 => _20.email]) || "You";
|
|
517
|
+
const customerAvatar = isViewerTheCustomer ? _nullishCoalesce(_optionalChain([identity, 'access', _21 => _21.user, 'optionalAccess', _22 => _22.avatarUrl]), () => ( void 0)) : void 0;
|
|
518
|
+
if (isLoading) {
|
|
519
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: `${TICKET_FEED_FRAME} ${TICKET_FEED_HEIGHT}`, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: TICKET_FEED_INNER, children: Array.from({ length: TICKET_FEED_SKELETON_ROWS }, (_, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYWDC5BXMcjs.ChatMessageRowSkeleton, {}, i)) }) });
|
|
520
|
+
}
|
|
372
521
|
if (bodyTurns.length === 0 && engagements.length === 0) {
|
|
373
|
-
if (isLoading) {
|
|
374
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkIH76P5R6cjs.ConversationCardRowSkeletonList, { rows: 2 });
|
|
375
|
-
}
|
|
376
522
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
377
|
-
|
|
523
|
+
_chunkG2HHSZ3Scjs.EmptyState,
|
|
378
524
|
{
|
|
379
525
|
type: "generic",
|
|
380
526
|
title: "No conversation yet",
|
|
@@ -383,31 +529,29 @@ function TicketTimelinePanel({ ticket }) {
|
|
|
383
529
|
}
|
|
384
530
|
);
|
|
385
531
|
}
|
|
386
|
-
return /* @__PURE__ */ _jsxruntime.
|
|
532
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { ref: scrollRef, className: `${TICKET_FEED_FRAME} ${TICKET_FEED_HEIGHT}`, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { ref: contentRef, className: TICKET_FEED_INNER, children: [
|
|
387
533
|
bodyTurns.map((turn, i) => {
|
|
534
|
+
if (i === 0 && suppressBodyTurnZero) return null;
|
|
388
535
|
const isResolution = turn.startsWith("[Resolution]");
|
|
389
|
-
const role = i === 0 ? "Original message" : isResolution ? "Resolution" : `Update ${i}`;
|
|
390
536
|
const text = isResolution ? turn.replace(/^\[Resolution\]\s*/, "") : turn;
|
|
391
537
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
392
|
-
|
|
538
|
+
_chunkYWDC5BXMcjs.ChatMessageRow,
|
|
393
539
|
{
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
body: text,
|
|
398
|
-
variant: "current-user"
|
|
540
|
+
displayName: customerName,
|
|
541
|
+
avatarUrl: customerAvatar,
|
|
542
|
+
body: text
|
|
399
543
|
},
|
|
400
544
|
`body-${i}-${turn.slice(0, 24)}`
|
|
401
545
|
);
|
|
402
546
|
}),
|
|
403
547
|
engagements.map((eng) => {
|
|
404
548
|
const isCustomer = eng.authorRole === "customer";
|
|
405
|
-
const isOwnReply = isCustomer && !!eng.authorId && !!_optionalChain([identity, 'access',
|
|
549
|
+
const isOwnReply = isCustomer && !!eng.authorId && !!_optionalChain([identity, 'access', _23 => _23.user, 'optionalAccess', _24 => _24.email]) && eng.authorId.toLowerCase() === identity.user.email.toLowerCase();
|
|
406
550
|
let author;
|
|
407
551
|
let avatarSrc;
|
|
408
552
|
if (isCustomer && isOwnReply) {
|
|
409
|
-
author = _optionalChain([identity, 'access',
|
|
410
|
-
avatarSrc = _nullishCoalesce(_optionalChain([identity, 'access',
|
|
553
|
+
author = _optionalChain([identity, 'access', _25 => _25.user, 'optionalAccess', _26 => _26.name, 'optionalAccess', _27 => _27.trim, 'call', _28 => _28()]) || customerName;
|
|
554
|
+
avatarSrc = _nullishCoalesce(_optionalChain([identity, 'access', _29 => _29.user, 'optionalAccess', _30 => _30.avatarUrl]), () => ( void 0));
|
|
411
555
|
} else if (isCustomer) {
|
|
412
556
|
author = ticketCustomerName || "Customer";
|
|
413
557
|
avatarSrc = void 0;
|
|
@@ -418,32 +562,30 @@ function TicketTimelinePanel({ ticket }) {
|
|
|
418
562
|
author = "Support team";
|
|
419
563
|
avatarSrc = void 0;
|
|
420
564
|
}
|
|
565
|
+
const engAttachments = mapEngagementAttachments(eng.attachments);
|
|
421
566
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
422
|
-
|
|
567
|
+
_chunkYWDC5BXMcjs.ChatMessageRow,
|
|
423
568
|
{
|
|
424
|
-
author,
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
timestamp: eng.createdAt,
|
|
569
|
+
displayName: author,
|
|
570
|
+
avatarUrl: avatarSrc,
|
|
571
|
+
timeLabel: eng.createdAt ? _chunkYWDC5BXMcjs.formatRelativeTime.call(void 0, eng.createdAt) : null,
|
|
428
572
|
body: stripAttachmentsPreamble(_nullishCoalesce(eng.body, () => ( ""))),
|
|
429
|
-
|
|
430
|
-
variant: isCustomer ? "current-user" : "support"
|
|
573
|
+
footer: engAttachments.length > 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mt-2", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYWDC5BXMcjs.TicketAttachmentsList, { attachments: engAttachments, size: "compact" }) }) : null
|
|
431
574
|
},
|
|
432
575
|
eng.id
|
|
433
576
|
);
|
|
434
|
-
})
|
|
435
|
-
|
|
436
|
-
// content rendered — drawer is showing the customer's body
|
|
437
|
-
// turns + cached engagements while a background refetch is
|
|
438
|
-
// in flight. Single row keeps the placeholder modest.
|
|
439
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkIH76P5R6cjs.ConversationCardRowSkeletonList, { rows: 1 })
|
|
440
|
-
] });
|
|
577
|
+
})
|
|
578
|
+
] }) });
|
|
441
579
|
}
|
|
442
580
|
function mapEngagementAttachments(files) {
|
|
443
581
|
return files.map((f) => ({
|
|
444
582
|
id: f.id,
|
|
445
583
|
fileName: _nullishCoalesce(f.name, () => ( `file-${f.id}`)),
|
|
446
584
|
fileSize: f.size ? formatBytes(f.size) : "",
|
|
585
|
+
// Show an inline thumbnail for image attachments (the signed `url` is a
|
|
586
|
+
// viewable URL). Non-images fall back to the file-type icon. SquareAvatar
|
|
587
|
+
// degrades to initials on a broken/expired image URL.
|
|
588
|
+
thumbnailSrc: f.url && (_nullishCoalesce(_optionalChain([f, 'access', _31 => _31.mime, 'optionalAccess', _32 => _32.startsWith, 'call', _33 => _33("image/")]), () => ( false))) ? f.url : void 0,
|
|
447
589
|
onDownload: f.url ? () => window.open(f.url, "_blank", "noopener,noreferrer") : void 0
|
|
448
590
|
}));
|
|
449
591
|
}
|
|
@@ -470,6 +612,8 @@ function ReopenAction({
|
|
|
470
612
|
_chunkXDPSSE4Ocjs.Button,
|
|
471
613
|
{
|
|
472
614
|
type: "button",
|
|
615
|
+
variant: "outline",
|
|
616
|
+
size: "small",
|
|
473
617
|
onClick: () => void handleReopen(),
|
|
474
618
|
disabled: busy || supportSystemDown,
|
|
475
619
|
loading: busy,
|
|
@@ -477,133 +621,6 @@ function ReopenAction({
|
|
|
477
621
|
}
|
|
478
622
|
) });
|
|
479
623
|
}
|
|
480
|
-
function OpenActions({
|
|
481
|
-
ticket,
|
|
482
|
-
busy,
|
|
483
|
-
supportSystemDown,
|
|
484
|
-
onSendMessage,
|
|
485
|
-
onClose,
|
|
486
|
-
onActionCollapsed
|
|
487
|
-
}) {
|
|
488
|
-
const [messageText, setMessageText] = _react.useState.call(void 0, "");
|
|
489
|
-
const [resolution, setResolution] = _react.useState.call(void 0, "");
|
|
490
|
-
const [closeDialogOpen, setCloseDialogOpen] = _react.useState.call(void 0, false);
|
|
491
|
-
const attachments = _chunkZGTDUPTWcjs.useChatAttachments.call(void 0, );
|
|
492
|
-
const disabled = busy || supportSystemDown;
|
|
493
|
-
const ticketRef = { id: ticket.id, external_id: ticket.external_id };
|
|
494
|
-
const hasText = messageText.trim().length > 0;
|
|
495
|
-
const hasReadyFiles = attachments.readyAttachments.length > 0;
|
|
496
|
-
const canSend = !disabled && (hasText || hasReadyFiles) && !attachments.hasInflightUploads;
|
|
497
|
-
const sendMessage = async () => {
|
|
498
|
-
if (!canSend) return;
|
|
499
|
-
const ok = await onSendMessage(ticketRef, messageText.trim(), attachments.readyAttachments);
|
|
500
|
-
if (ok) {
|
|
501
|
-
setMessageText("");
|
|
502
|
-
attachments.clear();
|
|
503
|
-
}
|
|
504
|
-
};
|
|
505
|
-
const confirmClose = async () => {
|
|
506
|
-
setCloseDialogOpen(false);
|
|
507
|
-
await onClose(ticketRef, resolution.trim() || void 0);
|
|
508
|
-
setResolution("");
|
|
509
|
-
};
|
|
510
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-3", children: [
|
|
511
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-2", children: [
|
|
512
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
513
|
-
_chunkZGTDUPTWcjs.Textarea,
|
|
514
|
-
{
|
|
515
|
-
value: messageText,
|
|
516
|
-
onChange: (e) => setMessageText(e.target.value),
|
|
517
|
-
placeholder: "Type a reply\u2026 (attach files if needed)",
|
|
518
|
-
disabled,
|
|
519
|
-
rows: 3,
|
|
520
|
-
maxLength: TICKET_TEXT_MAX_CHARS
|
|
521
|
-
}
|
|
522
|
-
),
|
|
523
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
524
|
-
_chunkZGTDUPTWcjs.ChatAttachmentChipStrip,
|
|
525
|
-
{
|
|
526
|
-
attachments: attachments.attachments,
|
|
527
|
-
onRemove: attachments.removeAttachment,
|
|
528
|
-
disabled
|
|
529
|
-
}
|
|
530
|
-
),
|
|
531
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex justify-between items-center gap-2 flex-wrap", children: [
|
|
532
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2", children: [
|
|
533
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
534
|
-
_chunkZGTDUPTWcjs.ChatAttachmentAddButton,
|
|
535
|
-
{
|
|
536
|
-
attachmentsEnabled: !supportSystemDown,
|
|
537
|
-
attachmentsCount: attachments.attachments.length,
|
|
538
|
-
onAddFiles: attachments.addFiles,
|
|
539
|
-
disabled
|
|
540
|
-
}
|
|
541
|
-
),
|
|
542
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-xs text-ods-text-secondary", children: "Attach files" })
|
|
543
|
-
] }),
|
|
544
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2", children: [
|
|
545
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
546
|
-
_chunkXDPSSE4Ocjs.Button,
|
|
547
|
-
{
|
|
548
|
-
type: "button",
|
|
549
|
-
variant: "transparent",
|
|
550
|
-
onClick: () => setCloseDialogOpen(true),
|
|
551
|
-
disabled,
|
|
552
|
-
className: "bg-ods-error hover:bg-ods-error-hover text-white border-transparent",
|
|
553
|
-
children: "Close ticket"
|
|
554
|
-
}
|
|
555
|
-
),
|
|
556
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
557
|
-
_chunkXDPSSE4Ocjs.Button,
|
|
558
|
-
{
|
|
559
|
-
type: "button",
|
|
560
|
-
onClick: () => void sendMessage(),
|
|
561
|
-
disabled: !canSend,
|
|
562
|
-
loading: busy,
|
|
563
|
-
children: "Send reply"
|
|
564
|
-
}
|
|
565
|
-
)
|
|
566
|
-
] })
|
|
567
|
-
] })
|
|
568
|
-
] }),
|
|
569
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkZGTDUPTWcjs.AlertDialog, { open: closeDialogOpen, onOpenChange: setCloseDialogOpen, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkZGTDUPTWcjs.AlertDialogContent, { className: "bg-ods-card border-ods-border", children: [
|
|
570
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkZGTDUPTWcjs.AlertDialogHeader, { children: [
|
|
571
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkZGTDUPTWcjs.AlertDialogTitle, { className: "text-ods-text-primary font-['DM_Sans'] text-[20px] font-semibold", children: "Close this ticket?" }),
|
|
572
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkZGTDUPTWcjs.AlertDialogDescription, { className: "text-ods-text-secondary font-['DM_Sans'] text-[14px]", children: "Add an optional resolution note below. You can reopen the ticket later if needed." })
|
|
573
|
-
] }),
|
|
574
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
575
|
-
_chunkZGTDUPTWcjs.Textarea,
|
|
576
|
-
{
|
|
577
|
-
value: resolution,
|
|
578
|
-
onChange: (e) => setResolution(e.target.value),
|
|
579
|
-
placeholder: "Resolution (optional)",
|
|
580
|
-
rows: 3,
|
|
581
|
-
maxLength: TICKET_TEXT_MAX_CHARS,
|
|
582
|
-
className: "mt-2"
|
|
583
|
-
}
|
|
584
|
-
),
|
|
585
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkZGTDUPTWcjs.AlertDialogFooter, { children: [
|
|
586
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
587
|
-
_chunkZGTDUPTWcjs.AlertDialogCancel,
|
|
588
|
-
{
|
|
589
|
-
disabled: busy,
|
|
590
|
-
className: "bg-transparent border-ods-border text-ods-text-primary hover:bg-ods-border",
|
|
591
|
-
children: "Cancel"
|
|
592
|
-
}
|
|
593
|
-
),
|
|
594
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
595
|
-
_chunkZGTDUPTWcjs.AlertDialogAction,
|
|
596
|
-
{
|
|
597
|
-
onClick: () => void confirmClose(),
|
|
598
|
-
disabled: busy,
|
|
599
|
-
className: "bg-ods-error hover:bg-ods-error-hover text-white",
|
|
600
|
-
children: "Close ticket"
|
|
601
|
-
}
|
|
602
|
-
)
|
|
603
|
-
] })
|
|
604
|
-
] }) })
|
|
605
|
-
] });
|
|
606
|
-
}
|
|
607
624
|
function ReplyFailureBanner({
|
|
608
625
|
error,
|
|
609
626
|
onDismiss
|
|
@@ -634,18 +651,18 @@ function ReplyFailureBanner({
|
|
|
634
651
|
function AssignedAgentRow({
|
|
635
652
|
assignedOwner
|
|
636
653
|
}) {
|
|
637
|
-
const trimmedName = _optionalChain([assignedOwner, 'optionalAccess',
|
|
638
|
-
const emailFallback = _optionalChain([assignedOwner, 'optionalAccess',
|
|
654
|
+
const trimmedName = _optionalChain([assignedOwner, 'optionalAccess', _34 => _34.name, 'optionalAccess', _35 => _35.trim, 'call', _36 => _36()]) || null;
|
|
655
|
+
const emailFallback = _optionalChain([assignedOwner, 'optionalAccess', _37 => _37.email, 'optionalAccess', _38 => _38.trim, 'call', _39 => _39()]) || null;
|
|
639
656
|
const displayLabel = _nullishCoalesce(trimmedName, () => ( (emailFallback ? emailFallback.split("@")[0] : null)));
|
|
640
657
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2 text-xs", children: [
|
|
641
658
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-ods-text-secondary uppercase tracking-wider font-medium", children: "Assigned to" }),
|
|
642
659
|
displayLabel ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex items-center gap-1.5 text-ods-text-primary font-medium", children: [
|
|
643
660
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
644
|
-
|
|
661
|
+
_chunkYWDC5BXMcjs.SquareAvatar,
|
|
645
662
|
{
|
|
646
663
|
size: "sm",
|
|
647
664
|
variant: "round",
|
|
648
|
-
src: _nullishCoalesce(_optionalChain([assignedOwner, 'optionalAccess',
|
|
665
|
+
src: _nullishCoalesce(_optionalChain([assignedOwner, 'optionalAccess', _40 => _40.avatarUrl]), () => ( void 0)),
|
|
649
666
|
alt: displayLabel,
|
|
650
667
|
fallback: displayLabel
|
|
651
668
|
}
|
|
@@ -672,7 +689,7 @@ function TicketRow({
|
|
|
672
689
|
const rowRef = _react.useRef.call(void 0, null);
|
|
673
690
|
const handleClick = _react.useCallback.call(void 0, () => {
|
|
674
691
|
onToggle(ticket.id);
|
|
675
|
-
|
|
692
|
+
_chunkYWDC5BXMcjs.scrollElementIntoView.call(void 0, rowRef.current, {
|
|
676
693
|
adjustTargetY: (raw) => {
|
|
677
694
|
if (!rowRef.current) return raw;
|
|
678
695
|
const expandedDrawer = document.querySelector(
|
|
@@ -698,7 +715,7 @@ function TicketRow({
|
|
|
698
715
|
// so the badge accurately reflects "Closed" with a checkmark.
|
|
699
716
|
statusLabel: _nullishCoalesce(ticket.pipeline_stage_label, () => ( void 0)),
|
|
700
717
|
category: _nullishCoalesce(ticket.customer_company, () => ( void 0)),
|
|
701
|
-
timeAgo: ticket.hubspot_updated_at ?
|
|
718
|
+
timeAgo: ticket.hubspot_updated_at ? _chunkYWDC5BXMcjs.formatRelativeTime.call(void 0, ticket.hubspot_updated_at) : void 0,
|
|
702
719
|
// Linked-work chip: surfaced whenever the ticket has a linked
|
|
703
720
|
// ClickUp task. Uses the linked task's own status so the chip text
|
|
704
721
|
// reads "Working" / "Waiting on version release" / etc. — useful
|
|
@@ -713,7 +730,7 @@ function TicketRow({
|
|
|
713
730
|
className: "border-b border-ods-border last:border-b-0",
|
|
714
731
|
children: [
|
|
715
732
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
716
|
-
|
|
733
|
+
_chunkYWDC5BXMcjs.ChatTicketItem,
|
|
717
734
|
{
|
|
718
735
|
ticket: tileData,
|
|
719
736
|
onClick: optimistic ? void 0 : handleClick,
|
|
@@ -758,6 +775,7 @@ function useTicketsList(filters) {
|
|
|
758
775
|
const pageSize = Math.max(1, Math.min(100, Math.floor(_nullishCoalesce(filters.pageSize, () => ( DEFAULT_PAGE_SIZE))) || DEFAULT_PAGE_SIZE));
|
|
759
776
|
const enabled = !!customerEmail;
|
|
760
777
|
const identityKey = customerEmail || "anon";
|
|
778
|
+
const refetchInterval = _nullishCoalesce(filters.refetchInterval, () => ( false));
|
|
761
779
|
const query = _reactquery.useQuery.call(void 0, {
|
|
762
780
|
queryKey: ["tickets", "self", identityKey, search, statusFilter, page, pageSize],
|
|
763
781
|
enabled,
|
|
@@ -770,6 +788,10 @@ function useTicketsList(filters) {
|
|
|
770
788
|
gcTime: 0,
|
|
771
789
|
refetchOnMount: "always",
|
|
772
790
|
refetchOnWindowFocus: true,
|
|
791
|
+
// Live status: poll while the caller opts in (drawer open). Defaults to
|
|
792
|
+
// false. `refetchIntervalInBackground` stays false (the default) so polling
|
|
793
|
+
// pauses on a hidden tab — no wasted requests when the user tabs away.
|
|
794
|
+
refetchInterval,
|
|
773
795
|
queryFn: async () => {
|
|
774
796
|
const body = {
|
|
775
797
|
query: search,
|
|
@@ -777,7 +799,7 @@ function useTicketsList(filters) {
|
|
|
777
799
|
pageSize
|
|
778
800
|
};
|
|
779
801
|
if (statusFilter) body.status = statusFilter;
|
|
780
|
-
const response = await
|
|
802
|
+
const response = await _chunkYWDC5BXMcjs.embedAuthedFetch.call(void 0, FIND_TICKET_ENDPOINT, {
|
|
781
803
|
method: "POST",
|
|
782
804
|
body: JSON.stringify(body)
|
|
783
805
|
});
|
|
@@ -789,12 +811,12 @@ function useTicketsList(filters) {
|
|
|
789
811
|
}
|
|
790
812
|
});
|
|
791
813
|
const data = query.data;
|
|
792
|
-
const totalCount = _nullishCoalesce(_nullishCoalesce(_optionalChain([data, 'optionalAccess',
|
|
793
|
-
const echoedPage = _nullishCoalesce(_optionalChain([data, 'optionalAccess',
|
|
794
|
-
const echoedPageSize = _nullishCoalesce(_optionalChain([data, 'optionalAccess',
|
|
795
|
-
const totalPages = _nullishCoalesce(_optionalChain([data, 'optionalAccess',
|
|
814
|
+
const totalCount = _nullishCoalesce(_nullishCoalesce(_optionalChain([data, 'optionalAccess', _41 => _41.totalCount]), () => ( _optionalChain([data, 'optionalAccess', _42 => _42.count]))), () => ( (_nullishCoalesce(_optionalChain([data, 'optionalAccess', _43 => _43.tickets, 'optionalAccess', _44 => _44.length]), () => ( 0)))));
|
|
815
|
+
const echoedPage = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _45 => _45.page]), () => ( page));
|
|
816
|
+
const echoedPageSize = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _46 => _46.pageSize]), () => ( pageSize));
|
|
817
|
+
const totalPages = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _47 => _47.totalPages]), () => ( Math.max(1, Math.ceil(totalCount / echoedPageSize))));
|
|
796
818
|
return {
|
|
797
|
-
tickets: _nullishCoalesce(_optionalChain([data, 'optionalAccess',
|
|
819
|
+
tickets: _nullishCoalesce(_optionalChain([data, 'optionalAccess', _48 => _48.tickets]), () => ( [])),
|
|
798
820
|
// Loading-state-truth = `data === undefined`. TanStack v5's
|
|
799
821
|
// `isPending` / `isLoading` flags can be `false` in transient
|
|
800
822
|
// windows where the query is enabled-but-fetch-not-yet-fired
|
|
@@ -816,7 +838,7 @@ function useTicketsList(filters) {
|
|
|
816
838
|
// - Background refetch with existing data: data !== undefined → no load
|
|
817
839
|
// - Filter-change refetch landing on empty results: data?.tickets===[]
|
|
818
840
|
// + isFetching → bridge skeleton (the `||` branch)
|
|
819
|
-
isLoading: enabled && (data === void 0 || query.isFetching && (_nullishCoalesce(_optionalChain([data, 'optionalAccess',
|
|
841
|
+
isLoading: enabled && (data === void 0 || query.isFetching && (_nullishCoalesce(_optionalChain([data, 'optionalAccess', _49 => _49.tickets]), () => ( []))).length === 0),
|
|
820
842
|
isFetching: query.isFetching,
|
|
821
843
|
error: _nullishCoalesce(query.error, () => ( null)),
|
|
822
844
|
refetch: () => {
|
|
@@ -891,7 +913,7 @@ function useTicketActions(options) {
|
|
|
891
913
|
}, []);
|
|
892
914
|
const executeTicketAction = _react.useCallback.call(void 0,
|
|
893
915
|
async (toolName, args) => {
|
|
894
|
-
const res = await
|
|
916
|
+
const res = await _chunkYWDC5BXMcjs.embedAuthedFetch.call(void 0, TICKET_ACTION_ENDPOINT, {
|
|
895
917
|
method: "POST",
|
|
896
918
|
body: JSON.stringify({ tool_name: toolName, args })
|
|
897
919
|
});
|
|
@@ -1003,7 +1025,7 @@ function useTicketActions(options) {
|
|
|
1003
1025
|
const result = await executeTicketAction("create_ticket", {
|
|
1004
1026
|
subject: input.subject.trim(),
|
|
1005
1027
|
content: input.content.trim(),
|
|
1006
|
-
..._optionalChain([input, 'access',
|
|
1028
|
+
..._optionalChain([input, 'access', _50 => _50.attachments, 'optionalAccess', _51 => _51.length]) ? { attachments: input.attachments } : {}
|
|
1007
1029
|
});
|
|
1008
1030
|
if (result.mirror_synced === false) {
|
|
1009
1031
|
toast2(TOAST_COPY.open_mirror_pending);
|
|
@@ -1115,7 +1137,7 @@ function useTicketActions(options) {
|
|
|
1115
1137
|
ticket,
|
|
1116
1138
|
{
|
|
1117
1139
|
status: "CLOSED",
|
|
1118
|
-
..._optionalChain([resolution, 'optionalAccess',
|
|
1140
|
+
..._optionalChain([resolution, 'optionalAccess', _52 => _52.trim, 'call', _53 => _53()]) ? { resolution: resolution.trim() } : {}
|
|
1119
1141
|
},
|
|
1120
1142
|
TOAST_COPY.close_success,
|
|
1121
1143
|
"close ticket"
|
|
@@ -1188,7 +1210,7 @@ function mapTicketActionError(err) {
|
|
|
1188
1210
|
removeRowFromCache: false
|
|
1189
1211
|
};
|
|
1190
1212
|
case "RATE_LIMITED": {
|
|
1191
|
-
const retryAfterRaw = _optionalChain([err, 'access',
|
|
1213
|
+
const retryAfterRaw = _optionalChain([err, 'access', _54 => _54.response, 'optionalAccess', _55 => _55.headers, 'access', _56 => _56.get, 'call', _57 => _57("Retry-After")]);
|
|
1192
1214
|
const retryAfterSeconds = retryAfterRaw ? parseInt(retryAfterRaw, 10) : void 0;
|
|
1193
1215
|
return {
|
|
1194
1216
|
code: err.code,
|
|
@@ -1276,13 +1298,13 @@ function resolveErrorCode(bodyCode, status) {
|
|
|
1276
1298
|
// src/components/tickets/ticket-center.tsx
|
|
1277
1299
|
|
|
1278
1300
|
function TicketCenter({ toast: toast2 = _chunk5V6MSE3Bcjs.toast } = {}) {
|
|
1279
|
-
const identity =
|
|
1301
|
+
const identity = _chunkYWDC5BXMcjs.useChatIdentity.call(void 0, );
|
|
1280
1302
|
if (identity.isLoading) {
|
|
1281
1303
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TicketCenterSkeleton, {});
|
|
1282
1304
|
}
|
|
1283
|
-
if (identity.authTier === "anon" || !_optionalChain([identity, 'access',
|
|
1305
|
+
if (identity.authTier === "anon" || !_optionalChain([identity, 'access', _58 => _58.user, 'optionalAccess', _59 => _59.email])) {
|
|
1284
1306
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1285
|
-
|
|
1307
|
+
_chunkG2HHSZ3Scjs.EmptyState,
|
|
1286
1308
|
{
|
|
1287
1309
|
type: "generic",
|
|
1288
1310
|
title: "Sign in to manage tickets",
|
|
@@ -1353,7 +1375,7 @@ function TicketCenterAuthed({
|
|
|
1353
1375
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-3 text-xs text-ods-text-secondary", children: [
|
|
1354
1376
|
lastUpdatedAt && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { children: [
|
|
1355
1377
|
"Updated ",
|
|
1356
|
-
|
|
1378
|
+
_chunkYWDC5BXMcjs.formatRelativeTime.call(void 0, new Date(lastUpdatedAt))
|
|
1357
1379
|
] }),
|
|
1358
1380
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1359
1381
|
_chunkXDPSSE4Ocjs.Button,
|
|
@@ -1369,15 +1391,15 @@ function TicketCenterAuthed({
|
|
|
1369
1391
|
)
|
|
1370
1392
|
] })
|
|
1371
1393
|
] }),
|
|
1372
|
-
isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TicketListSkeleton, {}) : merged.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1373
|
-
|
|
1394
|
+
isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TicketListSkeleton, {}) : merged.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYWDC5BXMcjs.Card, { className: "p-6", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1395
|
+
_chunkG2HHSZ3Scjs.EmptyState,
|
|
1374
1396
|
{
|
|
1375
1397
|
type: "generic",
|
|
1376
1398
|
title: "No tickets yet",
|
|
1377
1399
|
description: "Open one above to start the conversation.",
|
|
1378
1400
|
showCTA: false
|
|
1379
1401
|
}
|
|
1380
|
-
) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1402
|
+
) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYWDC5BXMcjs.Card, { className: "overflow-hidden", children: merged.map((ticket) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1381
1403
|
TicketRow,
|
|
1382
1404
|
{
|
|
1383
1405
|
ticket,
|
|
@@ -1397,7 +1419,7 @@ function TicketCenterAuthed({
|
|
|
1397
1419
|
}
|
|
1398
1420
|
function TicketCenterSkeleton() {
|
|
1399
1421
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-6", children: [
|
|
1400
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1422
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkYWDC5BXMcjs.Card, { className: "p-6", children: [
|
|
1401
1423
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXDPSSE4Ocjs.Skeleton, { className: "h-7 w-48 mb-4" }),
|
|
1402
1424
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXDPSSE4Ocjs.Skeleton, { className: "h-10 w-full mb-3" }),
|
|
1403
1425
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXDPSSE4Ocjs.Skeleton, { className: "h-24 w-full" })
|
|
@@ -1406,7 +1428,7 @@ function TicketCenterSkeleton() {
|
|
|
1406
1428
|
] });
|
|
1407
1429
|
}
|
|
1408
1430
|
function TicketListSkeleton() {
|
|
1409
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1431
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYWDC5BXMcjs.Card, { className: "overflow-hidden", children: [0, 1, 2].map((i) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "h-20 px-4 flex items-center gap-4 border-b border-ods-border last:border-b-0", children: [
|
|
1410
1432
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex-1 flex flex-col gap-2", children: [
|
|
1411
1433
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXDPSSE4Ocjs.Skeleton, { className: "h-4 w-2/3" }),
|
|
1412
1434
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXDPSSE4Ocjs.Skeleton, { className: "h-3 w-full" })
|
|
@@ -1419,7 +1441,7 @@ function TicketListSkeleton() {
|
|
|
1419
1441
|
// src/components/tickets/help-center-list.tsx
|
|
1420
1442
|
|
|
1421
1443
|
|
|
1422
|
-
|
|
1444
|
+
_chunkG2HHSZ3Scjs.init_unified_pagination.call(void 0, );
|
|
1423
1445
|
|
|
1424
1446
|
// src/components/tickets/help-center-card.tsx
|
|
1425
1447
|
|
|
@@ -1441,7 +1463,7 @@ function HelpCenterCard({
|
|
|
1441
1463
|
const optimistic = isOptimistic(ticket);
|
|
1442
1464
|
const rawStatus = (_nullishCoalesce(ticket.status, () => ( "OPEN"))).toUpperCase();
|
|
1443
1465
|
const priority = (_nullishCoalesce(ticket.priority, () => ( ""))).toUpperCase();
|
|
1444
|
-
const relativeUpdated = ticket.hubspot_updated_at ?
|
|
1466
|
+
const relativeUpdated = ticket.hubspot_updated_at ? _chunkYWDC5BXMcjs.formatRelativeTime.call(void 0, ticket.hubspot_updated_at) : "recently";
|
|
1445
1467
|
const title = (ticket.subject || "").trim() || "(untitled)";
|
|
1446
1468
|
const subtitle = `UPDATED ${relativeUpdated}, #${ticket.external_id || "\u2014"}${ticket.pipeline_stage_label ? `, ${ticket.pipeline_stage_label}` : ""}`;
|
|
1447
1469
|
const description = _nullishCoalesce(_nullishCoalesce(ticket.preview, () => ( ticket.body)), () => ( ""));
|
|
@@ -1450,33 +1472,28 @@ function HelpCenterCard({
|
|
|
1450
1472
|
const rowRef = _react.useRef.call(void 0, null);
|
|
1451
1473
|
const handleClick = _react.useCallback.call(void 0, () => {
|
|
1452
1474
|
onToggle(ticket.id);
|
|
1453
|
-
_chunkZGTDUPTWcjs.scrollElementIntoView.call(void 0, rowRef.current, {
|
|
1454
|
-
headerOffset: STICKY_HEADER_OFFSET_PX,
|
|
1455
|
-
adjustTargetY: (raw) => {
|
|
1456
|
-
if (!rowRef.current) return raw;
|
|
1457
|
-
const expandedDrawer = document.querySelector(
|
|
1458
|
-
'div[id^="help-center-drawer-"]'
|
|
1459
|
-
);
|
|
1460
|
-
if (!(expandedDrawer instanceof HTMLElement)) return raw;
|
|
1461
|
-
const drawerRect = expandedDrawer.getBoundingClientRect();
|
|
1462
|
-
const myRect = rowRef.current.getBoundingClientRect();
|
|
1463
|
-
if (drawerRect.bottom > myRect.top) return raw;
|
|
1464
|
-
return raw - drawerRect.height;
|
|
1465
|
-
}
|
|
1466
|
-
});
|
|
1467
1475
|
}, [onToggle, ticket.id]);
|
|
1476
|
+
_react.useEffect.call(void 0, () => {
|
|
1477
|
+
if (!isExpanded) return;
|
|
1478
|
+
const raf = requestAnimationFrame(() => {
|
|
1479
|
+
_chunkYWDC5BXMcjs.scrollElementIntoView.call(void 0, rowRef.current, {
|
|
1480
|
+
headerOffset: STICKY_HEADER_OFFSET_PX
|
|
1481
|
+
});
|
|
1482
|
+
});
|
|
1483
|
+
return () => cancelAnimationFrame(raf);
|
|
1484
|
+
}, [isExpanded]);
|
|
1468
1485
|
const rightBadges = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
1469
1486
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1470
|
-
|
|
1487
|
+
_chunkYWDC5BXMcjs.StatusBadge,
|
|
1471
1488
|
{
|
|
1472
1489
|
text: rawStatus,
|
|
1473
|
-
colorScheme:
|
|
1490
|
+
colorScheme: _chunkYWDC5BXMcjs.getStatusColorScheme.call(void 0, rawStatus),
|
|
1474
1491
|
variant: "card",
|
|
1475
1492
|
className: "border border-ods-border"
|
|
1476
1493
|
}
|
|
1477
1494
|
),
|
|
1478
1495
|
priority && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1479
|
-
|
|
1496
|
+
_chunkYWDC5BXMcjs.StatusBadge,
|
|
1480
1497
|
{
|
|
1481
1498
|
text: priority,
|
|
1482
1499
|
colorScheme: mapPriorityScheme(priority),
|
|
@@ -1503,7 +1520,7 @@ function HelpCenterCard({
|
|
|
1503
1520
|
"aria-controls": isExpanded ? `help-center-drawer-${ticket.id}` : void 0,
|
|
1504
1521
|
className: "w-full text-left p-[12px] md:p-[16px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ods-accent focus-visible:ring-inset disabled:cursor-default",
|
|
1505
1522
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1506
|
-
|
|
1523
|
+
_chunkTYIBMDUZcjs.DevCardRowContent,
|
|
1507
1524
|
{
|
|
1508
1525
|
title,
|
|
1509
1526
|
subtitle,
|
|
@@ -1578,7 +1595,7 @@ function HelpCenterCreateForm({
|
|
|
1578
1595
|
const [subject, setSubject] = _react.useState.call(void 0, "");
|
|
1579
1596
|
const [subjectError, setSubjectError] = _react.useState.call(void 0, null);
|
|
1580
1597
|
const subjectField = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col", children: [
|
|
1581
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1598
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkYWDC5BXMcjs.Label, { htmlFor: "help-center-subject", children: [
|
|
1582
1599
|
"Subject",
|
|
1583
1600
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-ods-accent", children: "*" })
|
|
1584
1601
|
] }),
|
|
@@ -1610,7 +1627,7 @@ function HelpCenterCreateForm({
|
|
|
1610
1627
|
)
|
|
1611
1628
|
] });
|
|
1612
1629
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1613
|
-
|
|
1630
|
+
_chunk6DCKL73Fcjs.ContactForm,
|
|
1614
1631
|
{
|
|
1615
1632
|
title: "Open a new ticket",
|
|
1616
1633
|
footerText: "The support team typically responds within one business day.",
|
|
@@ -1648,20 +1665,21 @@ function HelpCenterCreateForm({
|
|
|
1648
1665
|
// src/components/tickets/help-center-list.tsx
|
|
1649
1666
|
|
|
1650
1667
|
function HelpCenterList({ toast: toast2 = _chunk5V6MSE3Bcjs.toast } = {}) {
|
|
1651
|
-
const identity =
|
|
1668
|
+
const identity = _chunkYWDC5BXMcjs.useChatIdentity.call(void 0, );
|
|
1652
1669
|
const searchParams = _chunkG7UE6RKVcjs.useSearchParams.call(void 0, );
|
|
1653
1670
|
const router = _chunkG7UE6RKVcjs.useRouter.call(void 0, );
|
|
1654
1671
|
const pathname = _chunkG7UE6RKVcjs.usePathname.call(void 0, );
|
|
1655
1672
|
const search = searchParams.get("search") || "";
|
|
1656
1673
|
const status = searchParams.get("status") || "all";
|
|
1674
|
+
const ticketParam = searchParams.get("ticket") || "";
|
|
1657
1675
|
const rawPage = Number(searchParams.get("page"));
|
|
1658
1676
|
const page = Number.isFinite(rawPage) && rawPage > 0 ? Math.floor(rawPage) : 1;
|
|
1659
1677
|
if (identity.isLoading) {
|
|
1660
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1678
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTYIBMDUZcjs.DevSectionPage, { sectionKey: "tickets", preControls: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HelpCenterCreateFormSkeleton, {}), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTYIBMDUZcjs.DevCardRowSkeletonList, {}) });
|
|
1661
1679
|
}
|
|
1662
|
-
if (identity.authTier === "anon" || !_optionalChain([identity, 'access',
|
|
1663
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1664
|
-
|
|
1680
|
+
if (identity.authTier === "anon" || !_optionalChain([identity, 'access', _60 => _60.user, 'optionalAccess', _61 => _61.email])) {
|
|
1681
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTYIBMDUZcjs.DevSectionPage, { sectionKey: "tickets", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1682
|
+
_chunkG2HHSZ3Scjs.EmptyState,
|
|
1665
1683
|
{
|
|
1666
1684
|
type: "generic",
|
|
1667
1685
|
title: "Sign in to manage tickets",
|
|
@@ -1670,7 +1688,7 @@ function HelpCenterList({ toast: toast2 = _chunk5V6MSE3Bcjs.toast } = {}) {
|
|
|
1670
1688
|
}
|
|
1671
1689
|
) });
|
|
1672
1690
|
}
|
|
1673
|
-
const sessionName = [_optionalChain([identity, 'access',
|
|
1691
|
+
const sessionName = [_optionalChain([identity, 'access', _62 => _62.user, 'optionalAccess', _63 => _63.firstName]), _optionalChain([identity, 'access', _64 => _64.user, 'optionalAccess', _65 => _65.lastName])].filter(Boolean).join(" ").trim() || _optionalChain([identity, 'access', _66 => _66.user, 'optionalAccess', _67 => _67.email, 'optionalAccess', _68 => _68.split, 'call', _69 => _69("@"), 'access', _70 => _70[0]]) || "Customer";
|
|
1674
1692
|
const sessionEmail = identity.user.email;
|
|
1675
1693
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1676
1694
|
HelpCenterListAuthed,
|
|
@@ -1678,6 +1696,7 @@ function HelpCenterList({ toast: toast2 = _chunk5V6MSE3Bcjs.toast } = {}) {
|
|
|
1678
1696
|
search,
|
|
1679
1697
|
status,
|
|
1680
1698
|
page,
|
|
1699
|
+
ticketParam,
|
|
1681
1700
|
searchParams,
|
|
1682
1701
|
router,
|
|
1683
1702
|
pathname,
|
|
@@ -1691,6 +1710,7 @@ function HelpCenterListAuthed({
|
|
|
1691
1710
|
search,
|
|
1692
1711
|
status,
|
|
1693
1712
|
page,
|
|
1713
|
+
ticketParam,
|
|
1694
1714
|
searchParams,
|
|
1695
1715
|
router,
|
|
1696
1716
|
pathname,
|
|
@@ -1699,6 +1719,18 @@ function HelpCenterListAuthed({
|
|
|
1699
1719
|
sessionEmail
|
|
1700
1720
|
}) {
|
|
1701
1721
|
const queryClient = _reactquery.useQueryClient.call(void 0, );
|
|
1722
|
+
const [optimisticTickets, setOptimisticTickets] = _react.useState.call(void 0, []);
|
|
1723
|
+
const [supportSystemDown, setSupportSystemDown] = _react.useState.call(void 0, false);
|
|
1724
|
+
const setOpenTicket = _react.useCallback.call(void 0,
|
|
1725
|
+
(externalId) => {
|
|
1726
|
+
const params = new URLSearchParams(searchParams.toString());
|
|
1727
|
+
if (externalId) params.set("ticket", externalId);
|
|
1728
|
+
else params.delete("ticket");
|
|
1729
|
+
const qs = params.toString();
|
|
1730
|
+
router.replace(qs ? `${pathname}?${qs}` : pathname, { scroll: false });
|
|
1731
|
+
},
|
|
1732
|
+
[searchParams, router, pathname]
|
|
1733
|
+
);
|
|
1702
1734
|
const { tickets, isLoading, isFetching, error, refetch, totalPages } = useTicketsList({
|
|
1703
1735
|
// `sessionEmail` is drilled in from the parent — see the same
|
|
1704
1736
|
// pattern + race-cause rationale documented in
|
|
@@ -1709,17 +1741,19 @@ function HelpCenterListAuthed({
|
|
|
1709
1741
|
customerEmail: sessionEmail,
|
|
1710
1742
|
search,
|
|
1711
1743
|
status,
|
|
1712
|
-
page
|
|
1744
|
+
page,
|
|
1745
|
+
// Live status: while a drawer is open, poll so an out-of-band HubSpot
|
|
1746
|
+
// status change (e.g. agent closes the ticket) flips the badge +
|
|
1747
|
+
// open/reopen affordance within one interval. Idle (no drawer) → no poll.
|
|
1748
|
+
// `ticketParam` (the open ticket's external_id) is the open signal.
|
|
1749
|
+
refetchInterval: ticketParam ? TICKET_LIVE_POLL_MS : false
|
|
1713
1750
|
});
|
|
1714
|
-
const [
|
|
1715
|
-
const [expandedTicketId, setExpandedTicketId] = _react.useState.call(void 0, null);
|
|
1716
|
-
const [supportSystemDown, setSupportSystemDown] = _react.useState.call(void 0, false);
|
|
1751
|
+
const expandedTicketId = ticketParam && _optionalChain([tickets, 'access', _71 => _71.find, 'call', _72 => _72((t) => t.external_id === ticketParam), 'optionalAccess', _73 => _73.id]) || null;
|
|
1717
1752
|
const prependOptimistic = _react.useCallback.call(void 0, (placeholder) => {
|
|
1718
1753
|
setOptimisticTickets((prev) => [placeholder, ...prev]);
|
|
1719
1754
|
}, []);
|
|
1720
1755
|
const removeOptimistic = _react.useCallback.call(void 0, (placeholderId) => {
|
|
1721
1756
|
setOptimisticTickets((prev) => prev.filter((t) => t.id !== placeholderId));
|
|
1722
|
-
setExpandedTicketId((prev) => prev === placeholderId ? null : prev);
|
|
1723
1757
|
}, []);
|
|
1724
1758
|
const removeTicketFromCache = _react.useCallback.call(void 0,
|
|
1725
1759
|
(ticketId) => {
|
|
@@ -1732,7 +1766,6 @@ function HelpCenterListAuthed({
|
|
|
1732
1766
|
return { ...prev, tickets: nextTickets };
|
|
1733
1767
|
}
|
|
1734
1768
|
);
|
|
1735
|
-
setExpandedTicketId((prev) => prev === ticketId ? null : prev);
|
|
1736
1769
|
},
|
|
1737
1770
|
[queryClient]
|
|
1738
1771
|
);
|
|
@@ -1743,9 +1776,14 @@ function HelpCenterListAuthed({
|
|
|
1743
1776
|
toast: toast2,
|
|
1744
1777
|
onSupportSystemDown: () => setSupportSystemDown(true)
|
|
1745
1778
|
});
|
|
1746
|
-
const toggleRow = _react.useCallback.call(void 0,
|
|
1747
|
-
|
|
1748
|
-
|
|
1779
|
+
const toggleRow = _react.useCallback.call(void 0,
|
|
1780
|
+
(id) => {
|
|
1781
|
+
const t = tickets.find((x) => x.id === id);
|
|
1782
|
+
if (!_optionalChain([t, 'optionalAccess', _74 => _74.external_id])) return;
|
|
1783
|
+
setOpenTicket(t.external_id === ticketParam ? null : t.external_id);
|
|
1784
|
+
},
|
|
1785
|
+
[tickets, ticketParam, setOpenTicket]
|
|
1786
|
+
);
|
|
1749
1787
|
const merged = [...optimisticTickets, ...tickets];
|
|
1750
1788
|
const hasActiveFilters = search !== "" || status !== "" && status !== "all";
|
|
1751
1789
|
const hasResults = merged.length > 0;
|
|
@@ -1766,15 +1804,15 @@ function HelpCenterListAuthed({
|
|
|
1766
1804
|
] }),
|
|
1767
1805
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXDPSSE4Ocjs.Button, { type: "button", variant: "accent", onClick: () => refetch(), children: "Retry" })
|
|
1768
1806
|
] }),
|
|
1769
|
-
!error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-full", children: isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1807
|
+
!error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-full", children: isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTYIBMDUZcjs.DevCardRowSkeletonList, {}) : !hasResults && isFetching ? (
|
|
1770
1808
|
// Bridge state — background refetch in flight and the
|
|
1771
1809
|
// optimistic placeholder was just removed by the mutation
|
|
1772
1810
|
// callback. Without this branch "No tickets yet" would flash
|
|
1773
1811
|
// for ~50ms between `removeOptimistic` and the server
|
|
1774
1812
|
// response landing.
|
|
1775
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1813
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTYIBMDUZcjs.DevCardRowSkeletonList, { rows: 1 })
|
|
1776
1814
|
) : !hasResults ? hasActiveFilters ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1777
|
-
|
|
1815
|
+
_chunkG2HHSZ3Scjs.EmptyState,
|
|
1778
1816
|
{
|
|
1779
1817
|
type: "search",
|
|
1780
1818
|
title: "No tickets found",
|
|
@@ -1789,7 +1827,7 @@ function HelpCenterListAuthed({
|
|
|
1789
1827
|
}
|
|
1790
1828
|
}
|
|
1791
1829
|
) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1792
|
-
|
|
1830
|
+
_chunkG2HHSZ3Scjs.EmptyState,
|
|
1793
1831
|
{
|
|
1794
1832
|
type: "generic",
|
|
1795
1833
|
title: "No tickets yet",
|
|
@@ -1816,16 +1854,16 @@ function HelpCenterListAuthed({
|
|
|
1816
1854
|
onSendMessage: actions.sendMessage,
|
|
1817
1855
|
onClose: actions.closeTicket,
|
|
1818
1856
|
onReopen: actions.reopenTicket,
|
|
1819
|
-
onActionCollapsed: () =>
|
|
1857
|
+
onActionCollapsed: () => setOpenTicket(null),
|
|
1820
1858
|
replyError: actions.replyErrorFor(ticket.external_id),
|
|
1821
1859
|
onClearReplyError: () => actions.clearReplyError(ticket.external_id)
|
|
1822
1860
|
},
|
|
1823
1861
|
ticket.id
|
|
1824
1862
|
)) })
|
|
1825
1863
|
) }),
|
|
1826
|
-
!error && totalPages > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1864
|
+
!error && totalPages > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkG2HHSZ3Scjs.UnifiedPagination, { currentPage: page, totalPages })
|
|
1827
1865
|
] });
|
|
1828
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1866
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTYIBMDUZcjs.DevSectionPage, { sectionKey: "tickets", preControls: form, children: body });
|
|
1829
1867
|
}
|
|
1830
1868
|
|
|
1831
1869
|
|
|
@@ -1843,5 +1881,6 @@ function HelpCenterListAuthed({
|
|
|
1843
1881
|
|
|
1844
1882
|
|
|
1845
1883
|
|
|
1846
|
-
|
|
1884
|
+
|
|
1885
|
+
exports.HelpCenterCard = HelpCenterCard; exports.HelpCenterCreateForm = HelpCenterCreateForm; exports.HelpCenterCreateFormSkeleton = HelpCenterCreateFormSkeleton; exports.HelpCenterList = HelpCenterList; exports.TICKET_TOAST_COPY = TOAST_COPY; exports.TicketCenter = TicketCenter; exports.TicketDetailDrawer = TicketDetailDrawer; exports.TicketLinkedDeliveryCard = TicketLinkedDeliveryCard; exports.TicketOpenForm = TicketOpenForm; exports.TicketReplyComposer = TicketReplyComposer; exports.TicketRow = TicketRow; exports.isOptimistic = isOptimistic; exports.mapTicketActionError = mapTicketActionError; exports.useTicketActions = useTicketActions; exports.useTicketEngagements = useTicketEngagements; exports.useTicketsList = useTicketsList;
|
|
1847
1886
|
//# sourceMappingURL=index.cjs.map
|