@flamingo-stack/openframe-frontend-core 0.0.215 → 0.0.216-snapshot.20260530192723

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 (230) hide show
  1. package/dist/chunk-2V4SACHE.js +302 -0
  2. package/dist/chunk-2V4SACHE.js.map +1 -0
  3. package/dist/chunk-572WQWIX.cjs +348 -0
  4. package/dist/chunk-572WQWIX.cjs.map +1 -0
  5. package/dist/{chunk-WT5JV2GS.cjs → chunk-5V6MSE3B.cjs} +39 -39
  6. package/dist/chunk-5V6MSE3B.cjs.map +1 -0
  7. package/dist/{chunk-WQZP3JIZ.js → chunk-CDLYRFDE.js} +1894 -1472
  8. package/dist/chunk-CDLYRFDE.js.map +1 -0
  9. package/dist/chunk-GVNQAGXB.js +232 -0
  10. package/dist/chunk-GVNQAGXB.js.map +1 -0
  11. package/dist/{chunk-P5EE2VJX.cjs → chunk-HOHDXYPR.cjs} +1 -1
  12. package/dist/chunk-HOHDXYPR.cjs.map +1 -0
  13. package/dist/chunk-IH76P5R6.cjs +232 -0
  14. package/dist/chunk-IH76P5R6.cjs.map +1 -0
  15. package/dist/{chunk-24KCAECR.cjs → chunk-JJR27M56.cjs} +3 -3
  16. package/dist/{chunk-24KCAECR.cjs.map → chunk-JJR27M56.cjs.map} +1 -1
  17. package/dist/chunk-K4DFAVSO.cjs +302 -0
  18. package/dist/chunk-K4DFAVSO.cjs.map +1 -0
  19. package/dist/{chunk-HICZPTRR.js → chunk-LCLTCCXS.js} +14 -14
  20. package/dist/chunk-LCLTCCXS.js.map +1 -0
  21. package/dist/{chunk-VFKQMAUF.cjs → chunk-OB45JHDY.cjs} +3 -3
  22. package/dist/{chunk-VFKQMAUF.cjs.map → chunk-OB45JHDY.cjs.map} +1 -1
  23. package/dist/{chunk-4XLJWX2N.js → chunk-ORJREQ2W.js} +4 -4
  24. package/dist/{chunk-7PCP7YQR.js → chunk-QTKU6ULP.js} +6 -6
  25. package/dist/{chunk-CIPO6DXK.js → chunk-QY75VKAS.js} +5 -5
  26. package/dist/{chunk-ZG2YY5E7.js → chunk-RFONYT63.js} +1 -1
  27. package/dist/chunk-RFONYT63.js.map +1 -0
  28. package/dist/{chunk-NGFP4RVL.cjs → chunk-SMCG2CCC.cjs} +30 -30
  29. package/dist/{chunk-NGFP4RVL.cjs.map → chunk-SMCG2CCC.cjs.map} +1 -1
  30. package/dist/{chunk-MX5MIFWA.js → chunk-UEBM4PC4.js} +5 -5
  31. package/dist/chunk-VC3ND5RB.js +348 -0
  32. package/dist/chunk-VC3ND5RB.js.map +1 -0
  33. package/dist/{chunk-UXZ3ZJ3M.cjs → chunk-XDPSSE4O.cjs} +4 -4
  34. package/dist/{chunk-UXZ3ZJ3M.cjs.map → chunk-XDPSSE4O.cjs.map} +1 -1
  35. package/dist/{chunk-D4MNFY67.cjs → chunk-ZGTDUPTW.cjs} +1316 -894
  36. package/dist/chunk-ZGTDUPTW.cjs.map +1 -0
  37. package/dist/components/chat/entity-cards/blog-card.d.ts +1 -1
  38. package/dist/components/chat/entity-cards/blog-card.d.ts.map +1 -1
  39. package/dist/components/chat/entity-cards/case-study-card.d.ts +1 -1
  40. package/dist/components/chat/entity-cards/case-study-card.d.ts.map +1 -1
  41. package/dist/components/chat/entity-cards/customer-interview-card.d.ts +1 -1
  42. package/dist/components/chat/entity-cards/customer-interview-card.d.ts.map +1 -1
  43. package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -1
  44. package/dist/components/chat/entity-cards/investor-update-card.d.ts +1 -1
  45. package/dist/components/chat/entity-cards/investor-update-card.d.ts.map +1 -1
  46. package/dist/components/chat/entity-cards/onboarding-guide-card.d.ts +1 -1
  47. package/dist/components/chat/entity-cards/onboarding-guide-card.d.ts.map +1 -1
  48. package/dist/components/chat/entity-cards/program-card.d.ts +1 -1
  49. package/dist/components/chat/entity-cards/program-card.d.ts.map +1 -1
  50. package/dist/components/chat/entity-cards/use-entity-card-link.d.ts +14 -0
  51. package/dist/components/chat/entity-cards/use-entity-card-link.d.ts.map +1 -0
  52. package/dist/components/chat/entity-cards/use-entity-card-placeholder.d.ts +13 -0
  53. package/dist/components/chat/entity-cards/use-entity-card-placeholder.d.ts.map +1 -0
  54. package/dist/components/chat/index.cjs +11 -11
  55. package/dist/components/chat/index.js +10 -10
  56. package/dist/components/contact/index.cjs +12 -12
  57. package/dist/components/contact/index.js +11 -11
  58. package/dist/components/features/captions-url.d.ts +18 -0
  59. package/dist/components/features/captions-url.d.ts.map +1 -0
  60. package/dist/components/features/index.cjs +23 -11
  61. package/dist/components/features/index.cjs.map +1 -1
  62. package/dist/components/features/index.d.ts +2 -0
  63. package/dist/components/features/index.d.ts.map +1 -1
  64. package/dist/components/features/index.js +24 -12
  65. package/dist/components/features/mux-origins.cjs +10 -0
  66. package/dist/components/features/mux-origins.cjs.map +1 -0
  67. package/dist/components/features/mux-origins.d.ts +26 -0
  68. package/dist/components/features/mux-origins.d.ts.map +1 -0
  69. package/dist/components/features/mux-origins.js +7 -0
  70. package/dist/components/features/mux-origins.js.map +1 -0
  71. package/dist/components/features/notifications/index.d.ts +2 -0
  72. package/dist/components/features/notifications/index.d.ts.map +1 -1
  73. package/dist/components/features/notifications/notification-drawer.d.ts +2 -1
  74. package/dist/components/features/notifications/notification-drawer.d.ts.map +1 -1
  75. package/dist/components/features/notifications/notification-popups.d.ts +10 -0
  76. package/dist/components/features/notifications/notification-popups.d.ts.map +1 -0
  77. package/dist/components/features/notifications/notifications-context.d.ts +8 -1
  78. package/dist/components/features/notifications/notifications-context.d.ts.map +1 -1
  79. package/dist/components/features/notifications/types.d.ts +1 -0
  80. package/dist/components/features/notifications/types.d.ts.map +1 -1
  81. package/dist/components/features/use-video-warmup.d.ts +53 -0
  82. package/dist/components/features/use-video-warmup.d.ts.map +1 -0
  83. package/dist/components/icons/index.cjs +3 -3
  84. package/dist/components/icons/index.js +2 -2
  85. package/dist/components/icons-v2-generated/index.cjs +2 -2
  86. package/dist/components/icons-v2-generated/index.cjs.map +1 -1
  87. package/dist/components/icons-v2-generated/index.js +4 -4
  88. package/dist/components/index.cjs +133 -103
  89. package/dist/components/index.cjs.map +1 -1
  90. package/dist/components/index.d.ts +1 -0
  91. package/dist/components/index.d.ts.map +1 -1
  92. package/dist/components/index.js +95 -65
  93. package/dist/components/index.js.map +1 -1
  94. package/dist/components/navigation/index.cjs +11 -11
  95. package/dist/components/navigation/index.js +10 -10
  96. package/dist/components/onboarding-guides/build-default-href.d.ts +15 -0
  97. package/dist/components/onboarding-guides/build-default-href.d.ts.map +1 -0
  98. package/dist/components/onboarding-guides/hooks/use-onboarding-guides.d.ts +28 -0
  99. package/dist/components/onboarding-guides/hooks/use-onboarding-guides.d.ts.map +1 -0
  100. package/dist/components/onboarding-guides/index.cjs +373 -0
  101. package/dist/components/onboarding-guides/index.cjs.map +1 -0
  102. package/dist/components/onboarding-guides/index.d.ts +25 -0
  103. package/dist/components/onboarding-guides/index.d.ts.map +1 -0
  104. package/dist/components/onboarding-guides/index.js +373 -0
  105. package/dist/components/onboarding-guides/index.js.map +1 -0
  106. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts +52 -0
  107. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -0
  108. package/dist/components/onboarding-guides/onboarding-guides-catalog-skeleton.d.ts +17 -0
  109. package/dist/components/onboarding-guides/onboarding-guides-catalog-skeleton.d.ts.map +1 -0
  110. package/dist/components/onboarding-guides/onboarding-guides-catalog-view.d.ts +43 -0
  111. package/dist/components/onboarding-guides/onboarding-guides-catalog-view.d.ts.map +1 -0
  112. package/dist/components/shared/doc-search/doc-search-bar.d.ts +59 -0
  113. package/dist/components/shared/doc-search/doc-search-bar.d.ts.map +1 -0
  114. package/dist/components/shared/doc-search/doc-search-result-row.d.ts +18 -0
  115. package/dist/components/shared/doc-search/doc-search-result-row.d.ts.map +1 -0
  116. package/dist/components/shared/doc-search/format-relative-path.d.ts +10 -0
  117. package/dist/components/shared/doc-search/format-relative-path.d.ts.map +1 -0
  118. package/dist/components/shared/doc-search/index.d.ts +8 -0
  119. package/dist/components/shared/doc-search/index.d.ts.map +1 -0
  120. package/dist/components/shared/doc-search/map-doc-search-results.d.ts +15 -0
  121. package/dist/components/shared/doc-search/map-doc-search-results.d.ts.map +1 -0
  122. package/dist/components/shared/doc-search/resolve-search-result-action.d.ts +37 -0
  123. package/dist/components/shared/doc-search/resolve-search-result-action.d.ts.map +1 -0
  124. package/dist/components/shared/doc-search/types.d.ts +29 -0
  125. package/dist/components/shared/doc-search/types.d.ts.map +1 -0
  126. package/dist/components/shared/doc-search/use-doc-search.d.ts +46 -0
  127. package/dist/components/shared/doc-search/use-doc-search.d.ts.map +1 -0
  128. package/dist/components/shared/legal-document/use-legal-docs.d.ts.map +1 -1
  129. package/dist/components/tickets/help-center-card.d.ts +5 -1
  130. package/dist/components/tickets/help-center-card.d.ts.map +1 -1
  131. package/dist/components/tickets/hooks/use-ticket-actions.d.ts +8 -0
  132. package/dist/components/tickets/hooks/use-ticket-actions.d.ts.map +1 -1
  133. package/dist/components/tickets/index.cjs +321 -145
  134. package/dist/components/tickets/index.cjs.map +1 -1
  135. package/dist/components/tickets/index.js +242 -66
  136. package/dist/components/tickets/index.js.map +1 -1
  137. package/dist/components/tickets/ticket-detail-drawer.d.ts +11 -2
  138. package/dist/components/tickets/ticket-detail-drawer.d.ts.map +1 -1
  139. package/dist/components/tickets/types.d.ts +50 -1
  140. package/dist/components/tickets/types.d.ts.map +1 -1
  141. package/dist/components/ui/file-manager/index.cjs +51 -51
  142. package/dist/components/ui/file-manager/index.cjs.map +1 -1
  143. package/dist/components/ui/file-manager/index.js +2 -2
  144. package/dist/components/ui/filter-pill-row.d.ts +20 -0
  145. package/dist/components/ui/filter-pill-row.d.ts.map +1 -0
  146. package/dist/components/ui/index.cjs +16 -14
  147. package/dist/components/ui/index.cjs.map +1 -1
  148. package/dist/components/ui/index.d.ts +1 -0
  149. package/dist/components/ui/index.d.ts.map +1 -1
  150. package/dist/components/ui/index.js +21 -19
  151. package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -1
  152. package/dist/contexts/chat-runtime-context.d.ts +42 -0
  153. package/dist/contexts/chat-runtime-context.d.ts.map +1 -1
  154. package/dist/contexts/index.cjs +2 -2
  155. package/dist/contexts/index.js +1 -1
  156. package/dist/embed-shims/index.cjs +3 -3
  157. package/dist/embed-shims/index.cjs.map +1 -1
  158. package/dist/embed-shims/index.js +5 -5
  159. package/dist/hooks/index.cjs +6 -6
  160. package/dist/hooks/index.js +5 -5
  161. package/dist/index.cjs +28 -14
  162. package/dist/index.cjs.map +1 -1
  163. package/dist/index.js +59 -45
  164. package/dist/utils/dev-sections/openframe-dev-sections.d.ts +2 -2
  165. package/dist/utils/dev-sections/openframe-dev-sections.d.ts.map +1 -1
  166. package/dist/utils/index.cjs +11 -5
  167. package/dist/utils/index.cjs.map +1 -1
  168. package/dist/utils/index.js +11 -5
  169. package/dist/utils/index.js.map +1 -1
  170. package/package.json +13 -1
  171. package/src/components/chat/entity-cards/blog-card.tsx +17 -5
  172. package/src/components/chat/entity-cards/case-study-card.tsx +23 -1
  173. package/src/components/chat/entity-cards/customer-interview-card.tsx +23 -1
  174. package/src/components/chat/entity-cards/dispatch.tsx +21 -0
  175. package/src/components/chat/entity-cards/investor-update-card.tsx +23 -1
  176. package/src/components/chat/entity-cards/onboarding-guide-card.tsx +30 -4
  177. package/src/components/chat/entity-cards/program-card.tsx +17 -3
  178. package/src/components/chat/entity-cards/use-entity-card-link.ts +66 -0
  179. package/src/components/chat/entity-cards/use-entity-card-placeholder.ts +50 -0
  180. package/src/components/features/captions-url.ts +25 -0
  181. package/src/components/features/index.ts +2 -0
  182. package/src/components/features/mux-origins.ts +27 -0
  183. package/src/components/features/notifications/index.ts +2 -0
  184. package/src/components/features/notifications/notification-drawer.tsx +100 -16
  185. package/src/components/features/notifications/notification-popups.tsx +105 -0
  186. package/src/components/features/notifications/notifications-context.tsx +16 -0
  187. package/src/components/features/notifications/types.ts +1 -0
  188. package/src/components/features/use-video-warmup.ts +176 -0
  189. package/src/components/index.ts +5 -0
  190. package/src/components/onboarding-guides/build-default-href.ts +16 -0
  191. package/src/components/onboarding-guides/hooks/use-onboarding-guides.ts +90 -0
  192. package/src/components/onboarding-guides/index.ts +39 -0
  193. package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +215 -0
  194. package/src/components/onboarding-guides/onboarding-guides-catalog-skeleton.tsx +62 -0
  195. package/src/components/onboarding-guides/onboarding-guides-catalog-view.tsx +230 -0
  196. package/src/components/shared/doc-search/doc-search-bar.tsx +100 -0
  197. package/src/components/shared/doc-search/doc-search-result-row.tsx +73 -0
  198. package/src/components/shared/doc-search/format-relative-path.ts +17 -0
  199. package/src/components/shared/doc-search/index.ts +24 -0
  200. package/src/components/shared/doc-search/map-doc-search-results.ts +113 -0
  201. package/src/components/shared/doc-search/resolve-search-result-action.ts +68 -0
  202. package/src/components/shared/doc-search/types.ts +28 -0
  203. package/src/components/shared/doc-search/use-doc-search.ts +263 -0
  204. package/src/components/shared/legal-document/use-legal-docs.ts +5 -1
  205. package/src/components/tickets/help-center-card.tsx +8 -0
  206. package/src/components/tickets/help-center-list.tsx +17 -3
  207. package/src/components/tickets/hooks/use-ticket-actions.ts +210 -14
  208. package/src/components/tickets/ticket-detail-drawer.tsx +175 -5
  209. package/src/components/tickets/types.ts +55 -0
  210. package/src/components/ui/filter-pill-row.tsx +72 -0
  211. package/src/components/ui/index.ts +1 -0
  212. package/src/components/ui/simple-markdown-renderer.tsx +24 -1
  213. package/src/components/ui/toaster.tsx +3 -3
  214. package/src/contexts/chat-runtime-context.tsx +41 -0
  215. package/src/stories/NotificationDrawer.stories.tsx +18 -2
  216. package/src/utils/dev-sections/openframe-dev-sections.ts +12 -5
  217. package/dist/chunk-2G3NXF6J.cjs +0 -521
  218. package/dist/chunk-2G3NXF6J.cjs.map +0 -1
  219. package/dist/chunk-D4MNFY67.cjs.map +0 -1
  220. package/dist/chunk-HICZPTRR.js.map +0 -1
  221. package/dist/chunk-P5EE2VJX.cjs.map +0 -1
  222. package/dist/chunk-R6MLPU4A.js +0 -521
  223. package/dist/chunk-R6MLPU4A.js.map +0 -1
  224. package/dist/chunk-WQZP3JIZ.js.map +0 -1
  225. package/dist/chunk-WT5JV2GS.cjs.map +0 -1
  226. package/dist/chunk-ZG2YY5E7.js.map +0 -1
  227. /package/dist/{chunk-4XLJWX2N.js.map → chunk-ORJREQ2W.js.map} +0 -0
  228. /package/dist/{chunk-7PCP7YQR.js.map → chunk-QTKU6ULP.js.map} +0 -0
  229. /package/dist/{chunk-CIPO6DXK.js.map → chunk-QY75VKAS.js.map} +0 -0
  230. /package/dist/{chunk-MX5MIFWA.js.map → chunk-UEBM4PC4.js.map} +0 -0
