@handled-ai/design-system 0.18.50 → 0.18.52
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/components/badge.d.ts +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/data-table-filter.d.ts +21 -6
- package/dist/components/data-table-filter.js +134 -9
- package/dist/components/data-table-filter.js.map +1 -1
- package/dist/components/pill.d.ts +1 -1
- package/dist/components/score-why-chips.d.ts +1 -1
- package/dist/components/signal-feedback-inline.d.ts +28 -12
- package/dist/components/signal-feedback-inline.js +146 -10
- package/dist/components/signal-feedback-inline.js.map +1 -1
- package/dist/components/signal-priority-popover.d.ts +1 -1
- package/dist/components/signal-priority-popover.js +7 -15
- package/dist/components/signal-priority-popover.js.map +1 -1
- package/dist/components/tabs.d.ts +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/prototype/index.d.ts +1 -1
- package/dist/prototype/prototype-accounts-view.d.ts +1 -1
- package/dist/prototype/prototype-admin-view.d.ts +1 -1
- package/dist/prototype/prototype-config.d.ts +1 -1
- package/dist/prototype/prototype-inbox-view.d.ts +3 -3
- package/dist/prototype/prototype-inbox-view.js +1 -2
- package/dist/prototype/prototype-inbox-view.js.map +1 -1
- package/dist/prototype/prototype-insights-view.d.ts +1 -1
- package/dist/prototype/prototype-shell.d.ts +1 -1
- package/dist/{signal-priority-popover-Cl98xw1n.d.ts → signal-priority-popover-QJngMAj7.d.ts} +4 -9
- package/package.json +1 -1
- package/src/components/__tests__/case-panel-why.test.tsx +126 -0
- package/src/components/__tests__/data-table-filter.test.tsx +130 -0
- package/src/components/__tests__/signal-priority-popover.test.tsx +4 -27
- package/src/components/data-table-filter.tsx +160 -9
- package/src/components/signal-feedback-inline.tsx +181 -20
- package/src/components/signal-priority-popover.tsx +6 -16
- package/src/prototype/__tests__/detail-view-opportunity-preview.test.tsx +90 -0
- package/src/prototype/__tests__/detail-view-score-why.test.tsx +0 -32
- package/src/prototype/prototype-config.ts +3 -5
- package/src/prototype/prototype-inbox-view.tsx +3 -4
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
"use client";
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
|
+
var __defProps = Object.defineProperties;
|
|
6
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
5
7
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
6
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
9
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
@@ -17,6 +19,7 @@ var __spreadValues = (a, b) => {
|
|
|
17
19
|
}
|
|
18
20
|
return a;
|
|
19
21
|
};
|
|
22
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
23
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
21
24
|
import * as React from "react";
|
|
22
25
|
import { Check, CirclePlus, ExternalLink, Loader2, Lock, ThumbsDown } from "lucide-react";
|
|
@@ -104,6 +107,7 @@ function Root({ children, companyName, opportunityUrl, scheduledTime, initialApp
|
|
|
104
107
|
const [requestingApproval, setRequestingApproval] = React.useState(false);
|
|
105
108
|
const mountedRef = React.useRef(true);
|
|
106
109
|
React.useEffect(() => {
|
|
110
|
+
mountedRef.current = true;
|
|
107
111
|
return () => {
|
|
108
112
|
mountedRef.current = false;
|
|
109
113
|
};
|
|
@@ -131,8 +135,8 @@ function Root({ children, companyName, opportunityUrl, scheduledTime, initialApp
|
|
|
131
135
|
const cancel = React.useCallback(() => {
|
|
132
136
|
setApprovalState("pending");
|
|
133
137
|
}, []);
|
|
134
|
-
const approve = React.useCallback(() => {
|
|
135
|
-
const result = onApprove == null ? void 0 : onApprove();
|
|
138
|
+
const approve = React.useCallback((draft) => {
|
|
139
|
+
const result = onApprove == null ? void 0 : onApprove(draft);
|
|
136
140
|
if (result && typeof result.then === "function") {
|
|
137
141
|
setApprovalState("creating");
|
|
138
142
|
result.then((success) => {
|
|
@@ -288,7 +292,45 @@ function SubmittedFeedback({
|
|
|
288
292
|
}
|
|
289
293
|
);
|
|
290
294
|
}
|
|
295
|
+
function optionValue(option) {
|
|
296
|
+
return typeof option === "string" ? option : option.value;
|
|
297
|
+
}
|
|
298
|
+
function optionLabel(option) {
|
|
299
|
+
return typeof option === "string" ? option : option.label;
|
|
300
|
+
}
|
|
301
|
+
function formatAmountDraftValue(value) {
|
|
302
|
+
if (value == null || value === "") return "";
|
|
303
|
+
if (typeof value === "number") {
|
|
304
|
+
return new Intl.NumberFormat("en-US", {
|
|
305
|
+
style: "currency",
|
|
306
|
+
currency: "USD",
|
|
307
|
+
maximumFractionDigits: 0
|
|
308
|
+
}).format(value);
|
|
309
|
+
}
|
|
310
|
+
return value;
|
|
311
|
+
}
|
|
312
|
+
function buildOpportunityDraft(preview) {
|
|
313
|
+
var _a, _b, _c, _d, _e;
|
|
314
|
+
return {
|
|
315
|
+
closeDate: (_b = (_a = preview == null ? void 0 : preview.closeDateValue) != null ? _a : preview == null ? void 0 : preview.closeDate) != null ? _b : "",
|
|
316
|
+
amount: (preview == null ? void 0 : preview.amountValue) === void 0 ? (_c = preview == null ? void 0 : preview.amount) != null ? _c : "" : formatAmountDraftValue(preview.amountValue),
|
|
317
|
+
description: (_d = preview == null ? void 0 : preview.description) != null ? _d : "",
|
|
318
|
+
churnType: (_e = preview == null ? void 0 : preview.churnType) != null ? _e : ""
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
function hasEditableOpportunityPreview(preview) {
|
|
322
|
+
var _a;
|
|
323
|
+
return !!preview && isValidDateInput((_a = preview.closeDateValue) != null ? _a : preview.closeDate);
|
|
324
|
+
}
|
|
325
|
+
function isValidDateInput(value) {
|
|
326
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
|
|
327
|
+
if (!match) return false;
|
|
328
|
+
const parsed = /* @__PURE__ */ new Date(`${value}T00:00:00Z`);
|
|
329
|
+
if (Number.isNaN(parsed.getTime())) return false;
|
|
330
|
+
return parsed.toISOString().slice(0, 10) === value;
|
|
331
|
+
}
|
|
291
332
|
function Actions() {
|
|
333
|
+
var _a;
|
|
292
334
|
const { approvalState, companyName, opportunityUrl, scheduledTime, labels, hideApproveButton, approveButtonIconUrl, opportunityPreview, requestingApproval, approve, submitApproveFeedback, skipApproveFeedback, dismiss, requestApproval, requestDismiss, cancel } = useSignalApproval();
|
|
293
335
|
const [selectedTopReason, setSelectedTopReason] = React.useState(null);
|
|
294
336
|
const [selectedSubReason, setSelectedSubReason] = React.useState(null);
|
|
@@ -296,6 +338,14 @@ function Actions() {
|
|
|
296
338
|
const [detailText, setDetailText] = React.useState("");
|
|
297
339
|
const [submittedFeedback, setSubmittedFeedback] = React.useState(null);
|
|
298
340
|
const [isEditing, setIsEditing] = React.useState(false);
|
|
341
|
+
const [opportunityDraft, setOpportunityDraft] = React.useState(() => buildOpportunityDraft(opportunityPreview));
|
|
342
|
+
React.useEffect(() => {
|
|
343
|
+
if (approvalState === "confirming") {
|
|
344
|
+
setOpportunityDraft(buildOpportunityDraft(opportunityPreview));
|
|
345
|
+
}
|
|
346
|
+
}, [approvalState, opportunityPreview]);
|
|
347
|
+
const churnTypeOptions = (_a = opportunityPreview == null ? void 0 : opportunityPreview.churnTypeOptions) != null ? _a : [];
|
|
348
|
+
const hasChurnTypeOptions = churnTypeOptions.length > 0;
|
|
299
349
|
const topNode = dismissReasonTree.find((n) => n.label === selectedTopReason);
|
|
300
350
|
const hasSubOptions = !!((topNode == null ? void 0 : topNode.subOptions) && topNode.subOptions.length > 0);
|
|
301
351
|
const isTopOther = selectedTopReason === "Other" && !hasSubOptions;
|
|
@@ -303,6 +353,8 @@ function Actions() {
|
|
|
303
353
|
const needsText = isTopOther || isSubOther;
|
|
304
354
|
const canSubmitDismiss = selectedTopReason !== null && (!hasSubOptions || selectedSubReason !== null) && (!needsText || detailText.trim().length > 0);
|
|
305
355
|
const canSubmitApprove = selectedReasons.length > 0 || detailText.trim().length > 0;
|
|
356
|
+
const isEditableOpportunityPreview = hasEditableOpportunityPreview(opportunityPreview);
|
|
357
|
+
const canConfirmOpportunity = !isEditableOpportunityPreview || isValidDateInput(opportunityDraft.closeDate);
|
|
306
358
|
const selectTopReason = (label) => {
|
|
307
359
|
if (selectedTopReason === label) {
|
|
308
360
|
setSelectedTopReason(null);
|
|
@@ -323,9 +375,9 @@ function Actions() {
|
|
|
323
375
|
);
|
|
324
376
|
};
|
|
325
377
|
const startEditing = () => {
|
|
326
|
-
var
|
|
378
|
+
var _a2, _b;
|
|
327
379
|
if (submittedFeedback) {
|
|
328
|
-
setSelectedTopReason((
|
|
380
|
+
setSelectedTopReason((_a2 = submittedFeedback.reasons[0]) != null ? _a2 : null);
|
|
329
381
|
setSelectedSubReason((_b = submittedFeedback.subReason) != null ? _b : null);
|
|
330
382
|
setSelectedReasons([...submittedFeedback.reasons]);
|
|
331
383
|
setDetailText(submittedFeedback.detail);
|
|
@@ -595,24 +647,108 @@ function Actions() {
|
|
|
595
647
|
/* @__PURE__ */ jsx("strong", { children: companyName }),
|
|
596
648
|
". Confirm?"
|
|
597
649
|
] }),
|
|
598
|
-
opportunityPreview && /* @__PURE__ */ jsx("div", { className: "mt-3 space-y-
|
|
650
|
+
opportunityPreview && !isEditableOpportunityPreview && /* @__PURE__ */ jsx("div", { className: "mt-3 space-y-2 border-t border-border/50 pt-3", children: [
|
|
599
651
|
{ label: "Opportunity", value: opportunityPreview.name },
|
|
600
652
|
{ label: "Account", value: opportunityPreview.accountName },
|
|
601
653
|
{ label: "Stage", value: opportunityPreview.stage },
|
|
602
654
|
{ label: "Close Date", value: opportunityPreview.closeDate },
|
|
603
655
|
{ label: "Amount", value: opportunityPreview.amount }
|
|
604
|
-
].map(({ label, value }) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
|
|
656
|
+
].map(({ label, value }) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 text-xs", children: [
|
|
605
657
|
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
|
|
606
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: value })
|
|
607
|
-
] }, label)) })
|
|
658
|
+
/* @__PURE__ */ jsx("span", { className: "text-right font-medium text-foreground", children: value })
|
|
659
|
+
] }, label)) }),
|
|
660
|
+
opportunityPreview && isEditableOpportunityPreview && /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-3 border-t border-border/50 pt-3", children: [
|
|
661
|
+
[
|
|
662
|
+
{ label: "Opportunity", value: opportunityPreview.name },
|
|
663
|
+
{ label: "Account", value: opportunityPreview.accountName },
|
|
664
|
+
{ label: "Stage", value: opportunityPreview.stage }
|
|
665
|
+
].map(({ label, value }) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 text-xs", children: [
|
|
666
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
|
|
667
|
+
/* @__PURE__ */ jsx("span", { className: "text-right font-medium text-foreground", children: value })
|
|
668
|
+
] }, label)),
|
|
669
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-2 sm:grid-cols-2", children: [
|
|
670
|
+
/* @__PURE__ */ jsxs("label", { className: "space-y-1 text-xs", children: [
|
|
671
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-muted-foreground", children: "Close Date" }),
|
|
672
|
+
/* @__PURE__ */ jsx(
|
|
673
|
+
"input",
|
|
674
|
+
{
|
|
675
|
+
type: "date",
|
|
676
|
+
value: opportunityDraft.closeDate,
|
|
677
|
+
onChange: (event) => setOpportunityDraft((draft) => __spreadProps(__spreadValues({}, draft), { closeDate: event.target.value })),
|
|
678
|
+
"aria-invalid": !canConfirmOpportunity,
|
|
679
|
+
className: "h-8 w-full rounded-md border border-border bg-background px-2 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-ring"
|
|
680
|
+
}
|
|
681
|
+
),
|
|
682
|
+
!canConfirmOpportunity && /* @__PURE__ */ jsx("span", { className: "text-[11px] text-red-600", children: "Enter a valid close date." })
|
|
683
|
+
] }),
|
|
684
|
+
/* @__PURE__ */ jsxs("label", { className: "space-y-1 text-xs", children: [
|
|
685
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-muted-foreground", children: "Amount" }),
|
|
686
|
+
/* @__PURE__ */ jsx(
|
|
687
|
+
"input",
|
|
688
|
+
{
|
|
689
|
+
type: "text",
|
|
690
|
+
inputMode: "decimal",
|
|
691
|
+
value: opportunityDraft.amount,
|
|
692
|
+
onChange: (event) => setOpportunityDraft((draft) => __spreadProps(__spreadValues({}, draft), { amount: event.target.value })),
|
|
693
|
+
placeholder: opportunityPreview.amount,
|
|
694
|
+
className: "h-8 w-full rounded-md border border-border bg-background px-2 text-xs text-foreground placeholder:text-muted-foreground/60 focus:outline-none focus:ring-1 focus:ring-ring"
|
|
695
|
+
}
|
|
696
|
+
)
|
|
697
|
+
] })
|
|
698
|
+
] }),
|
|
699
|
+
/* @__PURE__ */ jsxs("label", { className: "space-y-1 text-xs", children: [
|
|
700
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-muted-foreground", children: "Churn Type" }),
|
|
701
|
+
hasChurnTypeOptions ? /* @__PURE__ */ jsxs(
|
|
702
|
+
"select",
|
|
703
|
+
{
|
|
704
|
+
value: opportunityDraft.churnType,
|
|
705
|
+
onChange: (event) => setOpportunityDraft((draft) => __spreadProps(__spreadValues({}, draft), { churnType: event.target.value })),
|
|
706
|
+
className: "h-8 w-full rounded-md border border-border bg-background px-2 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-ring",
|
|
707
|
+
children: [
|
|
708
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "No churn type" }),
|
|
709
|
+
churnTypeOptions.map((option) => /* @__PURE__ */ jsx("option", { value: optionValue(option), children: optionLabel(option) }, optionValue(option)))
|
|
710
|
+
]
|
|
711
|
+
}
|
|
712
|
+
) : /* @__PURE__ */ jsx(
|
|
713
|
+
"input",
|
|
714
|
+
{
|
|
715
|
+
type: "text",
|
|
716
|
+
value: opportunityDraft.churnType,
|
|
717
|
+
onChange: (event) => setOpportunityDraft((draft) => __spreadProps(__spreadValues({}, draft), { churnType: event.target.value })),
|
|
718
|
+
placeholder: "No churn type",
|
|
719
|
+
className: "h-8 w-full rounded-md border border-border bg-background px-2 text-xs text-foreground placeholder:text-muted-foreground/60 focus:outline-none focus:ring-1 focus:ring-ring"
|
|
720
|
+
}
|
|
721
|
+
)
|
|
722
|
+
] }),
|
|
723
|
+
/* @__PURE__ */ jsxs("label", { className: "space-y-1 text-xs", children: [
|
|
724
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-muted-foreground", children: "Description" }),
|
|
725
|
+
/* @__PURE__ */ jsx(
|
|
726
|
+
"textarea",
|
|
727
|
+
{
|
|
728
|
+
value: opportunityDraft.description,
|
|
729
|
+
onChange: (event) => setOpportunityDraft((draft) => __spreadProps(__spreadValues({}, draft), { description: event.target.value })),
|
|
730
|
+
rows: 3,
|
|
731
|
+
placeholder: "Add a short description",
|
|
732
|
+
className: "w-full resize-none rounded-md border border-border bg-background px-2 py-1.5 text-xs text-foreground placeholder:text-muted-foreground/60 focus:outline-none focus:ring-1 focus:ring-ring"
|
|
733
|
+
}
|
|
734
|
+
)
|
|
735
|
+
] })
|
|
736
|
+
] })
|
|
608
737
|
] }),
|
|
609
738
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
610
739
|
/* @__PURE__ */ jsxs(
|
|
611
740
|
"button",
|
|
612
741
|
{
|
|
613
742
|
type: "button",
|
|
614
|
-
onClick:
|
|
615
|
-
|
|
743
|
+
onClick: () => {
|
|
744
|
+
if (!opportunityPreview) {
|
|
745
|
+
approve();
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
approve(isEditableOpportunityPreview ? opportunityDraft : void 0);
|
|
749
|
+
},
|
|
750
|
+
disabled: !canConfirmOpportunity,
|
|
751
|
+
className: "inline-flex h-7 items-center gap-1.5 rounded-md bg-foreground px-3 text-xs font-semibold text-background transition-colors hover:bg-foreground/90 disabled:cursor-not-allowed disabled:bg-muted disabled:text-muted-foreground",
|
|
616
752
|
children: [
|
|
617
753
|
/* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }),
|
|
618
754
|
"Confirm"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/signal-feedback-inline.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { Check, CirclePlus, ExternalLink, Loader2, Lock, ThumbsDown } from \"lucide-react\"\n\ninterface DismissReasonNode {\n label: string\n subOptions?: string[]\n}\n\nconst dismissReasonTree: DismissReasonNode[] = [\n {\n label: \"Not relevant for this account\",\n subOptions: [\n \"Business as usual for this account\",\n \"Account in maintenance mode\",\n \"Wrong contact for this signal\",\n \"Other\",\n ],\n },\n {\n label: \"Bad timing\",\n subOptions: [\n \"Too early in the relationship\",\n \"Too soon after last outreach\",\n \"Wrong time of year for this account\",\n \"Other\",\n ],\n },\n {\n label: \"Inaccurate data\",\n subOptions: [\n \"Wrong amount or number\",\n \"Stale data\",\n \"Account info wrong\",\n \"Other\",\n ],\n },\n {\n label: \"Wrong account\",\n subOptions: [\n \"Different account meant\",\n \"Account not in scope\",\n \"Other\",\n ],\n },\n {\n label: \"Already handled\",\n subOptions: [\n \"Already in conversation\",\n \"Already an open Opportunity\",\n \"Already escalated\",\n \"Other\",\n ],\n },\n {\n label: \"Not actionable\",\n subOptions: [\n \"No clear next step\",\n \"Outside our remit\",\n \"Other\",\n ],\n },\n { label: \"Other\" },\n]\n\nconst approveReasons = [\n \"Right timing\",\n \"Accurate data\",\n \"Good prospect fit\",\n \"Actionable\",\n]\n\ntype ApprovalState = \"pending\" | \"confirming\" | \"creating\" | \"approving-feedback\" | \"dismissing\" | \"approved\" | \"dismissed\" | \"auto-approved\"\n\ninterface SignalApprovalLabels {\n approveButton?: string\n dismissButton?: string\n approvedStatus?: string\n dismissedStatus?: string\n opportunityCreated?: string\n confirmPrompt?: string\n dismissPrompt?: string\n feedbackPrompt?: string\n /** Label shown while the approve action is in progress (e.g. \"Creating Opportunity...\"). */\n creatingStatus?: string\n}\n\nconst DEFAULT_LABELS: Required<SignalApprovalLabels> = {\n approveButton: \"Approve action\",\n dismissButton: \"Not Helpful\",\n approvedStatus: \"Action Approved\",\n dismissedStatus: \"Action Dismissed\",\n opportunityCreated: \"Opportunity Created\",\n confirmPrompt: \"This will approve this action for\",\n dismissPrompt: \"What\\u2019s the issue with this action?\",\n feedbackPrompt: \"Quick feedback \\u2014 what made this action useful?\",\n creatingStatus: \"Creating\\u2026\",\n}\n\ninterface SignalApprovalContextValue {\n approvalState: ApprovalState\n companyName: string\n opportunityUrl?: string\n scheduledTime?: string\n labels: Required<SignalApprovalLabels>\n hideApproveButton?: boolean\n approveButtonIconUrl?: string\n opportunityPreview?: RootProps['opportunityPreview']\n requestingApproval: boolean\n approve: () => void\n submitApproveFeedback: (reasons: string[], detail: string) => void\n skipApproveFeedback: () => void\n dismiss: (reasons: string[], detail: string, subReason?: string) => void\n requestApproval: () => void\n requestDismiss: () => void\n cancel: () => void\n}\n\nconst SignalApprovalCtx = React.createContext<SignalApprovalContextValue | null>(null)\n\nexport function useSignalApproval() {\n const ctx = React.useContext(SignalApprovalCtx)\n if (!ctx) throw new Error(\"SignalApproval components must be used within SignalApproval.Root\")\n return ctx\n}\n\ninterface RootProps {\n children: React.ReactNode\n companyName: string\n opportunityUrl?: string\n scheduledTime?: string\n initialApprovalState?: ApprovalState\n labels?: SignalApprovalLabels\n /** When true, the approve/create-opportunity button is hidden but the dismiss button remains. */\n hideApproveButton?: boolean\n /** Optional icon URL for the approve button. Renders an img instead of CirclePlus when provided. */\n approveButtonIconUrl?: string\n /** Optional structured preview data shown in the confirmation dialog. */\n opportunityPreview?: {\n name: string\n stage: string\n closeDate: string\n amount: string\n accountName: string\n }\n /**\n * Async callback fired when the user clicks the approve button, BEFORE\n * transitioning to the \"confirming\" state. While the promise is pending,\n * the button shows a loading spinner. On resolve, transitions to \"confirming\".\n * On reject, stays in \"pending\".\n */\n onRequestApproval?: () => Promise<void>\n /**\n * Called when the user confirms the approval action.\n *\n * - If the callback returns `void` (or `undefined`), the component transitions\n * directly to the feedback step (backward-compatible behavior).\n * - If the callback returns a `Promise<boolean>`, the component shows a\n * \"creating\" loading state while the promise is pending. On `true` it\n * transitions to the feedback step; on `false` it reverts to \"pending\".\n */\n onApprove?: () => void | Promise<boolean>\n onApproveFeedback?: (reasons: string[], detail: string) => void\n onDismiss?: (reasons: string[], detail: string, subReason?: string) => void\n}\n\nfunction Root({ children, companyName, opportunityUrl, scheduledTime, initialApprovalState, labels: labelOverrides, hideApproveButton, approveButtonIconUrl, opportunityPreview, onRequestApproval, onApprove, onApproveFeedback, onDismiss }: RootProps) {\n const labels = React.useMemo(() => ({ ...DEFAULT_LABELS, ...labelOverrides }), [labelOverrides])\n const [approvalState, setApprovalState] = React.useState<ApprovalState>(initialApprovalState ?? \"pending\")\n const [requestingApproval, setRequestingApproval] = React.useState(false)\n\n // Guard against state updates after unmount (e.g. user navigates away while\n // an async onApprove promise is still in flight).\n const mountedRef = React.useRef(true)\n React.useEffect(() => {\n return () => { mountedRef.current = false }\n }, [])\n\n const requestApproval = React.useCallback(() => {\n if (onRequestApproval) {\n setRequestingApproval(true)\n onRequestApproval()\n .then(() => {\n if (mountedRef.current) {\n setRequestingApproval(false)\n setApprovalState(\"confirming\")\n }\n })\n .catch(() => {\n if (mountedRef.current) {\n setRequestingApproval(false)\n }\n })\n } else {\n setApprovalState(\"confirming\")\n }\n }, [onRequestApproval])\n\n const requestDismiss = React.useCallback(() => {\n setApprovalState(\"dismissing\")\n }, [])\n\n const cancel = React.useCallback(() => {\n setApprovalState(\"pending\")\n }, [])\n\n const approve = React.useCallback(() => {\n const result = onApprove?.()\n // If the callback returns a Promise, show a loading state and wait for it.\n if (result && typeof (result as Promise<boolean>).then === \"function\") {\n setApprovalState(\"creating\")\n ;(result as Promise<boolean>).then((success) => {\n if (mountedRef.current) {\n setApprovalState(success ? \"approving-feedback\" : \"pending\")\n }\n }).catch(() => {\n if (mountedRef.current) {\n setApprovalState(\"pending\")\n }\n })\n } else {\n // Synchronous / void — transition immediately (backward-compatible).\n setApprovalState(\"approving-feedback\")\n }\n }, [onApprove])\n\n const submitApproveFeedback = React.useCallback(\n (reasons: string[], detail: string) => {\n setApprovalState(\"approved\")\n onApproveFeedback?.(reasons, detail)\n },\n [onApproveFeedback]\n )\n\n const skipApproveFeedback = React.useCallback(() => {\n setApprovalState(\"approved\")\n }, [])\n\n const dismiss = React.useCallback(\n (reasons: string[], detail: string, subReason?: string) => {\n setApprovalState(\"dismissed\")\n onDismiss?.(reasons, detail, subReason)\n },\n [onDismiss]\n )\n\n return (\n <SignalApprovalCtx.Provider\n value={{ approvalState, companyName, opportunityUrl, scheduledTime, labels, hideApproveButton, approveButtonIconUrl, opportunityPreview, requestingApproval, approve, submitApproveFeedback, skipApproveFeedback, dismiss, requestApproval, requestDismiss, cancel }}\n >\n {children}\n </SignalApprovalCtx.Provider>\n )\n}\n\n/** Shared dismiss reason picker used in both the \"editing\" and \"initial dismiss\" paths. */\nfunction DismissReasonPicker({\n selectedTopReason,\n selectedSubReason,\n selectTopReason,\n selectSubReason,\n detailText,\n setDetailText,\n needsText,\n canSubmitDismiss,\n handleDismissSubmit,\n topNode,\n submitLabel,\n onCancel,\n}: {\n selectedTopReason: string | null\n selectedSubReason: string | null\n selectTopReason: (label: string) => void\n selectSubReason: (label: string) => void\n detailText: string\n setDetailText: (value: string) => void\n needsText: boolean\n canSubmitDismiss: boolean\n handleDismissSubmit: () => void\n topNode: DismissReasonNode | undefined\n submitLabel: string\n onCancel: () => void\n}) {\n return (\n <>\n <div className=\"flex flex-wrap gap-1.5\">\n {dismissReasonTree.map((node) => {\n const selected = selectedTopReason === node.label\n return (\n <button\n key={node.label}\n type=\"button\"\n onClick={() => selectTopReason(node.label)}\n className={`rounded-full border px-2.5 py-1 text-[11px] font-medium transition-colors ${\n selected\n ? \"border-red-200 bg-red-100 text-red-700\"\n : \"border-border bg-background text-muted-foreground hover:bg-muted/50 hover:text-foreground\"\n }`}\n >\n {node.label}\n </button>\n )\n })}\n </div>\n\n {topNode?.subOptions && (\n <div className=\"ml-3 border-l-2 border-muted pl-3\">\n <div className=\"flex flex-wrap gap-1.5\">\n {topNode.subOptions.map((sub) => {\n const selected = selectedSubReason === sub\n return (\n <button\n key={sub}\n type=\"button\"\n onClick={() => selectSubReason(sub)}\n className={`rounded-full border px-2.5 py-1 text-[11px] font-medium transition-colors ${\n selected\n ? \"border-red-200 bg-red-100 text-red-700\"\n : \"border-border bg-background text-muted-foreground hover:bg-muted/50 hover:text-foreground\"\n }`}\n >\n {sub}\n </button>\n )\n })}\n </div>\n </div>\n )}\n\n {selectedTopReason && (\n <input\n type=\"text\"\n value={detailText}\n onChange={(e) => setDetailText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && canSubmitDismiss) handleDismissSubmit()\n }}\n placeholder={needsText ? \"Please describe (required)\" : \"Add context (optional)\"}\n className=\"h-7 w-full rounded-md border border-border bg-muted/20 px-2.5 text-xs text-foreground placeholder:text-muted-foreground/60 focus:outline-none focus:ring-1 focus:ring-ring\"\n />\n )}\n\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={handleDismissSubmit}\n disabled={!canSubmitDismiss}\n className={`inline-flex h-7 items-center gap-1.5 rounded-md px-3 text-xs font-semibold transition-colors ${\n canSubmitDismiss\n ? \"bg-foreground text-background hover:bg-foreground/90\"\n : \"cursor-not-allowed bg-muted text-muted-foreground\"\n }`}\n >\n {submitLabel}\n </button>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"inline-flex h-7 items-center rounded-md border border-border px-3 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n Cancel\n </button>\n </div>\n </>\n )\n}\n\nfunction SubmittedFeedback({\n reasons,\n detail,\n subReason,\n variant,\n onEdit,\n}: {\n reasons: string[]\n detail: string\n subReason?: string\n variant: \"approve\" | \"dismiss\"\n onEdit: () => void\n}) {\n if (reasons.length === 0 && !detail) return null\n const pillClass =\n variant === \"approve\"\n ? \"border-emerald-200/60 bg-emerald-50/50 text-emerald-700/70\"\n : \"border-red-200/60 bg-red-50/50 text-red-700/70\"\n\n return (\n <button\n type=\"button\"\n onClick={onEdit}\n className=\"w-full text-left space-y-1.5 group cursor-pointer\"\n >\n {reasons.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {reasons.map((r) => (\n <span\n key={r}\n className={`rounded-full border px-2 py-0.5 text-[10px] font-medium transition-colors group-hover:opacity-80 ${pillClass}`}\n >\n {r}\n </span>\n ))}\n {subReason && (\n <span\n className={`rounded-full border px-2 py-0.5 text-[10px] font-medium transition-colors group-hover:opacity-80 ${pillClass}`}\n >\n {subReason}\n </span>\n )}\n </div>\n )}\n {detail && (\n <p className=\"text-[11px] text-muted-foreground/70 leading-snug group-hover:text-muted-foreground transition-colors\">{detail}</p>\n )}\n </button>\n )\n}\n\nfunction Actions() {\n const { approvalState, companyName, opportunityUrl, scheduledTime, labels, hideApproveButton, approveButtonIconUrl, opportunityPreview, requestingApproval, approve, submitApproveFeedback, skipApproveFeedback, dismiss, requestApproval, requestDismiss, cancel } =\n useSignalApproval()\n const [selectedTopReason, setSelectedTopReason] = React.useState<string | null>(null)\n const [selectedSubReason, setSelectedSubReason] = React.useState<string | null>(null)\n const [selectedReasons, setSelectedReasons] = React.useState<string[]>([])\n const [detailText, setDetailText] = React.useState(\"\")\n const [submittedFeedback, setSubmittedFeedback] = React.useState<{ reasons: string[]; detail: string; subReason?: string } | null>(null)\n const [isEditing, setIsEditing] = React.useState(false)\n\n const topNode = dismissReasonTree.find((n) => n.label === selectedTopReason)\n const hasSubOptions = !!(topNode?.subOptions && topNode.subOptions.length > 0)\n const isTopOther = selectedTopReason === \"Other\" && !hasSubOptions\n const isSubOther = selectedSubReason === \"Other\"\n const needsText = isTopOther || isSubOther\n const canSubmitDismiss =\n selectedTopReason !== null &&\n (!hasSubOptions || selectedSubReason !== null) &&\n (!needsText || detailText.trim().length > 0)\n\n const canSubmitApprove = selectedReasons.length > 0 || detailText.trim().length > 0\n\n const selectTopReason = (label: string) => {\n if (selectedTopReason === label) {\n setSelectedTopReason(null)\n setSelectedSubReason(null)\n setDetailText(\"\")\n } else {\n setSelectedTopReason(label)\n setSelectedSubReason(null)\n setDetailText(\"\")\n }\n }\n\n const selectSubReason = (label: string) => {\n setSelectedSubReason(selectedSubReason === label ? null : label)\n }\n\n const toggleReason = (reason: string) => {\n setSelectedReasons((prev) =>\n prev.includes(reason) ? prev.filter((r) => r !== reason) : [...prev, reason]\n )\n }\n\n const startEditing = () => {\n if (submittedFeedback) {\n setSelectedTopReason(submittedFeedback.reasons[0] ?? null)\n setSelectedSubReason(submittedFeedback.subReason ?? null)\n // Note: selectedReasons is only used by the approve editing path.\n // For dismiss feedback this is harmless but unused — the dismiss path\n // reads selectedTopReason/selectedSubReason instead.\n setSelectedReasons([...submittedFeedback.reasons])\n setDetailText(submittedFeedback.detail)\n }\n setIsEditing(true)\n }\n\n const handleDismissSubmit = () => {\n if (!canSubmitDismiss || !selectedTopReason) return\n const fb = { reasons: [selectedTopReason], detail: detailText.trim(), subReason: selectedSubReason ?? undefined }\n setSubmittedFeedback(fb)\n dismiss([selectedTopReason], detailText.trim(), selectedSubReason ?? undefined)\n setSelectedTopReason(null)\n setSelectedSubReason(null)\n setDetailText(\"\")\n setIsEditing(false)\n }\n\n const handleApproveSubmit = () => {\n const fb = { reasons: [...selectedReasons], detail: detailText.trim() }\n setSubmittedFeedback(fb)\n submitApproveFeedback(selectedReasons, detailText.trim())\n setSelectedReasons([])\n setDetailText(\"\")\n setIsEditing(false)\n }\n\n const handleEditCancel = () => {\n setSelectedTopReason(null)\n setSelectedSubReason(null)\n setSelectedReasons([])\n setDetailText(\"\")\n setIsEditing(false)\n }\n\n const handleCancel = () => {\n cancel()\n setSelectedTopReason(null)\n setSelectedSubReason(null)\n setSelectedReasons([])\n setDetailText(\"\")\n }\n\n if (approvalState === \"creating\") {\n return (\n <div className=\"flex items-center gap-2 text-xs font-medium text-muted-foreground\">\n <svg className=\"h-3.5 w-3.5 animate-spin\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\" />\n </svg>\n <span>{labels.creatingStatus}</span>\n </div>\n )\n }\n\n if (approvalState === \"approved\") {\n if (isEditing) {\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-1.5 text-xs font-medium text-emerald-600 mb-2\">\n <Check className=\"h-3.5 w-3.5\" />\n {opportunityUrl ? (\n <a href={opportunityUrl} target=\"_blank\" rel=\"noopener noreferrer\" className=\"inline-flex items-center gap-1 hover:underline underline-offset-2\">\n {labels.approvedStatus} <ExternalLink className=\"h-3 w-3\" />\n </a>\n ) : (\n <span>{labels.approvedStatus}</span>\n )}\n </div>\n <p className=\"text-xs font-medium text-muted-foreground\">Edit your feedback</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {approveReasons.map((reason) => {\n const selected = selectedReasons.includes(reason)\n return (\n <button key={reason} type=\"button\" onClick={() => toggleReason(reason)}\n className={`rounded-full border px-2.5 py-1 text-[11px] font-medium transition-colors ${\n selected ? \"border-emerald-200 bg-emerald-100 text-emerald-700\" : \"border-border bg-background text-muted-foreground hover:bg-muted/50 hover:text-foreground\"\n }`}>{reason}</button>\n )\n })}\n </div>\n <input type=\"text\" value={detailText} onChange={(e) => setDetailText(e.target.value)}\n onKeyDown={(e) => { if (e.key === \"Enter\" && canSubmitApprove) handleApproveSubmit() }}\n placeholder=\"Tell us more (optional)\"\n className=\"h-7 w-full rounded-md border border-border bg-muted/20 px-2.5 text-xs text-foreground placeholder:text-muted-foreground/60 focus:outline-none focus:ring-1 focus:ring-ring\" />\n <div className=\"flex items-center gap-2\">\n <button type=\"button\" onClick={handleApproveSubmit} disabled={!canSubmitApprove}\n className={`inline-flex h-7 items-center gap-1.5 rounded-md px-3 text-xs font-semibold transition-colors ${canSubmitApprove ? \"bg-foreground text-background hover:bg-foreground/90\" : \"cursor-not-allowed bg-muted text-muted-foreground\"}`}>\n Save\n </button>\n <button type=\"button\" onClick={handleEditCancel}\n className=\"inline-flex h-7 items-center rounded-md border border-border px-3 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\">\n Cancel\n </button>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-1.5 text-xs font-medium text-emerald-600\">\n <Check className=\"h-3.5 w-3.5\" />\n {opportunityUrl ? (\n <a\n href={opportunityUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1 hover:underline underline-offset-2\"\n >\n {labels.opportunityCreated}\n <ExternalLink className=\"h-3 w-3\" />\n </a>\n ) : (\n <span>{labels.opportunityCreated}</span>\n )}\n </div>\n {submittedFeedback && (\n <SubmittedFeedback\n reasons={submittedFeedback.reasons}\n detail={submittedFeedback.detail}\n variant=\"approve\"\n onEdit={startEditing}\n />\n )}\n </div>\n )\n }\n\n if (approvalState === \"auto-approved\") {\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-1.5 text-xs font-medium text-emerald-600\">\n <Check className=\"h-3.5 w-3.5\" />\n <span>{labels.approvedStatus}</span>\n </div>\n {scheduledTime && (\n <p className=\"text-[11px] text-muted-foreground\">Scheduled: {scheduledTime}</p>\n )}\n </div>\n )\n }\n\n if (approvalState === \"approving-feedback\") {\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-1.5 text-xs font-medium text-emerald-600 mb-2\">\n <Check className=\"h-3.5 w-3.5\" />\n {opportunityUrl ? (\n <a\n href={opportunityUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1 hover:underline underline-offset-2\"\n >\n {labels.opportunityCreated}\n <ExternalLink className=\"h-3 w-3\" />\n </a>\n ) : (\n <span>{labels.opportunityCreated}</span>\n )}\n </div>\n <p className=\"text-xs font-medium text-muted-foreground\">{labels.feedbackPrompt}</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {approveReasons.map((reason) => {\n const selected = selectedReasons.includes(reason)\n return (\n <button\n key={reason}\n type=\"button\"\n onClick={() => toggleReason(reason)}\n className={`rounded-full border px-2.5 py-1 text-[11px] font-medium transition-colors ${\n selected\n ? \"border-emerald-200 bg-emerald-100 text-emerald-700\"\n : \"border-border bg-background text-muted-foreground hover:bg-muted/50 hover:text-foreground\"\n }`}\n >\n {reason}\n </button>\n )\n })}\n </div>\n\n <input\n type=\"text\"\n value={detailText}\n onChange={(e) => setDetailText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && canSubmitApprove) handleApproveSubmit()\n }}\n placeholder=\"Tell us more (optional)\"\n className=\"h-7 w-full rounded-md border border-border bg-muted/20 px-2.5 text-xs text-foreground placeholder:text-muted-foreground/60 focus:outline-none focus:ring-1 focus:ring-ring\"\n />\n\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={handleApproveSubmit}\n disabled={!canSubmitApprove}\n className={`inline-flex h-7 items-center gap-1.5 rounded-md px-3 text-xs font-semibold transition-colors ${\n canSubmitApprove\n ? \"bg-foreground text-background hover:bg-foreground/90\"\n : \"cursor-not-allowed bg-muted text-muted-foreground\"\n }`}\n >\n Submit\n </button>\n <button\n type=\"button\"\n onClick={skipApproveFeedback}\n className=\"inline-flex h-7 items-center rounded-md border border-border px-3 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n Skip\n </button>\n </div>\n </div>\n )\n }\n\n if (approvalState === \"dismissed\") {\n if (isEditing) {\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-1.5 text-xs text-muted-foreground mb-2\">\n <ThumbsDown className=\"h-3.5 w-3.5\" />\n <span>{labels.dismissedStatus}</span>\n </div>\n <p className=\"text-xs font-medium text-muted-foreground\">Edit your feedback</p>\n <DismissReasonPicker\n selectedTopReason={selectedTopReason}\n selectedSubReason={selectedSubReason}\n selectTopReason={selectTopReason}\n selectSubReason={selectSubReason}\n detailText={detailText}\n setDetailText={setDetailText}\n needsText={needsText}\n canSubmitDismiss={canSubmitDismiss}\n handleDismissSubmit={handleDismissSubmit}\n topNode={topNode}\n submitLabel=\"Save\"\n onCancel={handleEditCancel}\n />\n </div>\n )\n }\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <ThumbsDown className=\"h-3.5 w-3.5\" />\n <span>{labels.dismissedStatus}</span>\n </div>\n {submittedFeedback && (\n <SubmittedFeedback\n reasons={submittedFeedback.reasons}\n detail={submittedFeedback.detail}\n subReason={submittedFeedback.subReason}\n variant=\"dismiss\"\n onEdit={startEditing}\n />\n )}\n </div>\n )\n }\n\n if (approvalState === \"confirming\") {\n return (\n <div className=\"space-y-3\">\n <div className=\"rounded-md border border-border bg-muted/30 p-3\">\n <p className=\"text-sm text-foreground\">\n {labels.confirmPrompt} <strong>{companyName}</strong>. Confirm?\n </p>\n {opportunityPreview && (\n <div className=\"mt-3 space-y-1.5 border-t border-border/50 pt-3\">\n {[\n { label: \"Opportunity\", value: opportunityPreview.name },\n { label: \"Account\", value: opportunityPreview.accountName },\n { label: \"Stage\", value: opportunityPreview.stage },\n { label: \"Close Date\", value: opportunityPreview.closeDate },\n { label: \"Amount\", value: opportunityPreview.amount },\n ].map(({ label, value }) => (\n <div key={label} className=\"flex items-center justify-between text-xs\">\n <span className=\"text-muted-foreground\">{label}</span>\n <span className=\"font-medium text-foreground\">{value}</span>\n </div>\n ))}\n </div>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={approve}\n className=\"inline-flex h-7 items-center gap-1.5 rounded-md bg-foreground px-3 text-xs font-semibold text-background transition-colors hover:bg-foreground/90\"\n >\n <Check className=\"h-3 w-3\" />\n Confirm\n </button>\n <button\n type=\"button\"\n onClick={handleCancel}\n className=\"inline-flex h-7 items-center rounded-md border border-border px-3 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n Cancel\n </button>\n </div>\n </div>\n )\n }\n\n if (approvalState === \"dismissing\") {\n return (\n <div className=\"space-y-3\">\n <p className=\"text-xs font-medium text-muted-foreground\">{labels.dismissPrompt}</p>\n <DismissReasonPicker\n selectedTopReason={selectedTopReason}\n selectedSubReason={selectedSubReason}\n selectTopReason={selectTopReason}\n selectSubReason={selectSubReason}\n detailText={detailText}\n setDetailText={setDetailText}\n needsText={needsText}\n canSubmitDismiss={canSubmitDismiss}\n handleDismissSubmit={handleDismissSubmit}\n topNode={topNode}\n submitLabel=\"Submit\"\n onCancel={handleCancel}\n />\n </div>\n )\n }\n\n return (\n <div className=\"flex items-center gap-2\">\n {!hideApproveButton && (\n <button\n type=\"button\"\n onClick={requestApproval}\n disabled={requestingApproval}\n className=\"inline-flex h-7 items-center gap-1.5 rounded-md border border-border bg-foreground px-3 text-xs font-semibold text-background shadow-none transition-colors hover:bg-foreground/90 disabled:opacity-50\"\n >\n {requestingApproval ? (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n ) : approveButtonIconUrl ? (\n <img src={approveButtonIconUrl} alt=\"\" className=\"h-3.5 w-3.5 object-contain\" draggable={false} />\n ) : (\n <CirclePlus className=\"h-3.5 w-3.5\" />\n )}\n {labels.approveButton}\n </button>\n )}\n <button\n type=\"button\"\n onClick={requestDismiss}\n className=\"inline-flex h-7 items-center gap-1.5 rounded-md border border-border px-3 text-xs font-medium text-muted-foreground shadow-none transition-colors hover:bg-muted hover:text-foreground\"\n >\n <ThumbsDown className=\"h-3.5 w-3.5\" />\n {labels.dismissButton}\n </button>\n </div>\n )\n}\n\nfunction Gate({ children }: { children: React.ReactNode }) {\n const { approvalState, hideApproveButton } = useSignalApproval()\n // When the approve button is hidden, don't lock content behind approval\n const isLocked = !hideApproveButton &&\n (approvalState === \"pending\" || approvalState === \"confirming\" || approvalState === \"creating\" || approvalState === \"dismissing\")\n\n return (\n <div className=\"relative\">\n {isLocked && (\n <div className=\"pointer-events-none absolute inset-x-0 top-4 z-10 flex justify-center\">\n <div className=\"flex items-center gap-1.5 rounded-full border border-border bg-background px-3 py-1.5 text-xs text-muted-foreground shadow-sm\">\n <Lock className=\"h-3 w-3\" />\n Approve or dismiss the signal above to unlock\n </div>\n </div>\n )}\n <div\n className={`transition-opacity duration-300 ${isLocked ? \"pointer-events-none select-none opacity-40\" : \"opacity-100\"}`}\n >\n {children}\n </div>\n </div>\n )\n}\n\nexport {\n Root as SignalApprovalRoot,\n Actions as SignalApprovalActions,\n Gate as SignalApprovalGate,\n}\nexport const SignalApproval = { Root, Actions, Gate }\nexport type OpportunityPreview = NonNullable<RootProps['opportunityPreview']>\nexport type { ApprovalState, SignalApprovalLabels, SignalApprovalContextValue, RootProps as SignalApprovalRootProps }\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/signal-feedback-inline.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { Check, CirclePlus, ExternalLink, Loader2, Lock, ThumbsDown } from \"lucide-react\"\n\ninterface DismissReasonNode {\n label: string\n subOptions?: string[]\n}\n\nconst dismissReasonTree: DismissReasonNode[] = [\n {\n label: \"Not relevant for this account\",\n subOptions: [\n \"Business as usual for this account\",\n \"Account in maintenance mode\",\n \"Wrong contact for this signal\",\n \"Other\",\n ],\n },\n {\n label: \"Bad timing\",\n subOptions: [\n \"Too early in the relationship\",\n \"Too soon after last outreach\",\n \"Wrong time of year for this account\",\n \"Other\",\n ],\n },\n {\n label: \"Inaccurate data\",\n subOptions: [\n \"Wrong amount or number\",\n \"Stale data\",\n \"Account info wrong\",\n \"Other\",\n ],\n },\n {\n label: \"Wrong account\",\n subOptions: [\n \"Different account meant\",\n \"Account not in scope\",\n \"Other\",\n ],\n },\n {\n label: \"Already handled\",\n subOptions: [\n \"Already in conversation\",\n \"Already an open Opportunity\",\n \"Already escalated\",\n \"Other\",\n ],\n },\n {\n label: \"Not actionable\",\n subOptions: [\n \"No clear next step\",\n \"Outside our remit\",\n \"Other\",\n ],\n },\n { label: \"Other\" },\n]\n\nconst approveReasons = [\n \"Right timing\",\n \"Accurate data\",\n \"Good prospect fit\",\n \"Actionable\",\n]\n\ntype ApprovalState = \"pending\" | \"confirming\" | \"creating\" | \"approving-feedback\" | \"dismissing\" | \"approved\" | \"dismissed\" | \"auto-approved\"\n\ninterface OpportunityPreviewOption {\n value: string\n label: string\n}\n\ninterface OpportunityPreview {\n name: string\n stage: string\n closeDate: string\n closeDateValue?: string\n amount: string\n /** Raw draft input value. Numeric values render as currency in the editable field. */\n amountValue?: string | number | null\n accountName: string\n description?: string | null\n churnType?: string | null\n churnTypeOptions?: Array<string | OpportunityPreviewOption>\n}\n\ninterface OpportunityDraft {\n closeDate: string\n amount: string\n description: string\n churnType: string\n}\n\ninterface SignalApprovalLabels {\n approveButton?: string\n dismissButton?: string\n approvedStatus?: string\n dismissedStatus?: string\n opportunityCreated?: string\n confirmPrompt?: string\n dismissPrompt?: string\n feedbackPrompt?: string\n /** Label shown while the approve action is in progress (e.g. \"Creating Opportunity...\"). */\n creatingStatus?: string\n}\n\nconst DEFAULT_LABELS: Required<SignalApprovalLabels> = {\n approveButton: \"Approve action\",\n dismissButton: \"Not Helpful\",\n approvedStatus: \"Action Approved\",\n dismissedStatus: \"Action Dismissed\",\n opportunityCreated: \"Opportunity Created\",\n confirmPrompt: \"This will approve this action for\",\n dismissPrompt: \"What\\u2019s the issue with this action?\",\n feedbackPrompt: \"Quick feedback \\u2014 what made this action useful?\",\n creatingStatus: \"Creating\\u2026\",\n}\n\ninterface SignalApprovalContextValue {\n approvalState: ApprovalState\n companyName: string\n opportunityUrl?: string\n scheduledTime?: string\n labels: Required<SignalApprovalLabels>\n hideApproveButton?: boolean\n approveButtonIconUrl?: string\n opportunityPreview?: OpportunityPreview\n requestingApproval: boolean\n approve: (draft?: OpportunityDraft) => void\n submitApproveFeedback: (reasons: string[], detail: string) => void\n skipApproveFeedback: () => void\n dismiss: (reasons: string[], detail: string, subReason?: string) => void\n requestApproval: () => void\n requestDismiss: () => void\n cancel: () => void\n}\n\nconst SignalApprovalCtx = React.createContext<SignalApprovalContextValue | null>(null)\n\nexport function useSignalApproval() {\n const ctx = React.useContext(SignalApprovalCtx)\n if (!ctx) throw new Error(\"SignalApproval components must be used within SignalApproval.Root\")\n return ctx\n}\n\ninterface RootProps {\n children: React.ReactNode\n companyName: string\n opportunityUrl?: string\n scheduledTime?: string\n initialApprovalState?: ApprovalState\n labels?: SignalApprovalLabels\n /** When true, the approve/create-opportunity button is hidden but the dismiss button remains. */\n hideApproveButton?: boolean\n /** Optional icon URL for the approve button. Renders an img instead of CirclePlus when provided. */\n approveButtonIconUrl?: string\n /** Optional structured preview data shown in the confirmation dialog. */\n opportunityPreview?: OpportunityPreview\n /**\n * Async callback fired when the user clicks the approve button, BEFORE\n * transitioning to the \"confirming\" state. While the promise is pending,\n * the button shows a loading spinner. On resolve, transitions to \"confirming\".\n * On reject, stays in \"pending\".\n */\n onRequestApproval?: () => Promise<void>\n /**\n * Called when the user confirms the approval action.\n *\n * - If the callback returns `void` (or `undefined`), the component transitions\n * directly to the feedback step (backward-compatible behavior).\n * - If the callback returns a `Promise<boolean>`, the component shows a\n * \"creating\" loading state while the promise is pending. On `true` it\n * transitions to the feedback step; on `false` it reverts to \"pending\".\n */\n onApprove?: (draft?: OpportunityDraft) => void | Promise<boolean>\n onApproveFeedback?: (reasons: string[], detail: string) => void\n onDismiss?: (reasons: string[], detail: string, subReason?: string) => void\n}\n\nfunction Root({ children, companyName, opportunityUrl, scheduledTime, initialApprovalState, labels: labelOverrides, hideApproveButton, approveButtonIconUrl, opportunityPreview, onRequestApproval, onApprove, onApproveFeedback, onDismiss }: RootProps) {\n const labels = React.useMemo(() => ({ ...DEFAULT_LABELS, ...labelOverrides }), [labelOverrides])\n const [approvalState, setApprovalState] = React.useState<ApprovalState>(initialApprovalState ?? \"pending\")\n const [requestingApproval, setRequestingApproval] = React.useState(false)\n\n // Guard against state updates after unmount (e.g. user navigates away while\n // an async onApprove promise is still in flight).\n const mountedRef = React.useRef(true)\n React.useEffect(() => {\n mountedRef.current = true\n return () => { mountedRef.current = false }\n }, [])\n\n const requestApproval = React.useCallback(() => {\n if (onRequestApproval) {\n setRequestingApproval(true)\n onRequestApproval()\n .then(() => {\n if (mountedRef.current) {\n setRequestingApproval(false)\n setApprovalState(\"confirming\")\n }\n })\n .catch(() => {\n if (mountedRef.current) {\n setRequestingApproval(false)\n }\n })\n } else {\n setApprovalState(\"confirming\")\n }\n }, [onRequestApproval])\n\n const requestDismiss = React.useCallback(() => {\n setApprovalState(\"dismissing\")\n }, [])\n\n const cancel = React.useCallback(() => {\n setApprovalState(\"pending\")\n }, [])\n\n const approve = React.useCallback((draft?: OpportunityDraft) => {\n const result = onApprove?.(draft)\n // If the callback returns a Promise, show a loading state and wait for it.\n if (result && typeof (result as Promise<boolean>).then === \"function\") {\n setApprovalState(\"creating\")\n ;(result as Promise<boolean>).then((success) => {\n if (mountedRef.current) {\n setApprovalState(success ? \"approving-feedback\" : \"pending\")\n }\n }).catch(() => {\n if (mountedRef.current) {\n setApprovalState(\"pending\")\n }\n })\n } else {\n // Synchronous / void — transition immediately (backward-compatible).\n setApprovalState(\"approving-feedback\")\n }\n }, [onApprove])\n\n const submitApproveFeedback = React.useCallback(\n (reasons: string[], detail: string) => {\n setApprovalState(\"approved\")\n onApproveFeedback?.(reasons, detail)\n },\n [onApproveFeedback]\n )\n\n const skipApproveFeedback = React.useCallback(() => {\n setApprovalState(\"approved\")\n }, [])\n\n const dismiss = React.useCallback(\n (reasons: string[], detail: string, subReason?: string) => {\n setApprovalState(\"dismissed\")\n onDismiss?.(reasons, detail, subReason)\n },\n [onDismiss]\n )\n\n return (\n <SignalApprovalCtx.Provider\n value={{ approvalState, companyName, opportunityUrl, scheduledTime, labels, hideApproveButton, approveButtonIconUrl, opportunityPreview, requestingApproval, approve, submitApproveFeedback, skipApproveFeedback, dismiss, requestApproval, requestDismiss, cancel }}\n >\n {children}\n </SignalApprovalCtx.Provider>\n )\n}\n\n/** Shared dismiss reason picker used in both the \"editing\" and \"initial dismiss\" paths. */\nfunction DismissReasonPicker({\n selectedTopReason,\n selectedSubReason,\n selectTopReason,\n selectSubReason,\n detailText,\n setDetailText,\n needsText,\n canSubmitDismiss,\n handleDismissSubmit,\n topNode,\n submitLabel,\n onCancel,\n}: {\n selectedTopReason: string | null\n selectedSubReason: string | null\n selectTopReason: (label: string) => void\n selectSubReason: (label: string) => void\n detailText: string\n setDetailText: (value: string) => void\n needsText: boolean\n canSubmitDismiss: boolean\n handleDismissSubmit: () => void\n topNode: DismissReasonNode | undefined\n submitLabel: string\n onCancel: () => void\n}) {\n return (\n <>\n <div className=\"flex flex-wrap gap-1.5\">\n {dismissReasonTree.map((node) => {\n const selected = selectedTopReason === node.label\n return (\n <button\n key={node.label}\n type=\"button\"\n onClick={() => selectTopReason(node.label)}\n className={`rounded-full border px-2.5 py-1 text-[11px] font-medium transition-colors ${\n selected\n ? \"border-red-200 bg-red-100 text-red-700\"\n : \"border-border bg-background text-muted-foreground hover:bg-muted/50 hover:text-foreground\"\n }`}\n >\n {node.label}\n </button>\n )\n })}\n </div>\n\n {topNode?.subOptions && (\n <div className=\"ml-3 border-l-2 border-muted pl-3\">\n <div className=\"flex flex-wrap gap-1.5\">\n {topNode.subOptions.map((sub) => {\n const selected = selectedSubReason === sub\n return (\n <button\n key={sub}\n type=\"button\"\n onClick={() => selectSubReason(sub)}\n className={`rounded-full border px-2.5 py-1 text-[11px] font-medium transition-colors ${\n selected\n ? \"border-red-200 bg-red-100 text-red-700\"\n : \"border-border bg-background text-muted-foreground hover:bg-muted/50 hover:text-foreground\"\n }`}\n >\n {sub}\n </button>\n )\n })}\n </div>\n </div>\n )}\n\n {selectedTopReason && (\n <input\n type=\"text\"\n value={detailText}\n onChange={(e) => setDetailText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && canSubmitDismiss) handleDismissSubmit()\n }}\n placeholder={needsText ? \"Please describe (required)\" : \"Add context (optional)\"}\n className=\"h-7 w-full rounded-md border border-border bg-muted/20 px-2.5 text-xs text-foreground placeholder:text-muted-foreground/60 focus:outline-none focus:ring-1 focus:ring-ring\"\n />\n )}\n\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={handleDismissSubmit}\n disabled={!canSubmitDismiss}\n className={`inline-flex h-7 items-center gap-1.5 rounded-md px-3 text-xs font-semibold transition-colors ${\n canSubmitDismiss\n ? \"bg-foreground text-background hover:bg-foreground/90\"\n : \"cursor-not-allowed bg-muted text-muted-foreground\"\n }`}\n >\n {submitLabel}\n </button>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"inline-flex h-7 items-center rounded-md border border-border px-3 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n Cancel\n </button>\n </div>\n </>\n )\n}\n\nfunction SubmittedFeedback({\n reasons,\n detail,\n subReason,\n variant,\n onEdit,\n}: {\n reasons: string[]\n detail: string\n subReason?: string\n variant: \"approve\" | \"dismiss\"\n onEdit: () => void\n}) {\n if (reasons.length === 0 && !detail) return null\n const pillClass =\n variant === \"approve\"\n ? \"border-emerald-200/60 bg-emerald-50/50 text-emerald-700/70\"\n : \"border-red-200/60 bg-red-50/50 text-red-700/70\"\n\n return (\n <button\n type=\"button\"\n onClick={onEdit}\n className=\"w-full text-left space-y-1.5 group cursor-pointer\"\n >\n {reasons.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {reasons.map((r) => (\n <span\n key={r}\n className={`rounded-full border px-2 py-0.5 text-[10px] font-medium transition-colors group-hover:opacity-80 ${pillClass}`}\n >\n {r}\n </span>\n ))}\n {subReason && (\n <span\n className={`rounded-full border px-2 py-0.5 text-[10px] font-medium transition-colors group-hover:opacity-80 ${pillClass}`}\n >\n {subReason}\n </span>\n )}\n </div>\n )}\n {detail && (\n <p className=\"text-[11px] text-muted-foreground/70 leading-snug group-hover:text-muted-foreground transition-colors\">{detail}</p>\n )}\n </button>\n )\n}\n\nfunction optionValue(option: string | OpportunityPreviewOption): string {\n return typeof option === \"string\" ? option : option.value\n}\n\nfunction optionLabel(option: string | OpportunityPreviewOption): string {\n return typeof option === \"string\" ? option : option.label\n}\n\nfunction formatAmountDraftValue(value: string | number | null | undefined): string {\n if (value == null || value === \"\") return \"\"\n if (typeof value === \"number\") {\n return new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: \"USD\",\n maximumFractionDigits: 0,\n }).format(value)\n }\n return value\n}\n\nfunction buildOpportunityDraft(preview?: OpportunityPreview): OpportunityDraft {\n return {\n closeDate: preview?.closeDateValue ?? preview?.closeDate ?? \"\",\n amount: preview?.amountValue === undefined\n ? preview?.amount ?? \"\"\n : formatAmountDraftValue(preview.amountValue),\n description: preview?.description ?? \"\",\n churnType: preview?.churnType ?? \"\",\n }\n}\n\nfunction hasEditableOpportunityPreview(preview?: OpportunityPreview): boolean {\n return !!preview && isValidDateInput(preview.closeDateValue ?? preview.closeDate)\n}\n\nfunction isValidDateInput(value: string): boolean {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(value)\n if (!match) return false\n const parsed = new Date(`${value}T00:00:00Z`)\n if (Number.isNaN(parsed.getTime())) return false\n return parsed.toISOString().slice(0, 10) === value\n}\n\nfunction Actions() {\n const { approvalState, companyName, opportunityUrl, scheduledTime, labels, hideApproveButton, approveButtonIconUrl, opportunityPreview, requestingApproval, approve, submitApproveFeedback, skipApproveFeedback, dismiss, requestApproval, requestDismiss, cancel } =\n useSignalApproval()\n const [selectedTopReason, setSelectedTopReason] = React.useState<string | null>(null)\n const [selectedSubReason, setSelectedSubReason] = React.useState<string | null>(null)\n const [selectedReasons, setSelectedReasons] = React.useState<string[]>([])\n const [detailText, setDetailText] = React.useState(\"\")\n const [submittedFeedback, setSubmittedFeedback] = React.useState<{ reasons: string[]; detail: string; subReason?: string } | null>(null)\n const [isEditing, setIsEditing] = React.useState(false)\n const [opportunityDraft, setOpportunityDraft] = React.useState<OpportunityDraft>(() => buildOpportunityDraft(opportunityPreview))\n\n React.useEffect(() => {\n if (approvalState === \"confirming\") {\n setOpportunityDraft(buildOpportunityDraft(opportunityPreview))\n }\n }, [approvalState, opportunityPreview])\n\n const churnTypeOptions = opportunityPreview?.churnTypeOptions ?? []\n const hasChurnTypeOptions = churnTypeOptions.length > 0\n\n const topNode = dismissReasonTree.find((n) => n.label === selectedTopReason)\n const hasSubOptions = !!(topNode?.subOptions && topNode.subOptions.length > 0)\n const isTopOther = selectedTopReason === \"Other\" && !hasSubOptions\n const isSubOther = selectedSubReason === \"Other\"\n const needsText = isTopOther || isSubOther\n const canSubmitDismiss =\n selectedTopReason !== null &&\n (!hasSubOptions || selectedSubReason !== null) &&\n (!needsText || detailText.trim().length > 0)\n\n const canSubmitApprove = selectedReasons.length > 0 || detailText.trim().length > 0\n const isEditableOpportunityPreview = hasEditableOpportunityPreview(opportunityPreview)\n const canConfirmOpportunity = !isEditableOpportunityPreview || isValidDateInput(opportunityDraft.closeDate)\n\n const selectTopReason = (label: string) => {\n if (selectedTopReason === label) {\n setSelectedTopReason(null)\n setSelectedSubReason(null)\n setDetailText(\"\")\n } else {\n setSelectedTopReason(label)\n setSelectedSubReason(null)\n setDetailText(\"\")\n }\n }\n\n const selectSubReason = (label: string) => {\n setSelectedSubReason(selectedSubReason === label ? null : label)\n }\n\n const toggleReason = (reason: string) => {\n setSelectedReasons((prev) =>\n prev.includes(reason) ? prev.filter((r) => r !== reason) : [...prev, reason]\n )\n }\n\n const startEditing = () => {\n if (submittedFeedback) {\n setSelectedTopReason(submittedFeedback.reasons[0] ?? null)\n setSelectedSubReason(submittedFeedback.subReason ?? null)\n // Note: selectedReasons is only used by the approve editing path.\n // For dismiss feedback this is harmless but unused — the dismiss path\n // reads selectedTopReason/selectedSubReason instead.\n setSelectedReasons([...submittedFeedback.reasons])\n setDetailText(submittedFeedback.detail)\n }\n setIsEditing(true)\n }\n\n const handleDismissSubmit = () => {\n if (!canSubmitDismiss || !selectedTopReason) return\n const fb = { reasons: [selectedTopReason], detail: detailText.trim(), subReason: selectedSubReason ?? undefined }\n setSubmittedFeedback(fb)\n dismiss([selectedTopReason], detailText.trim(), selectedSubReason ?? undefined)\n setSelectedTopReason(null)\n setSelectedSubReason(null)\n setDetailText(\"\")\n setIsEditing(false)\n }\n\n const handleApproveSubmit = () => {\n const fb = { reasons: [...selectedReasons], detail: detailText.trim() }\n setSubmittedFeedback(fb)\n submitApproveFeedback(selectedReasons, detailText.trim())\n setSelectedReasons([])\n setDetailText(\"\")\n setIsEditing(false)\n }\n\n const handleEditCancel = () => {\n setSelectedTopReason(null)\n setSelectedSubReason(null)\n setSelectedReasons([])\n setDetailText(\"\")\n setIsEditing(false)\n }\n\n const handleCancel = () => {\n cancel()\n setSelectedTopReason(null)\n setSelectedSubReason(null)\n setSelectedReasons([])\n setDetailText(\"\")\n }\n\n if (approvalState === \"creating\") {\n return (\n <div className=\"flex items-center gap-2 text-xs font-medium text-muted-foreground\">\n <svg className=\"h-3.5 w-3.5 animate-spin\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\" />\n </svg>\n <span>{labels.creatingStatus}</span>\n </div>\n )\n }\n\n if (approvalState === \"approved\") {\n if (isEditing) {\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-1.5 text-xs font-medium text-emerald-600 mb-2\">\n <Check className=\"h-3.5 w-3.5\" />\n {opportunityUrl ? (\n <a href={opportunityUrl} target=\"_blank\" rel=\"noopener noreferrer\" className=\"inline-flex items-center gap-1 hover:underline underline-offset-2\">\n {labels.approvedStatus} <ExternalLink className=\"h-3 w-3\" />\n </a>\n ) : (\n <span>{labels.approvedStatus}</span>\n )}\n </div>\n <p className=\"text-xs font-medium text-muted-foreground\">Edit your feedback</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {approveReasons.map((reason) => {\n const selected = selectedReasons.includes(reason)\n return (\n <button key={reason} type=\"button\" onClick={() => toggleReason(reason)}\n className={`rounded-full border px-2.5 py-1 text-[11px] font-medium transition-colors ${\n selected ? \"border-emerald-200 bg-emerald-100 text-emerald-700\" : \"border-border bg-background text-muted-foreground hover:bg-muted/50 hover:text-foreground\"\n }`}>{reason}</button>\n )\n })}\n </div>\n <input type=\"text\" value={detailText} onChange={(e) => setDetailText(e.target.value)}\n onKeyDown={(e) => { if (e.key === \"Enter\" && canSubmitApprove) handleApproveSubmit() }}\n placeholder=\"Tell us more (optional)\"\n className=\"h-7 w-full rounded-md border border-border bg-muted/20 px-2.5 text-xs text-foreground placeholder:text-muted-foreground/60 focus:outline-none focus:ring-1 focus:ring-ring\" />\n <div className=\"flex items-center gap-2\">\n <button type=\"button\" onClick={handleApproveSubmit} disabled={!canSubmitApprove}\n className={`inline-flex h-7 items-center gap-1.5 rounded-md px-3 text-xs font-semibold transition-colors ${canSubmitApprove ? \"bg-foreground text-background hover:bg-foreground/90\" : \"cursor-not-allowed bg-muted text-muted-foreground\"}`}>\n Save\n </button>\n <button type=\"button\" onClick={handleEditCancel}\n className=\"inline-flex h-7 items-center rounded-md border border-border px-3 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\">\n Cancel\n </button>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-1.5 text-xs font-medium text-emerald-600\">\n <Check className=\"h-3.5 w-3.5\" />\n {opportunityUrl ? (\n <a\n href={opportunityUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1 hover:underline underline-offset-2\"\n >\n {labels.opportunityCreated}\n <ExternalLink className=\"h-3 w-3\" />\n </a>\n ) : (\n <span>{labels.opportunityCreated}</span>\n )}\n </div>\n {submittedFeedback && (\n <SubmittedFeedback\n reasons={submittedFeedback.reasons}\n detail={submittedFeedback.detail}\n variant=\"approve\"\n onEdit={startEditing}\n />\n )}\n </div>\n )\n }\n\n if (approvalState === \"auto-approved\") {\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-1.5 text-xs font-medium text-emerald-600\">\n <Check className=\"h-3.5 w-3.5\" />\n <span>{labels.approvedStatus}</span>\n </div>\n {scheduledTime && (\n <p className=\"text-[11px] text-muted-foreground\">Scheduled: {scheduledTime}</p>\n )}\n </div>\n )\n }\n\n if (approvalState === \"approving-feedback\") {\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-1.5 text-xs font-medium text-emerald-600 mb-2\">\n <Check className=\"h-3.5 w-3.5\" />\n {opportunityUrl ? (\n <a\n href={opportunityUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1 hover:underline underline-offset-2\"\n >\n {labels.opportunityCreated}\n <ExternalLink className=\"h-3 w-3\" />\n </a>\n ) : (\n <span>{labels.opportunityCreated}</span>\n )}\n </div>\n <p className=\"text-xs font-medium text-muted-foreground\">{labels.feedbackPrompt}</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {approveReasons.map((reason) => {\n const selected = selectedReasons.includes(reason)\n return (\n <button\n key={reason}\n type=\"button\"\n onClick={() => toggleReason(reason)}\n className={`rounded-full border px-2.5 py-1 text-[11px] font-medium transition-colors ${\n selected\n ? \"border-emerald-200 bg-emerald-100 text-emerald-700\"\n : \"border-border bg-background text-muted-foreground hover:bg-muted/50 hover:text-foreground\"\n }`}\n >\n {reason}\n </button>\n )\n })}\n </div>\n\n <input\n type=\"text\"\n value={detailText}\n onChange={(e) => setDetailText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && canSubmitApprove) handleApproveSubmit()\n }}\n placeholder=\"Tell us more (optional)\"\n className=\"h-7 w-full rounded-md border border-border bg-muted/20 px-2.5 text-xs text-foreground placeholder:text-muted-foreground/60 focus:outline-none focus:ring-1 focus:ring-ring\"\n />\n\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={handleApproveSubmit}\n disabled={!canSubmitApprove}\n className={`inline-flex h-7 items-center gap-1.5 rounded-md px-3 text-xs font-semibold transition-colors ${\n canSubmitApprove\n ? \"bg-foreground text-background hover:bg-foreground/90\"\n : \"cursor-not-allowed bg-muted text-muted-foreground\"\n }`}\n >\n Submit\n </button>\n <button\n type=\"button\"\n onClick={skipApproveFeedback}\n className=\"inline-flex h-7 items-center rounded-md border border-border px-3 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n Skip\n </button>\n </div>\n </div>\n )\n }\n\n if (approvalState === \"dismissed\") {\n if (isEditing) {\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-1.5 text-xs text-muted-foreground mb-2\">\n <ThumbsDown className=\"h-3.5 w-3.5\" />\n <span>{labels.dismissedStatus}</span>\n </div>\n <p className=\"text-xs font-medium text-muted-foreground\">Edit your feedback</p>\n <DismissReasonPicker\n selectedTopReason={selectedTopReason}\n selectedSubReason={selectedSubReason}\n selectTopReason={selectTopReason}\n selectSubReason={selectSubReason}\n detailText={detailText}\n setDetailText={setDetailText}\n needsText={needsText}\n canSubmitDismiss={canSubmitDismiss}\n handleDismissSubmit={handleDismissSubmit}\n topNode={topNode}\n submitLabel=\"Save\"\n onCancel={handleEditCancel}\n />\n </div>\n )\n }\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <ThumbsDown className=\"h-3.5 w-3.5\" />\n <span>{labels.dismissedStatus}</span>\n </div>\n {submittedFeedback && (\n <SubmittedFeedback\n reasons={submittedFeedback.reasons}\n detail={submittedFeedback.detail}\n subReason={submittedFeedback.subReason}\n variant=\"dismiss\"\n onEdit={startEditing}\n />\n )}\n </div>\n )\n }\n\n if (approvalState === \"confirming\") {\n return (\n <div className=\"space-y-3\">\n <div className=\"rounded-md border border-border bg-muted/30 p-3\">\n <p className=\"text-sm text-foreground\">\n {labels.confirmPrompt} <strong>{companyName}</strong>. Confirm?\n </p>\n {opportunityPreview && !isEditableOpportunityPreview && (\n <div className=\"mt-3 space-y-2 border-t border-border/50 pt-3\">\n {[\n { label: \"Opportunity\", value: opportunityPreview.name },\n { label: \"Account\", value: opportunityPreview.accountName },\n { label: \"Stage\", value: opportunityPreview.stage },\n { label: \"Close Date\", value: opportunityPreview.closeDate },\n { label: \"Amount\", value: opportunityPreview.amount },\n ].map(({ label, value }) => (\n <div key={label} className=\"flex items-center justify-between gap-3 text-xs\">\n <span className=\"text-muted-foreground\">{label}</span>\n <span className=\"text-right font-medium text-foreground\">{value}</span>\n </div>\n ))}\n </div>\n )}\n {opportunityPreview && isEditableOpportunityPreview && (\n <div className=\"mt-3 space-y-3 border-t border-border/50 pt-3\">\n {[\n { label: \"Opportunity\", value: opportunityPreview.name },\n { label: \"Account\", value: opportunityPreview.accountName },\n { label: \"Stage\", value: opportunityPreview.stage },\n ].map(({ label, value }) => (\n <div key={label} className=\"flex items-center justify-between gap-3 text-xs\">\n <span className=\"text-muted-foreground\">{label}</span>\n <span className=\"text-right font-medium text-foreground\">{value}</span>\n </div>\n ))}\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <label className=\"space-y-1 text-xs\">\n <span className=\"font-medium text-muted-foreground\">Close Date</span>\n <input\n type=\"date\"\n value={opportunityDraft.closeDate}\n onChange={(event) => setOpportunityDraft((draft) => ({ ...draft, closeDate: event.target.value }))}\n aria-invalid={!canConfirmOpportunity}\n className=\"h-8 w-full rounded-md border border-border bg-background px-2 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-ring\"\n />\n {!canConfirmOpportunity && (\n <span className=\"text-[11px] text-red-600\">Enter a valid close date.</span>\n )}\n </label>\n\n <label className=\"space-y-1 text-xs\">\n <span className=\"font-medium text-muted-foreground\">Amount</span>\n <input\n type=\"text\"\n inputMode=\"decimal\"\n value={opportunityDraft.amount}\n onChange={(event) => setOpportunityDraft((draft) => ({ ...draft, amount: event.target.value }))}\n placeholder={opportunityPreview.amount}\n className=\"h-8 w-full rounded-md border border-border bg-background px-2 text-xs text-foreground placeholder:text-muted-foreground/60 focus:outline-none focus:ring-1 focus:ring-ring\"\n />\n </label>\n </div>\n\n <label className=\"space-y-1 text-xs\">\n <span className=\"font-medium text-muted-foreground\">Churn Type</span>\n {hasChurnTypeOptions ? (\n <select\n value={opportunityDraft.churnType}\n onChange={(event) => setOpportunityDraft((draft) => ({ ...draft, churnType: event.target.value }))}\n className=\"h-8 w-full rounded-md border border-border bg-background px-2 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-ring\"\n >\n <option value=\"\">No churn type</option>\n {churnTypeOptions.map((option) => (\n <option key={optionValue(option)} value={optionValue(option)}>\n {optionLabel(option)}\n </option>\n ))}\n </select>\n ) : (\n <input\n type=\"text\"\n value={opportunityDraft.churnType}\n onChange={(event) => setOpportunityDraft((draft) => ({ ...draft, churnType: event.target.value }))}\n placeholder=\"No churn type\"\n className=\"h-8 w-full rounded-md border border-border bg-background px-2 text-xs text-foreground placeholder:text-muted-foreground/60 focus:outline-none focus:ring-1 focus:ring-ring\"\n />\n )}\n </label>\n\n <label className=\"space-y-1 text-xs\">\n <span className=\"font-medium text-muted-foreground\">Description</span>\n <textarea\n value={opportunityDraft.description}\n onChange={(event) => setOpportunityDraft((draft) => ({ ...draft, description: event.target.value }))}\n rows={3}\n placeholder=\"Add a short description\"\n className=\"w-full resize-none rounded-md border border-border bg-background px-2 py-1.5 text-xs text-foreground placeholder:text-muted-foreground/60 focus:outline-none focus:ring-1 focus:ring-ring\"\n />\n </label>\n </div>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => {\n if (!opportunityPreview) {\n approve()\n return\n }\n approve(isEditableOpportunityPreview ? opportunityDraft : undefined)\n }}\n disabled={!canConfirmOpportunity}\n className=\"inline-flex h-7 items-center gap-1.5 rounded-md bg-foreground px-3 text-xs font-semibold text-background transition-colors hover:bg-foreground/90 disabled:cursor-not-allowed disabled:bg-muted disabled:text-muted-foreground\"\n >\n <Check className=\"h-3 w-3\" />\n Confirm\n </button>\n <button\n type=\"button\"\n onClick={handleCancel}\n className=\"inline-flex h-7 items-center rounded-md border border-border px-3 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n Cancel\n </button>\n </div>\n </div>\n )\n }\n\n if (approvalState === \"dismissing\") {\n return (\n <div className=\"space-y-3\">\n <p className=\"text-xs font-medium text-muted-foreground\">{labels.dismissPrompt}</p>\n <DismissReasonPicker\n selectedTopReason={selectedTopReason}\n selectedSubReason={selectedSubReason}\n selectTopReason={selectTopReason}\n selectSubReason={selectSubReason}\n detailText={detailText}\n setDetailText={setDetailText}\n needsText={needsText}\n canSubmitDismiss={canSubmitDismiss}\n handleDismissSubmit={handleDismissSubmit}\n topNode={topNode}\n submitLabel=\"Submit\"\n onCancel={handleCancel}\n />\n </div>\n )\n }\n\n return (\n <div className=\"flex items-center gap-2\">\n {!hideApproveButton && (\n <button\n type=\"button\"\n onClick={requestApproval}\n disabled={requestingApproval}\n className=\"inline-flex h-7 items-center gap-1.5 rounded-md border border-border bg-foreground px-3 text-xs font-semibold text-background shadow-none transition-colors hover:bg-foreground/90 disabled:opacity-50\"\n >\n {requestingApproval ? (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n ) : approveButtonIconUrl ? (\n <img src={approveButtonIconUrl} alt=\"\" className=\"h-3.5 w-3.5 object-contain\" draggable={false} />\n ) : (\n <CirclePlus className=\"h-3.5 w-3.5\" />\n )}\n {labels.approveButton}\n </button>\n )}\n <button\n type=\"button\"\n onClick={requestDismiss}\n className=\"inline-flex h-7 items-center gap-1.5 rounded-md border border-border px-3 text-xs font-medium text-muted-foreground shadow-none transition-colors hover:bg-muted hover:text-foreground\"\n >\n <ThumbsDown className=\"h-3.5 w-3.5\" />\n {labels.dismissButton}\n </button>\n </div>\n )\n}\n\nfunction Gate({ children }: { children: React.ReactNode }) {\n const { approvalState, hideApproveButton } = useSignalApproval()\n // When the approve button is hidden, don't lock content behind approval\n const isLocked = !hideApproveButton &&\n (approvalState === \"pending\" || approvalState === \"confirming\" || approvalState === \"creating\" || approvalState === \"dismissing\")\n\n return (\n <div className=\"relative\">\n {isLocked && (\n <div className=\"pointer-events-none absolute inset-x-0 top-4 z-10 flex justify-center\">\n <div className=\"flex items-center gap-1.5 rounded-full border border-border bg-background px-3 py-1.5 text-xs text-muted-foreground shadow-sm\">\n <Lock className=\"h-3 w-3\" />\n Approve or dismiss the signal above to unlock\n </div>\n </div>\n )}\n <div\n className={`transition-opacity duration-300 ${isLocked ? \"pointer-events-none select-none opacity-40\" : \"opacity-100\"}`}\n >\n {children}\n </div>\n </div>\n )\n}\n\nexport {\n Root as SignalApprovalRoot,\n Actions as SignalApprovalActions,\n Gate as SignalApprovalGate,\n}\nexport const SignalApproval = { Root, Actions, Gate }\nexport type { ApprovalState, OpportunityPreview, OpportunityDraft, SignalApprovalLabels, SignalApprovalContextValue, RootProps as SignalApprovalRootProps }\n"],"mappings":"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","names":["_a"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import 'react';
|
|
2
2
|
import './feedback-primitives.js';
|
|
3
|
-
export { P as PriorityFactor, S as SignalPriorityPopover, k as SignalPriorityPopoverProps
|
|
3
|
+
export { P as PriorityFactor, S as SignalPriorityPopover, k as SignalPriorityPopoverProps } from '../signal-priority-popover-QJngMAj7.js';
|
|
4
4
|
import './quick-action-sidebar-nav.js';
|
|
5
5
|
import './quick-action-modal.js';
|
|
6
6
|
import './score-breakdown.js';
|
|
@@ -161,8 +161,7 @@ function SignalPriorityPopover({
|
|
|
161
161
|
className,
|
|
162
162
|
initialFactorFeedback,
|
|
163
163
|
onFactorFeedback,
|
|
164
|
-
initialPriorityFeedback
|
|
165
|
-
scoreDisplay = "number"
|
|
164
|
+
initialPriorityFeedback
|
|
166
165
|
}) {
|
|
167
166
|
const urgencyLabel = providedLabel != null ? providedLabel : getUrgencyLevel(score);
|
|
168
167
|
const scoreRange = getUrgencyRange(urgencyLabel);
|
|
@@ -203,24 +202,17 @@ function SignalPriorityPopover({
|
|
|
203
202
|
className: "z-50 w-[420px] rounded-lg border border-border bg-background shadow-lg p-0",
|
|
204
203
|
"data-testid": "priority-popover-content",
|
|
205
204
|
children: [
|
|
206
|
-
/* @__PURE__ */ jsxs("div", { className: "p-4 pb-3",
|
|
205
|
+
/* @__PURE__ */ jsxs("div", { className: "p-4 pb-3", children: [
|
|
207
206
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
|
|
208
207
|
/* @__PURE__ */ jsxs("p", { className: "text-sm font-semibold text-foreground", children: [
|
|
209
208
|
"Why this is ",
|
|
210
209
|
urgencyLabel.toLowerCase(),
|
|
211
210
|
" priority"
|
|
212
211
|
] }),
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
{
|
|
216
|
-
|
|
217
|
-
"data-testid": "priority-overall-score",
|
|
218
|
-
children: [
|
|
219
|
-
score,
|
|
220
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-normal text-muted-foreground", children: "/100" })
|
|
221
|
-
]
|
|
222
|
-
}
|
|
223
|
-
)
|
|
212
|
+
/* @__PURE__ */ jsxs("span", { className: "text-2xl font-bold tabular-nums text-foreground", children: [
|
|
213
|
+
score,
|
|
214
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-normal text-muted-foreground", children: "/100" })
|
|
215
|
+
] })
|
|
224
216
|
] }),
|
|
225
217
|
/* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-1.5 text-[11px] text-muted-foreground", children: [
|
|
226
218
|
/* @__PURE__ */ jsx(
|
|
@@ -243,7 +235,7 @@ function SignalPriorityPopover({
|
|
|
243
235
|
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-bold uppercase tracking-wider text-muted-foreground", children: "Contributing factors" }),
|
|
244
236
|
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-[10px] text-muted-foreground", children: [
|
|
245
237
|
/* @__PURE__ */ jsx(Info, { className: "h-3 w-3" }),
|
|
246
|
-
"
|
|
238
|
+
"Score = weighted sum"
|
|
247
239
|
] })
|
|
248
240
|
] }),
|
|
249
241
|
/* @__PURE__ */ jsx("div", { className: "divide-y divide-border/40", children: factors.map((factor) => /* @__PURE__ */ jsx(
|