@handled-ai/design-system 0.9.20 → 0.9.21
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/signal-feedback-inline.d.ts +2 -2
- package/dist/components/signal-feedback-inline.js +149 -37
- package/dist/components/signal-feedback-inline.js.map +1 -1
- package/dist/components/suggested-actions.d.ts +1 -0
- package/dist/components/suggested-actions.js +9 -3
- package/dist/components/suggested-actions.js.map +1 -1
- package/dist/prototype/prototype-config.d.ts +2 -1
- package/dist/prototype/prototype-inbox-view.d.ts +3 -2
- package/dist/prototype/prototype-inbox-view.js +13 -8
- package/dist/prototype/prototype-inbox-view.js.map +1 -1
- package/package.json +1 -1
- package/src/components/signal-feedback-inline.tsx +169 -33
- package/src/components/suggested-actions.tsx +11 -3
- package/src/prototype/prototype-config.ts +2 -1
- package/src/prototype/prototype-inbox-view.tsx +11 -3
|
@@ -3,13 +3,65 @@
|
|
|
3
3
|
import * as React from "react"
|
|
4
4
|
import { Check, CirclePlus, ExternalLink, Lock, ThumbsDown } from "lucide-react"
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
interface DismissReasonNode {
|
|
7
|
+
label: string
|
|
8
|
+
subOptions?: string[]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const dismissReasonTree: DismissReasonNode[] = [
|
|
12
|
+
{
|
|
13
|
+
label: "Not relevant for this account",
|
|
14
|
+
subOptions: [
|
|
15
|
+
"Business as usual for this account",
|
|
16
|
+
"Account in maintenance mode",
|
|
17
|
+
"Wrong contact for this signal",
|
|
18
|
+
"Other",
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
label: "Bad timing",
|
|
23
|
+
subOptions: [
|
|
24
|
+
"Too early in the relationship",
|
|
25
|
+
"Too soon after last outreach",
|
|
26
|
+
"Wrong time of year for this account",
|
|
27
|
+
"Other",
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
label: "Inaccurate data",
|
|
32
|
+
subOptions: [
|
|
33
|
+
"Wrong amount or number",
|
|
34
|
+
"Stale data",
|
|
35
|
+
"Account info wrong",
|
|
36
|
+
"Other",
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
label: "Wrong account",
|
|
41
|
+
subOptions: [
|
|
42
|
+
"Different account meant",
|
|
43
|
+
"Account not in scope",
|
|
44
|
+
"Other",
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
label: "Already handled",
|
|
49
|
+
subOptions: [
|
|
50
|
+
"Already in conversation",
|
|
51
|
+
"Already an open Opportunity",
|
|
52
|
+
"Already escalated",
|
|
53
|
+
"Other",
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
label: "Not actionable",
|
|
58
|
+
subOptions: [
|
|
59
|
+
"No clear next step",
|
|
60
|
+
"Outside our remit",
|
|
61
|
+
"Other",
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
{ label: "Other" },
|
|
13
65
|
]
|
|
14
66
|
|
|
15
67
|
const approveReasons = [
|
|
@@ -53,7 +105,7 @@ interface SignalApprovalContextValue {
|
|
|
53
105
|
approve: () => void
|
|
54
106
|
submitApproveFeedback: (reasons: string[], detail: string) => void
|
|
55
107
|
skipApproveFeedback: () => void
|
|
56
|
-
dismiss: (reasons: string[], detail: string) => void
|
|
108
|
+
dismiss: (reasons: string[], detail: string, subReason?: string) => void
|
|
57
109
|
requestApproval: () => void
|
|
58
110
|
requestDismiss: () => void
|
|
59
111
|
cancel: () => void
|
|
@@ -78,7 +130,7 @@ interface RootProps {
|
|
|
78
130
|
hideApproveButton?: boolean
|
|
79
131
|
onApprove?: () => void
|
|
80
132
|
onApproveFeedback?: (reasons: string[], detail: string) => void
|
|
81
|
-
onDismiss?: (reasons: string[], detail: string) => void
|
|
133
|
+
onDismiss?: (reasons: string[], detail: string, subReason?: string) => void
|
|
82
134
|
}
|
|
83
135
|
|
|
84
136
|
function Root({ children, companyName, opportunityUrl, scheduledTime, initialApprovalState, labels: labelOverrides, hideApproveButton, onApprove, onApproveFeedback, onDismiss }: RootProps) {
|
|
@@ -115,9 +167,9 @@ function Root({ children, companyName, opportunityUrl, scheduledTime, initialApp
|
|
|
115
167
|
}, [])
|
|
116
168
|
|
|
117
169
|
const dismiss = React.useCallback(
|
|
118
|
-
(reasons: string[], detail: string) => {
|
|
170
|
+
(reasons: string[], detail: string, subReason?: string) => {
|
|
119
171
|
setApprovalState("dismissed")
|
|
120
|
-
onDismiss?.(reasons, detail)
|
|
172
|
+
onDismiss?.(reasons, detail, subReason)
|
|
121
173
|
},
|
|
122
174
|
[onDismiss]
|
|
123
175
|
)
|
|
@@ -134,11 +186,13 @@ function Root({ children, companyName, opportunityUrl, scheduledTime, initialApp
|
|
|
134
186
|
function SubmittedFeedback({
|
|
135
187
|
reasons,
|
|
136
188
|
detail,
|
|
189
|
+
subReason,
|
|
137
190
|
variant,
|
|
138
191
|
onEdit,
|
|
139
192
|
}: {
|
|
140
193
|
reasons: string[]
|
|
141
194
|
detail: string
|
|
195
|
+
subReason?: string
|
|
142
196
|
variant: "approve" | "dismiss"
|
|
143
197
|
onEdit: () => void
|
|
144
198
|
}) {
|
|
@@ -164,6 +218,13 @@ function SubmittedFeedback({
|
|
|
164
218
|
{r}
|
|
165
219
|
</span>
|
|
166
220
|
))}
|
|
221
|
+
{subReason && (
|
|
222
|
+
<span
|
|
223
|
+
className={`rounded-full border px-2 py-0.5 text-[10px] font-medium transition-colors group-hover:opacity-80 ${pillClass}`}
|
|
224
|
+
>
|
|
225
|
+
{subReason}
|
|
226
|
+
</span>
|
|
227
|
+
)}
|
|
167
228
|
</div>
|
|
168
229
|
)}
|
|
169
230
|
{detail && (
|
|
@@ -176,15 +237,41 @@ function SubmittedFeedback({
|
|
|
176
237
|
function Actions() {
|
|
177
238
|
const { approvalState, companyName, opportunityUrl, scheduledTime, labels, hideApproveButton, approve, submitApproveFeedback, skipApproveFeedback, dismiss, requestApproval, requestDismiss, cancel } =
|
|
178
239
|
useSignalApproval()
|
|
240
|
+
const [selectedTopReason, setSelectedTopReason] = React.useState<string | null>(null)
|
|
241
|
+
const [selectedSubReason, setSelectedSubReason] = React.useState<string | null>(null)
|
|
179
242
|
const [selectedReasons, setSelectedReasons] = React.useState<string[]>([])
|
|
180
243
|
const [detailText, setDetailText] = React.useState("")
|
|
181
|
-
const [submittedFeedback, setSubmittedFeedback] = React.useState<{ reasons: string[]; detail: string } | null>(null)
|
|
244
|
+
const [submittedFeedback, setSubmittedFeedback] = React.useState<{ reasons: string[]; detail: string; subReason?: string } | null>(null)
|
|
182
245
|
const [isEditing, setIsEditing] = React.useState(false)
|
|
183
246
|
|
|
184
|
-
const
|
|
185
|
-
const
|
|
247
|
+
const topNode = dismissReasonTree.find((n) => n.label === selectedTopReason)
|
|
248
|
+
const hasSubOptions = !!(topNode?.subOptions && topNode.subOptions.length > 0)
|
|
249
|
+
const isTopOther = selectedTopReason === "Other" && !hasSubOptions
|
|
250
|
+
const isSubOther = selectedSubReason === "Other"
|
|
251
|
+
const needsText = isTopOther || isSubOther
|
|
252
|
+
const canSubmitDismiss =
|
|
253
|
+
selectedTopReason !== null &&
|
|
254
|
+
(!hasSubOptions || selectedSubReason !== null) &&
|
|
255
|
+
(!needsText || detailText.trim().length > 0)
|
|
256
|
+
|
|
186
257
|
const canSubmitApprove = selectedReasons.length > 0 || detailText.trim().length > 0
|
|
187
258
|
|
|
259
|
+
const selectTopReason = (label: string) => {
|
|
260
|
+
if (selectedTopReason === label) {
|
|
261
|
+
setSelectedTopReason(null)
|
|
262
|
+
setSelectedSubReason(null)
|
|
263
|
+
setDetailText("")
|
|
264
|
+
} else {
|
|
265
|
+
setSelectedTopReason(label)
|
|
266
|
+
setSelectedSubReason(null)
|
|
267
|
+
setDetailText("")
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const selectSubReason = (label: string) => {
|
|
272
|
+
setSelectedSubReason(selectedSubReason === label ? null : label)
|
|
273
|
+
}
|
|
274
|
+
|
|
188
275
|
const toggleReason = (reason: string) => {
|
|
189
276
|
setSelectedReasons((prev) =>
|
|
190
277
|
prev.includes(reason) ? prev.filter((r) => r !== reason) : [...prev, reason]
|
|
@@ -193,6 +280,8 @@ function Actions() {
|
|
|
193
280
|
|
|
194
281
|
const startEditing = () => {
|
|
195
282
|
if (submittedFeedback) {
|
|
283
|
+
setSelectedTopReason(submittedFeedback.reasons[0] ?? null)
|
|
284
|
+
setSelectedSubReason(submittedFeedback.subReason ?? null)
|
|
196
285
|
setSelectedReasons([...submittedFeedback.reasons])
|
|
197
286
|
setDetailText(submittedFeedback.detail)
|
|
198
287
|
}
|
|
@@ -200,11 +289,12 @@ function Actions() {
|
|
|
200
289
|
}
|
|
201
290
|
|
|
202
291
|
const handleDismissSubmit = () => {
|
|
203
|
-
if (!canSubmitDismiss) return
|
|
204
|
-
const fb = { reasons: [
|
|
292
|
+
if (!canSubmitDismiss || !selectedTopReason) return
|
|
293
|
+
const fb = { reasons: [selectedTopReason], detail: detailText.trim(), subReason: selectedSubReason ?? undefined }
|
|
205
294
|
setSubmittedFeedback(fb)
|
|
206
|
-
dismiss(
|
|
207
|
-
|
|
295
|
+
dismiss([selectedTopReason], detailText.trim(), selectedSubReason ?? undefined)
|
|
296
|
+
setSelectedTopReason(null)
|
|
297
|
+
setSelectedSubReason(null)
|
|
208
298
|
setDetailText("")
|
|
209
299
|
setIsEditing(false)
|
|
210
300
|
}
|
|
@@ -219,6 +309,8 @@ function Actions() {
|
|
|
219
309
|
}
|
|
220
310
|
|
|
221
311
|
const handleEditCancel = () => {
|
|
312
|
+
setSelectedTopReason(null)
|
|
313
|
+
setSelectedSubReason(null)
|
|
222
314
|
setSelectedReasons([])
|
|
223
315
|
setDetailText("")
|
|
224
316
|
setIsEditing(false)
|
|
@@ -226,6 +318,8 @@ function Actions() {
|
|
|
226
318
|
|
|
227
319
|
const handleCancel = () => {
|
|
228
320
|
cancel()
|
|
321
|
+
setSelectedTopReason(null)
|
|
322
|
+
setSelectedSubReason(null)
|
|
229
323
|
setSelectedReasons([])
|
|
230
324
|
setDetailText("")
|
|
231
325
|
}
|
|
@@ -404,20 +498,37 @@ function Actions() {
|
|
|
404
498
|
</div>
|
|
405
499
|
<p className="text-xs font-medium text-muted-foreground">Edit your feedback</p>
|
|
406
500
|
<div className="flex flex-wrap gap-1.5">
|
|
407
|
-
{
|
|
408
|
-
const selected =
|
|
501
|
+
{dismissReasonTree.map((node) => {
|
|
502
|
+
const selected = selectedTopReason === node.label
|
|
409
503
|
return (
|
|
410
|
-
<button key={
|
|
504
|
+
<button key={node.label} type="button" onClick={() => selectTopReason(node.label)}
|
|
411
505
|
className={`rounded-full border px-2.5 py-1 text-[11px] font-medium transition-colors ${
|
|
412
506
|
selected ? "border-red-200 bg-red-100 text-red-700" : "border-border bg-background text-muted-foreground hover:bg-muted/50 hover:text-foreground"
|
|
413
|
-
}`}>{
|
|
507
|
+
}`}>{node.label}</button>
|
|
414
508
|
)
|
|
415
509
|
})}
|
|
416
510
|
</div>
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
511
|
+
{topNode?.subOptions && (
|
|
512
|
+
<div className="ml-3 border-l-2 border-muted pl-3">
|
|
513
|
+
<div className="flex flex-wrap gap-1.5">
|
|
514
|
+
{topNode.subOptions.map((sub) => {
|
|
515
|
+
const selected = selectedSubReason === sub
|
|
516
|
+
return (
|
|
517
|
+
<button key={sub} type="button" onClick={() => selectSubReason(sub)}
|
|
518
|
+
className={`rounded-full border px-2.5 py-1 text-[11px] font-medium transition-colors ${
|
|
519
|
+
selected ? "border-red-200 bg-red-100 text-red-700" : "border-border bg-background text-muted-foreground hover:bg-muted/50 hover:text-foreground"
|
|
520
|
+
}`}>{sub}</button>
|
|
521
|
+
)
|
|
522
|
+
})}
|
|
523
|
+
</div>
|
|
524
|
+
</div>
|
|
525
|
+
)}
|
|
526
|
+
{selectedTopReason && (
|
|
527
|
+
<input type="text" value={detailText} onChange={(e) => setDetailText(e.target.value)}
|
|
528
|
+
onKeyDown={(e) => { if (e.key === "Enter" && canSubmitDismiss) handleDismissSubmit() }}
|
|
529
|
+
placeholder={needsText ? "Please describe (required)" : "Add context (optional)"}
|
|
530
|
+
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" />
|
|
531
|
+
)}
|
|
421
532
|
<div className="flex items-center gap-2">
|
|
422
533
|
<button type="button" onClick={handleDismissSubmit} disabled={!canSubmitDismiss}
|
|
423
534
|
className={`inline-flex h-7 items-center gap-1.5 rounded-md px-3 text-xs font-semibold transition-colors ${canSubmitDismiss ? "bg-foreground text-background hover:bg-foreground/90" : "cursor-not-allowed bg-muted text-muted-foreground"}`}>
|
|
@@ -442,6 +553,7 @@ function Actions() {
|
|
|
442
553
|
<SubmittedFeedback
|
|
443
554
|
reasons={submittedFeedback.reasons}
|
|
444
555
|
detail={submittedFeedback.detail}
|
|
556
|
+
subReason={submittedFeedback.subReason}
|
|
445
557
|
variant="dismiss"
|
|
446
558
|
onEdit={startEditing}
|
|
447
559
|
/>
|
|
@@ -484,26 +596,50 @@ function Actions() {
|
|
|
484
596
|
<div className="space-y-3">
|
|
485
597
|
<p className="text-xs font-medium text-muted-foreground">{labels.dismissPrompt}</p>
|
|
486
598
|
<div className="flex flex-wrap gap-1.5">
|
|
487
|
-
{
|
|
488
|
-
const selected =
|
|
599
|
+
{dismissReasonTree.map((node) => {
|
|
600
|
+
const selected = selectedTopReason === node.label
|
|
489
601
|
return (
|
|
490
602
|
<button
|
|
491
|
-
key={
|
|
603
|
+
key={node.label}
|
|
492
604
|
type="button"
|
|
493
|
-
onClick={() =>
|
|
605
|
+
onClick={() => selectTopReason(node.label)}
|
|
494
606
|
className={`rounded-full border px-2.5 py-1 text-[11px] font-medium transition-colors ${
|
|
495
607
|
selected
|
|
496
608
|
? "border-red-200 bg-red-100 text-red-700"
|
|
497
609
|
: "border-border bg-background text-muted-foreground hover:bg-muted/50 hover:text-foreground"
|
|
498
610
|
}`}
|
|
499
611
|
>
|
|
500
|
-
{
|
|
612
|
+
{node.label}
|
|
501
613
|
</button>
|
|
502
614
|
)
|
|
503
615
|
})}
|
|
504
616
|
</div>
|
|
505
617
|
|
|
506
|
-
{
|
|
618
|
+
{topNode?.subOptions && (
|
|
619
|
+
<div className="ml-3 border-l-2 border-muted pl-3">
|
|
620
|
+
<div className="flex flex-wrap gap-1.5">
|
|
621
|
+
{topNode.subOptions.map((sub) => {
|
|
622
|
+
const selected = selectedSubReason === sub
|
|
623
|
+
return (
|
|
624
|
+
<button
|
|
625
|
+
key={sub}
|
|
626
|
+
type="button"
|
|
627
|
+
onClick={() => selectSubReason(sub)}
|
|
628
|
+
className={`rounded-full border px-2.5 py-1 text-[11px] font-medium transition-colors ${
|
|
629
|
+
selected
|
|
630
|
+
? "border-red-200 bg-red-100 text-red-700"
|
|
631
|
+
: "border-border bg-background text-muted-foreground hover:bg-muted/50 hover:text-foreground"
|
|
632
|
+
}`}
|
|
633
|
+
>
|
|
634
|
+
{sub}
|
|
635
|
+
</button>
|
|
636
|
+
)
|
|
637
|
+
})}
|
|
638
|
+
</div>
|
|
639
|
+
</div>
|
|
640
|
+
)}
|
|
641
|
+
|
|
642
|
+
{selectedTopReason && (
|
|
507
643
|
<input
|
|
508
644
|
type="text"
|
|
509
645
|
value={detailText}
|
|
@@ -511,7 +647,7 @@ function Actions() {
|
|
|
511
647
|
onKeyDown={(e) => {
|
|
512
648
|
if (e.key === "Enter" && canSubmitDismiss) handleDismissSubmit()
|
|
513
649
|
}}
|
|
514
|
-
placeholder={
|
|
650
|
+
placeholder={needsText ? "Please describe (required)" : "Add context (optional)"}
|
|
515
651
|
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"
|
|
516
652
|
/>
|
|
517
653
|
)}
|
|
@@ -167,6 +167,7 @@ export interface SuggestedAction {
|
|
|
167
167
|
callMeta?: SuggestedActionCallMeta
|
|
168
168
|
manualMeta?: SuggestedActionManualMeta
|
|
169
169
|
browserMeta?: SuggestedActionBrowserMeta
|
|
170
|
+
onFeedback?: (type: "up" | "down", pills: string[], detail: string) => void
|
|
170
171
|
}
|
|
171
172
|
|
|
172
173
|
// ---------------------------------------------------------------------------
|
|
@@ -1253,6 +1254,7 @@ function SuggestedActionCard({
|
|
|
1253
1254
|
onOpenRecentActivity,
|
|
1254
1255
|
onMarkComplete,
|
|
1255
1256
|
onDispatchAgent,
|
|
1257
|
+
onFeedback,
|
|
1256
1258
|
iconMap,
|
|
1257
1259
|
sendLabel,
|
|
1258
1260
|
accountDetailsLabel,
|
|
@@ -1269,6 +1271,7 @@ function SuggestedActionCard({
|
|
|
1269
1271
|
onOpenRecentActivity?: () => void
|
|
1270
1272
|
onMarkComplete?: (id: number | string) => void
|
|
1271
1273
|
onDispatchAgent?: (id: number | string, editedContent?: string, settings?: { aiDisclosureEnabled?: boolean; maxDurationMinutes?: string; callRecordingEnabled?: boolean; recordingNoticeEnabled?: boolean }) => void
|
|
1274
|
+
onFeedback?: (type: "up" | "down", pills: string[], detail: string) => void
|
|
1272
1275
|
iconMap?: SuggestedActionsIconMap
|
|
1273
1276
|
sendLabel?: string
|
|
1274
1277
|
accountDetailsLabel?: string
|
|
@@ -1405,10 +1408,14 @@ function SuggestedActionCard({
|
|
|
1405
1408
|
{feedbackOpen && (
|
|
1406
1409
|
<div className="px-5 py-3 border-b border-border/40 animate-in fade-in slide-in-from-top-2 duration-200">
|
|
1407
1410
|
<DraftFeedbackInline
|
|
1408
|
-
onRegenerateRequest={(pills, detail) =>
|
|
1409
|
-
|
|
1411
|
+
onRegenerateRequest={(pills, detail) => {
|
|
1412
|
+
onFeedback?.("down", pills, detail)
|
|
1413
|
+
}}
|
|
1414
|
+
onSubmitFeedback={(type, pills, detail) => {
|
|
1415
|
+
onFeedback?.(type, pills, detail)
|
|
1416
|
+
}}
|
|
1410
1417
|
onDiscardRequest={(pills, detail) => {
|
|
1411
|
-
|
|
1418
|
+
onFeedback?.("down", pills, detail)
|
|
1412
1419
|
onDismiss?.(action.id)
|
|
1413
1420
|
}}
|
|
1414
1421
|
/>
|
|
@@ -1972,6 +1979,7 @@ export function SuggestedActions({
|
|
|
1972
1979
|
onOpenRecentActivity={onOpenRecentActivity}
|
|
1973
1980
|
onMarkComplete={onMarkComplete}
|
|
1974
1981
|
onDispatchAgent={onDispatchAgent}
|
|
1982
|
+
onFeedback={action.onFeedback}
|
|
1975
1983
|
iconMap={iconMap}
|
|
1976
1984
|
sendLabel={sendLabel}
|
|
1977
1985
|
accountDetailsLabel={accountDetailsLabel}
|
|
@@ -44,7 +44,7 @@ export interface SignalScoreData {
|
|
|
44
44
|
confidence: number
|
|
45
45
|
onFactorFeedback?: (factorKey: string, type: "up" | "down" | null, detail?: string) => void
|
|
46
46
|
onApproveFeedback?: (reasons: string[], detail: string) => void
|
|
47
|
-
onDismissFeedback?: (reasons: string[], detail: string) => void
|
|
47
|
+
onDismissFeedback?: (reasons: string[], detail: string, subReason?: string) => void
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
// ---------------------------------------------------------------------------
|
|
@@ -72,6 +72,7 @@ export interface InboxViewConfig {
|
|
|
72
72
|
hideToolbarActions?: boolean
|
|
73
73
|
hideHoverActions?: boolean
|
|
74
74
|
onSuggestedActionFeedback?: (actionId: number | string, feedback: string, actionTitle?: string) => void
|
|
75
|
+
onScoreFeedback?: (type: "up" | "down", pills: string[], detail: string) => void
|
|
75
76
|
buildEntityChips?: (item: QueueItem) => Array<{ id: string; label: string; avatarLetter: string; onClick?: () => void }>
|
|
76
77
|
quickFilterTabs?: Array<{ id: string; label: string; matchValue?: string; count?: number }>
|
|
77
78
|
hideAccountsButton?: boolean
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
} from "../components/inbox-toolbar"
|
|
31
31
|
import { GroupedListView, type GroupedListGroup } from "../components/item-list"
|
|
32
32
|
import { SignalApproval, type ApprovalState } from "../components/signal-feedback-inline"
|
|
33
|
+
import { ScoreFeedback } from "../components/score-feedback"
|
|
33
34
|
import { ScoreBreakdown } from "../components/score-breakdown"
|
|
34
35
|
import { Citation, type SourceDef } from "../components/detail-view"
|
|
35
36
|
import {
|
|
@@ -107,6 +108,7 @@ export interface DetailViewProps {
|
|
|
107
108
|
hideApproveButton?: boolean
|
|
108
109
|
signalBriefCopy?: InboxViewConfig["signalBriefCopy"]
|
|
109
110
|
renderDetailExtra?: (item: QueueItem) => React.ReactNode
|
|
111
|
+
onScoreFeedback?: (type: "up" | "down", pills: string[], detail: string) => void
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
export function DetailView({
|
|
@@ -128,6 +130,7 @@ export function DetailView({
|
|
|
128
130
|
hideApproveButton,
|
|
129
131
|
signalBriefCopy,
|
|
130
132
|
renderDetailExtra,
|
|
133
|
+
onScoreFeedback,
|
|
131
134
|
}: DetailViewProps) {
|
|
132
135
|
const [evidenceExpanded, setEvidenceExpanded] = React.useState(false)
|
|
133
136
|
const [showTimeline, setShowTimeline] = React.useState(false)
|
|
@@ -180,9 +183,8 @@ export function DetailView({
|
|
|
180
183
|
signalData.onApproveFeedback?.(reasons, detail)
|
|
181
184
|
console.log("Approval feedback:", { taskId: item.id, company: item.company, reasons, detail })
|
|
182
185
|
}}
|
|
183
|
-
onDismiss={(reasons, detail) => {
|
|
184
|
-
signalData.onDismissFeedback?.(reasons, detail)
|
|
185
|
-
console.log("Dismissed signal:", { taskId: item.id, reasons, detail })
|
|
186
|
+
onDismiss={(reasons, detail, subReason) => {
|
|
187
|
+
signalData.onDismissFeedback?.(reasons, detail, subReason)
|
|
186
188
|
}}
|
|
187
189
|
>
|
|
188
190
|
<div className="mx-auto w-full max-w-3xl p-6 pb-12 md:p-8">
|
|
@@ -277,14 +279,17 @@ export function DetailView({
|
|
|
277
279
|
{signalData.whyNow}
|
|
278
280
|
</p>
|
|
279
281
|
|
|
282
|
+
<ScoreFeedback.Root onSubmitFeedback={(type, pills, detail) => onScoreFeedback?.(type, pills, detail)}>
|
|
280
283
|
<div className="mb-5 rounded-md border border-border bg-muted/20 p-3">
|
|
281
284
|
<div className="flex items-center justify-between mb-1.5">
|
|
282
285
|
<span className="text-[10px] font-bold text-muted-foreground uppercase tracking-wider">Signal Score</span>
|
|
283
286
|
<div className="flex items-center gap-2">
|
|
284
287
|
<span className="text-sm font-bold text-foreground">{signalData.score}/100</span>
|
|
285
288
|
<span className={`text-[10px] font-bold uppercase ${scoreColor}`}>{scoreLabel}</span>
|
|
289
|
+
<ScoreFeedback.Trigger />
|
|
286
290
|
</div>
|
|
287
291
|
</div>
|
|
292
|
+
<ScoreFeedback.Panel />
|
|
288
293
|
<div className="h-1.5 bg-muted rounded-full overflow-hidden mb-2">
|
|
289
294
|
<div
|
|
290
295
|
className={`h-full rounded-full transition-all duration-500 ${barColor}`}
|
|
@@ -320,6 +325,7 @@ export function DetailView({
|
|
|
320
325
|
</div>
|
|
321
326
|
)}
|
|
322
327
|
</div>
|
|
328
|
+
</ScoreFeedback.Root>
|
|
323
329
|
|
|
324
330
|
{!evidenceExpanded && <SignalApproval.Actions />}
|
|
325
331
|
</div>
|
|
@@ -398,6 +404,7 @@ export function PrototypeInboxView({
|
|
|
398
404
|
hideToolbarActions,
|
|
399
405
|
hideHoverActions,
|
|
400
406
|
onSuggestedActionFeedback,
|
|
407
|
+
onScoreFeedback,
|
|
401
408
|
headerActions,
|
|
402
409
|
onOpenEntityPanel,
|
|
403
410
|
onOpenRecentActivity,
|
|
@@ -640,6 +647,7 @@ export function PrototypeInboxView({
|
|
|
640
647
|
hideApproveButton,
|
|
641
648
|
signalBriefCopy,
|
|
642
649
|
renderDetailExtra,
|
|
650
|
+
onScoreFeedback,
|
|
643
651
|
}
|
|
644
652
|
|
|
645
653
|
return (
|