@@ -1,19 +1,21 @@
1
1
  "use client";
2
2
  import {
3
- ConversationCardRow,
4
- ConversationCardRowSkeletonList,
5
3
  DeliveryRow,
6
- DevCardRowContent,
7
- DevCardRowSkeletonList,
8
- DevSectionPage,
9
4
  EmptyState,
10
5
  UnifiedPagination,
11
6
  init_unified_pagination
12
- } from "../../chunk-R6MLPU4A.js";
13
- import "../../chunk-4XLJWX2N.js";
7
+ } from "../../chunk-2V4SACHE.js";
8
+ import {
9
+ ConversationCardRow,
10
+ ConversationCardRowSkeletonList,
11
+ DevCardRowContent,
12
+ DevCardRowSkeletonList,
13
+ DevSectionPage
14
+ } from "../../chunk-GVNQAGXB.js";
15
+ import "../../chunk-ORJREQ2W.js";
14
16
  import {
15
17
  ContactForm
16
- } from "../../chunk-7PCP7YQR.js";
18
+ } from "../../chunk-QTKU6ULP.js";
17
19
  import {
18
20
  AlertDialog,
19
21
  AlertDialogAction,
@@ -28,6 +30,7 @@ import {
28
30
  ChatAttachmentChipStrip,
29
31
  ChatTicketItem,
30
32
  Label,
33
+ SquareAvatar,
31
34
  StatusBadge,
32
35
  Textarea,
33
36
  embedAuthedFetch,
@@ -36,32 +39,32 @@ import {
36
39
  scrollElementIntoView,
37
40
  useChatAttachments,
38
41
  useChatIdentity
39
- } from "../../chunk-WQZP3JIZ.js";
40
- import {
41
- toast
42
- } from "../../chunk-HICZPTRR.js";
43
- import "../../chunk-CIPO6DXK.js";
44
- import "../../chunk-EDW2NVRV.js";
45
- import "../../chunk-W72U7OU7.js";
46
- import "../../chunk-ZG2YY5E7.js";
47
- import "../../chunk-MJNXIEV2.js";
42
+ } from "../../chunk-CDLYRFDE.js";
48
43
  import "../../chunk-LXC6P2EO.js";
49
44
  import "../../chunk-EL5YVPD5.js";
50
- import {
51
- usePathname,
52
- useRouter,
53
- useSearchParams
54
- } from "../../chunk-PLJLE4A4.js";
55
- import "../../chunk-CZR7ARBA.js";
56
45
  import {
57
46
  Button,
58
47
  Input,
59
48
  Skeleton,
60
49
  init_button2 as init_button
61
- } from "../../chunk-MX5MIFWA.js";
50
+ } from "../../chunk-UEBM4PC4.js";
51
+ import "../../chunk-OHPI2HRK.js";
52
+ import {
53
+ toast
54
+ } from "../../chunk-LCLTCCXS.js";
55
+ import {
56
+ usePathname,
57
+ useRouter,
58
+ useSearchParams
59
+ } from "../../chunk-PLJLE4A4.js";
60
+ import "../../chunk-QY75VKAS.js";
62
61
  import "../../chunk-KSOOKNBG.js";
