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

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 +271 -107
  26. package/dist/components/tickets/index.cjs.map +1 -1
  27. package/dist/components/tickets/index.js +201 -37
  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 +188 -12
  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);
@@ -951,10 +1046,23 @@ function useTicketActions(options) {
951
1046
  ticket_id: ticket.external_id
952
1047
  });
953
1048
  toast2(successCopy);
954
- await Promise.all([
955
- queryClient.invalidateQueries({ queryKey: ["tickets"] }),
956
- queryClient.invalidateQueries({ queryKey: ["ticket-engagements"] })
957
- ]);
1049
+ const statusUpdate = _nullishCoalesce(serverArgs.status, () => ( null));
1050
+ if (statusUpdate) {
1051
+ queryClient.setQueriesData(
1052
+ { queryKey: ["tickets"] },
1053
+ (prev) => {
1054
+ if (!prev) return prev;
1055
+ let mutated = false;
1056
+ const next = prev.map((t) => {
1057
+ if (t.id !== ticket.id || t.status === statusUpdate) return t;
1058
+ mutated = true;
1059
+ return { ...t, status: statusUpdate };
1060
+ });
1061
+ return mutated ? next : prev;
1062
+ }
1063
+ );
1064
+ }
1065
+ await queryClient.invalidateQueries({ queryKey: ["ticket-engagements"] });
958
1066
  return true;
959
1067
  });
