@handled-ai/design-system 0.18.2 → 0.18.3

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.
Files changed (37) hide show
  1. package/dist/charts/chart.d.ts +1 -1
  2. package/dist/components/feedback-primitives.d.ts +2 -21
  3. package/dist/components/feedback-primitives.js +6 -90
  4. package/dist/components/feedback-primitives.js.map +1 -1
  5. package/dist/components/score-why-chips.d.ts +1 -1
  6. package/dist/components/score-why-chips.js +5 -26
  7. package/dist/components/score-why-chips.js.map +1 -1
  8. package/dist/components/signal-priority-popover.d.ts +1 -1
  9. package/dist/components/signal-priority-popover.js +7 -172
  10. package/dist/components/signal-priority-popover.js.map +1 -1
  11. package/dist/components/timeline-activity.d.ts +16 -1
  12. package/dist/components/timeline-activity.js +69 -1
  13. package/dist/components/timeline-activity.js.map +1 -1
  14. package/dist/index.d.ts +3 -3
  15. package/dist/index.js.map +1 -1
  16. package/dist/prototype/index.d.ts +1 -1
  17. package/dist/prototype/prototype-accounts-view.d.ts +1 -1
  18. package/dist/prototype/prototype-admin-view.d.ts +1 -1
  19. package/dist/prototype/prototype-config.d.ts +1 -1
  20. package/dist/prototype/prototype-inbox-view.d.ts +12 -2
  21. package/dist/prototype/prototype-inbox-view.js +102 -37
  22. package/dist/prototype/prototype-inbox-view.js.map +1 -1
  23. package/dist/prototype/prototype-insights-view.d.ts +1 -1
  24. package/dist/prototype/prototype-shell.d.ts +1 -1
  25. package/dist/{signal-priority-popover-DWaAMhPI.d.ts → signal-priority-popover-DQ_VuHac.d.ts} +2 -26
  26. package/package.json +1 -3
  27. package/src/components/__tests__/timeline-activity.test.tsx +137 -0
  28. package/src/components/feedback-primitives.tsx +26 -148
  29. package/src/components/score-why-chips.tsx +2 -28
  30. package/src/components/signal-priority-popover.tsx +3 -194
  31. package/src/components/timeline-activity.tsx +112 -1
  32. package/src/index.ts +1 -1
  33. package/src/prototype/__tests__/detail-view-attention.test.tsx +2 -2
  34. package/src/prototype/__tests__/detail-view-timeline-system-events.test.tsx +322 -0
  35. package/src/prototype/prototype-config.ts +1 -11
  36. package/src/prototype/prototype-inbox-view.tsx +131 -33
  37. package/src/components/__tests__/wit-636-feedback-states.test.tsx +0 -546
@@ -48,7 +48,7 @@ declare function ChartTooltipContent({ active, payload, className, indicator, hi
48
48
  labelClassName?: string;
49
49
  color?: string;
50
50
  }): React.JSX.Element | null;