62
+ import "../../chunk-EDW2NVRV.js";
63
63
  import "../../chunk-6U3IUD57.js";
64
- import "../../chunk-OHPI2HRK.js";
64
+ import "../../chunk-W72U7OU7.js";
65
+ import "../../chunk-RFONYT63.js";
66
+ import "../../chunk-MJNXIEV2.js";
67
+ import "../../chunk-CZR7ARBA.js";
65
68
  import "../../chunk-GGWZFCYS.js";
66
69
 
67
70
  // src/components/tickets/ticket-center.tsx
@@ -311,35 +314,47 @@ function TicketDetailDrawer({
311
314
  onSendMessage,
312
315
  onClose,
313
316
  onReopen,
314
- onActionCollapsed
317
+ onActionCollapsed,
318
+ replyError,
319
+ onClearReplyError
315
320
  }) {
316
321
  const isClosed = (ticket.status ?? "").toUpperCase() === "CLOSED";
317
322
  return /* @__PURE__ */ jsxs2("div", { className: "bg-ods-card border-t border-ods-border px-4 py-4 flex flex-col gap-4", children: [
323
+ /* @__PURE__ */ jsx3(AssignedAgentRow, { assignedOwner: ticket.assignedOwner }),
318
324
  ticket.clickup && /* @__PURE__ */ jsx3(TicketLinkedDeliveryCard, { clickup: ticket.clickup }),
319
325
  /* @__PURE__ */ jsxs2("div", { children: [
320
326
  /* @__PURE__ */ jsx3("p", { className: "text-xs font-medium text-ods-text-secondary mb-2 uppercase tracking-wider", children: "Conversation" }),
321
327
  /* @__PURE__ */ jsx3(TicketTimelinePanel, { ticket })
322
328
  ] }),
323
- /* @__PURE__ */ jsx3("div", { className: "border-t border-ods-border pt-4", children: isClosed ? /* @__PURE__ */ jsx3(
324
- ReopenAction,
325
- {
326
- ticketRef: { id: ticket.id, external_id: ticket.external_id },
327
- busy,
328
- supportSystemDown,
329
- onReopen,
330
- onActionCollapsed
331
- }
332
- ) : /* @__PURE__ */ jsx3(
333
- OpenActions,
334
- {
335
- ticket,
336
- busy,
337
- supportSystemDown,
338
- onSendMessage,
339
- onClose,
340
- onActionCollapsed
341
- }
342
- ) })
329
+ /* @__PURE__ */ jsxs2("div", { className: "border-t border-ods-border pt-4", children: [
330
+ replyError && /* @__PURE__ */ jsx3(
331
+ ReplyFailureBanner,
332
+ {
333
+ error: replyError,
334
+ onDismiss: onClearReplyError ?? (() => void 0)
335
+ }
336
+ ),
337
+ isClosed ? /* @__PURE__ */ jsx3(
338
+ ReopenAction,
339
+ {
340
+ ticketRef: { id: ticket.id, external_id: ticket.external_id },
341
+ busy,
342
+ supportSystemDown,
343
+ onReopen,
344
+ onActionCollapsed
345
+ }
346
+ ) : /* @__PURE__ */ jsx3(
347
+ OpenActions,
348
+ {
349
+ ticket,
350
+ busy,
351
+ supportSystemDown,
352
+ onSendMessage,
353
+ onClose,
354
+ onActionCollapsed
355
+ }
356
+ )
357
+ ] })
343
358
  ] });
344
359
  }