960
1068
  } catch (err) {
@@ -974,12 +1082,13 @@ function useTicketActions(options) {
974
1082
  [setRowBusy, enqueue, executeTicketAction, queryClient, toast2, surfaceError, removeTicketFromCache]
975
1083
  );
976
1084
  const sendMessage = _react.useCallback.call(void 0,
977
- (ticket, text, attachments) => {
1085
+ async (ticket, text, attachments) => {
978
1086
  const trimmed = text.trim();
979
1087
  const hasText = trimmed.length > 0;
980
1088
  const hasFiles = attachments.length > 0;
981
- if (!hasText && !hasFiles) return Promise.resolve(false);
982
- return updateTicket(
1089
+ if (!hasText && !hasFiles) return false;
1090
+ lastUpdateErrorRef.current = null;
1091
+ const ok = await updateTicket(
983
1092
  ticket,
984
1093
  {
985
1094
  ...hasText ? { content_addendum: trimmed } : {},
@@ -988,15 +1097,25 @@ function useTicketActions(options) {
988
1097
  TOAST_COPY.comment_success,
989
1098
  "send message"
990
1099
  );
1100
+ if (ok) {
1101
+ clearReplyError(ticket.external_id);
1102
+ } else {
1103
+ const mapped = lastUpdateErrorRef.current;
1104
+ if (mapped && REPLY_BANNER_CODES.has(mapped.code)) {
1105
+ setReplyError(ticket.external_id, mapped);
1106
+ }
1107
+ lastUpdateErrorRef.current = null;
1108
+ }
1109
+ return ok;
991
1110
  },
992
- [updateTicket]
1111
+ [updateTicket, clearReplyError, setReplyError]
993
1112
  );
994
1113
  const closeTicket = _react.useCallback.call(void 0,
995
1114
  (ticket, resolution) => updateTicket(
996
1115
  ticket,
997
1116
  {
998
1117
  status: "CLOSED",
999
- ..._optionalChain([resolution, 'optionalAccess', _41 => _41.trim, 'call', _42 => _42()]) ? { resolution: resolution.trim() } : {}
1118
+ ..._optionalChain([resolution, 'optionalAccess', _48 => _48.trim, 'call', _49 => _49()]) ? { resolution: resolution.trim() } : {}
1000
1119
  },
1001
1120
  TOAST_COPY.close_success,
1002
1121
  "close ticket"
@@ -1014,9 +1133,20 @@ function useTicketActions(options) {
1014
1133
  closeTicket,
1015
1134
  reopenTicket,
1016
1135
  isSubmittingForm,
1017
- isRowBusy
1136
+ isRowBusy,
1137
+ replyErrorFor,
1138
+ clearReplyError
1018
1139
  }),
1019
- [submitTicket, sendMessage, closeTicket, reopenTicket, isSubmittingForm, isRowBusy]
1140
+ [
1141
+ submitTicket,
1142
+ sendMessage,
1143
+ closeTicket,
1144
+ reopenTicket,
1145
+ isSubmittingForm,
1146
+ isRowBusy,
1147
+ replyErrorFor,
1148
+ clearReplyError
1149
+ ]
1020
1150
  );
1021
1151
  }
1022
1152
  var TicketActionFailure = class extends Error {
@@ -1058,7 +1188,7 @@ function mapTicketActionError(err) {
1058
1188
  removeRowFromCache: false
1059
1189
  };
1060
1190
  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")]);
1191
+ const retryAfterRaw = _optionalChain([err, 'access', _50 => _50.response, 'optionalAccess', _51 => _51.headers, 'access', _52 => _52.get, 'call', _53 => _53("Retry-After")]);
1062
1192
  const retryAfterSeconds = retryAfterRaw ? parseInt(retryAfterRaw, 10) : void 0;
1063
1193
  return {
1064
1194
  code: err.code,
@@ -1075,6 +1205,34 @@ function mapTicketActionError(err) {
1075
1205
  supportSystemDown: false,
1076
1206
  removeRowFromCache: false
1077
1207
  };
1208
+ case "HUBSPOT_5XX":
1209
+ return {
1210
+ code: err.code,
1211
+ message: "We couldn't reach the support system. Your reply wasn't sent \u2014 please retry in a moment.",
1212
+ supportSystemDown: false,
1213
+ removeRowFromCache: false
1214
+ };
1215
+ case "HUBSPOT_400_VALIDATION":
1216
+ return {
1217
+ code: err.code,
1218
+ message: "Your reply was rejected. Please rephrase or remove unsupported content and try again.",
1219
+ supportSystemDown: false,
1220
+ removeRowFromCache: false
1221
+ };
1222
+ case "HUBSPOT_404_THREAD":
1223
+ return {
1224
+ code: err.code,
1225
+ message: "This conversation is no longer accepting replies. Open a new ticket to continue.",
1226
+ supportSystemDown: false,
1227
+ removeRowFromCache: false
1228
+ };
1229
+ case "HUBSPOT_REPLY_UNKNOWN":
1230
+ return {
1231
+ code: err.code,
1232
+ message: "Your reply didn't go through. Please retry.",
1233
+ supportSystemDown: false,
1234
+ removeRowFromCache: false
1235
+ };
1078
1236
  default:
1079
1237
  return {
1080
1238
  code: "UNKNOWN",
@@ -1116,13 +1274,13 @@ function resolveErrorCode(bodyCode, status) {
1116
1274
  // src/components/tickets/ticket-center.tsx
1117
1275
 
1118
1276
  function TicketCenter({ toast: toast2 = _chunkWT5JV2GScjs.toast } = {}) {
1119
- const identity = _chunkYZUUFTIKcjs.useChatIdentity.call(void 0, );
1277
+ const identity = _chunkD4MNFY67cjs.useChatIdentity.call(void 0, );
1120
1278
  if (identity.isLoading) {
1121
1279
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TicketCenterSkeleton, {});
1122
1280
  }
1123
- if (identity.authTier === "anon" || !_optionalChain([identity, 'access', _47 => _47.user, 'optionalAccess', _48 => _48.email])) {
1281
+ if (identity.authTier === "anon" || !_optionalChain([identity, 'access', _54 => _54.user, 'optionalAccess', _55 => _55.email])) {
1124
1282
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1125
- _chunkKDNGUYZMcjs.EmptyState,
1283
+ _chunk2G3NXF6Jcjs.EmptyState,
1126
1284
  {
1127
1285
  type: "generic",
1128
1286
  title: "Sign in to manage tickets",
@@ -1193,7 +1351,7 @@ function TicketCenterAuthed({
1193
1351
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-3 text-xs text-ods-text-secondary", children: [
1194
1352
  lastUpdatedAt && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { children: [
1195
1353
  "Updated ",
1196
- _chunkYZUUFTIKcjs.formatRelativeTime.call(void 0, new Date(lastUpdatedAt))
1354
+ _chunkD4MNFY67cjs.formatRelativeTime.call(void 0, new Date(lastUpdatedAt))
1197
1355
  ] }),
1198
1356
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1199
1357
  _chunkUXZ3ZJ3Mcjs.Button,
@@ -1209,15 +1367,15 @@ function TicketCenterAuthed({
1209
1367
  )
1210
1368
  ] })
1211
1369
  ] }),
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,
1370
+ 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,
1371
+ _chunk2G3NXF6Jcjs.EmptyState,
1214
1372
  {
1215
1373
  type: "generic",
1216
1374
  title: "No tickets yet",
1217
1375
  description: "Open one above to start the conversation.",
1218
1376
  showCTA: false
1219
1377
  }
1220
- ) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYZUUFTIKcjs.Card, { className: "overflow-hidden", children: merged.map((ticket) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1378
+ ) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkD4MNFY67cjs.Card, { className: "overflow-hidden", children: merged.map((ticket) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1221
1379
  TicketRow,
1222
1380
  {
1223
1381
  ticket,
@@ -1237,7 +1395,7 @@ function TicketCenterAuthed({
1237
1395
  }
1238
1396
  function TicketCenterSkeleton() {
1239
1397
  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: [
1398
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkD4MNFY67cjs.Card, { className: "p-6", children: [
1241
1399
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUXZ3ZJ3Mcjs.Skeleton, { className: "h-7 w-48 mb-4" }),
1242
1400
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUXZ3ZJ3Mcjs.Skeleton, { className: "h-10 w-full mb-3" }),
1243
1401
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUXZ3ZJ3Mcjs.Skeleton, { className: "h-24 w-full" })
@@ -1246,7 +1404,7 @@ function TicketCenterSkeleton() {
1246
1404
  ] });
1247
1405
  }
1248
1406
  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: [
1407
+ 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
1408
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex-1 flex flex-col gap-2", children: [
1251
1409
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUXZ3ZJ3Mcjs.Skeleton, { className: "h-4 w-2/3" }),
1252
1410
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUXZ3ZJ3Mcjs.Skeleton, { className: "h-3 w-full" })
@@ -1259,7 +1417,7 @@ function TicketListSkeleton() {
1259
1417
  // src/components/tickets/help-center-list.tsx
1260
1418
 
1261
1419
 
1262
- _chunkKDNGUYZMcjs.init_unified_pagination.call(void 0, );
1420
+ _chunk2G3NXF6Jcjs.init_unified_pagination.call(void 0, );
1263
1421
 
1264
1422
  // src/components/tickets/help-center-card.tsx
1265
1423
 
@@ -1274,12 +1432,14 @@ function HelpCenterCard({
1274
1432
  onSendMessage,
1275
1433
  onClose,
1276
1434
  onReopen,
1277
- onActionCollapsed
1435
+ onActionCollapsed,
1436
+ replyError,
1437
+ onClearReplyError
1278
1438
  }) {
1279
1439
  const optimistic = isOptimistic(ticket);
1280
1440
  const rawStatus = (_nullishCoalesce(ticket.status, () => ( "OPEN"))).toUpperCase();
1281
1441
  const priority = (_nullishCoalesce(ticket.priority, () => ( ""))).toUpperCase();
1282
- const relativeUpdated = ticket.hubspot_updated_at ? _chunkYZUUFTIKcjs.formatRelativeTime.call(void 0, ticket.hubspot_updated_at) : "recently";
1442
+ const relativeUpdated = ticket.hubspot_updated_at ? _chunkD4MNFY67cjs.formatRelativeTime.call(void 0, ticket.hubspot_updated_at) : "recently";
1283
1443
  const title = (ticket.subject || "").trim() || "(untitled)";
1284
1444
  const subtitle = `UPDATED ${relativeUpdated}, #${ticket.external_id || "\u2014"}${ticket.pipeline_stage_label ? `, ${ticket.pipeline_stage_label}` : ""}`;
1285
1445
  const description = _nullishCoalesce(_nullishCoalesce(ticket.preview, () => ( ticket.body)), () => ( ""));
@@ -1288,7 +1448,7 @@ function HelpCenterCard({
1288
1448
  const rowRef = _react.useRef.call(void 0, null);
1289
1449
  const handleClick = _react.useCallback.call(void 0, () => {
1290
1450
  onToggle(ticket.id);
1291
- _chunkYZUUFTIKcjs.scrollElementIntoView.call(void 0, rowRef.current, {
1451
+ _chunkD4MNFY67cjs.scrollElementIntoView.call(void 0, rowRef.current, {
1292
1452
  headerOffset: STICKY_HEADER_OFFSET_PX,
1293
1453
  adjustTargetY: (raw) => {
1294
1454
  if (!rowRef.current) return raw;
@@ -1305,16 +1465,16 @@ function HelpCenterCard({
1305
1465
  }, [onToggle, ticket.id]);
1306
1466
  const rightBadges = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1307
1467
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1308
- _chunkYZUUFTIKcjs.StatusBadge,
1468
+ _chunkD4MNFY67cjs.StatusBadge,
1309
1469
  {
1310
1470
  text: rawStatus,
1311
- colorScheme: _chunkYZUUFTIKcjs.getStatusColorScheme.call(void 0, rawStatus),
1471
+ colorScheme: _chunkD4MNFY67cjs.getStatusColorScheme.call(void 0, rawStatus),
1312
1472
  variant: "card",
1313
1473
  className: "border border-ods-border"
1314
1474
  }
1315
1475
  ),
1316
1476
  priority && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1317
- _chunkYZUUFTIKcjs.StatusBadge,
1477
+ _chunkD4MNFY67cjs.StatusBadge,
1318
1478
  {
1319
1479
  text: priority,
1320
1480
  colorScheme: mapPriorityScheme(priority),
@@ -1341,7 +1501,7 @@ function HelpCenterCard({
1341
1501
  "aria-controls": isExpanded ? `help-center-drawer-${ticket.id}` : void 0,
1342
1502
  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
1503
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1344
- _chunkKDNGUYZMcjs.DevCardRowContent,
1504
+ _chunk2G3NXF6Jcjs.DevCardRowContent,
1345
1505
  {
1346
1506
  title,
1347
1507
  subtitle,
@@ -1361,7 +1521,9 @@ function HelpCenterCard({
1361
1521
  onSendMessage,
1362
1522
  onClose,
1363
1523
  onReopen,
1364
- onActionCollapsed
1524
+ onActionCollapsed,
1525
+ replyError,
1526
+ onClearReplyError
1365
1527
  }
1366
1528
  ) })
1367
1529
  ]
@@ -1414,7 +1576,7 @@ function HelpCenterCreateForm({
1414
1576
  const [subject, setSubject] = _react.useState.call(void 0, "");
1415
1577
  const [subjectError, setSubjectError] = _react.useState.call(void 0, null);
1416
1578
  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: [
1579
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkD4MNFY67cjs.Label, { htmlFor: "help-center-subject", children: [
1418
1580
  "Subject",
1419
1581
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-ods-accent", children: "*" })
1420
1582
  ] }),
@@ -1446,7 +1608,7 @@ function HelpCenterCreateForm({
1446
1608
  )
1447
1609
  ] });
1448
1610
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1449
- _chunkIZL2KEH6cjs.ContactForm,
1611
+ _chunkNGFP4RVLcjs.ContactForm,
1450
1612
  {
1451
1613
  title: "Open a new ticket",
1452
1614
  footerText: "The support team typically responds within one business day.",
@@ -1484,7 +1646,7 @@ function HelpCenterCreateForm({
1484
1646
  // src/components/tickets/help-center-list.tsx
1485
1647
 
1486
1648
  function HelpCenterList({ toast: toast2 = _chunkWT5JV2GScjs.toast } = {}) {
1487
- const identity = _chunkYZUUFTIKcjs.useChatIdentity.call(void 0, );
1649
+ const identity = _chunkD4MNFY67cjs.useChatIdentity.call(void 0, );
1488
1650
  const searchParams = _chunkG7UE6RKVcjs.useSearchParams.call(void 0, );
1489
1651
  const router = _chunkG7UE6RKVcjs.useRouter.call(void 0, );
1490
1652
  const pathname = _chunkG7UE6RKVcjs.usePathname.call(void 0, );
@@ -1493,11 +1655,11 @@ function HelpCenterList({ toast: toast2 = _chunkWT5JV2GScjs.toast } = {}) {
1493
1655
  const rawPage = Number(searchParams.get("page"));
1494
1656
  const page = Number.isFinite(rawPage) && rawPage > 0 ? Math.floor(rawPage) : 1;
1495
1657
  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, {}) });
1658
+ 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
1659
  }
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,
1660
+ if (identity.authTier === "anon" || !_optionalChain([identity, 'access', _56 => _56.user, 'optionalAccess', _57 => _57.email])) {
1661
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2G3NXF6Jcjs.DevSectionPage, { sectionKey: "tickets", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1662
+ _chunk2G3NXF6Jcjs.EmptyState,
1501
1663
  {
1502
1664
  type: "generic",
1503
1665
  title: "Sign in to manage tickets",
@@ -1506,7 +1668,7 @@ function HelpCenterList({ toast: toast2 = _chunkWT5JV2GScjs.toast } = {}) {
1506
1668
  }
1507
1669
  ) });
1508
1670
  }
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";
1671
+ 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
1672
  const sessionEmail = identity.user.email;
1511
1673
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1512
1674
  HelpCenterListAuthed,
@@ -1597,15 +1759,15 @@ function HelpCenterListAuthed({
1597
1759
  ] }),
1598
1760
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUXZ3ZJ3Mcjs.Button, { type: "button", variant: "accent", onClick: () => refetch(), children: "Retry" })
1599
1761
  ] }),
1600
- !error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-full", children: isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKDNGUYZMcjs.DevCardRowSkeletonList, {}) : !hasResults && isFetching ? (
1762
+ !error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-full", children: isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2G3NXF6Jcjs.DevCardRowSkeletonList, {}) : !hasResults && isFetching ? (
1601
1763
  // Bridge state — background refetch in flight and the
1602
1764
  // optimistic placeholder was just removed by the mutation
1603
1765
  // callback. Without this branch "No tickets yet" would flash
1604
1766
  // for ~50ms between `removeOptimistic` and the server
1605
1767
  // response landing.
1606
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKDNGUYZMcjs.DevCardRowSkeletonList, { rows: 1 })
1768
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2G3NXF6Jcjs.DevCardRowSkeletonList, { rows: 1 })
1607
1769
  ) : !hasResults ? hasActiveFilters ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1608
- _chunkKDNGUYZMcjs.EmptyState,
1770
+ _chunk2G3NXF6Jcjs.EmptyState,
1609
1771
  {
1610
1772
  type: "search",
1611
1773
  title: "No tickets found",
@@ -1620,7 +1782,7 @@ function HelpCenterListAuthed({
1620
1782
  }
1621
1783
  }
1622
1784
  ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1623
- _chunkKDNGUYZMcjs.EmptyState,
1785
+ _chunk2G3NXF6Jcjs.EmptyState,
1624
1786
  {
1625
1787
  type: "generic",
1626
1788
  title: "No tickets yet",
@@ -1647,14 +1809,16 @@ function HelpCenterListAuthed({
1647
1809
  onSendMessage: actions.sendMessage,
1648
1810
  onClose: actions.closeTicket,
1649
1811
  onReopen: actions.reopenTicket,
1650
- onActionCollapsed: () => setExpandedTicketId(null)
1812
+ onActionCollapsed: () => setExpandedTicketId(null),
1813
+ replyError: actions.replyErrorFor(ticket.external_id),
1814
+ onClearReplyError: () => actions.clearReplyError(ticket.external_id)
1651
1815
  },
1652
1816
  ticket.id
1653
1817
  )) })
1654
1818
  ) }),
1655
- !error && totalPages > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKDNGUYZMcjs.UnifiedPagination, { currentPage: page, totalPages })
1819
+ !error && totalPages > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2G3NXF6Jcjs.UnifiedPagination, { currentPage: page, totalPages })
1656
1820
  ] });
1657
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKDNGUYZMcjs.DevSectionPage, { sectionKey: "tickets", preControls: form, children: body });
1821
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2G3NXF6Jcjs.DevSectionPage, { sectionKey: "tickets", preControls: form, children: body });
1658
1822
  }
1659
1823
 
1660
1824