@flamingo-stack/openframe-frontend-core 0.0.214 → 0.0.215-snapshot.20260529010429

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 (46) hide show
  1. package/dist/{chunk-KDNGUYZM.cjs → chunk-2G3NXF6J.cjs} +17 -17
  2. package/dist/{chunk-KDNGUYZM.cjs.map → chunk-2G3NXF6J.cjs.map} +1 -1
  3. package/dist/{chunk-HWY35EAK.js → chunk-7PCP7YQR.js} +2 -2
  4. package/dist/{chunk-YZUUFTIK.cjs → chunk-D4MNFY67.cjs} +3 -2
  5. package/dist/chunk-D4MNFY67.cjs.map +1 -0
  6. package/dist/{chunk-IZL2KEH6.cjs → chunk-NGFP4RVL.cjs} +24 -24
  7. package/dist/{chunk-IZL2KEH6.cjs.map → chunk-NGFP4RVL.cjs.map} +1 -1
  8. package/dist/{chunk-5OWDOFKK.js → chunk-R6MLPU4A.js} +2 -2
  9. package/dist/{chunk-UKND27XC.js → chunk-WQZP3JIZ.js} +3 -2
  10. package/dist/{chunk-UKND27XC.js.map → chunk-WQZP3JIZ.js.map} +1 -1
  11. package/dist/components/chat/index.cjs +2 -2
  12. package/dist/components/chat/index.js +1 -1
  13. package/dist/components/contact/index.cjs +3 -3
  14. package/dist/components/contact/index.js +2 -2
  15. package/dist/components/features/index.cjs +2 -2
  16. package/dist/components/features/index.js +1 -1
  17. package/dist/components/index.cjs +49 -49
  18. package/dist/components/index.js +2 -2
  19. package/dist/components/navigation/index.cjs +2 -2
  20. package/dist/components/navigation/index.js +1 -1
  21. package/dist/components/tickets/help-center-card.d.ts +5 -1
  22. package/dist/components/tickets/help-center-card.d.ts.map +1 -1
  23. package/dist/components/tickets/hooks/use-ticket-actions.d.ts +8 -0
  24. package/dist/components/tickets/hooks/use-ticket-actions.d.ts.map +1 -1
  25. package/dist/components/tickets/index.cjs +254 -103
  26. package/dist/components/tickets/index.cjs.map +1 -1
  27. package/dist/components/tickets/index.js +184 -33
  28. package/dist/components/tickets/index.js.map +1 -1
  29. package/dist/components/tickets/ticket-detail-drawer.d.ts +11 -2
  30. package/dist/components/tickets/ticket-detail-drawer.d.ts.map +1 -1
  31. package/dist/components/tickets/types.d.ts +28 -1
  32. package/dist/components/tickets/types.d.ts.map +1 -1
  33. package/dist/components/ui/index.cjs +2 -2
  34. package/dist/components/ui/index.js +1 -1
  35. package/dist/index.cjs +2 -2
  36. package/dist/index.js +1 -1
  37. package/package.json +1 -1
  38. package/src/components/platform/ShellTypeBadge.tsx +2 -2
  39. package/src/components/tickets/help-center-card.tsx +8 -0
  40. package/src/components/tickets/help-center-list.tsx +2 -0
  41. package/src/components/tickets/hooks/use-ticket-actions.ts +139 -5
  42. package/src/components/tickets/ticket-detail-drawer.tsx +129 -1
  43. package/src/components/tickets/types.ts +32 -0
  44. package/dist/chunk-YZUUFTIK.cjs.map +0 -1
  45. /package/dist/{chunk-HWY35EAK.js.map → chunk-7PCP7YQR.js.map} +0 -0
  46. /package/dist/{chunk-5OWDOFKK.js.map → chunk-R6MLPU4A.js.map} +0 -0
@@ -9,11 +9,11 @@
9
9
 
10
10
 
11
11
 
12
- var _chunkKDNGUYZMcjs = require('../../chunk-KDNGUYZM.cjs');
12
+ var _chunk2G3NXF6Jcjs = require('../../chunk-2G3NXF6J.cjs');
13
13
  require('../../chunk-VFKQMAUF.cjs');
14
14
 
15
15
 
16
- var _chunkIZL2KEH6cjs = require('../../chunk-IZL2KEH6.cjs');
16
+ var _chunkNGFP4RVLcjs = require('../../chunk-NGFP4RVL.cjs');
17
17
 
18
18
 
19
19
 
@@ -36,7 +36,8 @@ var _chunkIZL2KEH6cjs = require('../../chunk-IZL2KEH6.cjs');
36
36
 
37
37
 
38
38
 
39
- var _chunkYZUUFTIKcjs = require('../../chunk-YZUUFTIK.cjs');
39
+
40
+ var _chunkD4MNFY67cjs = require('../../chunk-D4MNFY67.cjs');
40
41
 
41
42
 
42
43
  var _chunkWT5JV2GScjs = require('../../chunk-WT5JV2GS.cjs');