345
360
  var TURN_SEPARATOR_RE = /[\s]{1,16}---[\s]{1,16}/g;
@@ -348,6 +363,10 @@ function TicketTimelinePanel({ ticket }) {
348
363
  const externalId = isOptimistic(ticket) ? null : ticket.external_id;
349
364
  const { engagements, isLoading } = useTicketEngagements(externalId, !!externalId);
350
365
  const bodyTurns = ticket.body ? ticket.body.split(TURN_SEPARATOR_RE).map((t) => t.trim()).filter(Boolean) : [];
366
+ const customerEngagementBodies = new Set(
367
+ engagements.filter((e) => e.authorRole === "customer").map((e) => (e.body ?? "").trim()).filter(Boolean)
368
+ );
369
+ const suppressBodyTurnZero = bodyTurns.length > 0 && customerEngagementBodies.has(bodyTurns[0]);
351
370
  const sessionEmailLower = identity.user?.email?.trim().toLowerCase() ?? null;
352
371
  const isViewerTheCustomer = !!sessionEmailLower && ticket.customer_emails.some((e) => e.trim().toLowerCase() === sessionEmailLower);
353
372
  const viewerName = identity.user?.name?.trim() || null;
@@ -370,6 +389,7 @@ function TicketTimelinePanel({ ticket }) {
370
389
  }
371
390
  return /* @__PURE__ */ jsxs2("div", { className: "bg-ods-card border border-ods-border rounded-[6px] overflow-hidden w-full", children: [
372
391
  bodyTurns.map((turn, i) => {
392
+ if (i === 0 && suppressBodyTurnZero) return null;
373
393
  const isResolution = turn.startsWith("[Resolution]");
374
394
  const role = i === 0 ? "Original message" : isResolution ? "Resolution" : `Update ${i}`;
375
395
  const text = isResolution ? turn.replace(/^\[Resolution\]\s*/, "") : turn;
@@ -449,8 +469,7 @@ function ReopenAction({
449
469
  onActionCollapsed
450
470
  }) {
451
471
  const handleReopen = async () => {
452
- const ok = await onReopen(ticketRef);
453
- if (ok) onActionCollapsed();
472
+ void await onReopen(ticketRef);
454
473
  };
455
474
  return /* @__PURE__ */ jsx3("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx3(
456
475
  Button,
@@ -490,9 +509,8 @@ function OpenActions({
490
509
  };
491
510
  const confirmClose = async () => {
492
511
  setCloseDialogOpen(false);
493
- const ok = await onClose(ticketRef, resolution.trim() || void 0);
512
+ await onClose(ticketRef, resolution.trim() || void 0);
494
513
  setResolution("");
495
- if (ok) onActionCollapsed();
496
514
  };
497
515
  return /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-3", children: [
498
516
  /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-2", children: [
@@ -591,6 +609,56 @@ function OpenActions({
591
609
  ] }) })
592
610
  ] });
593
611
  }
612
+ function ReplyFailureBanner({
613
+ error,
614
+ onDismiss
615
+ }) {
616
+ return /* @__PURE__ */ jsxs2(
617
+ "div",
618
+ {
619
+ role: "status",
620
+ "aria-live": "polite",
621
+ 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",
622
+ children: [
623
+ /* @__PURE__ */ jsx3("span", { className: "font-medium leading-snug", children: error.message }),
624
+ /* @__PURE__ */ jsx3(
625
+ Button,
626
+ {
627
+ type: "button",
628
+ variant: "transparent",
629
+ onClick: onDismiss,
630
+ "aria-label": "Dismiss reply failure",
631
+ 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",
632
+ children: "Dismiss"
633
+ }
634
+ )
635
+ ]
636
+ }
637
+ );
638
+ }
639
+ function AssignedAgentRow({
640
+ assignedOwner
641
+ }) {
642
+ const trimmedName = assignedOwner?.name?.trim() || null;
643
+ const emailFallback = assignedOwner?.email?.trim() || null;
644
+ const displayLabel = trimmedName ?? (emailFallback ? emailFallback.split("@")[0] : null);
645
+ return /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 text-xs", children: [
646
+ /* @__PURE__ */ jsx3("span", { className: "text-ods-text-secondary uppercase tracking-wider font-medium", children: "Assigned to" }),
647
+ displayLabel ? /* @__PURE__ */ jsxs2("span", { className: "flex items-center gap-1.5 text-ods-text-primary font-medium", children: [
648
+ /* @__PURE__ */ jsx3(
649
+ SquareAvatar,
650
+ {
651
+ size: "sm",
652
+ variant: "round",
653
+ src: assignedOwner?.avatarUrl ?? void 0,
654
+ alt: displayLabel,
655
+ fallback: displayLabel
656
+ }
657
+ ),
658
+ displayLabel
659
+ ] }) : /* @__PURE__ */ jsx3("span", { className: "text-ods-text-secondary italic", children: "Unassigned" })
660
+ ] });
661
+ }
594
662
 
