@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.
- package/dist/{chunk-KDNGUYZM.cjs → chunk-2G3NXF6J.cjs} +17 -17
- package/dist/{chunk-KDNGUYZM.cjs.map → chunk-2G3NXF6J.cjs.map} +1 -1
- package/dist/{chunk-HWY35EAK.js → chunk-7PCP7YQR.js} +2 -2
- package/dist/{chunk-YZUUFTIK.cjs → chunk-D4MNFY67.cjs} +3 -2
- package/dist/chunk-D4MNFY67.cjs.map +1 -0
- package/dist/{chunk-IZL2KEH6.cjs → chunk-NGFP4RVL.cjs} +24 -24
- package/dist/{chunk-IZL2KEH6.cjs.map → chunk-NGFP4RVL.cjs.map} +1 -1
- package/dist/{chunk-5OWDOFKK.js → chunk-R6MLPU4A.js} +2 -2
- package/dist/{chunk-UKND27XC.js → chunk-WQZP3JIZ.js} +3 -2
- package/dist/{chunk-UKND27XC.js.map → chunk-WQZP3JIZ.js.map} +1 -1
- package/dist/components/chat/index.cjs +2 -2
- package/dist/components/chat/index.js +1 -1
- package/dist/components/contact/index.cjs +3 -3
- package/dist/components/contact/index.js +2 -2
- package/dist/components/features/index.cjs +2 -2
- package/dist/components/features/index.js +1 -1
- package/dist/components/index.cjs +49 -49
- package/dist/components/index.js +2 -2
- package/dist/components/navigation/index.cjs +2 -2
- package/dist/components/navigation/index.js +1 -1
- package/dist/components/tickets/help-center-card.d.ts +5 -1
- package/dist/components/tickets/help-center-card.d.ts.map +1 -1
- package/dist/components/tickets/hooks/use-ticket-actions.d.ts +8 -0
- package/dist/components/tickets/hooks/use-ticket-actions.d.ts.map +1 -1
- package/dist/components/tickets/index.cjs +254 -103
- package/dist/components/tickets/index.cjs.map +1 -1
- package/dist/components/tickets/index.js +184 -33
- package/dist/components/tickets/index.js.map +1 -1
- package/dist/components/tickets/ticket-detail-drawer.d.ts +11 -2
- package/dist/components/tickets/ticket-detail-drawer.d.ts.map +1 -1
- package/dist/components/tickets/types.d.ts +28 -1
- package/dist/components/tickets/types.d.ts.map +1 -1
- package/dist/components/ui/index.cjs +2 -2
- package/dist/components/ui/index.js +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/platform/ShellTypeBadge.tsx +2 -2
- package/src/components/tickets/help-center-card.tsx +8 -0
- package/src/components/tickets/help-center-list.tsx +2 -0
- package/src/components/tickets/hooks/use-ticket-actions.ts +139 -5
- package/src/components/tickets/ticket-detail-drawer.tsx +129 -1
- package/src/components/tickets/types.ts +32 -0
- package/dist/chunk-YZUUFTIK.cjs.map +0 -1
- /package/dist/{chunk-HWY35EAK.js.map → chunk-7PCP7YQR.js.map} +0 -0
- /package/dist/{chunk-5OWDOFKK.js.map → chunk-R6MLPU4A.js.map} +0 -0
|
@@ -9,11 +9,11 @@ import {
|
|
|
9
9
|
EmptyState,
|
|
10
10
|
UnifiedPagination,
|
|
11
11
|
init_unified_pagination
|
|
12
|
-
} from "../../chunk-
|
|
12
|
+
} from "../../chunk-R6MLPU4A.js";
|
|
13
13
|
import "../../chunk-4XLJWX2N.js";
|
|
14
14
|
import {
|
|
15
15
|
ContactForm
|
|
16
|
-
} from "../../chunk-
|
|
16
|
+
} from "../../chunk-7PCP7YQR.js";
|
|
17
17
|
import {
|
|
18
18
|
AlertDialog,
|
|
19
19
|
AlertDialogAction,
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
ChatAttachmentChipStrip,
|
|
29
29
|
ChatTicketItem,
|
|
30
30
|
Label,
|
|
31
|
+
SquareAvatar,
|
|
31
32
|
StatusBadge,
|
|
32
33
|
Textarea,
|
|
33
34
|
embedAuthedFetch,
|
|
@@ -36,7 +37,7 @@ import {
|
|
|
36
37
|
scrollElementIntoView,
|
|
37
38
|
useChatAttachments,
|
|
38
39
|
useChatIdentity
|
|
39
|
-
} from "../../chunk-
|
|
40
|
+
} from "../../chunk-WQZP3JIZ.js";
|
|
40
41
|
import {
|
|
41
42
|
toast
|
|
42
43
|
} from "../../chunk-HICZPTRR.js";
|
|
@@ -311,35 +312,47 @@ 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 = (ticket.status ?? "").toUpperCase() === "CLOSED";
|
|
317
320
|
return /* @__PURE__ */ jsxs2("div", { className: "bg-ods-card border-t border-ods-border px-4 py-4 flex flex-col gap-4", children: [
|
|
321
|
+
/* @__PURE__ */ jsx3(AssignedAgentRow, { assignedOwner: ticket.assignedOwner }),
|
|
318
322
|
ticket.clickup && /* @__PURE__ */ jsx3(TicketLinkedDeliveryCard, { clickup: ticket.clickup }),
|
|
319
323
|
/* @__PURE__ */ jsxs2("div", { children: [
|
|
320
324
|
/* @__PURE__ */ jsx3("p", { className: "text-xs font-medium text-ods-text-secondary mb-2 uppercase tracking-wider", children: "Conversation" }),
|
|
321
325
|
/* @__PURE__ */ jsx3(TicketTimelinePanel, { ticket })
|
|
322
326
|
] }),
|
|
323
|
-
/* @__PURE__ */
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
327
|
+
/* @__PURE__ */ jsxs2("div", { className: "border-t border-ods-border pt-4", children: [
|
|
328
|
+
replyError && /* @__PURE__ */ jsx3(
|
|
329
|
+
ReplyFailureBanner,
|
|
330
|
+
{
|
|
331
|
+
error: replyError,
|
|
332
|
+
onDismiss: onClearReplyError ?? (() => void 0)
|
|
333
|
+
}
|
|
334
|
+
),
|
|
335
|
+
isClosed ? /* @__PURE__ */ jsx3(
|
|
336
|
+
ReopenAction,
|
|
337
|
+
{
|
|
338
|
+
ticketRef: { id: ticket.id, external_id: ticket.external_id },
|
|
339
|
+
busy,
|
|
340
|
+
supportSystemDown,
|
|
341
|
+
onReopen,
|
|
342
|
+
onActionCollapsed
|
|
343
|
+
}
|
|
344
|
+
) : /* @__PURE__ */ jsx3(
|
|
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;
|
|
@@ -591,6 +604,56 @@ function OpenActions({
|
|
|
591
604
|
] }) })
|
|
592
605
|
] });
|
|
593
606
|
}
|
|
607
|
+
function ReplyFailureBanner({
|
|
608
|
+
error,
|
|
609
|
+
onDismiss
|
|
610
|
+
}) {
|
|
611
|
+
return /* @__PURE__ */ jsxs2(
|
|
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__ */ jsx3("span", { className: "font-medium leading-snug", children: error.message }),
|
|
619
|
+
/* @__PURE__ */ jsx3(
|
|
620
|
+
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 = assignedOwner?.name?.trim() || null;
|
|
638
|
+
const emailFallback = assignedOwner?.email?.trim() || null;
|
|
639
|
+
const displayLabel = trimmedName ?? (emailFallback ? emailFallback.split("@")[0] : null);
|
|
640
|
+
return /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 text-xs", children: [
|
|
641
|
+
/* @__PURE__ */ jsx3("span", { className: "text-ods-text-secondary uppercase tracking-wider font-medium", children: "Assigned to" }),
|
|
642
|
+
displayLabel ? /* @__PURE__ */ jsxs2("span", { className: "flex items-center gap-1.5 text-ods-text-primary font-medium", children: [
|
|
643
|
+
/* @__PURE__ */ jsx3(
|
|
644
|
+
SquareAvatar,
|
|
645
|
+
{
|
|
646
|
+
size: "sm",
|
|
647
|
+
variant: "round",
|
|
648
|
+
src: assignedOwner?.avatarUrl ?? void 0,
|
|
649
|
+
alt: displayLabel,
|
|
650
|
+
fallback: displayLabel
|
|
651
|
+
}
|
|
652
|
+
),
|
|
653
|
+
displayLabel
|
|
654
|
+
] }) : /* @__PURE__ */ jsx3("span", { className: "text-ods-text-secondary italic", children: "Unassigned" })
|
|
655
|
+
] });
|
|
656
|
+
}
|
|
594
657
|
|
|
595
658
|
// src/components/tickets/ticket-row.tsx
|
|
596
659
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
@@ -771,6 +834,12 @@ function useTicketsList(filters) {
|
|
|
771
834
|
import { useCallback as useCallback2, useEffect, useMemo, useRef as useRef2, useState as useState3 } from "react";
|
|
772
835
|
import { useQueryClient } from "@tanstack/react-query";
|
|
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 = useQueryClient();
|
|
@@ -785,6 +854,26 @@ function useTicketActions(options) {
|
|
|
785
854
|
setBusyRows(new Set(busyRowsRef.current));
|
|
786
855
|
}, []);
|
|
787
856
|
const isRowBusy = useCallback2((id) => busyRows.has(id), [busyRows]);
|
|
857
|
+
const [replyErrorByTicket, setReplyErrorByTicket] = useState3(() => /* @__PURE__ */ new Map());
|
|
858
|
+
const setReplyError = useCallback2(
|
|
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 = useCallback2(
|
|
870
|
+
(externalId) => replyErrorByTicket.get(externalId) ?? null,
|
|
871
|
+
[replyErrorByTicket]
|
|
872
|
+
);
|
|
873
|
+
const clearReplyError = useCallback2(
|
|
874
|
+
(externalId) => setReplyError(externalId, null),
|
|
875
|
+
[setReplyError]
|
|
876
|
+
);
|
|
788
877
|
const watcherControllersRef = useRef2(/* @__PURE__ */ new Map());
|
|
789
878
|
useEffect(() => {
|
|
790
879
|
return () => {
|
|
@@ -862,9 +951,11 @@ function useTicketActions(options) {
|
|
|
862
951
|
},
|
|
863
952
|
[queryClient, removeOptimistic, toast2]
|
|
864
953
|
);
|
|
954
|
+
const lastUpdateErrorRef = useRef2(null);
|
|
865
955
|
const surfaceError = useCallback2(
|
|
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
|
};
|
|
@@ -974,12 +1069,13 @@ function useTicketActions(options) {
|
|
|
974
1069
|
[setRowBusy, enqueue, executeTicketAction, queryClient, toast2, surfaceError, removeTicketFromCache]
|
|
975
1070
|
);
|
|
976
1071
|
const sendMessage = useCallback2(
|
|
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
|
|
982
|
-
|
|
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,8 +1084,18 @@ 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 = useCallback2(
|
|
995
1101
|
(ticket, resolution) => updateTicket(
|
|
@@ -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
|
-
[
|
|
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 {
|
|
@@ -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",
|
|
@@ -1274,7 +1419,9 @@ 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 = (ticket.status ?? "OPEN").toUpperCase();
|
|
@@ -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
|
]
|
|
@@ -1647,7 +1796,9 @@ 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
|
)) })
|