spaps-issue-reporting-react 0.4.1 → 0.5.0
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 +6 -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.js
CHANGED
|
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
FloatingIssueReportButton: () => FloatingIssueReportButton,
|
|
34
|
+
IssueReportMessageThread: () => IssueReportMessageThread,
|
|
34
35
|
IssueReportingPageConfig: () => IssueReportingPageConfig,
|
|
35
36
|
IssueReportingProvider: () => IssueReportingProvider,
|
|
36
37
|
ReportModeContext: () => ReportModeContext,
|
|
@@ -44,9 +45,13 @@ __export(index_exports, {
|
|
|
44
45
|
getIssueStatusClassName: () => getIssueStatusClassName,
|
|
45
46
|
isClosedIssueStatus: () => isClosedIssueStatus,
|
|
46
47
|
isOpenIssueStatus: () => isOpenIssueStatus,
|
|
48
|
+
isReporterMessageConflict: () => isReporterMessageConflict,
|
|
47
49
|
issueReportingKeys: () => issueReportingKeys,
|
|
50
|
+
selectReporterVisibleMessages: () => selectReporterVisibleMessages,
|
|
48
51
|
useIssueReporting: () => useIssueReporting,
|
|
49
52
|
useIssueReportingHistory: () => useIssueReportingHistory,
|
|
53
|
+
useIssueReportingMessageMutation: () => useIssueReportingMessageMutation,
|
|
54
|
+
useIssueReportingMessages: () => useIssueReportingMessages,
|
|
50
55
|
useIssueReportingMutations: () => useIssueReportingMutations,
|
|
51
56
|
useIssueReportingStatus: () => useIssueReportingStatus,
|
|
52
57
|
useReportMode: () => useReportMode
|
|
@@ -158,13 +163,31 @@ var defaultIssueReportingCopy = {
|
|
|
158
163
|
retryAction: "Retry",
|
|
159
164
|
originHumanLabel: "Human",
|
|
160
165
|
originMachineLabel: "Machine",
|
|
161
|
-
machineOriginFallback: "system"
|
|
166
|
+
machineOriginFallback: "system",
|
|
167
|
+
threadTitle: "Conversation",
|
|
168
|
+
threadDescription: "Messages from the support team about this report, and your replies.",
|
|
169
|
+
threadLoading: "Loading conversation...",
|
|
170
|
+
threadLoadFailed: "Failed to load the conversation",
|
|
171
|
+
threadEmpty: "No messages on this report yet.",
|
|
172
|
+
threadNeedsResponseBadge: "Needs your response",
|
|
173
|
+
threadAuthorOperator: "Support",
|
|
174
|
+
threadAuthorReporter: "You",
|
|
175
|
+
threadKindClarificationRequest: "Question",
|
|
176
|
+
threadKindReporterResponse: "Your reply",
|
|
177
|
+
threadKindFinalResponse: "Resolution",
|
|
178
|
+
threadResponsePlaceholder: "Write your response...",
|
|
179
|
+
threadResponseLabel: "Respond to the support team",
|
|
180
|
+
threadResponseSubmitAction: "Send response",
|
|
181
|
+
threadResponseSubmittingAction: "Sending...",
|
|
182
|
+
threadResponseConflict: "That response was already sent, or the message changed. Refresh and try again.",
|
|
183
|
+
threadResponseFailed: "Failed to send your response"
|
|
162
184
|
};
|
|
163
185
|
var issueReportingKeys = {
|
|
164
186
|
all: ["spaps-issue-reporting"],
|
|
165
187
|
status: (scope) => [...issueReportingKeys.all, "status", scope],
|
|
166
188
|
history: (scope) => [...issueReportingKeys.all, "history", scope],
|
|
167
|
-
detail: (issueReportId) => [...issueReportingKeys.all, "detail", issueReportId]
|
|
189
|
+
detail: (issueReportId) => [...issueReportingKeys.all, "detail", issueReportId],
|
|
190
|
+
messages: (issueReportId) => [...issueReportingKeys.all, "messages", issueReportId]
|
|
168
191
|
};
|
|
169
192
|
function resolvePageUrl(getPageUrl) {
|
|
170
193
|
if (getPageUrl) {
|
|
@@ -334,6 +357,27 @@ function getEntryPointClassName(state) {
|
|
|
334
357
|
}
|
|
335
358
|
return "text-slate-500";
|
|
336
359
|
}
|
|
360
|
+
function selectReporterVisibleMessages(messages) {
|
|
361
|
+
return messages.filter(
|
|
362
|
+
(message) => message.reporter_visible && message.state === "active"
|
|
363
|
+
).slice().sort((a, b) => a.created_at.localeCompare(b.created_at));
|
|
364
|
+
}
|
|
365
|
+
function isReporterMessageConflict(error) {
|
|
366
|
+
if (!error || typeof error !== "object") {
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
const record = error;
|
|
370
|
+
const code = record.code ?? record.error?.code;
|
|
371
|
+
if (typeof code === "string" && code === "ISSUE_REPORT_MESSAGE_CONFLICT") {
|
|
372
|
+
return true;
|
|
373
|
+
}
|
|
374
|
+
const status = record.status ?? record.statusCode ?? record.status_code ?? void 0;
|
|
375
|
+
if (status === 409) {
|
|
376
|
+
return true;
|
|
377
|
+
}
|
|
378
|
+
const message = error instanceof Error ? error.message : typeof record.message === "string" ? record.message : "";
|
|
379
|
+
return /ISSUE_REPORT_MESSAGE_CONFLICT/i.test(message) || /\b409\b/.test(message);
|
|
380
|
+
}
|
|
337
381
|
function getIssueNoteLengthMessage(note, copy) {
|
|
338
382
|
if (note.length < NOTE_MIN_LENGTH) {
|
|
339
383
|
return `${NOTE_MIN_LENGTH - note.length} ${copy.noteMinimumSuffix}`;
|
|
@@ -457,6 +501,39 @@ function useIssueReportingMutations() {
|
|
|
457
501
|
replyMutation
|
|
458
502
|
};
|
|
459
503
|
}
|
|
504
|
+
function useIssueReportingMessages(issueReportId) {
|
|
505
|
+
const { client, isEligible } = useIssueReporting();
|
|
506
|
+
const listMessages = client.issueReporting.listMessages;
|
|
507
|
+
return (0, import_react_query.useQuery)({
|
|
508
|
+
queryKey: issueReportingKeys.messages(issueReportId ?? "none"),
|
|
509
|
+
queryFn: () => listMessages(issueReportId),
|
|
510
|
+
enabled: isEligible && Boolean(issueReportId) && Boolean(listMessages),
|
|
511
|
+
retry: false
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
function useIssueReportingMessageMutation(issueReportId) {
|
|
515
|
+
const queryClient = (0, import_react_query.useQueryClient)();
|
|
516
|
+
const { client } = useIssueReporting();
|
|
517
|
+
return (0, import_react_query.useMutation)({
|
|
518
|
+
mutationFn: (payload) => {
|
|
519
|
+
const submit = client.issueReporting.submitMessage;
|
|
520
|
+
if (!submit || !issueReportId) {
|
|
521
|
+
return Promise.reject(
|
|
522
|
+
new Error("This client does not support submitting messages.")
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
return submit(issueReportId, payload);
|
|
526
|
+
},
|
|
527
|
+
onSuccess: async () => {
|
|
528
|
+
if (!issueReportId) {
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
await queryClient.invalidateQueries({
|
|
532
|
+
queryKey: issueReportingKeys.messages(issueReportId)
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
});
|
|
536
|
+
}
|
|
460
537
|
function IssueReportingProvider({
|
|
461
538
|
client,
|
|
462
539
|
isEligible,
|
|
@@ -486,6 +563,7 @@ function IssueReportingProvider({
|
|
|
486
563
|
const [scope, setScope] = (0, import_react2.useState)(
|
|
487
564
|
() => resolveInitialScope(defaultScope, allowTenantScope)
|
|
488
565
|
);
|
|
566
|
+
const [needsResponseMap, setNeedsResponseMap] = (0, import_react2.useState)({});
|
|
489
567
|
const [pageConfigs, setPageConfigs] = (0, import_react2.useState)([]);
|
|
490
568
|
const [registeredTargets, setRegisteredTargets] = (0, import_react2.useState)(
|
|
491
569
|
[]
|
|
@@ -510,6 +588,21 @@ function IssueReportingProvider({
|
|
|
510
588
|
(0, import_react2.useEffect)(() => {
|
|
511
589
|
setScope(resolveInitialScope(defaultScope, allowTenantScope));
|
|
512
590
|
}, [allowTenantScope, defaultScope]);
|
|
591
|
+
const setNeedsResponse = (0, import_react2.useCallback)(
|
|
592
|
+
(issueReportId, needsResponse) => {
|
|
593
|
+
setNeedsResponseMap((current) => {
|
|
594
|
+
if (Boolean(current[issueReportId]) === needsResponse) {
|
|
595
|
+
return current;
|
|
596
|
+
}
|
|
597
|
+
return { ...current, [issueReportId]: needsResponse };
|
|
598
|
+
});
|
|
599
|
+
},
|
|
600
|
+
[]
|
|
601
|
+
);
|
|
602
|
+
const needsResponseIssueIds = (0, import_react2.useMemo)(
|
|
603
|
+
() => Object.entries(needsResponseMap).filter(([, needs]) => needs).map(([id]) => id),
|
|
604
|
+
[needsResponseMap]
|
|
605
|
+
);
|
|
513
606
|
const closePopover = (0, import_react2.useCallback)(() => {
|
|
514
607
|
setIsPopoverOpen(false);
|
|
515
608
|
}, []);
|
|
@@ -697,7 +790,9 @@ function IssueReportingProvider({
|
|
|
697
790
|
createMode,
|
|
698
791
|
inputModes: resolvedInputModes,
|
|
699
792
|
defaultInputMode: resolvedDefaultInputMode,
|
|
700
|
-
voice: resolvedVoiceConfig
|
|
793
|
+
voice: resolvedVoiceConfig,
|
|
794
|
+
needsResponseIssueIds,
|
|
795
|
+
setNeedsResponse
|
|
701
796
|
}),
|
|
702
797
|
[
|
|
703
798
|
allowTenantScope,
|
|
@@ -713,6 +808,7 @@ function IssueReportingProvider({
|
|
|
713
808
|
isReportMode,
|
|
714
809
|
mergedCopy,
|
|
715
810
|
modalState,
|
|
811
|
+
needsResponseIssueIds,
|
|
716
812
|
openExistingIssueModal,
|
|
717
813
|
openPageIssueModal,
|
|
718
814
|
openPopover,
|
|
@@ -724,6 +820,7 @@ function IssueReportingProvider({
|
|
|
724
820
|
resolvedVoiceConfig,
|
|
725
821
|
scope,
|
|
726
822
|
selectPanel,
|
|
823
|
+
setNeedsResponse,
|
|
727
824
|
startNewIssue
|
|
728
825
|
]
|
|
729
826
|
);
|
|
@@ -1142,7 +1239,8 @@ function IssueReportModalBody({
|
|
|
1142
1239
|
children: isSubmitting ? copy.submittingAction : copy.submitAction
|
|
1143
1240
|
}
|
|
1144
1241
|
)
|
|
1145
|
-
] })
|
|
1242
|
+
] }),
|
|
1243
|
+
mode !== "create" && issue ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(IssueReportMessageThread, { issueReportId: issue.id }) : null
|
|
1146
1244
|
] });
|
|
1147
1245
|
}
|
|
1148
1246
|
function useIssueReportVoiceCapture({
|
|
@@ -1496,6 +1594,237 @@ function useAttachmentState(existingAttachments) {
|
|
|
1496
1594
|
reset
|
|
1497
1595
|
};
|
|
1498
1596
|
}
|
|
1597
|
+
var REPORTER_MESSAGE_MIN_LENGTH = 1;
|
|
1598
|
+
var REPORTER_MESSAGE_MAX_LENGTH = 2e3;
|
|
1599
|
+
function generateIdempotencyKey() {
|
|
1600
|
+
const cryptoObj = typeof globalThis !== "undefined" ? globalThis.crypto : void 0;
|
|
1601
|
+
if (cryptoObj && typeof cryptoObj.randomUUID === "function") {
|
|
1602
|
+
return `reporter-msg-${cryptoObj.randomUUID()}`;
|
|
1603
|
+
}
|
|
1604
|
+
return `reporter-msg-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
1605
|
+
}
|
|
1606
|
+
function getMessageKindLabel(kind, copy) {
|
|
1607
|
+
switch (kind) {
|
|
1608
|
+
case "clarification_request":
|
|
1609
|
+
return copy.threadKindClarificationRequest;
|
|
1610
|
+
case "reporter_response":
|
|
1611
|
+
return copy.threadKindReporterResponse;
|
|
1612
|
+
case "final_response":
|
|
1613
|
+
return copy.threadKindFinalResponse;
|
|
1614
|
+
default:
|
|
1615
|
+
return kind;
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
function getMessageKindClassName(kind) {
|
|
1619
|
+
switch (kind) {
|
|
1620
|
+
case "clarification_request":
|
|
1621
|
+
return "bg-amber-100 text-amber-700";
|
|
1622
|
+
case "final_response":
|
|
1623
|
+
return "bg-emerald-100 text-emerald-700";
|
|
1624
|
+
default:
|
|
1625
|
+
return "bg-slate-100 text-slate-600";
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
function MessageBubble({
|
|
1629
|
+
message,
|
|
1630
|
+
copy
|
|
1631
|
+
}) {
|
|
1632
|
+
const isReporter = message.actor.author_type === "reporter";
|
|
1633
|
+
const isFinal = message.kind === "final_response";
|
|
1634
|
+
const authorLabel = isReporter ? copy.threadAuthorReporter : copy.threadAuthorOperator;
|
|
1635
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1636
|
+
"li",
|
|
1637
|
+
{
|
|
1638
|
+
className: cn(
|
|
1639
|
+
"flex flex-col gap-1",
|
|
1640
|
+
isReporter ? "items-end" : "items-start"
|
|
1641
|
+
),
|
|
1642
|
+
children: [
|
|
1643
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1644
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1645
|
+
"span",
|
|
1646
|
+
{
|
|
1647
|
+
className: cn(
|
|
1648
|
+
"rounded-full px-2 py-0.5 font-medium",
|
|
1649
|
+
BADGE_TEXT,
|
|
1650
|
+
getMessageKindClassName(message.kind)
|
|
1651
|
+
),
|
|
1652
|
+
children: getMessageKindLabel(message.kind, copy)
|
|
1653
|
+
}
|
|
1654
|
+
),
|
|
1655
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: cn("font-medium text-slate-600", LABEL_TEXT), children: authorLabel }),
|
|
1656
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1657
|
+
"time",
|
|
1658
|
+
{
|
|
1659
|
+
className: "text-xs text-slate-400",
|
|
1660
|
+
dateTime: message.created_at,
|
|
1661
|
+
children: formatRelativeTime(message.created_at)
|
|
1662
|
+
}
|
|
1663
|
+
)
|
|
1664
|
+
] }),
|
|
1665
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1666
|
+
"div",
|
|
1667
|
+
{
|
|
1668
|
+
className: cn(
|
|
1669
|
+
"max-w-[85%] whitespace-pre-wrap rounded-2xl border px-3 py-2 text-sm",
|
|
1670
|
+
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"
|
|
1671
|
+
),
|
|
1672
|
+
children: message.body
|
|
1673
|
+
}
|
|
1674
|
+
)
|
|
1675
|
+
]
|
|
1676
|
+
}
|
|
1677
|
+
);
|
|
1678
|
+
}
|
|
1679
|
+
function ReporterResponseComposer({
|
|
1680
|
+
issueReportId,
|
|
1681
|
+
copy
|
|
1682
|
+
}) {
|
|
1683
|
+
const mutation = useIssueReportingMessageMutation(issueReportId);
|
|
1684
|
+
const idempotencyKeyRef = (0, import_react5.useRef)(generateIdempotencyKey());
|
|
1685
|
+
const [body, setBody] = (0, import_react5.useState)("");
|
|
1686
|
+
const [submitError, setSubmitError] = (0, import_react5.useState)(null);
|
|
1687
|
+
const normalized = body.trim();
|
|
1688
|
+
const isValid = normalized.length >= REPORTER_MESSAGE_MIN_LENGTH && normalized.length <= REPORTER_MESSAGE_MAX_LENGTH;
|
|
1689
|
+
const isSubmitting = mutation.isPending;
|
|
1690
|
+
const handleSubmit = async () => {
|
|
1691
|
+
if (!isValid || isSubmitting) {
|
|
1692
|
+
return;
|
|
1693
|
+
}
|
|
1694
|
+
setSubmitError(null);
|
|
1695
|
+
try {
|
|
1696
|
+
await mutation.mutateAsync({
|
|
1697
|
+
body: normalized,
|
|
1698
|
+
idempotency_key: idempotencyKeyRef.current
|
|
1699
|
+
});
|
|
1700
|
+
setBody("");
|
|
1701
|
+
idempotencyKeyRef.current = generateIdempotencyKey();
|
|
1702
|
+
} catch (error) {
|
|
1703
|
+
if (isReporterMessageConflict(error)) {
|
|
1704
|
+
setSubmitError(copy.threadResponseConflict);
|
|
1705
|
+
idempotencyKeyRef.current = generateIdempotencyKey();
|
|
1706
|
+
return;
|
|
1707
|
+
}
|
|
1708
|
+
setSubmitError(resolveErrorMessage(error, copy.threadResponseFailed));
|
|
1709
|
+
}
|
|
1710
|
+
};
|
|
1711
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mt-3 space-y-2", children: [
|
|
1712
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1713
|
+
"label",
|
|
1714
|
+
{
|
|
1715
|
+
htmlFor: "issue-report-thread-response",
|
|
1716
|
+
className: cn(
|
|
1717
|
+
"block font-medium uppercase tracking-wide text-slate-500",
|
|
1718
|
+
LABEL_TEXT
|
|
1719
|
+
),
|
|
1720
|
+
children: copy.threadResponseLabel
|
|
1721
|
+
}
|
|
1722
|
+
),
|
|
1723
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1724
|
+
"textarea",
|
|
1725
|
+
{
|
|
1726
|
+
id: "issue-report-thread-response",
|
|
1727
|
+
value: body,
|
|
1728
|
+
onChange: (event) => setBody(event.target.value),
|
|
1729
|
+
onKeyDown: (event) => {
|
|
1730
|
+
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
|
|
1731
|
+
event.preventDefault();
|
|
1732
|
+
void handleSubmit();
|
|
1733
|
+
}
|
|
1734
|
+
},
|
|
1735
|
+
placeholder: copy.threadResponsePlaceholder,
|
|
1736
|
+
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",
|
|
1737
|
+
disabled: isSubmitting
|
|
1738
|
+
}
|
|
1739
|
+
),
|
|
1740
|
+
submitError ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1741
|
+
"div",
|
|
1742
|
+
{
|
|
1743
|
+
className: "rounded-xl border border-rose-200 bg-rose-50 px-3 py-2 text-xs text-rose-700",
|
|
1744
|
+
role: "alert",
|
|
1745
|
+
children: submitError
|
|
1746
|
+
}
|
|
1747
|
+
) : null,
|
|
1748
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1749
|
+
"button",
|
|
1750
|
+
{
|
|
1751
|
+
type: "button",
|
|
1752
|
+
className: cn(
|
|
1753
|
+
"rounded-full px-4 py-2 text-sm font-semibold text-white transition",
|
|
1754
|
+
isValid && !isSubmitting ? "bg-slate-900 hover:bg-slate-800" : "cursor-not-allowed bg-slate-300"
|
|
1755
|
+
),
|
|
1756
|
+
onClick: () => void handleSubmit(),
|
|
1757
|
+
disabled: !isValid || isSubmitting,
|
|
1758
|
+
children: isSubmitting ? copy.threadResponseSubmittingAction : copy.threadResponseSubmitAction
|
|
1759
|
+
}
|
|
1760
|
+
) })
|
|
1761
|
+
] });
|
|
1762
|
+
}
|
|
1763
|
+
function IssueReportMessageThread({
|
|
1764
|
+
issueReportId
|
|
1765
|
+
}) {
|
|
1766
|
+
const { copy, client, setNeedsResponse } = useIssueReporting();
|
|
1767
|
+
const supportsMessages = Boolean(client.issueReporting.listMessages);
|
|
1768
|
+
const supportsSubmit = Boolean(client.issueReporting.submitMessage);
|
|
1769
|
+
const query = useIssueReportingMessages(issueReportId);
|
|
1770
|
+
const needsResponse = query.data?.needs_response ?? false;
|
|
1771
|
+
(0, import_react5.useEffect)(() => {
|
|
1772
|
+
setNeedsResponse(issueReportId, needsResponse);
|
|
1773
|
+
return () => {
|
|
1774
|
+
setNeedsResponse(issueReportId, false);
|
|
1775
|
+
};
|
|
1776
|
+
}, [issueReportId, needsResponse, setNeedsResponse]);
|
|
1777
|
+
if (!supportsMessages) {
|
|
1778
|
+
return null;
|
|
1779
|
+
}
|
|
1780
|
+
const visibleMessages = selectReporterVisibleMessages(query.data?.items ?? []);
|
|
1781
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1782
|
+
"section",
|
|
1783
|
+
{
|
|
1784
|
+
"aria-label": copy.threadTitle,
|
|
1785
|
+
className: "mt-6 border-t border-slate-100 pt-5",
|
|
1786
|
+
children: [
|
|
1787
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
|
|
1788
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "text-sm font-semibold text-slate-900", children: copy.threadTitle }),
|
|
1789
|
+
needsResponse ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1790
|
+
"span",
|
|
1791
|
+
{
|
|
1792
|
+
className: cn(
|
|
1793
|
+
"rounded-full px-2 py-0.5 font-medium",
|
|
1794
|
+
BADGE_TEXT,
|
|
1795
|
+
"bg-amber-100 text-amber-700"
|
|
1796
|
+
),
|
|
1797
|
+
children: copy.threadNeedsResponseBadge
|
|
1798
|
+
}
|
|
1799
|
+
) : null
|
|
1800
|
+
] }),
|
|
1801
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "mt-1 text-xs text-slate-500", children: copy.threadDescription }),
|
|
1802
|
+
query.isPending ? /* @__PURE__ */ (0, import_jsx_runtime2.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: [
|
|
1803
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react4.Spinner, { className: "h-4 w-4 animate-spin" }),
|
|
1804
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: copy.threadLoading })
|
|
1805
|
+
] }) : query.error ? /* @__PURE__ */ (0, import_jsx_runtime2.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: [
|
|
1806
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: resolveErrorMessage(query.error, copy.threadLoadFailed) }),
|
|
1807
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1808
|
+
"button",
|
|
1809
|
+
{
|
|
1810
|
+
type: "button",
|
|
1811
|
+
className: "rounded-full border border-rose-300 px-3 py-1 font-medium transition hover:bg-rose-100",
|
|
1812
|
+
onClick: () => void query.refetch(),
|
|
1813
|
+
children: copy.retryAction
|
|
1814
|
+
}
|
|
1815
|
+
)
|
|
1816
|
+
] }) : visibleMessages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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__ */ (0, import_jsx_runtime2.jsx)("ul", { className: "mt-4 space-y-3", children: visibleMessages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MessageBubble, { message, copy }, message.id)) }),
|
|
1817
|
+
supportsSubmit ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1818
|
+
ReporterResponseComposer,
|
|
1819
|
+
{
|
|
1820
|
+
issueReportId,
|
|
1821
|
+
copy
|
|
1822
|
+
}
|
|
1823
|
+
) : null
|
|
1824
|
+
]
|
|
1825
|
+
}
|
|
1826
|
+
);
|
|
1827
|
+
}
|
|
1499
1828
|
function IssueReportModeBanner() {
|
|
1500
1829
|
const { copy } = useIssueReporting();
|
|
1501
1830
|
const reportMode = useReportMode();
|
|
@@ -2047,33 +2376,44 @@ function FloatingIssueReportButton({
|
|
|
2047
2376
|
isReportMode,
|
|
2048
2377
|
isPopoverOpen,
|
|
2049
2378
|
openPopover,
|
|
2050
|
-
closePopover
|
|
2379
|
+
closePopover,
|
|
2380
|
+
needsResponseIssueIds
|
|
2051
2381
|
} = useIssueReporting();
|
|
2052
2382
|
const status = useIssueReportingStatus();
|
|
2053
2383
|
const entryPointState = getEntryPointState(status.data);
|
|
2384
|
+
const needsResponse = needsResponseIssueIds.length > 0;
|
|
2054
2385
|
if (!isEligible) {
|
|
2055
2386
|
return null;
|
|
2056
2387
|
}
|
|
2057
2388
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2058
2389
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(IssueReportModeBanner, {}),
|
|
2059
|
-
!isReportMode ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: cn("fixed bottom-12 right-4", Z_FLOATING_BUTTON, positionClassName), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(IssueReportPopover, { children: /* @__PURE__ */ (0, import_jsx_runtime2.
|
|
2390
|
+
!isReportMode ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: cn("fixed bottom-12 right-4", Z_FLOATING_BUTTON, positionClassName), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(IssueReportPopover, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2060
2391
|
"button",
|
|
2061
2392
|
{
|
|
2062
2393
|
type: "button",
|
|
2063
|
-
"aria-label": copy.entryAriaLabel,
|
|
2394
|
+
"aria-label": needsResponse ? `${copy.entryAriaLabel} (${copy.threadNeedsResponseBadge})` : copy.entryAriaLabel,
|
|
2064
2395
|
onClick: () => isPopoverOpen ? closePopover() : openPopover(),
|
|
2065
2396
|
className: cn(
|
|
2066
|
-
"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",
|
|
2397
|
+
"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",
|
|
2067
2398
|
status.isPending && "animate-pulse",
|
|
2068
2399
|
className
|
|
2069
2400
|
),
|
|
2070
|
-
children:
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2401
|
+
children: [
|
|
2402
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2403
|
+
import_react4.BugBeetle,
|
|
2404
|
+
{
|
|
2405
|
+
className: cn("h-6 w-6", getEntryPointClassName(entryPointState)),
|
|
2406
|
+
weight: "fill"
|
|
2407
|
+
}
|
|
2408
|
+
),
|
|
2409
|
+
needsResponse ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2410
|
+
"span",
|
|
2411
|
+
{
|
|
2412
|
+
"data-testid": "issue-report-needs-response-badge",
|
|
2413
|
+
className: "absolute -right-0.5 -top-0.5 h-3 w-3 rounded-full border-2 border-white bg-amber-500"
|
|
2414
|
+
}
|
|
2415
|
+
) : null
|
|
2416
|
+
]
|
|
2077
2417
|
}
|
|
2078
2418
|
) }) }) : null,
|
|
2079
2419
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(IssueReportModal, {})
|
|
@@ -2126,6 +2466,7 @@ function ReportableSection({
|
|
|
2126
2466
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2127
2467
|
0 && (module.exports = {
|
|
2128
2468
|
FloatingIssueReportButton,
|
|
2469
|
+
IssueReportMessageThread,
|
|
2129
2470
|
IssueReportingPageConfig,
|
|
2130
2471
|
IssueReportingProvider,
|
|
2131
2472
|
ReportModeContext,
|
|
@@ -2139,9 +2480,13 @@ function ReportableSection({
|
|
|
2139
2480
|
getIssueStatusClassName,
|
|
2140
2481
|
isClosedIssueStatus,
|
|
2141
2482
|
isOpenIssueStatus,
|
|
2483
|
+
isReporterMessageConflict,
|
|
2142
2484
|
issueReportingKeys,
|
|
2485
|
+
selectReporterVisibleMessages,
|
|
2143
2486
|
useIssueReporting,
|
|
2144
2487
|
useIssueReportingHistory,
|
|
2488
|
+
useIssueReportingMessageMutation,
|
|
2489
|
+
useIssueReportingMessages,
|
|
2145
2490
|
useIssueReportingMutations,
|
|
2146
2491
|
useIssueReportingStatus,
|
|
2147
2492
|
useReportMode
|