595
663
  // src/components/tickets/ticket-row.tsx
596
664
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
@@ -771,6 +839,12 @@ function useTicketsList(filters) {
771
839
  import { useCallback as useCallback2, useEffect, useMemo, useRef as useRef2, useState as useState3 } from "react";
772
840
  import { useQueryClient } from "@tanstack/react-query";
773
841
  var TICKET_ACTION_ENDPOINT = "/api/chat/agent/ticket-action";
842
+ var REPLY_BANNER_CODES = /* @__PURE__ */ new Set([
843
+ "HUBSPOT_5XX",
844
+ "HUBSPOT_400_VALIDATION",
845
+ "HUBSPOT_404_THREAD",
846
+ "HUBSPOT_REPLY_UNKNOWN"
847
+ ]);
774
848
  var MIRROR_SYNC_BACKOFF_MS = [3e3, 6e3, 12e3];
775
849
  function useTicketActions(options) {
776
850
  const queryClient = useQueryClient();
@@ -785,6 +859,26 @@ function useTicketActions(options) {
785
859
  setBusyRows(new Set(busyRowsRef.current));
786
860
  }, []);
787
861
  const isRowBusy = useCallback2((id) => busyRows.has(id), [busyRows]);
862
+ const [replyErrorByTicket, setReplyErrorByTicket] = useState3(() => /* @__PURE__ */ new Map());
863
+ const setReplyError = useCallback2(
864
+ (externalId, mapped) => {
865
+ setReplyErrorByTicket((prev) => {
866
+ const next = new Map(prev);
867
+ if (mapped) next.set(externalId, mapped);
868
+ else next.delete(externalId);
869
+ return next;
870
+ });
871
+ },
872
+ []
873
+ );
874
+ const replyErrorFor = useCallback2(
875
+ (externalId) => replyErrorByTicket.get(externalId) ?? null,
876
+ [replyErrorByTicket]
877
+ );
878
+ const clearReplyError = useCallback2(
879
+ (externalId) => setReplyError(externalId, null),
880
+ [setReplyError]
881
+ );
788
882
  const watcherControllersRef = useRef2(/* @__PURE__ */ new Map());
789
883
  useEffect(() => {
790
884
  return () => {
@@ -862,9 +956,11 @@ function useTicketActions(options) {
862
956
  },
863
957
  [queryClient, removeOptimistic, toast2]
864
958
  );
959
+ const lastUpdateErrorRef = useRef2(null);
865
960
  const surfaceError = useCallback2(
866
961
  (err, action) => {
867
962
  const mapped = mapTicketActionError(err);
963
+ lastUpdateErrorRef.current = mapped;
868
964
  if (mapped.supportSystemDown) onSupportSystemDown();
869
965
  toast2({
870
966
  title: `Could not ${action}`,
@@ -899,6 +995,10 @@ function useTicketActions(options) {
899
995
  // seconds via the mirror refetch. Drawer uses live chat
900
996
  // identity for own-replies during this window anyway.
901
997
  customer_name: null,
998
+ // No assignee until the real ticket lands. Drawer renders
999
+ // "Unassigned" for this brief window.
1000
+ assigned_to: null,
1001
+ assignedOwner: null,
902
1002
  hubspot_updated_at: (/* @__PURE__ */ new Date()).toISOString(),
903
1003
  _optimistic: true
904
1004
  };
@@ -951,10 +1051,23 @@ function useTicketActions(options) {
951
1051
  ticket_id: ticket.external_id
952
1052
  });
953
1053
  toast2(successCopy);
954
- await Promise.all([
955
- queryClient.invalidateQueries({ queryKey: ["tickets"] }),
956
- queryClient.invalidateQueries({ queryKey: ["ticket-engagements"] })
957
- ]);
1054
+ const statusUpdate = serverArgs.status ?? null;
1055
+ if (statusUpdate) {
1056
+ queryClient.setQueriesData(
1057
+ { queryKey: ["tickets"] },
1058
+ (prev) => {
1059
+ if (!prev || !Array.isArray(prev.tickets)) return prev;
1060
+ let mutated = false;
1061
+ const nextTickets = prev.tickets.map((t) => {
1062
+ if (t.id !== ticket.id || t.status === statusUpdate) return t;
1063
+ mutated = true;
1064
+ return { ...t, status: statusUpdate };
1065
+ });
1066
+ return mutated ? { ...prev, tickets: nextTickets } : prev;
1067
+ }
1068
+ );
1069
+ }
1070
+ await queryClient.invalidateQueries({ queryKey: ["ticket-engagements"] });
958
1071
  return true;
959
1072
  });
960
1073
  } catch (err) {
@@ -974,12 +1087,13 @@ function useTicketActions(options) {
974
1087
  [setRowBusy, enqueue, executeTicketAction, queryClient, toast2, surfaceError, removeTicketFromCache]
975
1088
  );
976
1089
  const sendMessage = useCallback2(
977
- (ticket, text, attachments) => {
1090
+ async (ticket, text, attachments) => {
978
1091
  const trimmed = text.trim();
979
1092
  const hasText = trimmed.length > 0;
980
1093
  const hasFiles = attachments.length > 0;
981
- if (!hasText && !hasFiles) return Promise.resolve(false);
982
- return updateTicket(
1094
+ if (!hasText && !hasFiles) return false;
1095
+ lastUpdateErrorRef.current = null;
1096
+ const ok = await updateTicket(
983
1097
  ticket,
984
1098
  {
985
1099
  ...hasText ? { content_addendum: trimmed } : {},
@@ -988,8 +1102,18 @@ function useTicketActions(options) {
988
1102
  TOAST_COPY.comment_success,
989
1103
  "send message"
990
1104
  );
1105
+ if (ok) {
1106
+ clearReplyError(ticket.external_id);
1107
+ } else {
1108
+ const mapped = lastUpdateErrorRef.current;
1109
+ if (mapped && REPLY_BANNER_CODES.has(mapped.code)) {
1110
+ setReplyError(ticket.external_id, mapped);
1111
+ }
1112
+ lastUpdateErrorRef.current = null;
1113
+ }
1114
+ return ok;
991
1115
  },
992
- [updateTicket]
1116
+ [updateTicket, clearReplyError, setReplyError]
993
1117
  );
994
1118
  const closeTicket = useCallback2(
995
1119
  (ticket, resolution) => updateTicket(
@@ -1014,9 +1138,20 @@ function useTicketActions(options) {
1014
1138
  closeTicket,
1015
1139
  reopenTicket,
1016
1140
  isSubmittingForm,
1017
- isRowBusy
1141
+ isRowBusy,
1142
+ replyErrorFor,
1143
+ clearReplyError
1018
1144
  }),
1019
- [submitTicket, sendMessage, closeTicket, reopenTicket, isSubmittingForm, isRowBusy]
1145
+ [
1146
+ submitTicket,
1147
+ sendMessage,
1148
+ closeTicket,
1149
+ reopenTicket,
1150
+ isSubmittingForm,
1151
+ isRowBusy,
1152
+ replyErrorFor,
1153
+ clearReplyError
1154
+ ]
1020
1155
  );
1021
1156
  }
1022
1157
  var TicketActionFailure = class extends Error {
@@ -1075,6 +1210,34 @@ function mapTicketActionError(err) {
1075
1210
  supportSystemDown: false,
1076
1211
  removeRowFromCache: false
1077
1212
  };
1213
+ case "HUBSPOT_5XX":
1214
+ return {
1215
+ code: err.code,
1216
+ message: "We couldn't reach the support system. Your reply wasn't sent \u2014 please retry in a moment.",
1217
+ supportSystemDown: false,
1218
+ removeRowFromCache: false
1219
+ };
1220
+ case "HUBSPOT_400_VALIDATION":
1221
+ return {
1222
+ code: err.code,
1223
+ message: "Your reply was rejected. Please rephrase or remove unsupported content and try again.",
1224
+ supportSystemDown: false,
1225
+ removeRowFromCache: false
1226
+ };
1227
+ case "HUBSPOT_404_THREAD":
1228
+ return {
1229
+ code: err.code,
1230
+ message: "This conversation is no longer accepting replies. Open a new ticket to continue.",
1231
+ supportSystemDown: false,
1232
+ removeRowFromCache: false
1233
+ };
1234
+ case "HUBSPOT_REPLY_UNKNOWN":
1235
+ return {
1236
+ code: err.code,
1237
+ message: "Your reply didn't go through. Please retry.",
1238
+ supportSystemDown: false,
1239
+ removeRowFromCache: false
1240
+ };
1078
1241
  default:
1079
1242
  return {
1080
1243
  code: "UNKNOWN",
@@ -1098,9 +1261,11 @@ function cryptoRandomId() {
1098
1261
  return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
1099
1262
  }
1100
1263
  function cacheContainsTicket(queryClient, expectedTicketId) {
1101
- const entries = queryClient.getQueriesData({ queryKey: ["tickets"] });
1264
+ const entries = queryClient.getQueriesData({
1265
+ queryKey: ["tickets"]
1266
+ });
1102
1267
  for (const [, data] of entries) {
1103
- if (Array.isArray(data) && data.some((t) => t.external_id === expectedTicketId)) {
1268
+ if (data && Array.isArray(data.tickets) && data.tickets.some((t) => t.external_id === expectedTicketId)) {
1104
1269
  return true;
1105
1270
  }
1106
1271
  }
@@ -1274,7 +1439,9 @@ function HelpCenterCard({
1274
1439
  onSendMessage,
1275
1440
  onClose,
1276
1441
  onReopen,
1277
- onActionCollapsed
1442
+ onActionCollapsed,
1443
+ replyError,
1444
+ onClearReplyError
1278
1445
  }) {
1279
1446
  const optimistic = isOptimistic(ticket);
1280
1447
  const rawStatus = (ticket.status ?? "OPEN").toUpperCase();
@@ -1361,7 +1528,9 @@ function HelpCenterCard({
1361
1528
  onSendMessage,
1362
1529
  onClose,
1363
1530
  onReopen,
1364
- onActionCollapsed
1531
+ onActionCollapsed,
1532
+ replyError,
1533
+ onClearReplyError
1365
1534
  }
1366
1535
  ) })
1367
1536
  ]
@@ -1561,7 +1730,12 @@ function HelpCenterListAuthed({
1561
1730
  (ticketId) => {
1562
1731
  queryClient.setQueriesData(
1563
1732
  { queryKey: ["tickets"] },
1564
- (prev) => (prev ?? []).filter((t) => t.id !== ticketId)
1733
+ (prev) => {
1734
+ if (!prev || !Array.isArray(prev.tickets)) return prev;
1735
+ const nextTickets = prev.tickets.filter((t) => t.id !== ticketId);
1736
+ if (nextTickets.length === prev.tickets.length) return prev;
1737
+ return { ...prev, tickets: nextTickets };
1738
+ }
1565
1739
  );
1566
1740
  setExpandedTicketId((prev) => prev === ticketId ? null : prev);
1567
1741
  },
@@ -1647,7 +1821,9 @@ function HelpCenterListAuthed({
1647
1821
  onSendMessage: actions.sendMessage,
1648
1822
  onClose: actions.closeTicket,
1649
1823
  onReopen: actions.reopenTicket,
1650
- onActionCollapsed: () => setExpandedTicketId(null)
1824
+ onActionCollapsed: () => setExpandedTicketId(null),
1825
+ replyError: actions.replyErrorFor(ticket.external_id),
1826
+ onClearReplyError: () => actions.clearReplyError(ticket.external_id)
1651
1827
  },
1652
1828
  ticket.id
1653
1829
  )) })