51
- declare const ChartLegend: React.MemoExoticComponent<(outsideProps: RechartsPrimitive.LegendProps) => React.ReactPortal | null>;
51
+ declare const ChartLegend: typeof RechartsPrimitive.Legend;
52
52
  type LegendPayloadItem = {
53
53
  value?: string;
54
54
  dataKey?: string;
@@ -16,18 +16,6 @@ interface FeedbackSubmitData {
16
16
  pills: string[];
17
17
  detail: string;
18
18
  }
19
- /**
20
- * Persisted feedback data from a previous submission, used to hydrate the
21
- * footer into its "already submitted" visual state.
22
- */
23
- interface PersistedFeedbackData {
24
- sentiment: "positive" | "negative";
25
- reasonTop?: string;
26
- reasonSub?: string;
27
- pills?: string[];
28
- detail?: string;
29
- ownershipLabel: "Your feedback" | "Team feedback";
30
- }
31
19
  /**
32
20
  * Defines a tier-1 chip that may have tier-2 sub-chips.
33
21
  */
@@ -72,14 +60,7 @@ interface FeedbackFooterProps {
72
60
  negativeChips?: FeedbackChipTree[];
73
61
  positiveChips?: string[];
74
62
  className?: string;
75
- /** Pre-existing feedback to hydrate from (e.g. after page reload). */
76
- initialFeedback?: PersistedFeedbackData | null;
77
- /** Label shown in the transient confirmation pill after submit. */
78
- submittedLabel?: string;
79
- /** Stable key for syncing initialFeedback into local state. When this
80
- * changes, the component resets to the new initialFeedback value. */
81
- feedbackKey?: string;
82
63
  }
83
- declare function FeedbackFooter({ feedback, onFeedbackChange, onSubmit, metaText, positivePrompt, negativePrompt, negativeChips, positiveChips, className, initialFeedback, submittedLabel, feedbackKey, }: FeedbackFooterProps): React.JSX.Element;
64
+ declare function FeedbackFooter({ feedback, onFeedbackChange, onSubmit, metaText, positivePrompt, negativePrompt, negativeChips, positiveChips, className, }: FeedbackFooterProps): React.JSX.Element;
84
65
 
85
- export { FeedbackActions, type FeedbackActionsProps, FeedbackChipGroup, type FeedbackChipGroupProps, type FeedbackChipTree, FeedbackFooter, type FeedbackFooterProps, FeedbackInput, type FeedbackInputProps, type FeedbackSubmitData, type PersistedFeedbackData };
66
+ export { FeedbackActions, type FeedbackActionsProps, FeedbackChipGroup, type FeedbackChipGroupProps, type FeedbackChipTree, FeedbackFooter, type FeedbackFooterProps, FeedbackInput, type FeedbackInputProps, type FeedbackSubmitData };
@@ -3,7 +3,7 @@
3
3
  "use client";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
  import * as React from "react";
6
- import { ThumbsUp, ThumbsDown, Check, Pencil } from "lucide-react";
6
+ import { ThumbsUp, ThumbsDown } from "lucide-react";
7
7
  import { cn } from "../lib/utils.js";
8
8
  const CHIP_SELECTED_CLASSES = {
9
9
  negative: "bg-red-50 text-red-700 border-red-200",
@@ -107,10 +107,7 @@ function FeedbackFooter({
107
107
  negativePrompt = "What's the issue?",
108
108
  negativeChips = [],
109
109
  positiveChips = [],
110
- className,
111
- initialFeedback,
112
- submittedLabel = "Saved",
113
- feedbackKey
110
+ className
114
111
  }) {
115
112
  const [expanded, setExpanded] = React.useState(false);
116
113
  const [selectedTier1, setSelectedTier1] = React.useState(null);
@@ -120,32 +117,6 @@ function FeedbackFooter({
120
117
  const [activeTreeIndex, setActiveTreeIndex] = React.useState(
121
118
  null
122
119
  );
123
- const [submitted, setSubmitted] = React.useState(false);
124
- const [persisted, setPersisted] = React.useState(
125
- initialFeedback != null ? initialFeedback : null
126
- );
127
- const [isEditing, setIsEditing] = React.useState(false);
128
- const lastKeyRef = React.useRef(feedbackKey);
129
- React.useEffect(() => {
130
- const keyChanged = feedbackKey !== lastKeyRef.current;
131
- lastKeyRef.current = feedbackKey;
132
- if (keyChanged) {
133
- setPersisted(initialFeedback != null ? initialFeedback : null);
134
- setSubmitted(false);
135
- setExpanded(false);
136
- setIsEditing(false);
137
- if (initialFeedback) {
138
- onFeedbackChange(initialFeedback.sentiment);
139
- } else {
140
- onFeedbackChange(null);
141
- }
142
- } else if (!isEditing) {
143
- setPersisted(initialFeedback != null ? initialFeedback : null);
144
- if (initialFeedback) {
145
- onFeedbackChange(initialFeedback.sentiment);
146
- }
147
- }
148
- }, [initialFeedback, feedbackKey]);
149
120
  const resetState = React.useCallback(() => {
150
121
  setExpanded(false);
151
122
  setSelectedTier1(null);
@@ -153,31 +124,15 @@ function FeedbackFooter({
153
124
  setAdditionalPills([]);
154
125
  setDetailText("");
155
126
  setActiveTreeIndex(null);
156
- setIsEditing(false);
157
127
  }, []);
158
128
  const handleSentimentClick = React.useCallback(
159
129
  (sentiment) => {
160
130
  onFeedbackChange(sentiment);
161
131
  resetState();
162
132
  setExpanded(true);
163
- setSubmitted(false);
164
- setPersisted(null);
165
- setIsEditing(true);
166
133
  },
167
134
  [onFeedbackChange, resetState]
168
135
  );
169
- const handlePersistedClick = React.useCallback(() => {
170
- var _a, _b, _c, _d;
171
- if (!persisted) return;
172
- onFeedbackChange(persisted.sentiment);
173
- setSelectedTier1((_a = persisted.reasonTop) != null ? _a : null);
174
- setSelectedTier2((_b = persisted.reasonSub) != null ? _b : null);
175
- setAdditionalPills((_c = persisted.pills) != null ? _c : []);
176
- setDetailText((_d = persisted.detail) != null ? _d : "");
177
- setExpanded(true);
178
- setSubmitted(false);
179
- setIsEditing(true);
180
- }, [persisted, onFeedbackChange]);
181
136
  const handleTier1Toggle = React.useCallback(
182
137
  (chipLabel) => {
183
138
  if (selectedTier1 === chipLabel) {
@@ -227,21 +182,15 @@ function FeedbackFooter({
227
182
  pills: additionalPills,
228
183
  detail: detailText
229
184
  });
230
- setSubmitted(true);
231
- setExpanded(false);
232
- setSelectedTier1(null);
233
- setSelectedTier2(null);
234
- setAdditionalPills([]);
235
- setDetailText("");
236
- setActiveTreeIndex(null);
237
- setIsEditing(false);
185
+ resetState();
238
186
  }, [
239
187
  feedback,
240
188
  selectedTier1,
241
189
  selectedTier2,
242
190
  additionalPills,
243
191
  detailText,
244
- onSubmit
192
+ onSubmit,
193
+ resetState
245
194
  ]);
246
195
  const handleCancel = React.useCallback(() => {
247
196
  resetState();
@@ -254,30 +203,9 @@ function FeedbackFooter({
254
203
  return result;
255
204
  }, [selectedTier1, additionalPills]);
256
205
  const activeTree = activeTreeIndex !== null ? negativeChips[activeTreeIndex] : null;
257
- const showPersistedIndicator = persisted && !expanded && !submitted;
258
206
  return /* @__PURE__ */ jsxs("div", { className: cn("space-y-3", className), children: [
259
207
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
260
- showPersistedIndicator ? (
261
- /* Persisted feedback indicator — clickable to reopen editor */
262
- /* @__PURE__ */ jsxs(
263
- "button",
264
- {
265
- type: "button",
266
- onClick: handlePersistedClick,
267
- className: "group flex items-center gap-1.5 text-[11px] text-muted-foreground hover:text-foreground transition-colors",
268
- "data-testid": "persisted-feedback-indicator",
269
- children: [
270
- /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
271
- persisted.ownershipLabel,
272
- ":"
273
- ] }),
274
- persisted.sentiment === "positive" ? /* @__PURE__ */ jsx(ThumbsUp, { className: "h-[11px] w-[11px]" }) : /* @__PURE__ */ jsx(ThumbsDown, { className: "h-[11px] w-[11px]" }),
275
- persisted.detail && /* @__PURE__ */ jsx("span", { className: "max-w-[200px] truncate text-muted-foreground/70", children: persisted.detail }),
276
- /* @__PURE__ */ jsx(Pencil, { className: "h-[9px] w-[9px] opacity-0 group-hover:opacity-100 transition-opacity" })
277
- ]
278
- }
279
- )
280
- ) : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
208
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
281
209
  /* @__PURE__ */ jsxs(
282
210
  "button",
283
211
  {
@@ -307,18 +235,6 @@ function FeedbackFooter({
307
235
  "Not helpful"
308
236
  ]
309
237
  }
310
- ),
311
- submitted && feedback && /* @__PURE__ */ jsxs(
312
- "span",
313
- {
314
- className: "inline-flex items-center gap-1 text-[11px] font-medium text-emerald-600",
315
- role: "status",
316
- "data-testid": "feedback-submitted-pill",
317
- children: [
318
- /* @__PURE__ */ jsx(Check, { className: "h-[11px] w-[11px]" }),
319
- submittedLabel
320
- ]
321
- }
322
238
  )
323
239
  ] }),
324
240
  metaText && /* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground", children: metaText })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/feedback-primitives.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { ThumbsUp, ThumbsDown, Check, Pencil } from \"lucide-react\"\nimport { cn } from \"../lib/utils\"\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Structured feedback data shape.\n *\n * Preserves the tree structure for DB persistence:\n * reasonTop -> tier-1 chip label (maps to case_feedback.reason_top)\n * reasonSub -> tier-2 sub-chip label (maps to case_feedback.reason_sub)\n * pills -> any additional selected chips (maps to case_feedback.pills)\n * detail -> free-text input (maps to case_feedback.free_text)\n */\nexport interface FeedbackSubmitData {\n sentiment: \"positive\" | \"negative\"\n reasonTop?: string\n reasonSub?: string\n pills: string[]\n detail: string\n}\n\n/**\n * Persisted feedback data from a previous submission, used to hydrate the\n * footer into its \"already submitted\" visual state.\n */\nexport interface PersistedFeedbackData {\n sentiment: \"positive\" | \"negative\"\n reasonTop?: string\n reasonSub?: string\n pills?: string[]\n detail?: string\n ownershipLabel: \"Your feedback\" | \"Team feedback\"\n}\n\n/**\n * Defines a tier-1 chip that may have tier-2 sub-chips.\n */\nexport interface FeedbackChipTree {\n label: string\n subPrompt?: string\n subChips?: string[]\n}\n\n// ---------------------------------------------------------------------------\n// FeedbackChipGroup\n// ---------------------------------------------------------------------------\n\nexport interface FeedbackChipGroupProps {\n chips: string[]\n selected: string[]\n onToggle: (chip: string) => void\n flavor: \"positive\" | \"negative\"\n className?: string\n}\n\nconst CHIP_SELECTED_CLASSES: Record<\"positive\" | \"negative\", string> = {\n negative: \"bg-red-50 text-red-700 border-red-200\",\n positive: \"bg-muted text-foreground border-border\",\n}\n\nconst CHIP_IDLE_CLASS =\n \"bg-background text-muted-foreground border-border hover:bg-muted/50\"\n\nexport function FeedbackChipGroup({\n chips,\n selected,\n onToggle,\n flavor,\n className,\n}: FeedbackChipGroupProps) {\n return (\n <div className={cn(\"flex flex-wrap gap-1.5\", className)}>\n {chips.map((chip) => {\n const isSelected = selected.includes(chip)\n return (\n <button\n key={chip}\n type=\"button\"\n onClick={() => onToggle(chip)}\n className={cn(\n \"rounded-md px-2.5 py-1 text-[11px] font-medium border transition-colors\",\n isSelected ? CHIP_SELECTED_CLASSES[flavor] : CHIP_IDLE_CLASS,\n )}\n >\n {chip}\n </button>\n )\n })}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// FeedbackInput\n// ---------------------------------------------------------------------------\n\nexport interface FeedbackInputProps {\n placeholder?: string\n value: string\n onChange: (value: string) => void\n onSubmit?: () => void\n className?: string\n}\n\nexport function FeedbackInput({\n placeholder,\n value,\n onChange,\n onSubmit,\n className,\n}: FeedbackInputProps) {\n return (\n <input\n type=\"text\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && onSubmit) {\n e.preventDefault()\n onSubmit()\n }\n }}\n placeholder={placeholder}\n className={cn(\n \"w-full text-xs bg-background border border-border rounded-md px-2.5 py-2 text-foreground placeholder:text-muted-foreground/50 focus:outline-none focus:ring-1 focus:ring-ring\",\n className,\n )}\n />\n )\n}\n\n// ---------------------------------------------------------------------------\n// FeedbackActions\n// ---------------------------------------------------------------------------\n\nexport interface FeedbackActionsProps {\n onSubmit: () => void\n onCancel: () => void\n submitDisabled?: boolean\n submitLabel?: string\n cancelLabel?: string\n hint?: string\n className?: string\n}\n\nexport function FeedbackActions({\n onSubmit,\n onCancel,\n submitDisabled = false,\n submitLabel = \"Submit\",\n cancelLabel = \"Cancel\",\n hint,\n className,\n}: FeedbackActionsProps) {\n return (\n <div className={cn(\"flex items-center gap-2\", className)}>\n <button\n type=\"button\"\n onClick={onSubmit}\n disabled={submitDisabled}\n className=\"bg-foreground text-background rounded-md px-3 py-1.5 text-xs font-semibold disabled:opacity-50\"\n >\n {submitLabel}\n </button>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"border border-border rounded-md px-3 py-1.5 text-xs font-medium\"\n >\n {cancelLabel}\n </button>\n {hint && (\n <span className=\"ml-auto text-[11px] text-muted-foreground\">\n {hint}\n </span>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// FeedbackFooter\n// ---------------------------------------------------------------------------\n\nexport interface FeedbackFooterProps {\n feedback: \"positive\" | \"negative\" | null\n onFeedbackChange: (value: \"positive\" | \"negative\" | null) => void\n onSubmit: (data: FeedbackSubmitData) => void\n metaText?: string\n positivePrompt?: string\n negativePrompt?: string\n negativeChips?: FeedbackChipTree[]\n positiveChips?: string[]\n className?: string\n /** Pre-existing feedback to hydrate from (e.g. after page reload). */\n initialFeedback?: PersistedFeedbackData | null\n /** Label shown in the transient confirmation pill after submit. */\n submittedLabel?: string\n /** Stable key for syncing initialFeedback into local state. When this\n * changes, the component resets to the new initialFeedback value. */\n feedbackKey?: string\n}\n\nconst SENTIMENT_BUTTON_ACTIVE: Record<\"positive\" | \"negative\", string> = {\n negative: \"text-red-600 bg-red-50 border-red-200\",\n positive: \"text-foreground bg-muted border-border\",\n}\n\nconst SENTIMENT_BUTTON_IDLE =\n \"text-muted-foreground hover:text-foreground\"\n\nexport function FeedbackFooter({\n feedback,\n onFeedbackChange,\n onSubmit,\n metaText,\n positivePrompt = \"Thanks! Anything to keep about this score?\",\n negativePrompt = \"What's the issue?\",\n negativeChips = [],\n positiveChips = [],\n className,\n initialFeedback,\n submittedLabel = \"Saved\",\n feedbackKey,\n}: FeedbackFooterProps) {\n const [expanded, setExpanded] = React.useState(false)\n const [selectedTier1, setSelectedTier1] = React.useState<string | null>(null)\n const [selectedTier2, setSelectedTier2] = React.useState<string | null>(null)\n const [additionalPills, setAdditionalPills] = React.useState<string[]>([])\n const [detailText, setDetailText] = React.useState(\"\")\n const [activeTreeIndex, setActiveTreeIndex] = React.useState<number | null>(\n null,\n )\n /** Transient \"Saved\" confirmation — shown after successful submit. */\n const [submitted, setSubmitted] = React.useState(false)\n /** Persisted feedback shown as a clickable indicator (survives reload). */\n const [persisted, setPersisted] = React.useState<PersistedFeedbackData | null>(\n initialFeedback ?? null,\n )\n /** Tracks whether the user is actively editing (to guard against prop overwrites). */\n const [isEditing, setIsEditing] = React.useState(false)\n /** Track the last synced feedbackKey to detect key changes. */\n const lastKeyRef = React.useRef<string | undefined>(feedbackKey)\n\n // Sync initialFeedback into local state via useEffect keyed on feedbackKey.\n // When feedbackKey changes, reset to new target. Preserve active edits\n // when feedbackKey stays the same.\n React.useEffect(() => {\n const keyChanged = feedbackKey !== lastKeyRef.current\n lastKeyRef.current = feedbackKey\n\n if (keyChanged) {\n // Key changed — full reset to new target\n setPersisted(initialFeedback ?? null)\n setSubmitted(false)\n setExpanded(false)\n setIsEditing(false)\n if (initialFeedback) {\n onFeedbackChange(initialFeedback.sentiment)\n } else {\n onFeedbackChange(null)\n }\n } else if (!isEditing) {\n // Same key, not actively editing — safe to sync\n setPersisted(initialFeedback ?? null)\n if (initialFeedback) {\n onFeedbackChange(initialFeedback.sentiment)\n }\n }\n }, [initialFeedback, feedbackKey]) // eslint-disable-line react-hooks/exhaustive-deps -- reads isEditing as guard, not trigger\n\n // Reset state when feedback collapses\n const resetState = React.useCallback(() => {\n setExpanded(false)\n setSelectedTier1(null)\n setSelectedTier2(null)\n setAdditionalPills([])\n setDetailText(\"\")\n setActiveTreeIndex(null)\n setIsEditing(false)\n }, [])\n\n const handleSentimentClick = React.useCallback(\n (sentiment: \"positive\" | \"negative\") => {\n onFeedbackChange(sentiment)\n // Reset chip state when switching sentiment, then expand\n resetState()\n setExpanded(true)\n setSubmitted(false)\n setPersisted(null)\n setIsEditing(true)\n },\n [onFeedbackChange, resetState],\n )\n\n /** Open the persisted indicator for editing. */\n const handlePersistedClick = React.useCallback(() => {\n if (!persisted) return\n onFeedbackChange(persisted.sentiment)\n setSelectedTier1(persisted.reasonTop ?? null)\n setSelectedTier2(persisted.reasonSub ?? null)\n setAdditionalPills(persisted.pills ?? [])\n setDetailText(persisted.detail ?? \"\")\n setExpanded(true)\n setSubmitted(false)\n setIsEditing(true)\n }, [persisted, onFeedbackChange])\n\n const handleTier1Toggle = React.useCallback(\n (chipLabel: string) => {\n if (selectedTier1 === chipLabel) {\n // Deselect the tier-1 chip\n setSelectedTier1(null)\n setSelectedTier2(null)\n setActiveTreeIndex(null)\n } else if (selectedTier1 === null) {\n // First selection becomes the primary reasonTop\n setSelectedTier1(chipLabel)\n setSelectedTier2(null)\n // Find the chip's tree index to show sub-chips\n const idx = negativeChips.findIndex((c) => c.label === chipLabel)\n if (idx !== -1 && negativeChips[idx].subChips) {\n setActiveTreeIndex(idx)\n } else {\n setActiveTreeIndex(null)\n }\n } else {\n // Additional selections become pills\n setAdditionalPills((prev) =>\n prev.includes(chipLabel)\n ? prev.filter((p) => p !== chipLabel)\n : [...prev, chipLabel],\n )\n }\n },\n [selectedTier1, negativeChips],\n )\n\n const handleTier2Toggle = React.useCallback((subChip: string) => {\n setSelectedTier2((prev) => (prev === subChip ? null : subChip))\n }, [])\n\n const handlePositiveChipToggle = React.useCallback(\n (chip: string) => {\n if (selectedTier1 === chip) {\n setSelectedTier1(null)\n } else if (selectedTier1 === null) {\n setSelectedTier1(chip)\n } else {\n setAdditionalPills((prev) =>\n prev.includes(chip)\n ? prev.filter((p) => p !== chip)\n : [...prev, chip],\n )\n }\n },\n [selectedTier1],\n )\n\n const handleSubmit = React.useCallback(() => {\n if (!feedback) return\n onSubmit({\n sentiment: feedback,\n reasonTop: selectedTier1 ?? undefined,\n reasonSub: selectedTier2 ?? undefined,\n pills: additionalPills,\n detail: detailText,\n })\n // Show transient \"Saved\" confirmation\n setSubmitted(true)\n // Collapse expansion but keep sentiment visible\n setExpanded(false)\n setSelectedTier1(null)\n setSelectedTier2(null)\n setAdditionalPills([])\n setDetailText(\"\")\n setActiveTreeIndex(null)\n setIsEditing(false)\n }, [\n feedback,\n selectedTier1,\n selectedTier2,\n additionalPills,\n detailText,\n onSubmit,\n ])\n\n const handleCancel = React.useCallback(() => {\n resetState()\n onFeedbackChange(null)\n }, [resetState, onFeedbackChange])\n\n // Determine which chips are selected (combining tier1 + additionalPills)\n const allSelectedChips = React.useMemo(() => {\n const result: string[] = []\n if (selectedTier1) result.push(selectedTier1)\n result.push(...additionalPills)\n return result\n }, [selectedTier1, additionalPills])\n\n // Active tier-1 chip tree (for showing sub-chips)\n const activeTree =\n activeTreeIndex !== null ? negativeChips[activeTreeIndex] : null\n\n // Determine if we should show the persisted indicator instead of bare buttons\n const showPersistedIndicator = persisted && !expanded && !submitted\n\n return (\n <div className={cn(\"space-y-3\", className)}>\n {/* Sentiment buttons + meta text bar */}\n <div className=\"flex items-center justify-between\">\n {showPersistedIndicator ? (\n /* Persisted feedback indicator — clickable to reopen editor */\n <button\n type=\"button\"\n onClick={handlePersistedClick}\n className=\"group flex items-center gap-1.5 text-[11px] text-muted-foreground hover:text-foreground transition-colors\"\n data-testid=\"persisted-feedback-indicator\"\n >\n <span className=\"font-medium\">{persisted.ownershipLabel}:</span>\n {persisted.sentiment === \"positive\" ? (\n <ThumbsUp className=\"h-[11px] w-[11px]\" />\n ) : (\n <ThumbsDown className=\"h-[11px] w-[11px]\" />\n )}\n {persisted.detail && (\n <span className=\"max-w-[200px] truncate text-muted-foreground/70\">\n {persisted.detail}\n </span>\n )}\n <Pencil className=\"h-[9px] w-[9px] opacity-0 group-hover:opacity-100 transition-opacity\" />\n </button>\n ) : (\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => handleSentimentClick(\"positive\")}\n className={cn(\n \"flex gap-1 items-center text-[11px] font-medium rounded-md px-2 py-1 transition-colors\",\n feedback === \"positive\"\n ? SENTIMENT_BUTTON_ACTIVE.positive\n : SENTIMENT_BUTTON_IDLE,\n )}\n >\n <ThumbsUp className=\"h-[11px] w-[11px]\" />\n Helpful\n </button>\n <button\n type=\"button\"\n onClick={() => handleSentimentClick(\"negative\")}\n className={cn(\n \"flex gap-1 items-center text-[11px] font-medium rounded-md px-2 py-1 transition-colors\",\n feedback === \"negative\"\n ? SENTIMENT_BUTTON_ACTIVE.negative\n : SENTIMENT_BUTTON_IDLE,\n )}\n >\n <ThumbsDown className=\"h-[11px] w-[11px]\" />\n Not helpful\n </button>\n {/* Transient \"Saved\" confirmation pill */}\n {submitted && feedback && (\n <span\n className=\"inline-flex items-center gap-1 text-[11px] font-medium text-emerald-600\"\n role=\"status\"\n data-testid=\"feedback-submitted-pill\"\n >\n <Check className=\"h-[11px] w-[11px]\" />\n {submittedLabel}\n </span>\n )}\n </div>\n )}\n {metaText && (\n <span className=\"text-[11px] text-muted-foreground\">{metaText}</span>\n )}\n </div>\n\n {/* Expanded feedback area */}\n {expanded && feedback && (\n <div className=\"space-y-3\">\n {/* Prompt text */}\n <p className=\"text-xs text-muted-foreground\">\n {feedback === \"negative\" ? negativePrompt : positivePrompt}\n </p>\n\n {/* Chip area */}\n {feedback === \"negative\" && negativeChips.length > 0 && (\n <div className=\"space-y-2\">\n {/* Tier-1 chips */}\n <FeedbackChipGroup\n chips={negativeChips.map((c) => c.label)}\n selected={allSelectedChips}\n onToggle={handleTier1Toggle}\n flavor=\"negative\"\n />\n\n {/* Tier-2 sub-chips (shown when a tier-1 with sub-chips is active) */}\n {activeTree && activeTree.subChips && (\n <div className=\"pl-3 space-y-1.5\">\n {activeTree.subPrompt && (\n <p className=\"text-[11px] text-muted-foreground\">\n {activeTree.subPrompt}\n </p>\n )}\n <FeedbackChipGroup\n chips={activeTree.subChips}\n selected={selectedTier2 ? [selectedTier2] : []}\n onToggle={handleTier2Toggle}\n flavor=\"negative\"\n />\n </div>\n )}\n </div>\n )}\n\n {feedback === \"positive\" && positiveChips.length > 0 && (\n <FeedbackChipGroup\n chips={positiveChips}\n selected={allSelectedChips}\n onToggle={handlePositiveChipToggle}\n flavor=\"positive\"\n />\n )}\n\n {/* Detail text input */}\n <FeedbackInput\n placeholder=\"Add optional detail…\"\n value={detailText}\n onChange={setDetailText}\n onSubmit={handleSubmit}\n />\n\n {/* Action buttons */}\n <FeedbackActions onSubmit={handleSubmit} onCancel={handleCancel} />\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/feedback-primitives.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { ThumbsUp, ThumbsDown } from \"lucide-react\"\nimport { cn } from \"../lib/utils\"\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Structured feedback data shape.\n *\n * Preserves the tree structure for DB persistence:\n * reasonTop -> tier-1 chip label (maps to case_feedback.reason_top)\n * reasonSub -> tier-2 sub-chip label (maps to case_feedback.reason_sub)\n * pills -> any additional selected chips (maps to case_feedback.pills)\n * detail -> free-text input (maps to case_feedback.free_text)\n */\nexport interface FeedbackSubmitData {\n sentiment: \"positive\" | \"negative\"\n reasonTop?: string\n reasonSub?: string\n pills: string[]\n detail: string\n}\n\n/**\n * Defines a tier-1 chip that may have tier-2 sub-chips.\n */\nexport interface FeedbackChipTree {\n label: string\n subPrompt?: string\n subChips?: string[]\n}\n\n// ---------------------------------------------------------------------------\n// FeedbackChipGroup\n// ---------------------------------------------------------------------------\n\nexport interface FeedbackChipGroupProps {\n chips: string[]\n selected: string[]\n onToggle: (chip: string) => void\n flavor: \"positive\" | \"negative\"\n className?: string\n}\n\nconst CHIP_SELECTED_CLASSES: Record<\"positive\" | \"negative\", string> = {\n negative: \"bg-red-50 text-red-700 border-red-200\",\n positive: \"bg-muted text-foreground border-border\",\n}\n\nconst CHIP_IDLE_CLASS =\n \"bg-background text-muted-foreground border-border hover:bg-muted/50\"\n\nexport function FeedbackChipGroup({\n chips,\n selected,\n onToggle,\n flavor,\n className,\n}: FeedbackChipGroupProps) {\n return (\n <div className={cn(\"flex flex-wrap gap-1.5\", className)}>\n {chips.map((chip) => {\n const isSelected = selected.includes(chip)\n return (\n <button\n key={chip}\n type=\"button\"\n onClick={() => onToggle(chip)}\n className={cn(\n \"rounded-md px-2.5 py-1 text-[11px] font-medium border transition-colors\",\n isSelected ? CHIP_SELECTED_CLASSES[flavor] : CHIP_IDLE_CLASS,\n )}\n >\n {chip}\n </button>\n )\n })}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// FeedbackInput\n// ---------------------------------------------------------------------------\n\nexport interface FeedbackInputProps {\n placeholder?: string\n value: string\n onChange: (value: string) => void\n onSubmit?: () => void\n className?: string\n}\n\nexport function FeedbackInput({\n placeholder,\n value,\n onChange,\n onSubmit,\n className,\n}: FeedbackInputProps) {\n return (\n <input\n type=\"text\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && onSubmit) {\n e.preventDefault()\n onSubmit()\n }\n }}\n placeholder={placeholder}\n className={cn(\n \"w-full text-xs bg-background border border-border rounded-md px-2.5 py-2 text-foreground placeholder:text-muted-foreground/50 focus:outline-none focus:ring-1 focus:ring-ring\",\n className,\n )}\n />\n )\n}\n\n// ---------------------------------------------------------------------------\n// FeedbackActions\n// ---------------------------------------------------------------------------\n\nexport interface FeedbackActionsProps {\n onSubmit: () => void\n onCancel: () => void\n submitDisabled?: boolean\n submitLabel?: string\n cancelLabel?: string\n hint?: string\n className?: string\n}\n\nexport function FeedbackActions({\n onSubmit,\n onCancel,\n submitDisabled = false,\n submitLabel = \"Submit\",\n cancelLabel = \"Cancel\",\n hint,\n className,\n}: FeedbackActionsProps) {\n return (\n <div className={cn(\"flex items-center gap-2\", className)}>\n <button\n type=\"button\"\n onClick={onSubmit}\n disabled={submitDisabled}\n className=\"bg-foreground text-background rounded-md px-3 py-1.5 text-xs font-semibold disabled:opacity-50\"\n >\n {submitLabel}\n </button>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"border border-border rounded-md px-3 py-1.5 text-xs font-medium\"\n >\n {cancelLabel}\n </button>\n {hint && (\n <span className=\"ml-auto text-[11px] text-muted-foreground\">\n {hint}\n </span>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// FeedbackFooter\n// ---------------------------------------------------------------------------\n\nexport interface FeedbackFooterProps {\n feedback: \"positive\" | \"negative\" | null\n onFeedbackChange: (value: \"positive\" | \"negative\" | null) => void\n onSubmit: (data: FeedbackSubmitData) => void\n metaText?: string\n positivePrompt?: string\n negativePrompt?: string\n negativeChips?: FeedbackChipTree[]\n positiveChips?: string[]\n className?: string\n}\n\nconst SENTIMENT_BUTTON_ACTIVE: Record<\"positive\" | \"negative\", string> = {\n negative: \"text-red-600 bg-red-50 border-red-200\",\n positive: \"text-foreground bg-muted border-border\",\n}\n\nconst SENTIMENT_BUTTON_IDLE =\n \"text-muted-foreground hover:text-foreground\"\n\nexport function FeedbackFooter({\n feedback,\n onFeedbackChange,\n onSubmit,\n metaText,\n positivePrompt = \"Thanks! Anything to keep about this score?\",\n negativePrompt = \"What's the issue?\",\n negativeChips = [],\n positiveChips = [],\n className,\n}: FeedbackFooterProps) {\n const [expanded, setExpanded] = React.useState(false)\n const [selectedTier1, setSelectedTier1] = React.useState<string | null>(null)\n const [selectedTier2, setSelectedTier2] = React.useState<string | null>(null)\n const [additionalPills, setAdditionalPills] = React.useState<string[]>([])\n const [detailText, setDetailText] = React.useState(\"\")\n const [activeTreeIndex, setActiveTreeIndex] = React.useState<number | null>(\n null,\n )\n\n // Reset state when feedback collapses\n const resetState = React.useCallback(() => {\n setExpanded(false)\n setSelectedTier1(null)\n setSelectedTier2(null)\n setAdditionalPills([])\n setDetailText(\"\")\n setActiveTreeIndex(null)\n }, [])\n\n const handleSentimentClick = React.useCallback(\n (sentiment: \"positive\" | \"negative\") => {\n onFeedbackChange(sentiment)\n // Reset chip state when switching sentiment, then expand\n resetState()\n setExpanded(true)\n },\n [onFeedbackChange, resetState],\n )\n\n const handleTier1Toggle = React.useCallback(\n (chipLabel: string) => {\n if (selectedTier1 === chipLabel) {\n // Deselect the tier-1 chip\n setSelectedTier1(null)\n setSelectedTier2(null)\n setActiveTreeIndex(null)\n } else if (selectedTier1 === null) {\n // First selection becomes the primary reasonTop\n setSelectedTier1(chipLabel)\n setSelectedTier2(null)\n // Find the chip's tree index to show sub-chips\n const idx = negativeChips.findIndex((c) => c.label === chipLabel)\n if (idx !== -1 && negativeChips[idx].subChips) {\n setActiveTreeIndex(idx)\n } else {\n setActiveTreeIndex(null)\n }\n } else {\n // Additional selections become pills\n setAdditionalPills((prev) =>\n prev.includes(chipLabel)\n ? prev.filter((p) => p !== chipLabel)\n : [...prev, chipLabel],\n )\n }\n },\n [selectedTier1, negativeChips],\n )\n\n const handleTier2Toggle = React.useCallback((subChip: string) => {\n setSelectedTier2((prev) => (prev === subChip ? null : subChip))\n }, [])\n\n const handlePositiveChipToggle = React.useCallback(\n (chip: string) => {\n if (selectedTier1 === chip) {\n setSelectedTier1(null)\n } else if (selectedTier1 === null) {\n setSelectedTier1(chip)\n } else {\n setAdditionalPills((prev) =>\n prev.includes(chip)\n ? prev.filter((p) => p !== chip)\n : [...prev, chip],\n )\n }\n },\n [selectedTier1],\n )\n\n const handleSubmit = React.useCallback(() => {\n if (!feedback) return\n onSubmit({\n sentiment: feedback,\n reasonTop: selectedTier1 ?? undefined,\n reasonSub: selectedTier2 ?? undefined,\n pills: additionalPills,\n detail: detailText,\n })\n resetState()\n }, [\n feedback,\n selectedTier1,\n selectedTier2,\n additionalPills,\n detailText,\n onSubmit,\n resetState,\n ])\n\n const handleCancel = React.useCallback(() => {\n resetState()\n onFeedbackChange(null)\n }, [resetState, onFeedbackChange])\n\n // Determine which chips are selected (combining tier1 + additionalPills)\n const allSelectedChips = React.useMemo(() => {\n const result: string[] = []\n if (selectedTier1) result.push(selectedTier1)\n result.push(...additionalPills)\n return result\n }, [selectedTier1, additionalPills])\n\n // Active tier-1 chip tree (for showing sub-chips)\n const activeTree =\n activeTreeIndex !== null ? negativeChips[activeTreeIndex] : null\n\n return (\n <div className={cn(\"space-y-3\", className)}>\n {/* Sentiment buttons + meta text bar */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => handleSentimentClick(\"positive\")}\n className={cn(\n \"flex gap-1 items-center text-[11px] font-medium rounded-md px-2 py-1 transition-colors\",\n feedback === \"positive\"\n ? SENTIMENT_BUTTON_ACTIVE.positive\n : SENTIMENT_BUTTON_IDLE,\n )}\n >\n <ThumbsUp className=\"h-[11px] w-[11px]\" />\n Helpful\n </button>\n <button\n type=\"button\"\n onClick={() => handleSentimentClick(\"negative\")}\n className={cn(\n \"flex gap-1 items-center text-[11px] font-medium rounded-md px-2 py-1 transition-colors\",\n feedback === \"negative\"\n ? SENTIMENT_BUTTON_ACTIVE.negative\n : SENTIMENT_BUTTON_IDLE,\n )}\n >\n <ThumbsDown className=\"h-[11px] w-[11px]\" />\n Not helpful\n </button>\n </div>\n {metaText && (\n <span className=\"text-[11px] text-muted-foreground\">{metaText}</span>\n )}\n </div>\n\n {/* Expanded feedback area */}\n {expanded && feedback && (\n <div className=\"space-y-3\">\n {/* Prompt text */}\n <p className=\"text-xs text-muted-foreground\">\n {feedback === \"negative\" ? negativePrompt : positivePrompt}\n </p>\n\n {/* Chip area */}\n {feedback === \"negative\" && negativeChips.length > 0 && (\n <div className=\"space-y-2\">\n {/* Tier-1 chips */}\n <FeedbackChipGroup\n chips={negativeChips.map((c) => c.label)}\n selected={allSelectedChips}\n onToggle={handleTier1Toggle}\n flavor=\"negative\"\n />\n\n {/* Tier-2 sub-chips (shown when a tier-1 with sub-chips is active) */}\n {activeTree && activeTree.subChips && (\n <div className=\"pl-3 space-y-1.5\">\n {activeTree.subPrompt && (\n <p className=\"text-[11px] text-muted-foreground\">\n {activeTree.subPrompt}\n </p>\n )}\n <FeedbackChipGroup\n chips={activeTree.subChips}\n selected={selectedTier2 ? [selectedTier2] : []}\n onToggle={handleTier2Toggle}\n flavor=\"negative\"\n />\n </div>\n )}\n </div>\n )}\n\n {feedback === \"positive\" && positiveChips.length > 0 && (\n <FeedbackChipGroup\n chips={positiveChips}\n selected={allSelectedChips}\n onToggle={handlePositiveChipToggle}\n flavor=\"positive\"\n />\n )}\n\n {/* Detail text input */}\n <FeedbackInput\n placeholder=\"Add optional detail…\"\n value={detailText}\n onChange={setDetailText}\n onSubmit={handleSubmit}\n />\n\n {/* Action buttons */}\n <FeedbackActions onSubmit={handleSubmit} onCancel={handleCancel} />\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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","names":[]}
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { Q as QueueItem, l as SignalScoreData, o as SignalScoreUrgencyLabel } from '../signal-priority-popover-DWaAMhPI.js';
2
+ import { Q as QueueItem, l as SignalScoreData, o as SignalScoreUrgencyLabel } from '../signal-priority-popover-DQ_VuHac.js';
3
3
  import './feedback-primitives.js';
4
4
  import './quick-action-sidebar-nav.js';
5
5
  import './quick-action-modal.js';
@@ -165,7 +165,6 @@ function StructuredSignalRow({ item, bucketKey, signal, tone, onOpenSignalBucket
165
165
  const IconComponent = resolveIcon(signal.signalTypeName);
166
166
  const toneClass = tone ? (_a = SIGNAL_TONE_CLASSES[tone]) != null ? _a : DEFAULT_TONE_CLASS : DEFAULT_TONE_CLASS;
167
167
  const isCombined = signal.signalTypeName === "combined_signal" && signal.components && signal.components.length > 0;
168
- const hasBalance = Boolean(signal.currentBalance || signal.balanceContext);
169
168
  const rowContent = /* @__PURE__ */ jsxs(Fragment, { children: [
170
169
  /* @__PURE__ */ jsx("div", { className: cn("flex h-5 w-5 shrink-0 items-center justify-center rounded", toneClass), children: /* @__PURE__ */ jsx(IconComponent, { className: "h-3 w-3" }) }),
171
170
  /* @__PURE__ */ jsx("div", { className: "min-w-0", children: isCombined ? /* @__PURE__ */ jsx(CombinedSignalMiniChips, { components: signal.components }) : /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-1.5", children: [
@@ -174,24 +173,7 @@ function StructuredSignalRow({ item, bucketKey, signal, tone, onOpenSignalBucket
174
173
  ] }) }),
175
174
  /* @__PURE__ */ jsx("div", { className: "min-w-0", children: /* @__PURE__ */ jsx("span", { className: "block truncate text-xs text-muted-foreground", children: slotValue(signal.counterparty) }) }),
176
175
  /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[11px] text-muted-foreground/70", children: slotValue(signal.time) }),
177
- /* @__PURE__ */ jsx(ChevronRight, { className: "h-3 w-3 shrink-0 text-muted-foreground/60 transition-transform group-hover:translate-x-0.5 group-hover:text-foreground/50" }),
178
- hasBalance && /* @__PURE__ */ jsxs(
179
- "div",
180
- {
181
- className: "col-span-full mt-0.5 text-[10px] text-muted-foreground/70",
182
- "data-testid": "balance-context-strip",
183
- children: [
184
- signal.currentBalance && /* @__PURE__ */ jsxs("span", { children: [
185
- "Current balance ",
186
- /* @__PURE__ */ jsx("span", { className: "font-medium text-muted-foreground", children: signal.currentBalance })
187
- ] }),
188
- signal.balanceContext && /* @__PURE__ */ jsxs("span", { children: [
189
- signal.currentBalance ? " \xB7 " : "",
190
- signal.balanceContext
191
- ] })
192
- ]
193
- }
194
- )
176
+ /* @__PURE__ */ jsx(ChevronRight, { className: "h-3 w-3 shrink-0 text-muted-foreground/60 transition-transform group-hover:translate-x-0.5 group-hover:text-foreground/50" })
195
177
  ] });
196
178
  if (signal.id && onOpenSignalBucket) {
197
179
  return /* @__PURE__ */ jsx(
@@ -248,7 +230,7 @@ function hasStructuredData(signal) {
248
230
  signal.primaryValue || signal.qualifier || signal.counterparty || signal.components && signal.components.length > 0
249
231
  );
250
232
  }
251
- function WhyCard({ bucket, signals, item, panelId, onOpenSignalBucket, onBucketFeedback, initialBucketFeedback }) {
233
+ function WhyCard({ bucket, signals, item, panelId, onOpenSignalBucket, onBucketFeedback }) {
252
234
  var _a;
253
235
  const [showAll, setShowAll] = React.useState(false);
254
236
  const [bucketFeedback, setBucketFeedback] = React.useState(null);
@@ -317,9 +299,7 @@ function WhyCard({ bucket, signals, item, panelId, onOpenSignalBucket, onBucketF
317
299
  onSubmit: (data) => onBucketFeedback(bucket.key, data),
318
300
  negativeChips: BUCKET_NEGATIVE_CHIPS,
319
301
  negativePrompt: "Was this bucket useful?",
320
- positivePrompt: "Thanks! What was useful about this bucket?",
321
- initialFeedback: initialBucketFeedback,
322
- feedbackKey: bucket.key
302
+ positivePrompt: "Thanks! What was useful about this bucket?"
323
303
  }
324
304
  ) })
325
305
  ]
@@ -332,7 +312,7 @@ function ScoreWhyChips({
332
312
  onOpenSignalBucket,
333
313
  className
334
314
  }) {
335
- var _a, _b;
315
+ var _a;
336
316
  const [selectedBucketKey, setSelectedBucketKey] = React.useState(null);
337
317
  React.useEffect(() => {
338
318
  setSelectedBucketKey(null);
@@ -372,8 +352,7 @@ function ScoreWhyChips({
372
352
  item,
373
353
  panelId: selectedPanelId,
374
354
  onOpenSignalBucket,
375
- onBucketFeedback: signalData.onBucketFeedback,
376
- initialBucketFeedback: (_b = signalData.initialBucketFeedback) == null ? void 0 : _b[selectedBucket.key]
355
+ onBucketFeedback: signalData.onBucketFeedback
377
356
  }
378
357
  )
379
358
  ] });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/score-why-chips.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport {\n ChevronDown,\n ChevronUp,\n ChevronRight,\n X,\n TrendingDown,\n ArrowUpRight,\n Radar,\n ArrowDownLeft,\n GitMerge,\n Activity,\n} from \"lucide-react\"\nimport type { LucideIcon } from \"lucide-react\"\nimport { FeedbackFooter } from \"./feedback-primitives\"\nimport type { FeedbackChipTree, FeedbackSubmitData, PersistedFeedbackData } from \"./feedback-primitives\"\nimport { cn } from \"../lib/utils\"\nimport type {\n QueueItem,\n SignalScoreData,\n SignalScoreExplanationBucket,\n SignalScoreExplanationSignal,\n SignalScoreUrgencyLabel,\n} from \"../prototype/prototype-config\"\n\n// ---------------------------------------------------------------------------\n// Constants & helpers\n// ---------------------------------------------------------------------------\n\nexport function getSignalScoreUrgencyLabel(\n score: number,\n providedLabel?: SignalScoreUrgencyLabel,\n): SignalScoreUrgencyLabel {\n if (providedLabel) return providedLabel\n if (score >= 80) return \"Urgent\"\n if (score >= 60) return \"High\"\n if (score >= 35) return \"Medium\"\n return \"Low\"\n}\n\nexport function scoreRangeForUrgency(label: SignalScoreUrgencyLabel): string {\n switch (label) {\n case \"Urgent\":\n return \"80-100\"\n case \"High\":\n return \"60-79\"\n case \"Medium\":\n return \"35-59\"\n case \"Low\":\n return \"0-34\"\n }\n}\n\nfunction makeDomId(...parts: Array<string | undefined>): string {\n return parts\n .filter((part): part is string => Boolean(part))\n .join(\"-\")\n .replace(/[^A-Za-z0-9_-]+/g, \"-\")\n}\n\nfunction bucketHasSignalRows(bucket: SignalScoreExplanationBucket): boolean {\n return (\n (bucket.signals?.length ?? 0) > 0 ||\n (bucket.signalIds?.length ?? 0) > 0 ||\n Boolean(bucket.primarySignalId)\n )\n}\n\nfunction getSignalScoreBuckets(signalData: SignalScoreData): SignalScoreExplanationBucket[] {\n return (signalData.explanationBuckets ?? []).filter(\n (bucket) => bucket.kind !== \"factor\" && bucketHasSignalRows(bucket),\n )\n}\n\nfunction getBucketSignals(bucket: SignalScoreExplanationBucket): SignalScoreExplanationSignal[] {\n if (bucket.signals && bucket.signals.length > 0) return bucket.signals\n\n const signalIds = bucket.signalIds && bucket.signalIds.length > 0 ? bucket.signalIds : bucket.primarySignalId ? [bucket.primarySignalId] : []\n const uniqueSignalIds = Array.from(new Set(signalIds))\n\n return uniqueSignalIds.map((signalId) => ({\n id: signalId,\n label: `${bucket.label} signal`,\n }))\n}\n\n// ---------------------------------------------------------------------------\n// Signal type icon map - keyed by signal type name (Tailwind v4 source scanned)\n// ---------------------------------------------------------------------------\n\nconst SIGNAL_TYPE_ICONS: Record<string, LucideIcon> = {\n treasury_liquidation: TrendingDown,\n cumulative_treasury_outflow: ArrowUpRight,\n test_transaction: Radar,\n micro_deposit: ArrowDownLeft,\n combined_signal: GitMerge,\n}\n\nfunction resolveIcon(iconName?: string): LucideIcon {\n if (!iconName) return Activity\n return SIGNAL_TYPE_ICONS[iconName] ?? Activity\n}\n\n// ---------------------------------------------------------------------------\n// Static tone class maps (REQUIRED for Tailwind v4 source scanning)\n// ---------------------------------------------------------------------------\n\n/** Shared tone-to-class map. Re-exported for signal-priority-popover. */\nexport const SIGNAL_TONE_CLASSES: Record<string, string> = {\n alert: \"bg-red-50 text-red-600\",\n warn: \"bg-amber-50 text-amber-600\",\n info: \"bg-blue-50 text-blue-600\",\n}\n\n/** Default tone for missing/unknown tone values */\nexport const DEFAULT_TONE_CLASS = \"bg-muted text-muted-foreground\"\n\n// ---------------------------------------------------------------------------\n// Em-dash fallback for missing slot data\n// ---------------------------------------------------------------------------\n\nfunction slotValue(value: string | null | undefined): string {\n return value && value.trim().length > 0 ? value : \"\"\n}\n\n// ---------------------------------------------------------------------------\n// Bucket feedback chip config\n// ---------------------------------------------------------------------------\n\nconst BUCKET_NEGATIVE_CHIPS: FeedbackChipTree[] = [\n {\n label: \"Not relevant for this account\",\n subPrompt: \"Why isn't it relevant?\",\n subChips: [\n \"Business as usual for this account\",\n \"Account in maintenance mode\",\n \"Wrong contact for this signal\",\n \"Other\",\n ],\n },\n { label: \"Bad timing\" },\n {\n label: \"Inaccurate data\",\n subPrompt: \"Which field?\",\n subChips: [\"Balance figures\", \"Counterparty\", \"Timestamp\", \"Other\"],\n },\n { label: \"Wrong account\" },\n { label: \"Already handled\" },\n { label: \"Other\" },\n]\n\n// ---------------------------------------------------------------------------\n// Default visible row count for long lists\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_VISIBLE_ROWS = 8\n\n// ---------------------------------------------------------------------------\n// WhyPill - Bucket toggle button with icon, count badge, chevron, close\n// ---------------------------------------------------------------------------\n\ninterface WhyPillProps {\n bucket: SignalScoreExplanationBucket\n isSelected: boolean\n signalCount: number\n panelId: string\n onToggle: () => void\n onClose: () => void\n}\n\nfunction WhyPill({ bucket, isSelected, signalCount, panelId, onToggle, onClose }: WhyPillProps) {\n const IconComponent = resolveIcon(bucket.icon)\n\n const sharedClasses = cn(\n \"inline-flex items-center text-[11px] font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n isSelected\n ? \"border-border bg-muted text-foreground\"\n : \"border-border bg-background text-muted-foreground hover:bg-muted/60 hover:text-foreground\",\n )\n\n return (\n <div className=\"inline-flex h-[26px] items-stretch\">\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={isSelected}\n aria-controls={panelId}\n className={cn(\n sharedClasses,\n \"gap-1.5 rounded-lg border px-2.5 py-1\",\n isSelected && \"rounded-b-none rounded-r-none border-r-0\",\n )}\n >\n <IconComponent className=\"h-3 w-3 shrink-0\" />\n {bucket.label}\n {signalCount > 1 && (\n <span className={cn(\"rounded-full px-1.5 py-0 text-[10px]\", isSelected ? \"bg-background/60\" : \"bg-muted\")}>\n x{signalCount}\n </span>\n )}\n {isSelected ? (\n <ChevronUp className=\"h-3 w-3 shrink-0\" />\n ) : (\n <ChevronDown className=\"h-3 w-3 shrink-0\" />\n )}\n </button>\n {isSelected && (\n <button\n type=\"button\"\n aria-label={`Close ${bucket.label}`}\n onClick={onClose}\n className={cn(\n sharedClasses,\n \"rounded-lg rounded-b-none rounded-l-none border border-l-0 border-border px-1.5 py-1 hover:bg-background/60\",\n )}\n >\n <X className=\"h-3 w-3\" />\n </button>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// CombinedSignalMiniChips - renders component type chips for combined signals\n// ---------------------------------------------------------------------------\n\ninterface CombinedSignalMiniChipsProps {\n components: Array<{ type: string; count: number }>\n}\n\nfunction CombinedSignalMiniChips({ components }: CombinedSignalMiniChipsProps) {\n return (\n <div className=\"flex flex-wrap items-center gap-1\">\n {components.map((comp, idx) => {\n const CompIcon = resolveIcon(comp.type)\n return (\n <React.Fragment key={comp.type}>\n {idx > 0 && <span className=\"text-[10px] text-muted-foreground/60\">+</span>}\n <span className=\"inline-flex items-center gap-0.5 rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground\">\n <CompIcon className=\"h-2.5 w-2.5 shrink-0\" />\n {comp.type.replace(/_/g, \" \")} x{comp.count}\n </span>\n </React.Fragment>\n )\n })}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// StructuredSignalRow - CSS grid slot grammar signal row\n// ---------------------------------------------------------------------------\n\ninterface StructuredSignalRowProps {\n item: QueueItem\n bucketKey: string\n signal: SignalScoreExplanationSignal\n tone?: \"alert\" | \"warn\" | \"info\"\n onOpenSignalBucket?: ScoreWhyChipsProps[\"onOpenSignalBucket\"]\n}\n\nfunction StructuredSignalRow({ item, bucketKey, signal, tone, onOpenSignalBucket }: StructuredSignalRowProps) {\n const IconComponent = resolveIcon(signal.signalTypeName)\n const toneClass = tone ? (SIGNAL_TONE_CLASSES[tone] ?? DEFAULT_TONE_CLASS) : DEFAULT_TONE_CLASS\n const isCombined = signal.signalTypeName === \"combined_signal\" && signal.components && signal.components.length > 0\n const hasBalance = Boolean(signal.currentBalance || signal.balanceContext)\n\n const rowContent = (\n <>\n {/* Slot 1: Icon */}\n <div className={cn(\"flex h-5 w-5 shrink-0 items-center justify-center rounded\", toneClass)}>\n <IconComponent className=\"h-3 w-3\" />\n </div>\n\n {/* Slot 2: Primary value + qualifier */}\n <div className=\"min-w-0\">\n {isCombined ? (\n <CombinedSignalMiniChips components={signal.components!} />\n ) : (\n <div className=\"flex items-baseline gap-1.5\">\n <span className=\"text-sm font-semibold tabular-nums text-foreground\">\n {slotValue(signal.primaryValue)}\n </span>\n <span className=\"text-xs text-muted-foreground\">\n {slotValue(signal.qualifier)}\n </span>\n </div>\n )}\n </div>\n\n {/* Slot 3: Counterparty */}\n <div className=\"min-w-0\">\n <span className=\"block truncate text-xs text-muted-foreground\">\n {slotValue(signal.counterparty)}\n </span>\n </div>\n\n {/* Slot 4: Time */}\n <span className=\"shrink-0 text-[11px] text-muted-foreground/70\">\n {slotValue(signal.time)}\n </span>\n\n {/* Slot 5: Chevron */}\n <ChevronRight className=\"h-3 w-3 shrink-0 text-muted-foreground/60 transition-transform group-hover:translate-x-0.5 group-hover:text-foreground/50\" />\n\n {/* Balance context strip — spans full row below grid columns */}\n {hasBalance && (\n <div\n className=\"col-span-full mt-0.5 text-[10px] text-muted-foreground/70\"\n data-testid=\"balance-context-strip\"\n >\n {signal.currentBalance && (\n <span>\n Current balance <span className=\"font-medium text-muted-foreground\">{signal.currentBalance}</span>\n </span>\n )}\n {signal.balanceContext && (\n <span>\n {signal.currentBalance ? \" · \" : \"\"}\n {signal.balanceContext}\n </span>\n )}\n </div>\n )}\n </>\n )\n\n if (signal.id && onOpenSignalBucket) {\n return (\n <button\n type=\"button\"\n className=\"group grid w-full cursor-pointer items-center gap-x-3 gap-y-1 rounded-md px-3 py-2 text-left transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n style={{ gridTemplateColumns: \"20px minmax(0,1fr) minmax(0,1fr) auto 16px\" }}\n onClick={() => onOpenSignalBucket({ item, bucketKey, signalId: signal.id! })}\n >\n {rowContent}\n </button>\n )\n }\n\n return (\n <div\n className=\"grid w-full items-center gap-x-3 gap-y-1 rounded-md px-3 py-2\"\n style={{ gridTemplateColumns: \"20px minmax(0,1fr) minmax(0,1fr) auto 16px\" }}\n >\n {rowContent}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Legacy SignalRow (for signals without structured data)\n// ---------------------------------------------------------------------------\n\ninterface SignalRowProps {\n item: QueueItem\n bucketKey: string\n signal: SignalScoreExplanationSignal\n onOpenSignalBucket?: ScoreWhyChipsProps[\"onOpenSignalBucket\"]\n}\n\nfunction LegacySignalRow({ item, bucketKey, signal, onOpenSignalBucket }: SignalRowProps) {\n const isClickable = !!(signal.id && onOpenSignalBucket)\n const rowContent = (\n <>\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-medium text-foreground\">{signal.label}</p>\n {signal.description ? <p className=\"mt-1 leading-relaxed text-muted-foreground\">{signal.description}</p> : null}\n {(signal.source || signal.metric) && (\n <div className=\"mt-1.5 flex flex-wrap gap-1.5 text-[11px] text-muted-foreground/80\">\n {signal.source ? <span className=\"rounded-full bg-muted px-2 py-0.5\">{signal.source}</span> : null}\n {signal.metric ? <span className=\"rounded-full bg-muted px-2 py-0.5\">{signal.metric}</span> : null}\n </div>\n )}\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n {signal.time ? <span className=\"text-[11px] text-muted-foreground/70\">{signal.time}</span> : null}\n {isClickable && (\n <ChevronRight className=\"h-3 w-3 text-muted-foreground/60 transition-transform group-hover:translate-x-0.5 group-hover:text-foreground/50\" />\n )}\n </div>\n </div>\n </>\n )\n\n if (isClickable) {\n return (\n <button\n type=\"button\"\n className=\"group w-full cursor-pointer rounded-md bg-background/80 p-3 text-left text-xs transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n onClick={() => onOpenSignalBucket!({ item, bucketKey, signalId: signal.id! })}\n >\n {rowContent}\n </button>\n )\n }\n\n return <div className=\"rounded-md bg-background/80 p-3 text-xs\">{rowContent}</div>\n}\n\n/**\n * Determine whether a signal has structured slot data.\n * If it has primaryValue, counterparty, qualifier, or components, use the structured row.\n */\nfunction hasStructuredData(signal: SignalScoreExplanationSignal): boolean {\n return Boolean(\n signal.primaryValue ||\n signal.qualifier ||\n signal.counterparty ||\n (signal.components && signal.components.length > 0),\n )\n}\n\n// ---------------------------------------------------------------------------\n// WhyCard - Expanded panel under a pill\n// ---------------------------------------------------------------------------\n\ninterface WhyCardProps {\n bucket: SignalScoreExplanationBucket\n signals: SignalScoreExplanationSignal[]\n item: QueueItem\n panelId: string\n onOpenSignalBucket?: ScoreWhyChipsProps[\"onOpenSignalBucket\"]\n onBucketFeedback?: (bucketKey: string, data: FeedbackSubmitData) => void\n /** Persisted bucket-level feedback to hydrate from. */\n initialBucketFeedback?: PersistedFeedbackData | null\n}\n\nfunction WhyCard({ bucket, signals, item, panelId, onOpenSignalBucket, onBucketFeedback, initialBucketFeedback }: WhyCardProps) {\n const [showAll, setShowAll] = React.useState(false)\n const [bucketFeedback, setBucketFeedback] = React.useState<\"positive\" | \"negative\" | null>(null)\n const totalCount = bucket.signalCount ?? signals.length\n const visibleSignals = showAll ? signals : signals.slice(0, DEFAULT_VISIBLE_ROWS)\n const hiddenCount = signals.length - DEFAULT_VISIBLE_ROWS\n\n // Determine whether to use structured rows (any signal has structured data)\n const useStructured = signals.some(hasStructuredData)\n\n return (\n <div\n id={panelId}\n className=\"rounded-lg rounded-t-none border border-t-0 border-border bg-muted/20 p-3\"\n role=\"region\"\n aria-label={`${bucket.label} details`}\n >\n {/* Card header */}\n <div className=\"mb-2 flex items-center justify-between\">\n <span className=\"text-[10px] font-bold uppercase tracking-wider text-muted-foreground\">\n {totalCount} signal{totalCount !== 1 ? \"s\" : \"\"} &ndash; {bucket.label}\n </span>\n </div>\n\n {/* Signal rows */}\n {visibleSignals.length > 0 ? (\n <ul className=\"divide-y divide-border/30\" aria-label=\"Matching signals\">\n {visibleSignals.map((signal, index) => (\n <li key={signal.id ?? `${bucket.key}-signal-${index}`}>\n {useStructured ? (\n <StructuredSignalRow\n item={item}\n bucketKey={bucket.key}\n signal={signal}\n tone={bucket.tone}\n onOpenSignalBucket={onOpenSignalBucket}\n />\n ) : (\n <LegacySignalRow\n item={item}\n bucketKey={bucket.key}\n signal={signal}\n onOpenSignalBucket={onOpenSignalBucket}\n />\n )}\n </li>\n ))}\n </ul>\n ) : bucket.evidence && bucket.evidence.length > 0 ? (\n <ul className=\"mt-3 space-y-1.5\" aria-label=\"Matching signals\">\n {bucket.evidence.map((evidence, index) => (\n <li key={`${bucket.key}-evidence-${index}`} className=\"flex gap-2 text-xs text-muted-foreground\">\n <span className=\"mt-1.5 h-1 w-1 shrink-0 rounded-full bg-primary\" />\n <span className=\"leading-relaxed\">{evidence}</span>\n </li>\n ))}\n </ul>\n ) : null}\n\n {/* \"Show N more\" button */}\n {!showAll && hiddenCount > 0 && (\n <button\n type=\"button\"\n onClick={() => setShowAll(true)}\n className=\"mt-2 flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground\"\n >\n <ChevronDown className=\"h-3 w-3\" />\n Show {hiddenCount} more\n </button>\n )}\n\n {/* Bucket feedback footer */}\n {onBucketFeedback && (\n <div className=\"mt-3 border-t border-border/40 pt-3\">\n <FeedbackFooter\n feedback={bucketFeedback}\n onFeedbackChange={setBucketFeedback}\n onSubmit={(data) => onBucketFeedback(bucket.key, data)}\n negativeChips={BUCKET_NEGATIVE_CHIPS}\n negativePrompt=\"Was this bucket useful?\"\n positivePrompt=\"Thanks! What was useful about this bucket?\"\n initialFeedback={initialBucketFeedback}\n feedbackKey={bucket.key}\n />\n </div>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// ScoreWhyChips - Main export\n// ---------------------------------------------------------------------------\n\nexport interface ScoreWhyChipsProps {\n item: QueueItem\n signalData: SignalScoreData\n onOpenSignalBucket?: (args: { item: QueueItem; bucketKey: string; signalId: string }) => void\n className?: string\n}\n\nexport function ScoreWhyChips({\n item,\n signalData,\n onOpenSignalBucket,\n className,\n}: ScoreWhyChipsProps) {\n const [selectedBucketKey, setSelectedBucketKey] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n setSelectedBucketKey(null)\n }, [item.id])\n\n const reactId = React.useId()\n const idPrefix = makeDomId(\"score-why\", reactId, item.id)\n const buckets = React.useMemo(() => getSignalScoreBuckets(signalData), [signalData])\n const selectedBucket = buckets.find((bucket) => bucket.key === selectedBucketKey) ?? null\n const selectedBucketSignals = selectedBucket ? getBucketSignals(selectedBucket) : []\n const selectedPanelId = selectedBucket ? `${idPrefix}-panel-${makeDomId(selectedBucket.key)}` : undefined\n\n if (buckets.length === 0) return null\n\n return (\n <div className={cn(\"mt-4\", className)}>\n <div className=\"mb-2 flex items-center gap-2\">\n <span className=\"text-[10px] font-bold uppercase tracking-wider text-muted-foreground\">Why</span>\n </div>\n <div className=\"flex flex-wrap gap-1.5\">\n {buckets.map((bucket) => {\n const isSelected = selectedBucketKey === bucket.key\n const panelId = `${idPrefix}-panel-${makeDomId(bucket.key)}`\n const signals = getBucketSignals(bucket)\n const signalCount = bucket.signalCount ?? signals.length\n return (\n <div key={bucket.key} className=\"flex flex-col\">\n <WhyPill\n bucket={bucket}\n isSelected={isSelected}\n signalCount={signalCount}\n panelId={panelId}\n onToggle={() => setSelectedBucketKey((prev) => (prev === bucket.key ? null : bucket.key))}\n onClose={() => setSelectedBucketKey(null)}\n />\n </div>\n )\n })}\n </div>\n\n {selectedBucket && selectedPanelId && (\n <WhyCard\n bucket={selectedBucket}\n signals={selectedBucketSignals}\n item={item}\n panelId={selectedPanelId}\n onOpenSignalBucket={onOpenSignalBucket}\n onBucketFeedback={signalData.onBucketFeedback}\n initialBucketFeedback={signalData.initialBucketFeedback?.[selectedBucket.key]}\n />\n )}\n </div>\n )\n}\n"],"mappings":"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","names":["_a"]}
1
+ {"version":3,"sources":["../../src/components/score-why-chips.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport {\n ChevronDown,\n ChevronUp,\n ChevronRight,\n X,\n TrendingDown,\n ArrowUpRight,\n Radar,\n ArrowDownLeft,\n GitMerge,\n Activity,\n} from \"lucide-react\"\nimport type { LucideIcon } from \"lucide-react\"\nimport { FeedbackFooter } from \"./feedback-primitives\"\nimport type { FeedbackChipTree, FeedbackSubmitData } from \"./feedback-primitives\"\nimport { cn } from \"../lib/utils\"\nimport type {\n QueueItem,\n SignalScoreData,\n SignalScoreExplanationBucket,\n SignalScoreExplanationSignal,\n SignalScoreUrgencyLabel,\n} from \"../prototype/prototype-config\"\n\n// ---------------------------------------------------------------------------\n// Constants & helpers\n// ---------------------------------------------------------------------------\n\nexport function getSignalScoreUrgencyLabel(\n score: number,\n providedLabel?: SignalScoreUrgencyLabel,\n): SignalScoreUrgencyLabel {\n if (providedLabel) return providedLabel\n if (score >= 80) return \"Urgent\"\n if (score >= 60) return \"High\"\n if (score >= 35) return \"Medium\"\n return \"Low\"\n}\n\nexport function scoreRangeForUrgency(label: SignalScoreUrgencyLabel): string {\n switch (label) {\n case \"Urgent\":\n return \"80-100\"\n case \"High\":\n return \"60-79\"\n case \"Medium\":\n return \"35-59\"\n case \"Low\":\n return \"0-34\"\n }\n}\n\nfunction makeDomId(...parts: Array<string | undefined>): string {\n return parts\n .filter((part): part is string => Boolean(part))\n .join(\"-\")\n .replace(/[^A-Za-z0-9_-]+/g, \"-\")\n}\n\nfunction bucketHasSignalRows(bucket: SignalScoreExplanationBucket): boolean {\n return (\n (bucket.signals?.length ?? 0) > 0 ||\n (bucket.signalIds?.length ?? 0) > 0 ||\n Boolean(bucket.primarySignalId)\n )\n}\n\nfunction getSignalScoreBuckets(signalData: SignalScoreData): SignalScoreExplanationBucket[] {\n return (signalData.explanationBuckets ?? []).filter(\n (bucket) => bucket.kind !== \"factor\" && bucketHasSignalRows(bucket),\n )\n}\n\nfunction getBucketSignals(bucket: SignalScoreExplanationBucket): SignalScoreExplanationSignal[] {\n if (bucket.signals && bucket.signals.length > 0) return bucket.signals\n\n const signalIds = bucket.signalIds && bucket.signalIds.length > 0 ? bucket.signalIds : bucket.primarySignalId ? [bucket.primarySignalId] : []\n const uniqueSignalIds = Array.from(new Set(signalIds))\n\n return uniqueSignalIds.map((signalId) => ({\n id: signalId,\n label: `${bucket.label} signal`,\n }))\n}\n\n// ---------------------------------------------------------------------------\n// Signal type icon map - keyed by signal type name (Tailwind v4 source scanned)\n// ---------------------------------------------------------------------------\n\nconst SIGNAL_TYPE_ICONS: Record<string, LucideIcon> = {\n treasury_liquidation: TrendingDown,\n cumulative_treasury_outflow: ArrowUpRight,\n test_transaction: Radar,\n micro_deposit: ArrowDownLeft,\n combined_signal: GitMerge,\n}\n\nfunction resolveIcon(iconName?: string): LucideIcon {\n if (!iconName) return Activity\n return SIGNAL_TYPE_ICONS[iconName] ?? Activity\n}\n\n// ---------------------------------------------------------------------------\n// Static tone class maps (REQUIRED for Tailwind v4 source scanning)\n// ---------------------------------------------------------------------------\n\n/** Shared tone-to-class map. Re-exported for signal-priority-popover. */\nexport const SIGNAL_TONE_CLASSES: Record<string, string> = {\n alert: \"bg-red-50 text-red-600\",\n warn: \"bg-amber-50 text-amber-600\",\n info: \"bg-blue-50 text-blue-600\",\n}\n\n/** Default tone for missing/unknown tone values */\nexport const DEFAULT_TONE_CLASS = \"bg-muted text-muted-foreground\"\n\n// ---------------------------------------------------------------------------\n// Em-dash fallback for missing slot data\n// ---------------------------------------------------------------------------\n\nfunction slotValue(value: string | null | undefined): string {\n return value && value.trim().length > 0 ? value : \"\"\n}\n\n// ---------------------------------------------------------------------------\n// Bucket feedback chip config\n// ---------------------------------------------------------------------------\n\nconst BUCKET_NEGATIVE_CHIPS: FeedbackChipTree[] = [\n {\n label: \"Not relevant for this account\",\n subPrompt: \"Why isn't it relevant?\",\n subChips: [\n \"Business as usual for this account\",\n \"Account in maintenance mode\",\n \"Wrong contact for this signal\",\n \"Other\",\n ],\n },\n { label: \"Bad timing\" },\n {\n label: \"Inaccurate data\",\n subPrompt: \"Which field?\",\n subChips: [\"Balance figures\", \"Counterparty\", \"Timestamp\", \"Other\"],\n },\n { label: \"Wrong account\" },\n { label: \"Already handled\" },\n { label: \"Other\" },\n]\n\n// ---------------------------------------------------------------------------\n// Default visible row count for long lists\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_VISIBLE_ROWS = 8\n\n// ---------------------------------------------------------------------------\n// WhyPill - Bucket toggle button with icon, count badge, chevron, close\n// ---------------------------------------------------------------------------\n\ninterface WhyPillProps {\n bucket: SignalScoreExplanationBucket\n isSelected: boolean\n signalCount: number\n panelId: string\n onToggle: () => void\n onClose: () => void\n}\n\nfunction WhyPill({ bucket, isSelected, signalCount, panelId, onToggle, onClose }: WhyPillProps) {\n const IconComponent = resolveIcon(bucket.icon)\n\n const sharedClasses = cn(\n \"inline-flex items-center text-[11px] font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n isSelected\n ? \"border-border bg-muted text-foreground\"\n : \"border-border bg-background text-muted-foreground hover:bg-muted/60 hover:text-foreground\",\n )\n\n return (\n <div className=\"inline-flex h-[26px] items-stretch\">\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={isSelected}\n aria-controls={panelId}\n className={cn(\n sharedClasses,\n \"gap-1.5 rounded-lg border px-2.5 py-1\",\n isSelected && \"rounded-b-none rounded-r-none border-r-0\",\n )}\n >\n <IconComponent className=\"h-3 w-3 shrink-0\" />\n {bucket.label}\n {signalCount > 1 && (\n <span className={cn(\"rounded-full px-1.5 py-0 text-[10px]\", isSelected ? \"bg-background/60\" : \"bg-muted\")}>\n x{signalCount}\n </span>\n )}\n {isSelected ? (\n <ChevronUp className=\"h-3 w-3 shrink-0\" />\n ) : (\n <ChevronDown className=\"h-3 w-3 shrink-0\" />\n )}\n </button>\n {isSelected && (\n <button\n type=\"button\"\n aria-label={`Close ${bucket.label}`}\n onClick={onClose}\n className={cn(\n sharedClasses,\n \"rounded-lg rounded-b-none rounded-l-none border border-l-0 border-border px-1.5 py-1 hover:bg-background/60\",\n )}\n >\n <X className=\"h-3 w-3\" />\n </button>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// CombinedSignalMiniChips - renders component type chips for combined signals\n// ---------------------------------------------------------------------------\n\ninterface CombinedSignalMiniChipsProps {\n components: Array<{ type: string; count: number }>\n}\n\nfunction CombinedSignalMiniChips({ components }: CombinedSignalMiniChipsProps) {\n return (\n <div className=\"flex flex-wrap items-center gap-1\">\n {components.map((comp, idx) => {\n const CompIcon = resolveIcon(comp.type)\n return (\n <React.Fragment key={comp.type}>\n {idx > 0 && <span className=\"text-[10px] text-muted-foreground/60\">+</span>}\n <span className=\"inline-flex items-center gap-0.5 rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground\">\n <CompIcon className=\"h-2.5 w-2.5 shrink-0\" />\n {comp.type.replace(/_/g, \" \")} x{comp.count}\n </span>\n </React.Fragment>\n )\n })}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// StructuredSignalRow - CSS grid slot grammar signal row\n// ---------------------------------------------------------------------------\n\ninterface StructuredSignalRowProps {\n item: QueueItem\n bucketKey: string\n signal: SignalScoreExplanationSignal\n tone?: \"alert\" | \"warn\" | \"info\"\n onOpenSignalBucket?: ScoreWhyChipsProps[\"onOpenSignalBucket\"]\n}\n\nfunction StructuredSignalRow({ item, bucketKey, signal, tone, onOpenSignalBucket }: StructuredSignalRowProps) {\n const IconComponent = resolveIcon(signal.signalTypeName)\n const toneClass = tone ? (SIGNAL_TONE_CLASSES[tone] ?? DEFAULT_TONE_CLASS) : DEFAULT_TONE_CLASS\n const isCombined = signal.signalTypeName === \"combined_signal\" && signal.components && signal.components.length > 0\n\n const rowContent = (\n <>\n {/* Slot 1: Icon */}\n <div className={cn(\"flex h-5 w-5 shrink-0 items-center justify-center rounded\", toneClass)}>\n <IconComponent className=\"h-3 w-3\" />\n </div>\n\n {/* Slot 2: Primary value + qualifier */}\n <div className=\"min-w-0\">\n {isCombined ? (\n <CombinedSignalMiniChips components={signal.components!} />\n ) : (\n <div className=\"flex items-baseline gap-1.5\">\n <span className=\"text-sm font-semibold tabular-nums text-foreground\">\n {slotValue(signal.primaryValue)}\n </span>\n <span className=\"text-xs text-muted-foreground\">\n {slotValue(signal.qualifier)}\n </span>\n </div>\n )}\n </div>\n\n {/* Slot 3: Counterparty */}\n <div className=\"min-w-0\">\n <span className=\"block truncate text-xs text-muted-foreground\">\n {slotValue(signal.counterparty)}\n </span>\n </div>\n\n {/* Slot 4: Time */}\n <span className=\"shrink-0 text-[11px] text-muted-foreground/70\">\n {slotValue(signal.time)}\n </span>\n\n {/* Slot 5: Chevron */}\n <ChevronRight className=\"h-3 w-3 shrink-0 text-muted-foreground/60 transition-transform group-hover:translate-x-0.5 group-hover:text-foreground/50\" />\n </>\n )\n\n if (signal.id && onOpenSignalBucket) {\n return (\n <button\n type=\"button\"\n className=\"group grid w-full cursor-pointer items-center gap-x-3 gap-y-1 rounded-md px-3 py-2 text-left transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n style={{ gridTemplateColumns: \"20px minmax(0,1fr) minmax(0,1fr) auto 16px\" }}\n onClick={() => onOpenSignalBucket({ item, bucketKey, signalId: signal.id! })}\n >\n {rowContent}\n </button>\n )\n }\n\n return (\n <div\n className=\"grid w-full items-center gap-x-3 gap-y-1 rounded-md px-3 py-2\"\n style={{ gridTemplateColumns: \"20px minmax(0,1fr) minmax(0,1fr) auto 16px\" }}\n >\n {rowContent}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Legacy SignalRow (for signals without structured data)\n// ---------------------------------------------------------------------------\n\ninterface SignalRowProps {\n item: QueueItem\n bucketKey: string\n signal: SignalScoreExplanationSignal\n onOpenSignalBucket?: ScoreWhyChipsProps[\"onOpenSignalBucket\"]\n}\n\nfunction LegacySignalRow({ item, bucketKey, signal, onOpenSignalBucket }: SignalRowProps) {\n const isClickable = !!(signal.id && onOpenSignalBucket)\n const rowContent = (\n <>\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-medium text-foreground\">{signal.label}</p>\n {signal.description ? <p className=\"mt-1 leading-relaxed text-muted-foreground\">{signal.description}</p> : null}\n {(signal.source || signal.metric) && (\n <div className=\"mt-1.5 flex flex-wrap gap-1.5 text-[11px] text-muted-foreground/80\">\n {signal.source ? <span className=\"rounded-full bg-muted px-2 py-0.5\">{signal.source}</span> : null}\n {signal.metric ? <span className=\"rounded-full bg-muted px-2 py-0.5\">{signal.metric}</span> : null}\n </div>\n )}\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n {signal.time ? <span className=\"text-[11px] text-muted-foreground/70\">{signal.time}</span> : null}\n {isClickable && (\n <ChevronRight className=\"h-3 w-3 text-muted-foreground/60 transition-transform group-hover:translate-x-0.5 group-hover:text-foreground/50\" />\n )}\n </div>\n </div>\n </>\n )\n\n if (isClickable) {\n return (\n <button\n type=\"button\"\n className=\"group w-full cursor-pointer rounded-md bg-background/80 p-3 text-left text-xs transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n onClick={() => onOpenSignalBucket!({ item, bucketKey, signalId: signal.id! })}\n >\n {rowContent}\n </button>\n )\n }\n\n return <div className=\"rounded-md bg-background/80 p-3 text-xs\">{rowContent}</div>\n}\n\n/**\n * Determine whether a signal has structured slot data.\n * If it has primaryValue, counterparty, qualifier, or components, use the structured row.\n */\nfunction hasStructuredData(signal: SignalScoreExplanationSignal): boolean {\n return Boolean(\n signal.primaryValue ||\n signal.qualifier ||\n signal.counterparty ||\n (signal.components && signal.components.length > 0),\n )\n}\n\n// ---------------------------------------------------------------------------\n// WhyCard - Expanded panel under a pill\n// ---------------------------------------------------------------------------\n\ninterface WhyCardProps {\n bucket: SignalScoreExplanationBucket\n signals: SignalScoreExplanationSignal[]\n item: QueueItem\n panelId: string\n onOpenSignalBucket?: ScoreWhyChipsProps[\"onOpenSignalBucket\"]\n onBucketFeedback?: (bucketKey: string, data: FeedbackSubmitData) => void\n}\n\nfunction WhyCard({ bucket, signals, item, panelId, onOpenSignalBucket, onBucketFeedback }: WhyCardProps) {\n const [showAll, setShowAll] = React.useState(false)\n const [bucketFeedback, setBucketFeedback] = React.useState<\"positive\" | \"negative\" | null>(null)\n const totalCount = bucket.signalCount ?? signals.length\n const visibleSignals = showAll ? signals : signals.slice(0, DEFAULT_VISIBLE_ROWS)\n const hiddenCount = signals.length - DEFAULT_VISIBLE_ROWS\n\n // Determine whether to use structured rows (any signal has structured data)\n const useStructured = signals.some(hasStructuredData)\n\n return (\n <div\n id={panelId}\n className=\"rounded-lg rounded-t-none border border-t-0 border-border bg-muted/20 p-3\"\n role=\"region\"\n aria-label={`${bucket.label} details`}\n >\n {/* Card header */}\n <div className=\"mb-2 flex items-center justify-between\">\n <span className=\"text-[10px] font-bold uppercase tracking-wider text-muted-foreground\">\n {totalCount} signal{totalCount !== 1 ? \"s\" : \"\"} &ndash; {bucket.label}\n </span>\n </div>\n\n {/* Signal rows */}\n {visibleSignals.length > 0 ? (\n <ul className=\"divide-y divide-border/30\" aria-label=\"Matching signals\">\n {visibleSignals.map((signal, index) => (\n <li key={signal.id ?? `${bucket.key}-signal-${index}`}>\n {useStructured ? (\n <StructuredSignalRow\n item={item}\n bucketKey={bucket.key}\n signal={signal}\n tone={bucket.tone}\n onOpenSignalBucket={onOpenSignalBucket}\n />\n ) : (\n <LegacySignalRow\n item={item}\n bucketKey={bucket.key}\n signal={signal}\n onOpenSignalBucket={onOpenSignalBucket}\n />\n )}\n </li>\n ))}\n </ul>\n ) : bucket.evidence && bucket.evidence.length > 0 ? (\n <ul className=\"mt-3 space-y-1.5\" aria-label=\"Matching signals\">\n {bucket.evidence.map((evidence, index) => (\n <li key={`${bucket.key}-evidence-${index}`} className=\"flex gap-2 text-xs text-muted-foreground\">\n <span className=\"mt-1.5 h-1 w-1 shrink-0 rounded-full bg-primary\" />\n <span className=\"leading-relaxed\">{evidence}</span>\n </li>\n ))}\n </ul>\n ) : null}\n\n {/* \"Show N more\" button */}\n {!showAll && hiddenCount > 0 && (\n <button\n type=\"button\"\n onClick={() => setShowAll(true)}\n className=\"mt-2 flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground\"\n >\n <ChevronDown className=\"h-3 w-3\" />\n Show {hiddenCount} more\n </button>\n )}\n\n {/* Bucket feedback footer */}\n {onBucketFeedback && (\n <div className=\"mt-3 border-t border-border/40 pt-3\">\n <FeedbackFooter\n feedback={bucketFeedback}\n onFeedbackChange={setBucketFeedback}\n onSubmit={(data) => onBucketFeedback(bucket.key, data)}\n negativeChips={BUCKET_NEGATIVE_CHIPS}\n negativePrompt=\"Was this bucket useful?\"\n positivePrompt=\"Thanks! What was useful about this bucket?\"\n />\n </div>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// ScoreWhyChips - Main export\n// ---------------------------------------------------------------------------\n\nexport interface ScoreWhyChipsProps {\n item: QueueItem\n signalData: SignalScoreData\n onOpenSignalBucket?: (args: { item: QueueItem; bucketKey: string; signalId: string }) => void\n className?: string\n}\n\nexport function ScoreWhyChips({\n item,\n signalData,\n onOpenSignalBucket,\n className,\n}: ScoreWhyChipsProps) {\n const [selectedBucketKey, setSelectedBucketKey] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n setSelectedBucketKey(null)\n }, [item.id])\n\n const reactId = React.useId()\n const idPrefix = makeDomId(\"score-why\", reactId, item.id)\n const buckets = React.useMemo(() => getSignalScoreBuckets(signalData), [signalData])\n const selectedBucket = buckets.find((bucket) => bucket.key === selectedBucketKey) ?? null\n const selectedBucketSignals = selectedBucket ? getBucketSignals(selectedBucket) : []\n const selectedPanelId = selectedBucket ? `${idPrefix}-panel-${makeDomId(selectedBucket.key)}` : undefined\n\n if (buckets.length === 0) return null\n\n return (\n <div className={cn(\"mt-4\", className)}>\n <div className=\"mb-2 flex items-center gap-2\">\n <span className=\"text-[10px] font-bold uppercase tracking-wider text-muted-foreground\">Why</span>\n </div>\n <div className=\"flex flex-wrap gap-1.5\">\n {buckets.map((bucket) => {\n const isSelected = selectedBucketKey === bucket.key\n const panelId = `${idPrefix}-panel-${makeDomId(bucket.key)}`\n const signals = getBucketSignals(bucket)\n const signalCount = bucket.signalCount ?? signals.length\n return (\n <div key={bucket.key} className=\"flex flex-col\">\n <WhyPill\n bucket={bucket}\n isSelected={isSelected}\n signalCount={signalCount}\n panelId={panelId}\n onToggle={() => setSelectedBucketKey((prev) => (prev === bucket.key ? null : bucket.key))}\n onClose={() => setSelectedBucketKey(null)}\n />\n </div>\n )\n })}\n </div>\n\n {selectedBucket && selectedPanelId && (\n <WhyCard\n bucket={selectedBucket}\n signals={selectedBucketSignals}\n item={item}\n panelId={selectedPanelId}\n onOpenSignalBucket={onOpenSignalBucket}\n onBucketFeedback={signalData.onBucketFeedback}\n />\n )}\n </div>\n )\n}\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 } from '../signal-priority-popover-DWaAMhPI.js';
3
+ export { P as PriorityFactor, S as SignalPriorityPopover, k as SignalPriorityPopoverProps } from '../signal-priority-popover-DQ_VuHac.js';
4
4
  import './quick-action-sidebar-nav.js';
5
5
  import './quick-action-modal.js';
6
6
  import './score-breakdown.js';