spaps-issue-reporting-react 0.4.1 → 0.4.2
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/CHANGELOG.md +4 -0
- package/README.md +59 -2
- package/dist/index.d.mts +71 -3
- package/dist/index.d.ts +71 -3
- package/dist/index.js +360 -15
- package/dist/index.mjs +355 -15
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -125,13 +125,31 @@ var defaultIssueReportingCopy = {
|
|
|
125
125
|
retryAction: "Retry",
|
|
126
126
|
originHumanLabel: "Human",
|
|
127
127
|
originMachineLabel: "Machine",
|
|
128
|
-
machineOriginFallback: "system"
|
|
128
|
+
machineOriginFallback: "system",
|
|
129
|
+
threadTitle: "Conversation",
|
|
130
|
+
threadDescription: "Messages from the support team about this report, and your replies.",
|
|
131
|
+
threadLoading: "Loading conversation...",
|
|
132
|
+
threadLoadFailed: "Failed to load the conversation",
|
|
133
|
+
threadEmpty: "No messages on this report yet.",
|
|
134
|
+
threadNeedsResponseBadge: "Needs your response",
|
|
135
|
+
threadAuthorOperator: "Support",
|
|
136
|
+
threadAuthorReporter: "You",
|
|
137
|
+
threadKindClarificationRequest: "Question",
|
|
138
|
+
threadKindReporterResponse: "Your reply",
|
|
139
|
+
threadKindFinalResponse: "Resolution",
|
|
140
|
+
threadResponsePlaceholder: "Write your response...",
|
|
141
|
+
threadResponseLabel: "Respond to the support team",
|
|
142
|
+
threadResponseSubmitAction: "Send response",
|
|
143
|
+
threadResponseSubmittingAction: "Sending...",
|
|
144
|
+
threadResponseConflict: "That response was already sent, or the message changed. Refresh and try again.",
|
|
145
|
+
threadResponseFailed: "Failed to send your response"
|
|
129
146
|
};
|
|
130
147
|
var issueReportingKeys = {
|
|
131
148
|
all: ["spaps-issue-reporting"],
|
|
132
149
|
status: (scope) => [...issueReportingKeys.all, "status", scope],
|
|
133
150
|
history: (scope) => [...issueReportingKeys.all, "history", scope],
|
|
134
|
-
detail: (issueReportId) => [...issueReportingKeys.all, "detail", issueReportId]
|
|
151
|
+
detail: (issueReportId) => [...issueReportingKeys.all, "detail", issueReportId],
|
|
152
|
+
messages: (issueReportId) => [...issueReportingKeys.all, "messages", issueReportId]
|
|
135
153
|
};
|
|
136
154
|
function resolvePageUrl(getPageUrl) {
|
|
137
155
|
if (getPageUrl) {
|
|
@@ -301,6 +319,27 @@ function getEntryPointClassName(state) {
|
|
|
301
319
|
}
|
|
302
320
|
return "text-slate-500";
|
|
303
321
|
}
|
|
322
|
+
function selectReporterVisibleMessages(messages) {
|
|
323
|
+
return messages.filter(
|
|
324
|
+
(message) => message.reporter_visible && message.state === "active"
|
|
325
|
+
).slice().sort((a, b) => a.created_at.localeCompare(b.created_at));
|
|
326
|
+
}
|
|
327
|
+
function isReporterMessageConflict(error) {
|
|
328
|
+
if (!error || typeof error !== "object") {
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
const record = error;
|
|
332
|
+
const code = record.code ?? record.error?.code;
|
|
333
|
+
if (typeof code === "string" && code === "ISSUE_REPORT_MESSAGE_CONFLICT") {
|
|
334
|
+
return true;
|
|
335
|
+
}
|
|
336
|
+
const status = record.status ?? record.statusCode ?? record.status_code ?? void 0;
|
|
337
|
+
if (status === 409) {
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
const message = error instanceof Error ? error.message : typeof record.message === "string" ? record.message : "";
|
|
341
|
+
return /ISSUE_REPORT_MESSAGE_CONFLICT/i.test(message) || /\b409\b/.test(message);
|
|
342
|
+
}
|
|
304
343
|
function getIssueNoteLengthMessage(note, copy) {
|
|
305
344
|
if (note.length < NOTE_MIN_LENGTH) {
|
|
306
345
|
return `${NOTE_MIN_LENGTH - note.length} ${copy.noteMinimumSuffix}`;
|
|
@@ -424,6 +463,39 @@ function useIssueReportingMutations() {
|
|
|
424
463
|
replyMutation
|
|
425
464
|
};
|
|
426
465
|
}
|
|
466
|
+
function useIssueReportingMessages(issueReportId) {
|
|
467
|
+
const { client, isEligible } = useIssueReporting();
|
|
468
|
+
const listMessages = client.issueReporting.listMessages;
|
|
469
|
+
return useQuery({
|
|
470
|
+
queryKey: issueReportingKeys.messages(issueReportId ?? "none"),
|
|
471
|
+
queryFn: () => listMessages(issueReportId),
|
|
472
|
+
enabled: isEligible && Boolean(issueReportId) && Boolean(listMessages),
|
|
473
|
+
retry: false
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
function useIssueReportingMessageMutation(issueReportId) {
|
|
477
|
+
const queryClient = useQueryClient();
|
|
478
|
+
const { client } = useIssueReporting();
|
|
479
|
+
return useMutation({
|
|
480
|
+
mutationFn: (payload) => {
|
|
481
|
+
const submit = client.issueReporting.submitMessage;
|
|
482
|
+
if (!submit || !issueReportId) {
|
|
483
|
+
return Promise.reject(
|
|
484
|
+
new Error("This client does not support submitting messages.")
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
return submit(issueReportId, payload);
|
|
488
|
+
},
|
|
489
|
+
onSuccess: async () => {
|
|
490
|
+
if (!issueReportId) {
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
await queryClient.invalidateQueries({
|
|
494
|
+
queryKey: issueReportingKeys.messages(issueReportId)
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
}
|
|
427
499
|
function IssueReportingProvider({
|
|
428
500
|
client,
|
|
429
501
|
isEligible,
|
|
@@ -453,6 +525,7 @@ function IssueReportingProvider({
|
|
|
453
525
|
const [scope, setScope] = useState(
|
|
454
526
|
() => resolveInitialScope(defaultScope, allowTenantScope)
|
|
455
527
|
);
|
|
528
|
+
const [needsResponseMap, setNeedsResponseMap] = useState({});
|
|
456
529
|
const [pageConfigs, setPageConfigs] = useState([]);
|
|
457
530
|
const [registeredTargets, setRegisteredTargets] = useState(
|
|
458
531
|
[]
|
|
@@ -477,6 +550,21 @@ function IssueReportingProvider({
|
|
|
477
550
|
useEffect(() => {
|
|
478
551
|
setScope(resolveInitialScope(defaultScope, allowTenantScope));
|
|
479
552
|
}, [allowTenantScope, defaultScope]);
|
|
553
|
+
const setNeedsResponse = useCallback(
|
|
554
|
+
(issueReportId, needsResponse) => {
|
|
555
|
+
setNeedsResponseMap((current) => {
|
|
556
|
+
if (Boolean(current[issueReportId]) === needsResponse) {
|
|
557
|
+
return current;
|
|
558
|
+
}
|
|
559
|
+
return { ...current, [issueReportId]: needsResponse };
|
|
560
|
+
});
|
|
561
|
+
},
|
|
562
|
+
[]
|
|
563
|
+
);
|
|
564
|
+
const needsResponseIssueIds = useMemo(
|
|
565
|
+
() => Object.entries(needsResponseMap).filter(([, needs]) => needs).map(([id]) => id),
|
|
566
|
+
[needsResponseMap]
|
|
567
|
+
);
|
|
480
568
|
const closePopover = useCallback(() => {
|
|
481
569
|
setIsPopoverOpen(false);
|
|
482
570
|
}, []);
|
|
@@ -664,7 +752,9 @@ function IssueReportingProvider({
|
|
|
664
752
|
createMode,
|
|
665
753
|
inputModes: resolvedInputModes,
|
|
666
754
|
defaultInputMode: resolvedDefaultInputMode,
|
|
667
|
-
voice: resolvedVoiceConfig
|
|
755
|
+
voice: resolvedVoiceConfig,
|
|
756
|
+
needsResponseIssueIds,
|
|
757
|
+
setNeedsResponse
|
|
668
758
|
}),
|
|
669
759
|
[
|
|
670
760
|
allowTenantScope,
|
|
@@ -680,6 +770,7 @@ function IssueReportingProvider({
|
|
|
680
770
|
isReportMode,
|
|
681
771
|
mergedCopy,
|
|
682
772
|
modalState,
|
|
773
|
+
needsResponseIssueIds,
|
|
683
774
|
openExistingIssueModal,
|
|
684
775
|
openPageIssueModal,
|
|
685
776
|
openPopover,
|
|
@@ -691,6 +782,7 @@ function IssueReportingProvider({
|
|
|
691
782
|
resolvedVoiceConfig,
|
|
692
783
|
scope,
|
|
693
784
|
selectPanel,
|
|
785
|
+
setNeedsResponse,
|
|
694
786
|
startNewIssue
|
|
695
787
|
]
|
|
696
788
|
);
|
|
@@ -1109,7 +1201,8 @@ function IssueReportModalBody({
|
|
|
1109
1201
|
children: isSubmitting ? copy.submittingAction : copy.submitAction
|
|
1110
1202
|
}
|
|
1111
1203
|
)
|
|
1112
|
-
] })
|
|
1204
|
+
] }),
|
|
1205
|
+
mode !== "create" && issue ? /* @__PURE__ */ jsx2(IssueReportMessageThread, { issueReportId: issue.id }) : null
|
|
1113
1206
|
] });
|
|
1114
1207
|
}
|
|
1115
1208
|
function useIssueReportVoiceCapture({
|
|
@@ -1463,6 +1556,237 @@ function useAttachmentState(existingAttachments) {
|
|
|
1463
1556
|
reset
|
|
1464
1557
|
};
|
|
1465
1558
|
}
|
|
1559
|
+
var REPORTER_MESSAGE_MIN_LENGTH = 1;
|
|
1560
|
+
var REPORTER_MESSAGE_MAX_LENGTH = 2e3;
|
|
1561
|
+
function generateIdempotencyKey() {
|
|
1562
|
+
const cryptoObj = typeof globalThis !== "undefined" ? globalThis.crypto : void 0;
|
|
1563
|
+
if (cryptoObj && typeof cryptoObj.randomUUID === "function") {
|
|
1564
|
+
return `reporter-msg-${cryptoObj.randomUUID()}`;
|
|
1565
|
+
}
|
|
1566
|
+
return `reporter-msg-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
1567
|
+
}
|
|
1568
|
+
function getMessageKindLabel(kind, copy) {
|
|
1569
|
+
switch (kind) {
|
|
1570
|
+
case "clarification_request":
|
|
1571
|
+
return copy.threadKindClarificationRequest;
|
|
1572
|
+
case "reporter_response":
|
|
1573
|
+
return copy.threadKindReporterResponse;
|
|
1574
|
+
case "final_response":
|
|
1575
|
+
return copy.threadKindFinalResponse;
|
|
1576
|
+
default:
|
|
1577
|
+
return kind;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
function getMessageKindClassName(kind) {
|
|
1581
|
+
switch (kind) {
|
|
1582
|
+
case "clarification_request":
|
|
1583
|
+
return "bg-amber-100 text-amber-700";
|
|
1584
|
+
case "final_response":
|
|
1585
|
+
return "bg-emerald-100 text-emerald-700";
|
|
1586
|
+
default:
|
|
1587
|
+
return "bg-slate-100 text-slate-600";
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
function MessageBubble({
|
|
1591
|
+
message,
|
|
1592
|
+
copy
|
|
1593
|
+
}) {
|
|
1594
|
+
const isReporter = message.actor.author_type === "reporter";
|
|
1595
|
+
const isFinal = message.kind === "final_response";
|
|
1596
|
+
const authorLabel = isReporter ? copy.threadAuthorReporter : copy.threadAuthorOperator;
|
|
1597
|
+
return /* @__PURE__ */ jsxs(
|
|
1598
|
+
"li",
|
|
1599
|
+
{
|
|
1600
|
+
className: cn(
|
|
1601
|
+
"flex flex-col gap-1",
|
|
1602
|
+
isReporter ? "items-end" : "items-start"
|
|
1603
|
+
),
|
|
1604
|
+
children: [
|
|
1605
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1606
|
+
/* @__PURE__ */ jsx2(
|
|
1607
|
+
"span",
|
|
1608
|
+
{
|
|
1609
|
+
className: cn(
|
|
1610
|
+
"rounded-full px-2 py-0.5 font-medium",
|
|
1611
|
+
BADGE_TEXT,
|
|
1612
|
+
getMessageKindClassName(message.kind)
|
|
1613
|
+
),
|
|
1614
|
+
children: getMessageKindLabel(message.kind, copy)
|
|
1615
|
+
}
|
|
1616
|
+
),
|
|
1617
|
+
/* @__PURE__ */ jsx2("span", { className: cn("font-medium text-slate-600", LABEL_TEXT), children: authorLabel }),
|
|
1618
|
+
/* @__PURE__ */ jsx2(
|
|
1619
|
+
"time",
|
|
1620
|
+
{
|
|
1621
|
+
className: "text-xs text-slate-400",
|
|
1622
|
+
dateTime: message.created_at,
|
|
1623
|
+
children: formatRelativeTime(message.created_at)
|
|
1624
|
+
}
|
|
1625
|
+
)
|
|
1626
|
+
] }),
|
|
1627
|
+
/* @__PURE__ */ jsx2(
|
|
1628
|
+
"div",
|
|
1629
|
+
{
|
|
1630
|
+
className: cn(
|
|
1631
|
+
"max-w-[85%] whitespace-pre-wrap rounded-2xl border px-3 py-2 text-sm",
|
|
1632
|
+
isReporter ? "border-slate-900 bg-slate-900 text-white" : isFinal ? "border-emerald-200 bg-emerald-50 text-emerald-950" : "border-slate-200 bg-white text-slate-800"
|
|
1633
|
+
),
|
|
1634
|
+
children: message.body
|
|
1635
|
+
}
|
|
1636
|
+
)
|
|
1637
|
+
]
|
|
1638
|
+
}
|
|
1639
|
+
);
|
|
1640
|
+
}
|
|
1641
|
+
function ReporterResponseComposer({
|
|
1642
|
+
issueReportId,
|
|
1643
|
+
copy
|
|
1644
|
+
}) {
|
|
1645
|
+
const mutation = useIssueReportingMessageMutation(issueReportId);
|
|
1646
|
+
const idempotencyKeyRef = useRef2(generateIdempotencyKey());
|
|
1647
|
+
const [body, setBody] = useState2("");
|
|
1648
|
+
const [submitError, setSubmitError] = useState2(null);
|
|
1649
|
+
const normalized = body.trim();
|
|
1650
|
+
const isValid = normalized.length >= REPORTER_MESSAGE_MIN_LENGTH && normalized.length <= REPORTER_MESSAGE_MAX_LENGTH;
|
|
1651
|
+
const isSubmitting = mutation.isPending;
|
|
1652
|
+
const handleSubmit = async () => {
|
|
1653
|
+
if (!isValid || isSubmitting) {
|
|
1654
|
+
return;
|
|
1655
|
+
}
|
|
1656
|
+
setSubmitError(null);
|
|
1657
|
+
try {
|
|
1658
|
+
await mutation.mutateAsync({
|
|
1659
|
+
body: normalized,
|
|
1660
|
+
idempotency_key: idempotencyKeyRef.current
|
|
1661
|
+
});
|
|
1662
|
+
setBody("");
|
|
1663
|
+
idempotencyKeyRef.current = generateIdempotencyKey();
|
|
1664
|
+
} catch (error) {
|
|
1665
|
+
if (isReporterMessageConflict(error)) {
|
|
1666
|
+
setSubmitError(copy.threadResponseConflict);
|
|
1667
|
+
idempotencyKeyRef.current = generateIdempotencyKey();
|
|
1668
|
+
return;
|
|
1669
|
+
}
|
|
1670
|
+
setSubmitError(resolveErrorMessage(error, copy.threadResponseFailed));
|
|
1671
|
+
}
|
|
1672
|
+
};
|
|
1673
|
+
return /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-2", children: [
|
|
1674
|
+
/* @__PURE__ */ jsx2(
|
|
1675
|
+
"label",
|
|
1676
|
+
{
|
|
1677
|
+
htmlFor: "issue-report-thread-response",
|
|
1678
|
+
className: cn(
|
|
1679
|
+
"block font-medium uppercase tracking-wide text-slate-500",
|
|
1680
|
+
LABEL_TEXT
|
|
1681
|
+
),
|
|
1682
|
+
children: copy.threadResponseLabel
|
|
1683
|
+
}
|
|
1684
|
+
),
|
|
1685
|
+
/* @__PURE__ */ jsx2(
|
|
1686
|
+
"textarea",
|
|
1687
|
+
{
|
|
1688
|
+
id: "issue-report-thread-response",
|
|
1689
|
+
value: body,
|
|
1690
|
+
onChange: (event) => setBody(event.target.value),
|
|
1691
|
+
onKeyDown: (event) => {
|
|
1692
|
+
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
|
|
1693
|
+
event.preventDefault();
|
|
1694
|
+
void handleSubmit();
|
|
1695
|
+
}
|
|
1696
|
+
},
|
|
1697
|
+
placeholder: copy.threadResponsePlaceholder,
|
|
1698
|
+
className: "h-24 w-full resize-none rounded-2xl border border-slate-300 px-3 py-2 text-sm text-slate-800 outline-none transition focus:border-slate-500 focus:ring-2 focus:ring-slate-200",
|
|
1699
|
+
disabled: isSubmitting
|
|
1700
|
+
}
|
|
1701
|
+
),
|
|
1702
|
+
submitError ? /* @__PURE__ */ jsx2(
|
|
1703
|
+
"div",
|
|
1704
|
+
{
|
|
1705
|
+
className: "rounded-xl border border-rose-200 bg-rose-50 px-3 py-2 text-xs text-rose-700",
|
|
1706
|
+
role: "alert",
|
|
1707
|
+
children: submitError
|
|
1708
|
+
}
|
|
1709
|
+
) : null,
|
|
1710
|
+
/* @__PURE__ */ jsx2("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx2(
|
|
1711
|
+
"button",
|
|
1712
|
+
{
|
|
1713
|
+
type: "button",
|
|
1714
|
+
className: cn(
|
|
1715
|
+
"rounded-full px-4 py-2 text-sm font-semibold text-white transition",
|
|
1716
|
+
isValid && !isSubmitting ? "bg-slate-900 hover:bg-slate-800" : "cursor-not-allowed bg-slate-300"
|
|
1717
|
+
),
|
|
1718
|
+
onClick: () => void handleSubmit(),
|
|
1719
|
+
disabled: !isValid || isSubmitting,
|
|
1720
|
+
children: isSubmitting ? copy.threadResponseSubmittingAction : copy.threadResponseSubmitAction
|
|
1721
|
+
}
|
|
1722
|
+
) })
|
|
1723
|
+
] });
|
|
1724
|
+
}
|
|
1725
|
+
function IssueReportMessageThread({
|
|
1726
|
+
issueReportId
|
|
1727
|
+
}) {
|
|
1728
|
+
const { copy, client, setNeedsResponse } = useIssueReporting();
|
|
1729
|
+
const supportsMessages = Boolean(client.issueReporting.listMessages);
|
|
1730
|
+
const supportsSubmit = Boolean(client.issueReporting.submitMessage);
|
|
1731
|
+
const query = useIssueReportingMessages(issueReportId);
|
|
1732
|
+
const needsResponse = query.data?.needs_response ?? false;
|
|
1733
|
+
useEffect2(() => {
|
|
1734
|
+
setNeedsResponse(issueReportId, needsResponse);
|
|
1735
|
+
return () => {
|
|
1736
|
+
setNeedsResponse(issueReportId, false);
|
|
1737
|
+
};
|
|
1738
|
+
}, [issueReportId, needsResponse, setNeedsResponse]);
|
|
1739
|
+
if (!supportsMessages) {
|
|
1740
|
+
return null;
|
|
1741
|
+
}
|
|
1742
|
+
const visibleMessages = selectReporterVisibleMessages(query.data?.items ?? []);
|
|
1743
|
+
return /* @__PURE__ */ jsxs(
|
|
1744
|
+
"section",
|
|
1745
|
+
{
|
|
1746
|
+
"aria-label": copy.threadTitle,
|
|
1747
|
+
className: "mt-6 border-t border-slate-100 pt-5",
|
|
1748
|
+
children: [
|
|
1749
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
1750
|
+
/* @__PURE__ */ jsx2("h3", { className: "text-sm font-semibold text-slate-900", children: copy.threadTitle }),
|
|
1751
|
+
needsResponse ? /* @__PURE__ */ jsx2(
|
|
1752
|
+
"span",
|
|
1753
|
+
{
|
|
1754
|
+
className: cn(
|
|
1755
|
+
"rounded-full px-2 py-0.5 font-medium",
|
|
1756
|
+
BADGE_TEXT,
|
|
1757
|
+
"bg-amber-100 text-amber-700"
|
|
1758
|
+
),
|
|
1759
|
+
children: copy.threadNeedsResponseBadge
|
|
1760
|
+
}
|
|
1761
|
+
) : null
|
|
1762
|
+
] }),
|
|
1763
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-1 text-xs text-slate-500", children: copy.threadDescription }),
|
|
1764
|
+
query.isPending ? /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center gap-2 rounded-2xl border border-slate-200 bg-slate-50 px-4 py-4 text-sm text-slate-600", children: [
|
|
1765
|
+
/* @__PURE__ */ jsx2(Spinner, { className: "h-4 w-4 animate-spin" }),
|
|
1766
|
+
/* @__PURE__ */ jsx2("span", { children: copy.threadLoading })
|
|
1767
|
+
] }) : query.error ? /* @__PURE__ */ jsxs("div", { className: "mt-4 space-y-3 rounded-2xl border border-rose-200 bg-rose-50 px-4 py-4 text-sm text-rose-700", children: [
|
|
1768
|
+
/* @__PURE__ */ jsx2("div", { children: resolveErrorMessage(query.error, copy.threadLoadFailed) }),
|
|
1769
|
+
/* @__PURE__ */ jsx2(
|
|
1770
|
+
"button",
|
|
1771
|
+
{
|
|
1772
|
+
type: "button",
|
|
1773
|
+
className: "rounded-full border border-rose-300 px-3 py-1 font-medium transition hover:bg-rose-100",
|
|
1774
|
+
onClick: () => void query.refetch(),
|
|
1775
|
+
children: copy.retryAction
|
|
1776
|
+
}
|
|
1777
|
+
)
|
|
1778
|
+
] }) : visibleMessages.length === 0 ? /* @__PURE__ */ jsx2("div", { className: "mt-4 rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-6 text-center text-sm text-slate-500", children: copy.threadEmpty }) : /* @__PURE__ */ jsx2("ul", { className: "mt-4 space-y-3", children: visibleMessages.map((message) => /* @__PURE__ */ jsx2(MessageBubble, { message, copy }, message.id)) }),
|
|
1779
|
+
supportsSubmit ? /* @__PURE__ */ jsx2(
|
|
1780
|
+
ReporterResponseComposer,
|
|
1781
|
+
{
|
|
1782
|
+
issueReportId,
|
|
1783
|
+
copy
|
|
1784
|
+
}
|
|
1785
|
+
) : null
|
|
1786
|
+
]
|
|
1787
|
+
}
|
|
1788
|
+
);
|
|
1789
|
+
}
|
|
1466
1790
|
function IssueReportModeBanner() {
|
|
1467
1791
|
const { copy } = useIssueReporting();
|
|
1468
1792
|
const reportMode = useReportMode();
|
|
@@ -2014,33 +2338,44 @@ function FloatingIssueReportButton({
|
|
|
2014
2338
|
isReportMode,
|
|
2015
2339
|
isPopoverOpen,
|
|
2016
2340
|
openPopover,
|
|
2017
|
-
closePopover
|
|
2341
|
+
closePopover,
|
|
2342
|
+
needsResponseIssueIds
|
|
2018
2343
|
} = useIssueReporting();
|
|
2019
2344
|
const status = useIssueReportingStatus();
|
|
2020
2345
|
const entryPointState = getEntryPointState(status.data);
|
|
2346
|
+
const needsResponse = needsResponseIssueIds.length > 0;
|
|
2021
2347
|
if (!isEligible) {
|
|
2022
2348
|
return null;
|
|
2023
2349
|
}
|
|
2024
2350
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2025
2351
|
/* @__PURE__ */ jsx2(IssueReportModeBanner, {}),
|
|
2026
|
-
!isReportMode ? /* @__PURE__ */ jsx2("div", { className: cn("fixed bottom-12 right-4", Z_FLOATING_BUTTON, positionClassName), children: /* @__PURE__ */ jsx2(IssueReportPopover, { children: /* @__PURE__ */
|
|
2352
|
+
!isReportMode ? /* @__PURE__ */ jsx2("div", { className: cn("fixed bottom-12 right-4", Z_FLOATING_BUTTON, positionClassName), children: /* @__PURE__ */ jsx2(IssueReportPopover, { children: /* @__PURE__ */ jsxs(
|
|
2027
2353
|
"button",
|
|
2028
2354
|
{
|
|
2029
2355
|
type: "button",
|
|
2030
|
-
"aria-label": copy.entryAriaLabel,
|
|
2356
|
+
"aria-label": needsResponse ? `${copy.entryAriaLabel} (${copy.threadNeedsResponseBadge})` : copy.entryAriaLabel,
|
|
2031
2357
|
onClick: () => isPopoverOpen ? closePopover() : openPopover(),
|
|
2032
2358
|
className: cn(
|
|
2033
|
-
"flex h-12 w-12 items-center justify-center rounded-full border border-slate-200 bg-white shadow-lg transition hover:-translate-y-0.5 hover:shadow-xl focus:outline-none focus:ring-2 focus:ring-slate-300",
|
|
2359
|
+
"relative flex h-12 w-12 items-center justify-center rounded-full border border-slate-200 bg-white shadow-lg transition hover:-translate-y-0.5 hover:shadow-xl focus:outline-none focus:ring-2 focus:ring-slate-300",
|
|
2034
2360
|
status.isPending && "animate-pulse",
|
|
2035
2361
|
className
|
|
2036
2362
|
),
|
|
2037
|
-
children:
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2363
|
+
children: [
|
|
2364
|
+
/* @__PURE__ */ jsx2(
|
|
2365
|
+
BugBeetle,
|
|
2366
|
+
{
|
|
2367
|
+
className: cn("h-6 w-6", getEntryPointClassName(entryPointState)),
|
|
2368
|
+
weight: "fill"
|
|
2369
|
+
}
|
|
2370
|
+
),
|
|
2371
|
+
needsResponse ? /* @__PURE__ */ jsx2(
|
|
2372
|
+
"span",
|
|
2373
|
+
{
|
|
2374
|
+
"data-testid": "issue-report-needs-response-badge",
|
|
2375
|
+
className: "absolute -right-0.5 -top-0.5 h-3 w-3 rounded-full border-2 border-white bg-amber-500"
|
|
2376
|
+
}
|
|
2377
|
+
) : null
|
|
2378
|
+
]
|
|
2044
2379
|
}
|
|
2045
2380
|
) }) }) : null,
|
|
2046
2381
|
/* @__PURE__ */ jsx2(IssueReportModal, {})
|
|
@@ -2092,6 +2427,7 @@ function ReportableSection({
|
|
|
2092
2427
|
}
|
|
2093
2428
|
export {
|
|
2094
2429
|
FloatingIssueReportButton,
|
|
2430
|
+
IssueReportMessageThread,
|
|
2095
2431
|
IssueReportingPageConfig,
|
|
2096
2432
|
IssueReportingProvider,
|
|
2097
2433
|
ReportModeContext,
|
|
@@ -2105,9 +2441,13 @@ export {
|
|
|
2105
2441
|
getIssueStatusClassName,
|
|
2106
2442
|
isClosedIssueStatus,
|
|
2107
2443
|
isOpenIssueStatus,
|
|
2444
|
+
isReporterMessageConflict,
|
|
2108
2445
|
issueReportingKeys,
|
|
2446
|
+
selectReporterVisibleMessages,
|
|
2109
2447
|
useIssueReporting,
|
|
2110
2448
|
useIssueReportingHistory,
|
|
2449
|
+
useIssueReportingMessageMutation,
|
|
2450
|
+
useIssueReportingMessages,
|
|
2111
2451
|
useIssueReportingMutations,
|
|
2112
2452
|
useIssueReportingStatus,
|
|
2113
2453
|
useReportMode
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spaps-issue-reporting-react",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Shared React issue-reporting UI for Sweet Potato platform consumers",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@radix-ui/react-dialog": "^1.1.15",
|
|
41
41
|
"@radix-ui/react-popover": "^1.1.15",
|
|
42
42
|
"date-fns": "^4.1.0",
|
|
43
|
-
"spaps-types": "^1.4.
|
|
43
|
+
"spaps-types": "^1.4.2"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"@tanstack/react-query": ">=5.0.0",
|