@@ -99,7 +100,7 @@ function TicketOpenForm({
99
100
  }) {
100
101
  const [subject, setSubject] = _react.useState.call(void 0, "");
101
102
  const [content, setContent] = _react.useState.call(void 0, "");
102
- const { attachments, readyAttachments, hasInflightUploads, addFiles, removeAttachment, clear } = _chunkYZUUFTIKcjs.useChatAttachments.call(void 0, );
103
+ const { attachments, readyAttachments, hasInflightUploads, addFiles, removeAttachment, clear } = _chunkD4MNFY67cjs.useChatAttachments.call(void 0, );
103
104
  const trimmedSubject = subject.trim();
104
105
  const trimmedContent = content.trim();
105
106
  const overCap = content.length > TICKET_TEXT_MAX_CHARS;
@@ -119,7 +120,7 @@ function TicketOpenForm({
119
120
  clear();
120
121
  }
121
122
  };
122
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYZUUFTIKcjs.Card, { className: "p-6", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { onSubmit: handleSubmit, className: "flex flex-col md:flex-row gap-6", children: [
123
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkD4MNFY67cjs.Card, { className: "p-6", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { onSubmit: handleSubmit, className: "flex flex-col md:flex-row gap-6", children: [
123
124
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex-1 min-w-0 md:max-w-md", children: [
124
125
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "text-2xl font-semibold text-ods-text-primary mb-2", children: "Need Support?" }),
125
126
  /* @__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." }),
@@ -158,7 +159,7 @@ function TicketOpenForm({
158
159
  }
159
160
  ),
160
161
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
161
- _chunkYZUUFTIKcjs.Textarea,
162
+ _chunkD4MNFY67cjs.Textarea,
162
163
  {
163
164
  id: "ticket-content",
164
165
  placeholder: "Describe your issue or question in detail...",
@@ -182,7 +183,7 @@ function TicketOpenForm({
182
183
  )
183
184
  ] }),
184
185
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
185
- _chunkYZUUFTIKcjs.ChatAttachmentChipStrip,
186
+ _chunkD4MNFY67cjs.ChatAttachmentChipStrip,
186
187
  {
187
188
  attachments,
188
189
  onRemove: removeAttachment,
@@ -191,7 +192,7 @@ function TicketOpenForm({
191
192
  ),
192
193
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center justify-between gap-3", children: [
193
194
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
194
- _chunkYZUUFTIKcjs.ChatAttachmentAddButton,
195
+ _chunkD4MNFY67cjs.ChatAttachmentAddButton,
195
196
  {
196
197
  attachmentsEnabled: !supportSystemDown,
197
198
  attachmentsCount: attachments.length,
@@ -229,7 +230,7 @@ _chunkUXZ3ZJ3Mcjs.init_button2.call(void 0, );
229
230
 
230
231
  var LIST_ENGAGEMENTS_ENDPOINT = "/api/chat/agent/list-engagements";
231
232
  function useTicketEngagements(externalTicketId, enabled = true) {
232
- const identity = _chunkYZUUFTIKcjs.useChatIdentity.call(void 0, );
233
+ const identity = _chunkD4MNFY67cjs.useChatIdentity.call(void 0, );
233
234
  const identityKey = _nullishCoalesce(_optionalChain([identity, 'access', _ => _.user, 'optionalAccess', _2 => _2.email]), () => ( "anon"));
234
235
  const queryEnabled = enabled && identity.authTier !== "anon" && !!_optionalChain([identity, 'access', _3 => _3.user, 'optionalAccess', _4 => _4.email]) && !!externalTicketId && !externalTicketId.startsWith("temp-");
235
236
  const query = _reactquery.useQuery.call(void 0, {
@@ -243,7 +244,7 @@ function useTicketEngagements(externalTicketId, enabled = true) {
243
244
  refetchOnMount: "always",
244
245
  refetchOnWindowFocus: true,
245
246
  queryFn: async () => {
246
- const response = await _chunkYZUUFTIKcjs.embedAuthedFetch.call(void 0, LIST_ENGAGEMENTS_ENDPOINT, {
247
+ const response = await _chunkD4MNFY67cjs.embedAuthedFetch.call(void 0, LIST_ENGAGEMENTS_ENDPOINT, {
247
248
  method: "POST",
248
249
  body: JSON.stringify({ ticket_id: externalTicketId })
249
250
  });
@@ -291,7 +292,7 @@ function TicketLinkedDeliveryCard({
291
292
  {
292
293
  className: `rounded-md border border-ods-border bg-ods-bg overflow-hidden ${_nullishCoalesce(className, () => ( ""))}`,
293
294
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
294
- _chunkKDNGUYZMcjs.DeliveryRow,
295
+ _chunk2G3NXF6Jcjs.DeliveryRow,
295
296
  {
296
297
  item,
297
298
  href: clickup.delivery_href,
@@ -311,40 +312,52 @@ function TicketDetailDrawer({
311
312
  onSendMessage,
312
313
  onClose,
313
314
  onReopen,
314
- onActionCollapsed
315
+ onActionCollapsed,
316
+ replyError,
317
+ onClearReplyError
315
318
  }) {
316
319
  const isClosed = (_nullishCoalesce(ticket.status, () => ( ""))).toUpperCase() === "CLOSED";
317
320
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "bg-ods-card border-t border-ods-border px-4 py-4 flex flex-col gap-4", children: [
321
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AssignedAgentRow, { assignedOwner: ticket.assignedOwner }),
318
322
  ticket.clickup && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TicketLinkedDeliveryCard, { clickup: ticket.clickup }),
319
323
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
320
324
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-xs font-medium text-ods-text-secondary mb-2 uppercase tracking-wider", children: "Conversation" }),
321
325
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TicketTimelinePanel, { ticket })
322
326
  ] }),
323
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "border-t border-ods-border pt-4", children: isClosed ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
324
- ReopenAction,
325
- {
326
- ticketRef: { id: ticket.id, external_id: ticket.external_id },
327
- busy,
328
- supportSystemDown,
329
- onReopen,
330
- onActionCollapsed
331
- }
332
- ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
333
- OpenActions,
334
- {
335
- ticket,
336
- busy,
337
- supportSystemDown,
338
- onSendMessage,
339
- onClose,
340
- onActionCollapsed
341
- }
342
- ) })
327
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "border-t border-ods-border pt-4", children: [
328
+ replyError && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
329
+ ReplyFailureBanner,
330
+ {
331
+ error: replyError,
332
+ onDismiss: _nullishCoalesce(onClearReplyError, () => ( (() => void 0)))
333
+ }
334
+ ),
335
+ isClosed ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
336
+ ReopenAction,
337
+ {
338
+ ticketRef: { id: ticket.id, external_id: ticket.external_id },
339
+ busy,
340
+ supportSystemDown,
341
+ onReopen,
342
+ onActionCollapsed
343
+ }
344
+ ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
345
+ OpenActions,
346
+ {
347
+ ticket,
348
+ busy,
349
+ supportSystemDown,
350
+ onSendMessage,
351
+ onClose,
352
+ onActionCollapsed
353
+ }
354
+ )
355
+ ] })
343
356
  ] });
344
357
  }
345
358
  var TURN_SEPARATOR_RE = /[\s]{1,16}---[\s]{1,16}/g;
346
359
  function TicketTimelinePanel({ ticket }) {
347
- const identity = _chunkYZUUFTIKcjs.useChatIdentity.call(void 0, );
360
+ const identity = _chunkD4MNFY67cjs.useChatIdentity.call(void 0, );
348
361
  const externalId = isOptimistic(ticket) ? null : ticket.external_id;
349
362
  const { engagements, isLoading } = useTicketEngagements(externalId, !!externalId);
350
363
  const bodyTurns = ticket.body ? ticket.body.split(TURN_SEPARATOR_RE).map((t) => t.trim()).filter(Boolean) : [];
@@ -356,10 +369,10 @@ function TicketTimelinePanel({ ticket }) {
356
369
  const customerAvatar = isViewerTheCustomer ? _nullishCoalesce(_optionalChain([identity, 'access', _20 => _20.user, 'optionalAccess', _21 => _21.avatarUrl]), () => ( void 0)) : void 0;
357
370
  if (bodyTurns.length === 0 && engagements.length === 0) {
358
371
  if (isLoading) {
359
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKDNGUYZMcjs.ConversationCardRowSkeletonList, { rows: 2 });
372
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2G3NXF6Jcjs.ConversationCardRowSkeletonList, { rows: 2 });
360
373
  }
361
374
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
362
- _chunkKDNGUYZMcjs.EmptyState,
375
+ _chunk2G3NXF6Jcjs.EmptyState,
363
376
  {
364
377
  type: "generic",
365
378
  title: "No conversation yet",
@@ -374,7 +387,7 @@ function TicketTimelinePanel({ ticket }) {
374
387
  const role = i === 0 ? "Original message" : isResolution ? "Resolution" : `Update ${i}`;
375
388
  const text = isResolution ? turn.replace(/^\[Resolution\]\s*/, "") : turn;
376
389
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
377
- _chunkKDNGUYZMcjs.ConversationCardRow,
390
+ _chunk2G3NXF6Jcjs.ConversationCardRow,
378
391
  {
379
392
  author: customerName,
380
393
  role,
@@ -404,7 +417,7 @@ function TicketTimelinePanel({ ticket }) {
404
417
  avatarSrc = void 0;
405
418
  }
406
419
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
407
- _chunkKDNGUYZMcjs.ConversationCardRow,
420
+ _chunk2G3NXF6Jcjs.ConversationCardRow,
408
421
  {
409
422
  author,
410
423
  role: "Reply",
@@ -421,7 +434,7 @@ function TicketTimelinePanel({ ticket }) {
421
434
  // content rendered — drawer is showing the customer's body
422
435
  // turns + cached engagements while a background refetch is
423
436
  // in flight. Single row keeps the placeholder modest.
424
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKDNGUYZMcjs.ConversationCardRowSkeletonList, { rows: 1 })
437
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2G3NXF6Jcjs.ConversationCardRowSkeletonList, { rows: 1 })
425
438
  ] });
426
439
  }
427
440
  function mapEngagementAttachments(files) {
@@ -474,7 +487,7 @@ function OpenActions({
474
487
  const [messageText, setMessageText] = _react.useState.call(void 0, "");
475
488
  const [resolution, setResolution] = _react.useState.call(void 0, "");
476
489
  const [closeDialogOpen, setCloseDialogOpen] = _react.useState.call(void 0, false);
477
- const attachments = _chunkYZUUFTIKcjs.useChatAttachments.call(void 0, );
490
+ const attachments = _chunkD4MNFY67cjs.useChatAttachments.call(void 0, );
478
491
  const disabled = busy || supportSystemDown;
479
492
  const ticketRef = { id: ticket.id, external_id: ticket.external_id };
480
493
  const hasText = messageText.trim().length > 0;
@@ -497,7 +510,7 @@ function OpenActions({
497
510
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-3", children: [
498
511
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-2", children: [
499
512
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
500
- _chunkYZUUFTIKcjs.Textarea,
513
+ _chunkD4MNFY67cjs.Textarea,
501
514
  {
502
515
  value: messageText,
503
516
  onChange: (e) => setMessageText(e.target.value),
@@ -508,7 +521,7 @@ function OpenActions({
508
521
  }
509
522
  ),
510
523
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
511
- _chunkYZUUFTIKcjs.ChatAttachmentChipStrip,
524
+ _chunkD4MNFY67cjs.ChatAttachmentChipStrip,
512
525
  {
513
526
  attachments: attachments.attachments,
514
527
  onRemove: attachments.removeAttachment,
@@ -518,7 +531,7 @@ function OpenActions({
518
531
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex justify-between items-center gap-2 flex-wrap", children: [
519
532
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2", children: [
520
533
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
521
- _chunkYZUUFTIKcjs.ChatAttachmentAddButton,
534
+ _chunkD4MNFY67cjs.ChatAttachmentAddButton,
522
535
  {
523
536
  attachmentsEnabled: !supportSystemDown,
524
537
  attachmentsCount: attachments.attachments.length,
@@ -553,13 +566,13 @@ function OpenActions({
553
566
  ] })
554
567
  ] })
555
568
  ] }),
556
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYZUUFTIKcjs.AlertDialog, { open: closeDialogOpen, onOpenChange: setCloseDialogOpen, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkYZUUFTIKcjs.AlertDialogContent, { className: "bg-ods-card border-ods-border", children: [
557
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkYZUUFTIKcjs.AlertDialogHeader, { children: [
558
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYZUUFTIKcjs.AlertDialogTitle, { className: "text-ods-text-primary font-['DM_Sans'] text-[20px] font-semibold", children: "Close this ticket?" }),
559
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYZUUFTIKcjs.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." })
569
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkD4MNFY67cjs.AlertDialog, { open: closeDialogOpen, onOpenChange: setCloseDialogOpen, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkD4MNFY67cjs.AlertDialogContent, { className: "bg-ods-card border-ods-border", children: [
570
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkD4MNFY67cjs.AlertDialogHeader, { children: [
571
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkD4MNFY67cjs.AlertDialogTitle, { className: "text-ods-text-primary font-['DM_Sans'] text-[20px] font-semibold", children: "Close this ticket?" }),
572
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkD4MNFY67cjs.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." })
560
573
  ] }),
561
574
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
562
- _chunkYZUUFTIKcjs.Textarea,
575
+ _chunkD4MNFY67cjs.Textarea,
563
576
  {
564
577
  value: resolution,
565
578
  onChange: (e) => setResolution(e.target.value),
@@ -569,9 +582,9 @@ function OpenActions({
569
582
  className: "mt-2"
570
583
  }
571
584
  ),
572
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkYZUUFTIKcjs.AlertDialogFooter, { children: [
585
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkD4MNFY67cjs.AlertDialogFooter, { children: [
573
586
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
574
- _chunkYZUUFTIKcjs.AlertDialogCancel,
587
+ _chunkD4MNFY67cjs.AlertDialogCancel,
575
588
  {
576
589
  disabled: busy,
577
590
  className: "bg-transparent border-ods-border text-ods-text-primary hover:bg-ods-border",
@@ -579,7 +592,7 @@ function OpenActions({
579
592
  }
580
593
  ),
581
594
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
582
- _chunkYZUUFTIKcjs.AlertDialogAction,
595
+ _chunkD4MNFY67cjs.AlertDialogAction,
583
596
  {
584
597
  onClick: () => void confirmClose(),
585
598
  disabled: busy,
@@ -591,6 +604,56 @@ function OpenActions({
591
604
  ] }) })
592
605
  ] });
593
606
  }
607
+ function ReplyFailureBanner({
608
+ error,
609
+ onDismiss
610
+ }) {
611
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
612
+ "div",
613
+ {
614
+ role: "status",
615
+ "aria-live": "polite",
616
+ className: "mb-3 flex items-start gap-3 rounded-md border border-ods-attention-red-error bg-ods-attention-red-error-secondary px-3 py-2 text-sm text-ods-attention-red-error",
617
+ children: [
618
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "font-medium leading-snug", children: error.message }),
619
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
620
+ _chunkUXZ3ZJ3Mcjs.Button,
621
+ {
622
+ type: "button",
623
+ variant: "transparent",
624
+ onClick: onDismiss,
625
+ "aria-label": "Dismiss reply failure",
626
+ className: "ml-auto px-2 py-0.5 text-xs font-medium uppercase tracking-wider text-ods-attention-red-error hover:bg-ods-attention-red-error/10 border-transparent",
627
+ children: "Dismiss"
628
+ }
629
+ )
630
+ ]
631
+ }
632
+ );
633
+ }
634
+ function AssignedAgentRow({
635
+ assignedOwner
636
+ }) {
637
+ const trimmedName = _optionalChain([assignedOwner, 'optionalAccess', _30 => _30.name, 'optionalAccess', _31 => _31.trim, 'call', _32 => _32()]) || null;
638
+ const emailFallback = _optionalChain([assignedOwner, 'optionalAccess', _33 => _33.email, 'optionalAccess', _34 => _34.trim, 'call', _35 => _35()]) || null;
639
+ const displayLabel = _nullishCoalesce(trimmedName, () => ( (emailFallback ? emailFallback.split("@")[0] : null)));
640
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2 text-xs", children: [
641
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-ods-text-secondary uppercase tracking-wider font-medium", children: "Assigned to" }),
642
+ displayLabel ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex items-center gap-1.5 text-ods-text-primary font-medium", children: [
643
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
644
+ _chunkD4MNFY67cjs.SquareAvatar,
645
+ {
646
+ size: "sm",
647
+ variant: "round",
648
+ src: _nullishCoalesce(_optionalChain([assignedOwner, 'optionalAccess', _36 => _36.avatarUrl]), () => ( void 0)),
649
+ alt: displayLabel,
650
+ fallback: displayLabel
651
+ }
652
+ ),
653
+ displayLabel
654
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-ods-text-secondary italic", children: "Unassigned" })
655
+ ] });
656
+ }
594
657
 
595
658
  // src/components/tickets/ticket-row.tsx
596
659
 
@@ -609,7 +672,7 @@ function TicketRow({
609
672
  const rowRef = _react.useRef.call(void 0, null);
610
673
  const handleClick = _react.useCallback.call(void 0, () => {
611
674
  onToggle(ticket.id);
612
- _chunkYZUUFTIKcjs.scrollElementIntoView.call(void 0, rowRef.current, {
675
+ _chunkD4MNFY67cjs.scrollElementIntoView.call(void 0, rowRef.current, {
613
676
  adjustTargetY: (raw) => {
614
677
  if (!rowRef.current) return raw;
615
678
  const expandedDrawer = document.querySelector(
@@ -635,7 +698,7 @@ function TicketRow({
635
698
  // so the badge accurately reflects "Closed" with a checkmark.
636
699
  statusLabel: _nullishCoalesce(ticket.pipeline_stage_label, () => ( void 0)),
637
700
  category: _nullishCoalesce(ticket.customer_company, () => ( void 0)),
638
- timeAgo: ticket.hubspot_updated_at ? _chunkYZUUFTIKcjs.formatRelativeTime.call(void 0, ticket.hubspot_updated_at) : void 0,
701
+ timeAgo: ticket.hubspot_updated_at ? _chunkD4MNFY67cjs.formatRelativeTime.call(void 0, ticket.hubspot_updated_at) : void 0,
639
702
  // Linked-work chip: surfaced whenever the ticket has a linked
640
703
  // ClickUp task. Uses the linked task's own status so the chip text
641
704
  // reads "Working" / "Waiting on version release" / etc. — useful
@@ -650,7 +713,7 @@ function TicketRow({
650
713
  className: "border-b border-ods-border last:border-b-0",
651
714
  children: [
652
715
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
653
- _chunkYZUUFTIKcjs.ChatTicketItem,
716
+ _chunkD4MNFY67cjs.ChatTicketItem,
654
717
  {
655
718
  ticket: tileData,
656
719
  onClick: optimistic ? void 0 : handleClick,
@@ -714,7 +777,7 @@ function useTicketsList(filters) {
714
777
  pageSize
715
778
  };
716
779
  if (statusFilter) body.status = statusFilter;
717
- const response = await _chunkYZUUFTIKcjs.embedAuthedFetch.call(void 0, FIND_TICKET_ENDPOINT, {
780
+ const response = await _chunkD4MNFY67cjs.embedAuthedFetch.call(void 0, FIND_TICKET_ENDPOINT, {
718
781
  method: "POST",
719
782
  body: JSON.stringify(body)
720
783
  });
@@ -726,12 +789,12 @@ function useTicketsList(filters) {
726
789
  }
727
790
  });
728
791
  const data = query.data;
729
- const totalCount = _nullishCoalesce(_nullishCoalesce(_optionalChain([data, 'optionalAccess', _30 => _30.totalCount]), () => ( _optionalChain([data, 'optionalAccess', _31 => _31.count]))), () => ( (_nullishCoalesce(_optionalChain([data, 'optionalAccess', _32 => _32.tickets, 'optionalAccess', _33 => _33.length]), () => ( 0)))));
730
- const echoedPage = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _34 => _34.page]), () => ( page));
731
- const echoedPageSize = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _35 => _35.pageSize]), () => ( pageSize));
732
- const totalPages = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _36 => _36.totalPages]), () => ( Math.max(1, Math.ceil(totalCount / echoedPageSize))));
792
+ const totalCount = _nullishCoalesce(_nullishCoalesce(_optionalChain([data, 'optionalAccess', _37 => _37.totalCount]), () => ( _optionalChain([data, 'optionalAccess', _38 => _38.count]))), () => ( (_nullishCoalesce(_optionalChain([data, 'optionalAccess', _39 => _39.tickets, 'optionalAccess', _40 => _40.length]), () => ( 0)))));
793
+ const echoedPage = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _41 => _41.page]), () => ( page));
794
+ const echoedPageSize = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _42 => _42.pageSize]), () => ( pageSize));
795
+ const totalPages = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _43 => _43.totalPages]), () => ( Math.max(1, Math.ceil(totalCount / echoedPageSize))));
733
796
  return {
734
- tickets: _nullishCoalesce(_optionalChain([data, 'optionalAccess', _37 => _37.tickets]), () => ( [])),
797
+ tickets: _nullishCoalesce(_optionalChain([data, 'optionalAccess', _44 => _44.tickets]), () => ( [])),
735
798
  // Loading-state-truth = `data === undefined`. TanStack v5's
736
799
  // `isPending` / `isLoading` flags can be `false` in transient
737
800
  // windows where the query is enabled-but-fetch-not-yet-fired
@@ -753,7 +816,7 @@ function useTicketsList(filters) {
753
816
  // - Background refetch with existing data: data !== undefined → no load
754
817
  // - Filter-change refetch landing on empty results: data?.tickets===[]
755
818
  // + isFetching → bridge skeleton (the `||` branch)
756
- isLoading: enabled && (data === void 0 || query.isFetching && (_nullishCoalesce(_optionalChain([data, 'optionalAccess', _38 => _38.tickets]), () => ( []))).length === 0),
819
+ isLoading: enabled && (data === void 0 || query.isFetching && (_nullishCoalesce(_optionalChain([data, 'optionalAccess', _45 => _45.tickets]), () => ( []))).length === 0),
757
820
  isFetching: query.isFetching,
758
821
  error: _nullishCoalesce(query.error, () => ( null)),
759
822
  refetch: () => {
@@ -771,6 +834,12 @@ function useTicketsList(filters) {
771
834
 
772
835
 
773
836
  var TICKET_ACTION_ENDPOINT = "/api/chat/agent/ticket-action";
837
+ var REPLY_BANNER_CODES = /* @__PURE__ */ new Set([
838
+ "HUBSPOT_5XX",
839
+ "HUBSPOT_400_VALIDATION",
840
+ "HUBSPOT_404_THREAD",
841
+ "HUBSPOT_REPLY_UNKNOWN"
842
+ ]);
774
843
  var MIRROR_SYNC_BACKOFF_MS = [3e3, 6e3, 12e3];
775
844
  function useTicketActions(options) {
776
845
  const queryClient = _reactquery.useQueryClient.call(void 0, );
@@ -785,6 +854,26 @@ function useTicketActions(options) {
785
854
  setBusyRows(new Set(busyRowsRef.current));
786
855
  }, []);
787
856
  const isRowBusy = _react.useCallback.call(void 0, (id) => busyRows.has(id), [busyRows]);
857
+ const [replyErrorByTicket, setReplyErrorByTicket] = _react.useState.call(void 0, () => /* @__PURE__ */ new Map());
858
+ const setReplyError = _react.useCallback.call(void 0,
859
+ (externalId, mapped) => {
860
+ setReplyErrorByTicket((prev) => {
861
+ const next = new Map(prev);
862
+ if (mapped) next.set(externalId, mapped);
863
+ else next.delete(externalId);
864
+ return next;
865
+ });
866
+ },
867
+ []
868
+ );
869
+ const replyErrorFor = _react.useCallback.call(void 0,
870
+ (externalId) => _nullishCoalesce(replyErrorByTicket.get(externalId), () => ( null)),
871
+ [replyErrorByTicket]
872
+ );
873
+ const clearReplyError = _react.useCallback.call(void 0,
874
+ (externalId) => setReplyError(externalId, null),
875
+ [setReplyError]
876
+ );
788
877
  const watcherControllersRef = _react.useRef.call(void 0, /* @__PURE__ */ new Map());
789
878
  _react.useEffect.call(void 0, () => {
790
879
  return () => {
@@ -802,7 +891,7 @@ function useTicketActions(options) {
802
891
  }, []);
803
892
  const executeTicketAction = _react.useCallback.call(void 0,
804
893
  async (toolName, args) => {
805
- const res = await _chunkYZUUFTIKcjs.embedAuthedFetch.call(void 0, TICKET_ACTION_ENDPOINT, {
894
+ const res = await _chunkD4MNFY67cjs.embedAuthedFetch.call(void 0, TICKET_ACTION_ENDPOINT, {
806
895
  method: "POST",
807
896
  body: JSON.stringify({ tool_name: toolName, args })
808
897
  });
@@ -862,9 +951,11 @@ function useTicketActions(options) {
862
951
  },
863
952
  [queryClient, removeOptimistic, toast2]
864
953
  );
954
+ const lastUpdateErrorRef = _react.useRef.call(void 0, null);
865
955
  const surfaceError = _react.useCallback.call(void 0,
866
956
  (err, action) => {
867
957
  const mapped = mapTicketActionError(err);
958
+ lastUpdateErrorRef.current = mapped;
868
959
  if (mapped.supportSystemDown) onSupportSystemDown();
869
960
  toast2({
870
961
  title: `Could not ${action}`,
@@ -899,6 +990,10 @@ function useTicketActions(options) {
899
990
  // seconds via the mirror refetch. Drawer uses live chat
900
991
  // identity for own-replies during this window anyway.
901
992
  customer_name: null,
993
+ // No assignee until the real ticket lands. Drawer renders
994
+ // "Unassigned" for this brief window.
995
+ assigned_to: null,
996
+ assignedOwner: null,
902
997
  hubspot_updated_at: (/* @__PURE__ */ new Date()).toISOString(),
903
998
  _optimistic: true
904
999
  };
@@ -908,7 +1003,7 @@ function useTicketActions(options) {
908
1003
  const result = await executeTicketAction("create_ticket", {
909
1004
  subject: input.subject.trim(),
910
1005
  content: input.content.trim(),
911
- ..._optionalChain([input, 'access', _39 => _39.attachments, 'optionalAccess', _40 => _40.length]) ? { attachments: input.attachments } : {}
1006
+ ..._optionalChain([input, 'access', _46 => _46.attachments, 'optionalAccess', _47 => _47.length]) ? { attachments: input.attachments } : {}
912
1007
  });
913
1008
  if (result.mirror_synced === false) {
914
1009
  toast2(TOAST_COPY.open_mirror_pending);
@@ -974,12 +1069,13 @@ function useTicketActions(options) {
974
1069
  [setRowBusy, enqueue, executeTicketAction, queryClient, toast2, surfaceError, removeTicketFromCache]
975
1070
  );
976
1071
  const sendMessage = _react.useCallback.call(void 0,
977
- (ticket, text, attachments) => {
1072
+ async (ticket, text, attachments) => {
978
1073
  const trimmed = text.trim();
979
1074
  const hasText = trimmed.length > 0;
980
1075
  const hasFiles = attachments.length > 0;
981
- if (!hasText && !hasFiles) return Promise.resolve(false);
982
- return updateTicket(
1076
+ if (!hasText && !hasFiles) return false;
1077
+ lastUpdateErrorRef.current = null;
1078
+ const ok = await updateTicket(
983
1079
  ticket,
984
1080
  {
985
1081
  ...hasText ? { content_addendum: trimmed } : {},
@@ -988,15 +1084,25 @@ function useTicketActions(options) {
988
1084
  TOAST_COPY.comment_success,
989
1085
  "send message"
990
1086
  );
1087
+ if (ok) {
1088
+ clearReplyError(ticket.external_id);
1089
+ } else {
1090
+ const mapped = lastUpdateErrorRef.current;
1091
+ if (mapped && REPLY_BANNER_CODES.has(mapped.code)) {
1092
+ setReplyError(ticket.external_id, mapped);
1093
+ }
1094
+ lastUpdateErrorRef.current = null;
1095
+ }
1096
+ return ok;
991
1097
  },
992
- [updateTicket]
1098
+ [updateTicket, clearReplyError, setReplyError]
993
1099
  );
994
1100
  const closeTicket = _react.useCallback.call(void 0,
995
1101
  (ticket, resolution) => updateTicket(
996
1102
  ticket,
997
1103
  {
998
1104
  status: "CLOSED",
999
- ..._optionalChain([resolution, 'optionalAccess', _41 => _41.trim, 'call', _42 => _42()]) ? { resolution: resolution.trim() } : {}
1105
+ ..._optionalChain([resolution, 'optionalAccess', _48 => _48.trim, 'call', _49 => _49()]) ? { resolution: resolution.trim() } : {}
1000
1106
  },
1001
1107
  TOAST_COPY.close_success,
1002
1108
  "close ticket"
@@ -1014,9 +1120,20 @@ function useTicketActions(options) {
1014
1120
  closeTicket,
1015
1121
  reopenTicket,
1016
1122
  isSubmittingForm,
1017
- isRowBusy
1123
+ isRowBusy,
1124
+ replyErrorFor,
1125
+ clearReplyError
1018
1126
  }),
1019
- [submitTicket, sendMessage, closeTicket, reopenTicket, isSubmittingForm, isRowBusy]
1127
+ [
1128
+ submitTicket,
1129
+ sendMessage,
1130
+ closeTicket,
1131
+ reopenTicket,
1132
+ isSubmittingForm,
1133
+ isRowBusy,
1134
+ replyErrorFor,
1135
+ clearReplyError
1136
+ ]
1020
1137
  );
1021
1138
  }
1022
1139
  var TicketActionFailure = class extends Error {
@@ -1058,7 +1175,7 @@ function mapTicketActionError(err) {
1058
1175
  removeRowFromCache: false
1059
1176
  };
1060
1177
  case "RATE_LIMITED": {
1061
- const retryAfterRaw = _optionalChain([err, 'access', _43 => _43.response, 'optionalAccess', _44 => _44.headers, 'access', _45 => _45.get, 'call', _46 => _46("Retry-After")]);
1178
+ const retryAfterRaw = _optionalChain([err, 'access', _50 => _50.response, 'optionalAccess', _51 => _51.headers, 'access', _52 => _52.get, 'call', _53 => _53("Retry-After")]);
1062
1179
  const retryAfterSeconds = retryAfterRaw ? parseInt(retryAfterRaw, 10) : void 0;
1063
1180
  return {
1064
1181
  code: err.code,
@@ -1075,6 +1192,34 @@ function mapTicketActionError(err) {
1075
1192
  supportSystemDown: false,
1076
1193
  removeRowFromCache: false
1077
1194
  };
1195
+ case "HUBSPOT_5XX":
1196
+ return {
1197
+ code: err.code,
1198
+ message: "We couldn't reach the support system. Your reply wasn't sent \u2014 please retry in a moment.",
1199
+ supportSystemDown: false,
1200
+ removeRowFromCache: false
1201
+ };
1202
+ case "HUBSPOT_400_VALIDATION":
1203
+ return {
1204
+ code: err.code,
1205
+ message: "Your reply was rejected. Please rephrase or remove unsupported content and try again.",
1206
+ supportSystemDown: false,
1207
+ removeRowFromCache: false
1208
+ };
1209
+ case "HUBSPOT_404_THREAD":
1210
+ return {
1211
+ code: err.code,
1212
+ message: "This conversation is no longer accepting replies. Open a new ticket to continue.",
1213
+ supportSystemDown: false,
1214
+ removeRowFromCache: false
1215
+ };
1216
+ case "HUBSPOT_REPLY_UNKNOWN":
1217
+ return {
1218
+ code: err.code,
1219
+ message: "Your reply didn't go through. Please retry.",
1220
+ supportSystemDown: false,
1221
+ removeRowFromCache: false
1222
+ };
1078
1223
  default:
1079
1224
  return {
1080
1225
  code: "UNKNOWN",
@@ -1116,13 +1261,13 @@ function resolveErrorCode(bodyCode, status) {
1116
1261
  // src/components/tickets/ticket-center.tsx
1117
1262
 
1118
1263
  function TicketCenter({ toast: toast2 = _chunkWT5JV2GScjs.toast } = {}) {
1119
- const identity = _chunkYZUUFTIKcjs.useChatIdentity.call(void 0, );
1264
+ const identity = _chunkD4MNFY67cjs.useChatIdentity.call(void 0, );
1120
1265
  if (identity.isLoading) {
1121
1266
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TicketCenterSkeleton, {});
1122
1267
  }
1123
- if (identity.authTier === "anon" || !_optionalChain([identity, 'access', _47 => _47.user, 'optionalAccess', _48 => _48.email])) {
1268
+ if (identity.authTier === "anon" || !_optionalChain([identity, 'access', _54 => _54.user, 'optionalAccess', _55 => _55.email])) {
1124
1269
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1125
- _chunkKDNGUYZMcjs.EmptyState,
1270
+ _chunk2G3NXF6Jcjs.EmptyState,
1126
1271
  {
1127
1272
  type: "generic",
1128
1273
  title: "Sign in to manage tickets",
@@ -1193,7 +1338,7 @@ function TicketCenterAuthed({
1193
1338
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-3 text-xs text-ods-text-secondary", children: [
1194
1339
  lastUpdatedAt && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { children: [
1195
1340
  "Updated ",
1196
- _chunkYZUUFTIKcjs.formatRelativeTime.call(void 0, new Date(lastUpdatedAt))
1341
+ _chunkD4MNFY67cjs.formatRelativeTime.call(void 0, new Date(lastUpdatedAt))
1197
1342
  ] }),
1198
1343
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1199
1344
  _chunkUXZ3ZJ3Mcjs.Button,
@@ -1209,15 +1354,15 @@ function TicketCenterAuthed({
1209
1354
  )
1210
1355
  ] })
1211
1356
  ] }),
1212
- isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TicketListSkeleton, {}) : merged.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYZUUFTIKcjs.Card, { className: "p-6", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1213
- _chunkKDNGUYZMcjs.EmptyState,
1357
+ isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TicketListSkeleton, {}) : merged.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkD4MNFY67cjs.Card, { className: "p-6", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1358
+ _chunk2G3NXF6Jcjs.EmptyState,
1214
1359
  {
1215
1360
  type: "generic",
1216
1361
  title: "No tickets yet",
1217
1362
  description: "Open one above to start the conversation.",
1218
1363
  showCTA: false
1219
1364
  }
1220
- ) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYZUUFTIKcjs.Card, { className: "overflow-hidden", children: merged.map((ticket) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1365
+ ) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkD4MNFY67cjs.Card, { className: "overflow-hidden", children: merged.map((ticket) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1221
1366
  TicketRow,
1222
1367
  {
1223
1368
  ticket,
@@ -1237,7 +1382,7 @@ function TicketCenterAuthed({
1237
1382
  }
1238
1383
  function TicketCenterSkeleton() {
1239
1384
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-6", children: [
1240
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkYZUUFTIKcjs.Card, { className: "p-6", children: [
1385
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkD4MNFY67cjs.Card, { className: "p-6", children: [
1241
1386
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUXZ3ZJ3Mcjs.Skeleton, { className: "h-7 w-48 mb-4" }),
1242
1387
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUXZ3ZJ3Mcjs.Skeleton, { className: "h-10 w-full mb-3" }),
1243
1388
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUXZ3ZJ3Mcjs.Skeleton, { className: "h-24 w-full" })
@@ -1246,7 +1391,7 @@ function TicketCenterSkeleton() {
1246
1391
  ] });
1247
1392
  }
1248
1393
  function TicketListSkeleton() {
1249
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYZUUFTIKcjs.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: [
1394
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkD4MNFY67cjs.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: [
1250
1395
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex-1 flex flex-col gap-2", children: [
1251
1396
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUXZ3ZJ3Mcjs.Skeleton, { className: "h-4 w-2/3" }),
1252
1397
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUXZ3ZJ3Mcjs.Skeleton, { className: "h-3 w-full" })
@@ -1259,7 +1404,7 @@ function TicketListSkeleton() {
1259
1404
  // src/components/tickets/help-center-list.tsx
1260
1405
 
1261
1406
 
1262
- _chunkKDNGUYZMcjs.init_unified_pagination.call(void 0, );
1407
+ _chunk2G3NXF6Jcjs.init_unified_pagination.call(void 0, );
1263
1408
 
1264
1409
  // src/components/tickets/help-center-card.tsx
1265
1410
 
@@ -1274,12 +1419,14 @@ function HelpCenterCard({
1274
1419
  onSendMessage,
1275
1420
  onClose,
1276
1421
  onReopen,
1277
- onActionCollapsed
1422
+ onActionCollapsed,
1423
+ replyError,
1424
+ onClearReplyError
1278
1425
  }) {
1279
1426
  const optimistic = isOptimistic(ticket);
1280
1427
  const rawStatus = (_nullishCoalesce(ticket.status, () => ( "OPEN"))).toUpperCase();
1281
1428
  const priority = (_nullishCoalesce(ticket.priority, () => ( ""))).toUpperCase();
1282
- const relativeUpdated = ticket.hubspot_updated_at ? _chunkYZUUFTIKcjs.formatRelativeTime.call(void 0, ticket.hubspot_updated_at) : "recently";
1429
+ const relativeUpdated = ticket.hubspot_updated_at ? _chunkD4MNFY67cjs.formatRelativeTime.call(void 0, ticket.hubspot_updated_at) : "recently";
1283
1430
  const title = (ticket.subject || "").trim() || "(untitled)";
1284
1431
  const subtitle = `UPDATED ${relativeUpdated}, #${ticket.external_id || "\u2014"}${ticket.pipeline_stage_label ? `, ${ticket.pipeline_stage_label}` : ""}`;
1285
1432
  const description = _nullishCoalesce(_nullishCoalesce(ticket.preview, () => ( ticket.body)), () => ( ""));
@@ -1288,7 +1435,7 @@ function HelpCenterCard({
1288
1435
  const rowRef = _react.useRef.call(void 0, null);
1289
1436
  const handleClick = _react.useCallback.call(void 0, () => {
1290
1437
  onToggle(ticket.id);
1291
- _chunkYZUUFTIKcjs.scrollElementIntoView.call(void 0, rowRef.current, {
1438
+ _chunkD4MNFY67cjs.scrollElementIntoView.call(void 0, rowRef.current, {
1292
1439
  headerOffset: STICKY_HEADER_OFFSET_PX,
1293
1440
  adjustTargetY: (raw) => {
1294
1441
  if (!rowRef.current) return raw;
@@ -1305,16 +1452,16 @@ function HelpCenterCard({
1305
1452
  }, [onToggle, ticket.id]);
1306
1453
  const rightBadges = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1307
1454
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1308
- _chunkYZUUFTIKcjs.StatusBadge,
1455
+ _chunkD4MNFY67cjs.StatusBadge,
1309
1456
  {
1310
1457
  text: rawStatus,
1311
- colorScheme: _chunkYZUUFTIKcjs.getStatusColorScheme.call(void 0, rawStatus),
1458
+ colorScheme: _chunkD4MNFY67cjs.getStatusColorScheme.call(void 0, rawStatus),
1312
1459
  variant: "card",
1313
1460
  className: "border border-ods-border"
1314
1461
  }
1315
1462
  ),
1316
1463
  priority && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1317
- _chunkYZUUFTIKcjs.StatusBadge,
1464
+ _chunkD4MNFY67cjs.StatusBadge,
1318
1465
  {
1319
1466
  text: priority,
1320
1467
  colorScheme: mapPriorityScheme(priority),
@@ -1341,7 +1488,7 @@ function HelpCenterCard({
1341
1488
  "aria-controls": isExpanded ? `help-center-drawer-${ticket.id}` : void 0,
1342
1489
  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",
1343
1490
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1344
- _chunkKDNGUYZMcjs.DevCardRowContent,
1491
+ _chunk2G3NXF6Jcjs.DevCardRowContent,
1345
1492
  {
1346
1493
  title,
1347
1494
  subtitle,
@@ -1361,7 +1508,9 @@ function HelpCenterCard({
1361
1508
  onSendMessage,
1362
1509
  onClose,
1363
1510
  onReopen,
1364
- onActionCollapsed
1511
+ onActionCollapsed,
1512
+ replyError,
1513
+ onClearReplyError
1365
1514
  }
1366
1515
  ) })
1367
1516
  ]
@@ -1414,7 +1563,7 @@ function HelpCenterCreateForm({
1414
1563
  const [subject, setSubject] = _react.useState.call(void 0, "");
1415
1564
  const [subjectError, setSubjectError] = _react.useState.call(void 0, null);
1416
1565
  const subjectField = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col", children: [
1417
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkYZUUFTIKcjs.Label, { htmlFor: "help-center-subject", children: [
1566
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkD4MNFY67cjs.Label, { htmlFor: "help-center-subject", children: [
1418
1567
  "Subject",
1419
1568
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-ods-accent", children: "*" })
1420
1569
  ] }),
@@ -1446,7 +1595,7 @@ function HelpCenterCreateForm({
1446
1595
  )
1447
1596
  ] });
1448
1597
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1449
- _chunkIZL2KEH6cjs.ContactForm,
1598
+ _chunkNGFP4RVLcjs.ContactForm,
1450
1599
  {
1451
1600
  title: "Open a new ticket",
1452
1601
  footerText: "The support team typically responds within one business day.",
@@ -1484,7 +1633,7 @@ function HelpCenterCreateForm({
1484
1633
  // src/components/tickets/help-center-list.tsx
1485
1634
 
1486
1635
  function HelpCenterList({ toast: toast2 = _chunkWT5JV2GScjs.toast } = {}) {
1487
- const identity = _chunkYZUUFTIKcjs.useChatIdentity.call(void 0, );
1636
+ const identity = _chunkD4MNFY67cjs.useChatIdentity.call(void 0, );
1488
1637
  const searchParams = _chunkG7UE6RKVcjs.useSearchParams.call(void 0, );
1489
1638
  const router = _chunkG7UE6RKVcjs.useRouter.call(void 0, );
1490
1639
  const pathname = _chunkG7UE6RKVcjs.usePathname.call(void 0, );
@@ -1493,11 +1642,11 @@ function HelpCenterList({ toast: toast2 = _chunkWT5JV2GScjs.toast } = {}) {
1493
1642
  const rawPage = Number(searchParams.get("page"));
1494
1643
  const page = Number.isFinite(rawPage) && rawPage > 0 ? Math.floor(rawPage) : 1;
1495
1644
  if (identity.isLoading) {
1496
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKDNGUYZMcjs.DevSectionPage, { sectionKey: "tickets", preControls: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HelpCenterCreateFormSkeleton, {}), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKDNGUYZMcjs.DevCardRowSkeletonList, {}) });
1645
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2G3NXF6Jcjs.DevSectionPage, { sectionKey: "tickets", preControls: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HelpCenterCreateFormSkeleton, {}), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2G3NXF6Jcjs.DevCardRowSkeletonList, {}) });
1497
1646
  }
1498
- if (identity.authTier === "anon" || !_optionalChain([identity, 'access', _49 => _49.user, 'optionalAccess', _50 => _50.email])) {
1499
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKDNGUYZMcjs.DevSectionPage, { sectionKey: "tickets", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1500
- _chunkKDNGUYZMcjs.EmptyState,
1647
+ if (identity.authTier === "anon" || !_optionalChain([identity, 'access', _56 => _56.user, 'optionalAccess', _57 => _57.email])) {
1648
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2G3NXF6Jcjs.DevSectionPage, { sectionKey: "tickets", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1649
+ _chunk2G3NXF6Jcjs.EmptyState,
1501
1650
  {
1502
1651
  type: "generic",
1503
1652
  title: "Sign in to manage tickets",
@@ -1506,7 +1655,7 @@ function HelpCenterList({ toast: toast2 = _chunkWT5JV2GScjs.toast } = {}) {
1506
1655
  }
1507
1656
  ) });
1508
1657
  }
1509
- const sessionName = [_optionalChain([identity, 'access', _51 => _51.user, 'optionalAccess', _52 => _52.firstName]), _optionalChain([identity, 'access', _53 => _53.user, 'optionalAccess', _54 => _54.lastName])].filter(Boolean).join(" ").trim() || _optionalChain([identity, 'access', _55 => _55.user, 'optionalAccess', _56 => _56.email, 'optionalAccess', _57 => _57.split, 'call', _58 => _58("@"), 'access', _59 => _59[0]]) || "Customer";
1658
+ const sessionName = [_optionalChain([identity, 'access', _58 => _58.user, 'optionalAccess', _59 => _59.firstName]), _optionalChain([identity, 'access', _60 => _60.user, 'optionalAccess', _61 => _61.lastName])].filter(Boolean).join(" ").trim() || _optionalChain([identity, 'access', _62 => _62.user, 'optionalAccess', _63 => _63.email, 'optionalAccess', _64 => _64.split, 'call', _65 => _65("@"), 'access', _66 => _66[0]]) || "Customer";
1510
1659
  const sessionEmail = identity.user.email;
1511
1660
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1512
1661
  HelpCenterListAuthed,
@@ -1597,15 +1746,15 @@ function HelpCenterListAuthed({
1597
1746
  ] }),
1598
1747
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUXZ3ZJ3Mcjs.Button, { type: "button", variant: "accent", onClick: () => refetch(), children: "Retry" })
1599
1748
  ] }),
1600
- !error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-full", children: isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKDNGUYZMcjs.DevCardRowSkeletonList, {}) : !hasResults && isFetching ? (
1749
+ !error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-full", children: isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2G3NXF6Jcjs.DevCardRowSkeletonList, {}) : !hasResults && isFetching ? (
1601
1750
  // Bridge state — background refetch in flight and the
1602
1751
  // optimistic placeholder was just removed by the mutation
1603
1752
  // callback. Without this branch "No tickets yet" would flash
1604
1753
  // for ~50ms between `removeOptimistic` and the server
1605
1754
  // response landing.
1606
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKDNGUYZMcjs.DevCardRowSkeletonList, { rows: 1 })
1755
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2G3NXF6Jcjs.DevCardRowSkeletonList, { rows: 1 })
1607
1756
  ) : !hasResults ? hasActiveFilters ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1608
- _chunkKDNGUYZMcjs.EmptyState,
1757
+ _chunk2G3NXF6Jcjs.EmptyState,
1609
1758
  {
1610
1759
  type: "search",
1611
1760
  title: "No tickets found",
@@ -1620,7 +1769,7 @@ function HelpCenterListAuthed({
1620
1769
  }
1621
1770
  }
1622
1771
  ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1623
- _chunkKDNGUYZMcjs.EmptyState,
1772
+ _chunk2G3NXF6Jcjs.EmptyState,
1624
1773
  {
1625
1774
  type: "generic",
1626
1775
  title: "No tickets yet",
@@ -1647,14 +1796,16 @@ function HelpCenterListAuthed({
1647
1796
  onSendMessage: actions.sendMessage,
1648
1797
  onClose: actions.closeTicket,
1649
1798
  onReopen: actions.reopenTicket,
1650
- onActionCollapsed: () => setExpandedTicketId(null)
1799
+ onActionCollapsed: () => setExpandedTicketId(null),
1800
+ replyError: actions.replyErrorFor(ticket.external_id),
1801
+ onClearReplyError: () => actions.clearReplyError(ticket.external_id)
1651
1802
  },
1652
1803
  ticket.id
1653
1804
  )) })
1654
1805
  ) }),
1655
- !error && totalPages > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKDNGUYZMcjs.UnifiedPagination, { currentPage: page, totalPages })
1806
+ !error && totalPages > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2G3NXF6Jcjs.UnifiedPagination, { currentPage: page, totalPages })
1656
1807
  ] });
1657
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKDNGUYZMcjs.DevSectionPage, { sectionKey: "tickets", preControls: form, children: body });
1808
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2G3NXF6Jcjs.DevSectionPage, { sectionKey: "tickets", preControls: form, children: body });
1658
1809
  }
1659
1810
 
1660
1811