@handled-ai/design-system 0.19.2 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/score-why-chips.d.ts +1 -1
- package/dist/components/signal-priority-popover.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/prototype/index.d.ts +1 -1
- package/dist/prototype/prototype-accounts-view.d.ts +1 -1
- package/dist/prototype/prototype-admin-view.d.ts +1 -1
- package/dist/prototype/prototype-config.d.ts +1 -1
- package/dist/prototype/prototype-inbox-view.d.ts +9 -2
- package/dist/prototype/prototype-inbox-view.js +61 -71
- package/dist/prototype/prototype-inbox-view.js.map +1 -1
- package/dist/prototype/prototype-insights-view.d.ts +1 -1
- package/dist/prototype/prototype-shell.d.ts +1 -1
- package/dist/{signal-priority-popover-CZitE9xq.d.ts → signal-priority-popover-Cg9XPJsp.d.ts} +5 -0
- package/package.json +1 -1
- package/src/components/__tests__/conversation-panel.test.tsx +1 -1
- package/src/prototype/__tests__/detail-view-metadata-layout.test.tsx +97 -0
- package/src/prototype/__tests__/detail-view-title-slots.test.tsx +30 -2
- package/src/prototype/prototype-config.ts +5 -0
- package/src/prototype/prototype-inbox-view.tsx +94 -73
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { Q as QueueItem, m as SignalScoreData, p as SignalScoreUrgencyLabel } from '../signal-priority-popover-
|
|
2
|
+
import { Q as QueueItem, m as SignalScoreData, p as SignalScoreUrgencyLabel } from '../signal-priority-popover-Cg9XPJsp.js';
|
|
3
3
|
import './feedback-primitives.js';
|
|
4
4
|
import './quick-action-sidebar-nav.js';
|
|
5
5
|
import './quick-action-modal.js';
|
|
@@ -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, l as SignalPriorityScoreDisplay } from '../signal-priority-popover-
|
|
3
|
+
export { P as PriorityFactor, S as SignalPriorityPopover, k as SignalPriorityPopoverProps, l as SignalPriorityScoreDisplay } from '../signal-priority-popover-Cg9XPJsp.js';
|
|
4
4
|
import './quick-action-sidebar-nav.js';
|
|
5
5
|
import './quick-action-modal.js';
|
|
6
6
|
import './score-breakdown.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ export { EmptyState, EmptyStateProps } from './components/empty-state.js';
|
|
|
40
40
|
export { ActivityItem, ConnectedApps, EntityActivityItem, EntityDetails, EntityMetadataField, EntityMetadataGrid, EntityPanel, EntityPanelBrandIcons, EntityPanelHeader, EntityPanelTabs, EntitySection, PanelMode, PotentialContacts, RecentActivity, SystemActivity, useEntityPanel } from './components/entity-panel.js';
|
|
41
41
|
export { RelatedRecordActionCard, RelatedRecordActionCardKind, RelatedRecordActionCardProps, RelatedRecordActionIcon } from './components/related-record-action-card.js';
|
|
42
42
|
export { FeedbackActions, FeedbackActionsProps, FeedbackChipGroup, FeedbackChipGroupProps, FeedbackChipTree, FeedbackFooter, FeedbackFooterProps, FeedbackInput, FeedbackInputProps, FeedbackSubmitData, InlineFeedbackControl, InlineFeedbackControlProps, PersistedFeedbackData } from './components/feedback-primitives.js';
|
|
43
|
-
export { A as AccountFilterTab, a as AccountsViewConfig, b as AdminTab, c as AdminViewConfig, B as BriefStyleVariant, E as EntityPanelConfig, d as EntityPanelSection, I as InboxDetailSections, e as InboxSortOption, f as InboxViewConfig, g as InsightsCustomTab, h as InsightsViewConfig, P as PriorityFactor, i as PrototypeBrandConfig, j as PrototypeConfig, Q as QueueItem, S as SignalPriorityPopover, k as SignalPriorityPopoverProps, l as SignalPriorityScoreDisplay, m as SignalScoreData, n as SignalScoreExplanationBucket, o as SignalScoreExplanationSignal, p as SignalScoreUrgencyLabel, T as TimelineSystemEventsConfig, W as WorkQueueViewConfig } from './signal-priority-popover-
|
|
43
|
+
export { A as AccountFilterTab, a as AccountsViewConfig, b as AdminTab, c as AdminViewConfig, B as BriefStyleVariant, E as EntityPanelConfig, d as EntityPanelSection, I as InboxDetailSections, e as InboxSortOption, f as InboxViewConfig, g as InsightsCustomTab, h as InsightsViewConfig, P as PriorityFactor, i as PrototypeBrandConfig, j as PrototypeConfig, Q as QueueItem, S as SignalPriorityPopover, k as SignalPriorityPopoverProps, l as SignalPriorityScoreDisplay, m as SignalScoreData, n as SignalScoreExplanationBucket, o as SignalScoreExplanationSignal, p as SignalScoreUrgencyLabel, T as TimelineSystemEventsConfig, W as WorkQueueViewConfig } from './signal-priority-popover-Cg9XPJsp.js';
|
|
44
44
|
export { FilterChip, FilterChipProps } from './components/filter-chip.js';
|
|
45
45
|
export { InboxGroupHeader, InboxRow, InboxRowProps } from './components/inbox-row.js';
|
|
46
46
|
export { AssigneeFilter, InboxFilterCategory, InboxToolbar, InboxToolbarProps } from './components/inbox-toolbar.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as AccountFilterTab, a as AccountsViewConfig, b as AdminTab, c as AdminViewConfig, B as BriefStyleVariant, E as EntityPanelConfig, d as EntityPanelSection, I as InboxDetailSections, e as InboxSortOption, f as InboxViewConfig, g as InsightsCustomTab, h as InsightsViewConfig, i as PrototypeBrandConfig, j as PrototypeConfig, Q as QueueItem, m as SignalScoreData, n as SignalScoreExplanationBucket, o as SignalScoreExplanationSignal, p as SignalScoreUrgencyLabel, T as TimelineSystemEventsConfig, W as WorkQueueViewConfig } from '../signal-priority-popover-
|
|
1
|
+
export { A as AccountFilterTab, a as AccountsViewConfig, b as AdminTab, c as AdminViewConfig, B as BriefStyleVariant, E as EntityPanelConfig, d as EntityPanelSection, I as InboxDetailSections, e as InboxSortOption, f as InboxViewConfig, g as InsightsCustomTab, h as InsightsViewConfig, i as PrototypeBrandConfig, j as PrototypeConfig, Q as QueueItem, m as SignalScoreData, n as SignalScoreExplanationBucket, o as SignalScoreExplanationSignal, p as SignalScoreUrgencyLabel, T as TimelineSystemEventsConfig, W as WorkQueueViewConfig } from '../signal-priority-popover-Cg9XPJsp.js';
|
|
2
2
|
export { PrototypeShell, PrototypeShellProps } from './prototype-shell.js';
|
|
3
3
|
export { DetailView, DetailViewProps, PrototypeInboxView, PrototypeInboxViewProps } from './prototype-inbox-view.js';
|
|
4
4
|
export { PrototypeInsightsView, PrototypeInsightsViewProps } from './prototype-insights-view.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { a as AccountsViewConfig } from '../signal-priority-popover-
|
|
2
|
+
import { a as AccountsViewConfig } from '../signal-priority-popover-Cg9XPJsp.js';
|
|
3
3
|
import { DataRow } from '../components/data-table.js';
|
|
4
4
|
import '../components/feedback-primitives.js';
|
|
5
5
|
import '../components/quick-action-sidebar-nav.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { c as AdminViewConfig } from '../signal-priority-popover-
|
|
2
|
+
import { c as AdminViewConfig } from '../signal-priority-popover-Cg9XPJsp.js';
|
|
3
3
|
import '../components/feedback-primitives.js';
|
|
4
4
|
import '../components/quick-action-sidebar-nav.js';
|
|
5
5
|
import '../components/quick-action-modal.js';
|
|
@@ -11,7 +11,7 @@ import '../charts/pipeline-overview.js';
|
|
|
11
11
|
import '../components/timeline-activity.js';
|
|
12
12
|
import '../components/signal-feedback-inline.js';
|
|
13
13
|
import 'lucide-react';
|
|
14
|
-
export { A as AccountFilterTab, a as AccountsViewConfig, b as AdminTab, c as AdminViewConfig, B as BriefStyleVariant, E as EntityPanelConfig, d as EntityPanelSection, I as InboxDetailSections, e as InboxSortOption, f as InboxViewConfig, g as InsightsCustomTab, h as InsightsViewConfig, i as PrototypeBrandConfig, j as PrototypeConfig, Q as QueueItem, m as SignalScoreData, n as SignalScoreExplanationBucket, o as SignalScoreExplanationSignal, p as SignalScoreUrgencyLabel, T as TimelineSystemEventsConfig, W as WorkQueueViewConfig } from '../signal-priority-popover-
|
|
14
|
+
export { A as AccountFilterTab, a as AccountsViewConfig, b as AdminTab, c as AdminViewConfig, B as BriefStyleVariant, E as EntityPanelConfig, d as EntityPanelSection, I as InboxDetailSections, e as InboxSortOption, f as InboxViewConfig, g as InsightsCustomTab, h as InsightsViewConfig, i as PrototypeBrandConfig, j as PrototypeConfig, Q as QueueItem, m as SignalScoreData, n as SignalScoreExplanationBucket, o as SignalScoreExplanationSignal, p as SignalScoreUrgencyLabel, T as TimelineSystemEventsConfig, W as WorkQueueViewConfig } from '../signal-priority-popover-Cg9XPJsp.js';
|
|
15
15
|
import '../components/feedback-primitives.js';
|
|
16
16
|
import '../components/quick-action-modal.js';
|
|
17
17
|
import '../components/score-semantics.js';
|
|
@@ -3,7 +3,7 @@ import { OpportunityDraft, ApprovalState, OpportunityPreview } from '../componen
|
|
|
3
3
|
import { SourceDef } from '../components/detail-view.js';
|
|
4
4
|
import { SuggestedAction, SuggestedContact } from '../components/suggested-actions.js';
|
|
5
5
|
import { TimelineEvent } from '../components/timeline-activity.js';
|
|
6
|
-
import { Q as QueueItem, I as InboxDetailSections, m as SignalScoreData, f as InboxViewConfig, B as BriefStyleVariant, T as TimelineSystemEventsConfig } from '../signal-priority-popover-
|
|
6
|
+
import { Q as QueueItem, I as InboxDetailSections, m as SignalScoreData, f as InboxViewConfig, B as BriefStyleVariant, T as TimelineSystemEventsConfig } from '../signal-priority-popover-Cg9XPJsp.js';
|
|
7
7
|
import '../components/feedback-primitives.js';
|
|
8
8
|
import '../components/quick-action-sidebar-nav.js';
|
|
9
9
|
import '../components/quick-action-modal.js';
|
|
@@ -61,6 +61,13 @@ interface DetailViewProps {
|
|
|
61
61
|
renderTitleSubtext?: (item: QueueItem) => React.ReactNode;
|
|
62
62
|
/** Render extra metadata chips (e.g. assignee) inside the chips row below the title. */
|
|
63
63
|
renderMetadataExtra?: (item: QueueItem) => React.ReactNode;
|
|
64
|
+
/**
|
|
65
|
+
* Where the metadata chips row (priority · deadline · account · renderMetadataExtra) sits.
|
|
66
|
+
* - "default": above the signal brief (legacy layout, unchanged for existing consumers).
|
|
67
|
+
* - "below-brief": moved beneath the brief text, just before `renderBeforeScore`
|
|
68
|
+
* (case-panel redesign — chips + owners read as one block under the brief).
|
|
69
|
+
*/
|
|
70
|
+
metadataLayout?: "default" | "below-brief";
|
|
64
71
|
/** Override the built-in account details metadata button label. */
|
|
65
72
|
accountDetailsButtonLabel?: (item: QueueItem) => React.ReactNode;
|
|
66
73
|
/** Accessible label for the built-in account details metadata button. */
|
|
@@ -88,7 +95,7 @@ interface DetailViewProps {
|
|
|
88
95
|
/** @deprecated Use `timelineSystemEventsConfig.visibleHint`. */
|
|
89
96
|
timelineSystemEventsVisibleHint?: string;
|
|
90
97
|
}
|
|
91
|
-
declare function DetailView({ item, sections, getSignalScore, buildSuggestedActions, buildSourceItems: _buildSourceItems, getTimelineEvents, accountContacts, emailSignature, iconMap, onOpenEntityPanel, onOpenRecentActivity, onSuggestedActionFeedback: _onSuggestedActionFeedback, onScoreFeedback: _onScoreFeedback, onSignalApprove, getSignalApprovalState, signalLabels, hideApproveButton, signalBriefCopy, briefStyleVariant, renderDetailExtra, renderBeforeScore, renderAfterScore, lastActivityTime, renderTitleExtra, renderTitleActionRow, renderTitleSubtext, renderMetadataExtra, accountDetailsButtonLabel, getAccountDetailsButtonAriaLabel, onOpenSignalBucket, approveButtonIconUrl, opportunityPreview, onRequestApproval, attentionCount, timelineSystemEventsConfig: configProp, timelineSystemEventsToggleLabel, timelineSystemEventsStorageKey, timelineSystemEventsDefaultVisible, timelineSystemEventsHiddenHint, timelineSystemEventsVisibleHint, }: DetailViewProps): React.JSX.Element;
|
|
98
|
+
declare function DetailView({ item, sections, getSignalScore, buildSuggestedActions, buildSourceItems: _buildSourceItems, getTimelineEvents, accountContacts, emailSignature, iconMap, onOpenEntityPanel, onOpenRecentActivity, onSuggestedActionFeedback: _onSuggestedActionFeedback, onScoreFeedback: _onScoreFeedback, onSignalApprove, getSignalApprovalState, signalLabels, hideApproveButton, signalBriefCopy, briefStyleVariant, renderDetailExtra, renderBeforeScore, renderAfterScore, lastActivityTime, renderTitleExtra, renderTitleActionRow, renderTitleSubtext, renderMetadataExtra, metadataLayout, accountDetailsButtonLabel, getAccountDetailsButtonAriaLabel, onOpenSignalBucket, approveButtonIconUrl, opportunityPreview, onRequestApproval, attentionCount, timelineSystemEventsConfig: configProp, timelineSystemEventsToggleLabel, timelineSystemEventsStorageKey, timelineSystemEventsDefaultVisible, timelineSystemEventsHiddenHint, timelineSystemEventsVisibleHint, }: DetailViewProps): React.JSX.Element;
|
|
92
99
|
declare function PrototypeInboxView({ items, filterCategories, detailSections, accountContacts, buildAccountContacts, emailSignature, buildSuggestedActions: buildSuggestedActionsProp, buildSourceItems: buildSourceItemsProp, getSignalScore: getSignalScoreProp, getTimelineEvents, iconMap, hideToolbarActions, hideHoverActions, onSuggestedActionFeedback, onScoreFeedback, onOpenSignalBucket, headerActions, onOpenEntityPanel, onOpenRecentActivity, onItemSelect, defaultViewMode, buildEntityChips, quickFilterTabs, hideAccountsButton, accountDetailsLabel, onSignalApprove, getSignalApprovalState, signalLabels, hideApproveButton, signalBriefCopy, briefStyleVariant, renderDetailExtra, renderBeforeScore, renderAfterScore, lastActivityTime, timelineSystemEventsConfig, attentionCount, renderTitleExtra, renderTitleActionRow, renderTitleSubtext, accountDetailsButtonLabel, getAccountDetailsButtonAriaLabel, sortOptions, activeSortId, onSortChange, }: PrototypeInboxViewProps): React.JSX.Element;
|
|
93
100
|
|
|
94
101
|
export { DetailView, type DetailViewProps, PrototypeInboxView, type PrototypeInboxViewProps };
|
|
@@ -214,6 +214,7 @@ function DetailView({
|
|
|
214
214
|
renderTitleActionRow,
|
|
215
215
|
renderTitleSubtext,
|
|
216
216
|
renderMetadataExtra,
|
|
217
|
+
metadataLayout = "default",
|
|
217
218
|
accountDetailsButtonLabel,
|
|
218
219
|
getAccountDetailsButtonAriaLabel,
|
|
219
220
|
onOpenSignalBucket,
|
|
@@ -308,6 +309,63 @@ function DetailView({
|
|
|
308
309
|
},
|
|
309
310
|
[suggestedActions]
|
|
310
311
|
);
|
|
312
|
+
const timeChipToneClass = signalData.timeChipTone === "red" ? "border-red-300 bg-red-50 text-red-700 hover:bg-red-50" : signalData.timeChipTone === "amber" ? "border-amber-300 bg-amber-50 text-amber-700 hover:bg-amber-50" : "hover:bg-muted/50";
|
|
313
|
+
const metadataChips = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
314
|
+
/* @__PURE__ */ jsx(
|
|
315
|
+
SignalPriorityPopover,
|
|
316
|
+
{
|
|
317
|
+
score: signalData.score,
|
|
318
|
+
urgencyLabel: signalData.urgencyLabel,
|
|
319
|
+
urgencyExplanation: (_b = signalData.urgencyExplanation) != null ? _b : signalData.signalBrief,
|
|
320
|
+
scoreDisplay: signalData.priorityScoreDisplay,
|
|
321
|
+
formulaLabel: signalData.priorityFormulaLabel,
|
|
322
|
+
factors: (_c = signalData.priorityFactors) != null ? _c : [],
|
|
323
|
+
metaText: void 0,
|
|
324
|
+
feedbackChips: signalData.priorityFeedbackChips,
|
|
325
|
+
onFeedbackSubmit: signalData.onPriorityFeedback,
|
|
326
|
+
initialFactorFeedback: signalData.initialFactorPopoverFeedback,
|
|
327
|
+
onFactorFeedback: signalData.onFactorFeedback,
|
|
328
|
+
initialPriorityFeedback: signalData.initialPriorityFeedback
|
|
329
|
+
}
|
|
330
|
+
),
|
|
331
|
+
signalData.timeChipLabel && /* @__PURE__ */ jsx(
|
|
332
|
+
Badge,
|
|
333
|
+
{
|
|
334
|
+
variant: "outline",
|
|
335
|
+
title: (_d = signalData.timeChipDetail) != null ? _d : void 0,
|
|
336
|
+
className: `transition-colors ${timeChipToneClass}`,
|
|
337
|
+
children: signalData.timeChipLabel
|
|
338
|
+
}
|
|
339
|
+
),
|
|
340
|
+
/* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 300, children: /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
341
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
342
|
+
"button",
|
|
343
|
+
{
|
|
344
|
+
type: "button",
|
|
345
|
+
onClick: onOpenEntityPanel,
|
|
346
|
+
className: "group/account ml-1 inline-flex max-w-full items-center gap-2 rounded-md border border-border/60 bg-background px-2 py-1 transition-colors hover:border-border hover:bg-muted/50",
|
|
347
|
+
"aria-label": (_e = getAccountDetailsButtonAriaLabel == null ? void 0 : getAccountDetailsButtonAriaLabel(item)) != null ? _e : `View account details for ${item.company}`,
|
|
348
|
+
children: [
|
|
349
|
+
/* @__PURE__ */ jsx("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded bg-foreground text-[9px] font-semibold uppercase leading-none text-background", children: getCompanyInitials(item.company) }),
|
|
350
|
+
accountDetailsButtonLabel ? /* @__PURE__ */ jsx("span", { className: "inline-flex min-w-0 items-center gap-1.5 text-xs font-medium text-foreground", children: accountDetailsButtonLabel(item) }) : /* @__PURE__ */ jsx("span", { className: "truncate text-xs font-medium text-foreground", children: item.company }),
|
|
351
|
+
/* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1.5", children: [
|
|
352
|
+
/* @__PURE__ */ jsx(
|
|
353
|
+
"span",
|
|
354
|
+
{
|
|
355
|
+
"aria-hidden": true,
|
|
356
|
+
className: `h-1.5 w-1.5 shrink-0 rounded-full ${(_f = STATUS_DOT_CLASS[item.statusColor]) != null ? _f : "bg-muted-foreground/40"}`
|
|
357
|
+
}
|
|
358
|
+
),
|
|
359
|
+
/* @__PURE__ */ jsx("span", { className: "-ml-1.5 grid grid-cols-[0fr] transition-all duration-200 ease-out group-hover/account:ml-0 group-hover/account:grid-cols-[1fr]", children: /* @__PURE__ */ jsx("span", { className: "overflow-hidden", children: /* @__PURE__ */ jsx("span", { className: "block whitespace-nowrap text-xs font-medium text-muted-foreground/80", children: "View account" }) }) }),
|
|
360
|
+
/* @__PURE__ */ jsx(ChevronRight, { className: "h-3 w-3 shrink-0 text-muted-foreground/50 transition-transform duration-150 group-hover/account:translate-x-0.5 group-hover/account:text-muted-foreground" })
|
|
361
|
+
] })
|
|
362
|
+
]
|
|
363
|
+
}
|
|
364
|
+
) }),
|
|
365
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: "Open account panel" })
|
|
366
|
+
] }) }),
|
|
367
|
+
renderMetadataExtra == null ? void 0 : renderMetadataExtra(item)
|
|
368
|
+
] });
|
|
311
369
|
return /* @__PURE__ */ jsx(
|
|
312
370
|
SignalApproval.Root,
|
|
313
371
|
{
|
|
@@ -330,21 +388,7 @@ function DetailView({
|
|
|
330
388
|
},
|
|
331
389
|
children: /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-3xl p-6 pb-12 md:p-8", children: [
|
|
332
390
|
/* @__PURE__ */ jsxs("div", { className: "pb-8", children: [
|
|
333
|
-
/* @__PURE__ */
|
|
334
|
-
/* @__PURE__ */ jsxs(
|
|
335
|
-
"button",
|
|
336
|
-
{
|
|
337
|
-
type: "button",
|
|
338
|
-
className: "flex items-center gap-1.5 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground",
|
|
339
|
-
children: [
|
|
340
|
-
/* @__PURE__ */ jsx(ArrowLeft, { className: "h-3.5 w-3.5" }),
|
|
341
|
-
"Back"
|
|
342
|
-
]
|
|
343
|
-
}
|
|
344
|
-
),
|
|
345
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground/40", children: "\xB7" }),
|
|
346
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: item.company })
|
|
347
|
-
] }),
|
|
391
|
+
/* @__PURE__ */ jsx("div", { className: "mb-4 flex items-center gap-2", children: /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: item.company }) }),
|
|
348
392
|
/* @__PURE__ */ jsxs("div", { className: "mb-3 space-y-3", children: [
|
|
349
393
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start gap-x-3 gap-y-2", children: [
|
|
350
394
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
@@ -355,62 +399,7 @@ function DetailView({
|
|
|
355
399
|
] }),
|
|
356
400
|
renderTitleActionRow ? /* @__PURE__ */ jsx("div", { className: "flex w-full flex-wrap items-center gap-2", children: renderTitleActionRow(item) }) : null
|
|
357
401
|
] }),
|
|
358
|
-
/* @__PURE__ */
|
|
359
|
-
/* @__PURE__ */ jsx(
|
|
360
|
-
SignalPriorityPopover,
|
|
361
|
-
{
|
|
362
|
-
score: signalData.score,
|
|
363
|
-
urgencyLabel: signalData.urgencyLabel,
|
|
364
|
-
urgencyExplanation: (_b = signalData.urgencyExplanation) != null ? _b : signalData.signalBrief,
|
|
365
|
-
scoreDisplay: signalData.priorityScoreDisplay,
|
|
366
|
-
formulaLabel: signalData.priorityFormulaLabel,
|
|
367
|
-
factors: (_c = signalData.priorityFactors) != null ? _c : [],
|
|
368
|
-
metaText: void 0,
|
|
369
|
-
feedbackChips: signalData.priorityFeedbackChips,
|
|
370
|
-
onFeedbackSubmit: signalData.onPriorityFeedback,
|
|
371
|
-
initialFactorFeedback: signalData.initialFactorPopoverFeedback,
|
|
372
|
-
onFactorFeedback: signalData.onFactorFeedback,
|
|
373
|
-
initialPriorityFeedback: signalData.initialPriorityFeedback
|
|
374
|
-
}
|
|
375
|
-
),
|
|
376
|
-
signalData.timeChipLabel && /* @__PURE__ */ jsx(
|
|
377
|
-
Badge,
|
|
378
|
-
{
|
|
379
|
-
variant: "outline",
|
|
380
|
-
title: (_d = signalData.timeChipDetail) != null ? _d : void 0,
|
|
381
|
-
className: "transition-colors hover:bg-muted/50",
|
|
382
|
-
children: signalData.timeChipLabel
|
|
383
|
-
}
|
|
384
|
-
),
|
|
385
|
-
/* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 300, children: /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
386
|
-
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
387
|
-
"button",
|
|
388
|
-
{
|
|
389
|
-
type: "button",
|
|
390
|
-
onClick: onOpenEntityPanel,
|
|
391
|
-
className: "group/account ml-1 inline-flex max-w-full items-center gap-2 rounded-md border border-border/60 bg-background px-2 py-1 transition-colors hover:border-border hover:bg-muted/50",
|
|
392
|
-
"aria-label": (_e = getAccountDetailsButtonAriaLabel == null ? void 0 : getAccountDetailsButtonAriaLabel(item)) != null ? _e : `View account details for ${item.company}`,
|
|
393
|
-
children: [
|
|
394
|
-
/* @__PURE__ */ jsx("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded bg-foreground text-[9px] font-semibold uppercase leading-none text-background", children: getCompanyInitials(item.company) }),
|
|
395
|
-
accountDetailsButtonLabel ? /* @__PURE__ */ jsx("span", { className: "inline-flex min-w-0 items-center gap-1.5 text-xs font-medium text-foreground", children: accountDetailsButtonLabel(item) }) : /* @__PURE__ */ jsx("span", { className: "truncate text-xs font-medium text-foreground", children: item.company }),
|
|
396
|
-
/* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1.5", children: [
|
|
397
|
-
/* @__PURE__ */ jsx(
|
|
398
|
-
"span",
|
|
399
|
-
{
|
|
400
|
-
"aria-hidden": true,
|
|
401
|
-
className: `h-1.5 w-1.5 shrink-0 rounded-full ${(_f = STATUS_DOT_CLASS[item.statusColor]) != null ? _f : "bg-muted-foreground/40"}`
|
|
402
|
-
}
|
|
403
|
-
),
|
|
404
|
-
/* @__PURE__ */ jsx("span", { className: "-ml-1.5 grid grid-cols-[0fr] transition-all duration-200 ease-out group-hover/account:ml-0 group-hover/account:grid-cols-[1fr]", children: /* @__PURE__ */ jsx("span", { className: "overflow-hidden", children: /* @__PURE__ */ jsx("span", { className: "block whitespace-nowrap text-xs font-medium text-muted-foreground/80", children: "View account" }) }) }),
|
|
405
|
-
/* @__PURE__ */ jsx(ChevronRight, { className: "h-3 w-3 shrink-0 text-muted-foreground/50 transition-transform duration-150 group-hover/account:translate-x-0.5 group-hover/account:text-muted-foreground" })
|
|
406
|
-
] })
|
|
407
|
-
]
|
|
408
|
-
}
|
|
409
|
-
) }),
|
|
410
|
-
/* @__PURE__ */ jsx(TooltipContent, { children: "Open account panel" })
|
|
411
|
-
] }) }),
|
|
412
|
-
renderMetadataExtra == null ? void 0 : renderMetadataExtra(item)
|
|
413
|
-
] }),
|
|
402
|
+
metadataLayout === "default" ? /* @__PURE__ */ jsx("div", { className: "mb-6 flex flex-wrap items-center gap-2", children: metadataChips }) : null,
|
|
414
403
|
sections.signalBrief && (() => {
|
|
415
404
|
var _a2;
|
|
416
405
|
const briefHeading = (_a2 = signalBriefCopy == null ? void 0 : signalBriefCopy.heading) != null ? _a2 : "Signal brief";
|
|
@@ -421,6 +410,7 @@ function DetailView({
|
|
|
421
410
|
briefHeading ? /* @__PURE__ */ jsx("h3", { className: "text-xs font-bold text-muted-foreground uppercase tracking-wider mb-3", children: briefHeading }) : null,
|
|
422
411
|
briefIntro && !signalData.signalBrief ? /* @__PURE__ */ jsx("p", { className: isProminent ? "text-sm text-foreground/70 leading-relaxed mb-2" : "text-sm text-muted-foreground leading-relaxed mb-2", children: briefIntro }) : null,
|
|
423
412
|
signalData.signalBrief ? /* @__PURE__ */ jsx("p", { className: isProminent ? "text-base text-foreground leading-relaxed mb-4" : "text-sm text-foreground/90 leading-relaxed mb-4", children: signalData.signalBrief }) : /* @__PURE__ */ jsx("p", { className: isProminent ? "text-base text-foreground leading-relaxed mb-4" : "text-sm text-foreground/90 leading-relaxed mb-4", children: signalData.whyNow }),
|
|
413
|
+
metadataLayout === "below-brief" ? /* @__PURE__ */ jsx("div", { className: "mb-4 flex flex-wrap items-center gap-2", children: metadataChips }) : null,
|
|
424
414
|
renderBeforeScore == null ? void 0 : renderBeforeScore(item),
|
|
425
415
|
/* @__PURE__ */ jsx(
|
|
426
416
|
ScoreWhyChips,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/prototype/prototype-inbox-view.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport {\n ArrowLeft,\n ArrowUpDown,\n ChevronDown,\n ChevronRight,\n Filter,\n FileText,\n Clock,\n CheckSquare,\n Eye,\n Plus,\n\n Building,\n LayoutList,\n Columns2,\n Square,\n Tag,\n} from \"lucide-react\"\n\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuTrigger,\n} from \"../components/dropdown-menu\"\nimport { Button } from \"../components/button\"\nimport { Badge } from \"../components/badge\"\nimport { Input } from \"../components/input\"\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"../components/tooltip\"\nimport { ViewModeToggle } from \"../components/view-mode-toggle\"\nimport {\n InboxToolbar,\n type AssigneeFilter,\n type InboxFilterCategory,\n} from \"../components/inbox-toolbar\"\nimport { GroupedListView, type GroupedListGroup } from \"../components/item-list\"\nimport { SignalApproval, type ApprovalState, type OpportunityDraft, type OpportunityPreview } from \"../components/signal-feedback-inline\"\nimport { ScoreWhyChips } from \"../components/score-why-chips\"\nimport { SignalPriorityPopover } from \"../components/signal-priority-popover\"\nimport { type SourceDef } from \"../components/detail-view\"\nimport {\n SuggestedActions,\n type SuggestedAction,\n type SuggestedContact,\n} from \"../components/suggested-actions\"\nimport { TimelineActivity, type TimelineEvent } from \"../components/timeline-activity\"\nimport type {\n QueueItem,\n InboxViewConfig,\n InboxDetailSections,\n SignalScoreData,\n BriefStyleVariant,\n TimelineSystemEventsConfig,\n} from \"./prototype-config\"\n\n// ---------------------------------------------------------------------------\n// Dot color utility — maps statusColor to a Tailwind background class.\n// Centralised here so the list row and split-view card stay in sync and\n// future color additions are a single-edit change.\n// ---------------------------------------------------------------------------\n\nfunction dotColorClass(statusColor: string): string {\n if (statusColor === \"red\") return \"bg-[#f43f5e]\"\n if (statusColor === \"yellow\" || statusColor === \"amber\" || statusColor === \"orange\") return \"bg-[#eab308]\"\n if (statusColor === \"green\") return \"bg-[#22c55e]\"\n return \"bg-[#9ca3af]\"\n}\n\n// ---------------------------------------------------------------------------\n// Props\n// ---------------------------------------------------------------------------\n\nexport interface PrototypeInboxViewProps extends InboxViewConfig {\n /** Extra ReactNode rendered at the end of the header bar (e.g. exit button). */\n headerActions?: React.ReactNode\n onOpenEntityPanel?: () => void\n onOpenRecentActivity?: () => void\n onNavigateToInbox?: () => void\n onItemSelect?: (item: QueueItem) => void\n defaultViewMode?: \"list\" | \"split\"\n}\n\n// ---------------------------------------------------------------------------\n// Default detail sections\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_DETAIL_SECTIONS: InboxDetailSections = {\n signalBrief: true,\n suggestedActions: true,\n timeline: true,\n}\n\nconst DEFAULT_SIGNAL_SCORE: SignalScoreData = {\n score: 65,\n factors: [\n { key: \"trigger\", label: \"Trigger strength\", score: 70, why: \"Moderate signal detected based on account activity\" },\n { key: \"fit\", label: \"Company fit\", score: 65, why: \"Reasonable fit based on company profile\" },\n { key: \"timing\", label: \"Timing\", score: 58, why: \"Within general evaluation window\" },\n ],\n whyNow: \"Moderate signals detected that warrant review and potential outreach.\",\n evidence: [\n \"Activity patterns suggest potential opportunity\",\n \"Company profile aligns with target segment\",\n ],\n confidence: 72,\n}\n\n// ---------------------------------------------------------------------------\n// Detail View\n// ---------------------------------------------------------------------------\n\n/** Up to 2-character uppercase initials for a company name (e.g. \"Northwind Systems\" -> \"NW\"). */\nfunction getCompanyInitials(company: string): string {\n const words = company.trim().split(/\\s+/).filter(Boolean)\n if (words.length === 0) return \"?\"\n if (words.length === 1) return words[0].slice(0, 2).toUpperCase()\n return (words[0][0] + words[1][0]).toUpperCase()\n}\n\n/** Maps a QueueItem.statusColor to a Tailwind dot background class. */\nconst STATUS_DOT_CLASS: Record<string, string> = {\n red: \"bg-red-500\",\n orange: \"bg-orange-500\",\n amber: \"bg-amber-500\",\n yellow: \"bg-yellow-500\",\n green: \"bg-emerald-500\",\n emerald: \"bg-emerald-500\",\n blue: \"bg-blue-500\",\n gray: \"bg-gray-300\",\n grey: \"bg-gray-300\",\n}\n\nexport interface DetailViewProps {\n item: QueueItem\n sections: InboxDetailSections\n getSignalScore: (company: string, item?: QueueItem) => SignalScoreData\n buildSuggestedActions: (item: QueueItem) => SuggestedAction[]\n buildSourceItems: (item: QueueItem) => SourceDef[]\n getTimelineEvents?: (item: QueueItem) => TimelineEvent[]\n accountContacts: SuggestedContact[]\n emailSignature: string | React.ReactNode\n iconMap: Record<string, string>\n onOpenEntityPanel?: () => void\n onOpenRecentActivity?: () => void\n onSuggestedActionFeedback?: (actionId: number | string, feedback: string, actionTitle?: string) => void\n /** @deprecated The compact score UX no longer renders score-level thumbs by default. */\n onScoreFeedback?: (type: \"up\" | \"down\", pills: string[], detail: string) => void\n onSignalApprove?: (item: QueueItem, draft?: OpportunityDraft) => void | Promise<boolean>\n getSignalApprovalState?: (item: QueueItem) => ApprovalState | undefined\n signalLabels?: InboxViewConfig[\"signalLabels\"]\n hideApproveButton?: boolean\n signalBriefCopy?: InboxViewConfig[\"signalBriefCopy\"]\n briefStyleVariant?: BriefStyleVariant\n renderDetailExtra?: (item: QueueItem) => React.ReactNode\n /** Render content between the signal brief text and the signal score bar (e.g. \"Signals on Case\" chips). */\n renderBeforeScore?: (item: QueueItem) => React.ReactNode\n /** Render content between the signal score section and the activity timeline. */\n renderAfterScore?: (item: QueueItem) => React.ReactNode\n lastActivityTime?: string\n /** Render extra content inline with the detail title. */\n renderTitleExtra?: (item: QueueItem) => React.ReactNode\n /** Render a full-width action row below the detail title row. */\n renderTitleActionRow?: (item: QueueItem) => React.ReactNode\n /** Render supporting content below the detail title. */\n renderTitleSubtext?: (item: QueueItem) => React.ReactNode\n /** Render extra metadata chips (e.g. assignee) inside the chips row below the title. */\n renderMetadataExtra?: (item: QueueItem) => React.ReactNode\n /** Override the built-in account details metadata button label. */\n accountDetailsButtonLabel?: (item: QueueItem) => React.ReactNode\n /** Accessible label for the built-in account details metadata button. */\n getAccountDetailsButtonAriaLabel?: (item: QueueItem) => string\n onOpenSignalBucket?: (args: { item: QueueItem; bucketKey: string; signalId: string }) => void\n approveButtonIconUrl?: string\n opportunityPreview?: OpportunityPreview\n onRequestApproval?: () => Promise<void>\n /** Number of important/attention-worthy events to highlight on the collapsed timeline header. */\n attentionCount?: number\n /** Configuration for the system-noise events toggle (score changes, etc.). */\n timelineSystemEventsConfig?: TimelineSystemEventsConfig\n\n // ── Deprecated individual props (use timelineSystemEventsConfig instead) ──\n /** @deprecated Use `timelineSystemEventsConfig.toggleLabel`. */\n timelineSystemEventsToggleLabel?: string\n /** @deprecated Use `timelineSystemEventsConfig.storageKey`. */\n timelineSystemEventsStorageKey?: string\n /** @deprecated Use `timelineSystemEventsConfig.defaultVisible`. */\n timelineSystemEventsDefaultVisible?: boolean\n /** @deprecated Use `timelineSystemEventsConfig.hiddenHint`. */\n timelineSystemEventsHiddenHint?: string\n /** @deprecated Use `timelineSystemEventsConfig.visibleHint`. */\n timelineSystemEventsVisibleHint?: string\n}\n\n// ---------------------------------------------------------------------------\n// TimelineSection — extracted from the IIFE in DetailView for readability\n// ---------------------------------------------------------------------------\n\nfunction TimelineSection({\n timelineEvents,\n showTimeline,\n setShowTimeline,\n showSystemEvents,\n setShowSystemEvents,\n attentionCount,\n sysEvtConfig,\n lastActivityTime,\n}: {\n timelineEvents: TimelineEvent[]\n showTimeline: boolean\n setShowTimeline: React.Dispatch<React.SetStateAction<boolean>>\n showSystemEvents: boolean\n setShowSystemEvents: React.Dispatch<React.SetStateAction<boolean>>\n attentionCount?: number\n sysEvtConfig?: TimelineSystemEventsConfig\n lastActivityTime?: string\n}) {\n // Single-pass partition: compute visibleEvents and hiddenCount together\n const visibleEvents: TimelineEvent[] = []\n let hiddenCount = 0\n for (const e of timelineEvents) {\n if (e.isSystemNoise) hiddenCount++\n if (!e.isSystemNoise || showSystemEvents) visibleEvents.push(e)\n }\n const hasSystemNoise = hiddenCount > 0\n\n // The toggle renders whenever there are system-noise events — even if no\n // config was provided — so consumers that emit `isSystemNoise: true` always\n // give users a way to reveal those events.\n const toggleLabel = sysEvtConfig?.toggleLabel ?? \"System events\"\n\n // Derive \"Last activity\" from the first *visible* event so the collapsed\n // header never points at a hidden score-update. The caller-supplied\n // `lastActivityTime` is only used when system-noise filtering is NOT active\n // (i.e. all events are visible) since it may come from an unfiltered source\n // such as `case.last_activity_at`.\n const firstVisibleTime =\n (!hasSystemNoise || showSystemEvents) && lastActivityTime\n ? lastActivityTime\n : visibleEvents.length > 0\n ? visibleEvents[0].time\n : \"\"\n\n const visibleCount = visibleEvents.length\n const eventCountLabel = `${visibleCount} ${visibleCount === 1 ? \"event\" : \"events\"}`\n\n return (\n <div className=\"mb-8\">\n {/* Header — outer non-interactive container */}\n <div\n className=\"group/timeline flex w-full items-center justify-between gap-2 py-2 rounded-md transition-colors hover:bg-muted/40 -mx-2 px-2\"\n data-testid=\"timeline-header\"\n >\n {/* Left: collapse/expand button */}\n <button\n type=\"button\"\n onClick={() => setShowTimeline((prev) => !prev)}\n className=\"flex items-center gap-2 cursor-pointer bg-transparent border-0 p-0\"\n data-testid=\"timeline-collapse-btn\"\n >\n <h3 className=\"text-xs font-bold text-muted-foreground uppercase tracking-wider group-hover/timeline:text-foreground transition-colors\">Activity timeline</h3>\n {!showTimeline && attentionCount != null && attentionCount > 0 && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-destructive/10 px-1.5 py-0.5 text-[10px] font-semibold text-destructive border border-destructive/20\">\n {attentionCount} new\n </span>\n )}\n {!showTimeline && firstVisibleTime && (\n <span className=\"text-[11px] text-muted-foreground/60\" data-testid=\"last-activity-hint\">\n · Last activity {firstVisibleTime}\n </span>\n )}\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-[11px] font-medium text-muted-foreground\" data-testid=\"event-count\">{eventCountLabel}</span>\n <ChevronDown className={`h-3.5 w-3.5 text-muted-foreground transition-transform duration-200 ${showTimeline ? \"rotate-180\" : \"\"}`} />\n </div>\n </button>\n\n {/* Right: system-events toggle — always rendered when noise events exist */}\n {hasSystemNoise && (\n <button\n type=\"button\"\n onClick={() => setShowSystemEvents((prev) => !prev)}\n className=\"flex shrink-0 items-center gap-1.5 rounded-full border border-border bg-background px-2.5 py-1 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-muted/40 hover:text-foreground cursor-pointer\"\n aria-pressed={showSystemEvents}\n data-testid=\"system-events-toggle\"\n >\n {toggleLabel}\n <span\n className=\"inline-flex items-center justify-center rounded-full bg-muted px-1.5 text-[10px] font-semibold min-w-[18px] tabular-nums\"\n data-testid=\"hidden-count-badge\"\n >\n {hiddenCount}\n </span>\n </button>\n )}\n </div>\n\n {/* Timeline body */}\n {showTimeline && visibleEvents.length > 0 && (\n <div className=\"mt-3\">\n <TimelineActivity events={visibleEvents} />\n </div>\n )}\n\n {/* Footer hint */}\n {showTimeline && !showSystemEvents && sysEvtConfig?.hiddenHint && hasSystemNoise && (\n <p className=\"mt-2 text-[11px] text-muted-foreground/60 border-t border-dashed border-border pt-2\" data-testid=\"timeline-footer-hint\">\n {sysEvtConfig.hiddenHint}\n </p>\n )}\n {showTimeline && showSystemEvents && sysEvtConfig?.visibleHint && hasSystemNoise && (\n <p className=\"mt-2 text-[11px] text-muted-foreground/60 border-t border-dashed border-border pt-2\" data-testid=\"timeline-footer-hint\">\n {sysEvtConfig.visibleHint.replace(\"{count}\", String(hiddenCount))}\n </p>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Detail View\n// ---------------------------------------------------------------------------\n\nexport function DetailView({\n item,\n sections,\n getSignalScore,\n buildSuggestedActions,\n buildSourceItems: _buildSourceItems,\n getTimelineEvents,\n accountContacts,\n emailSignature,\n iconMap,\n onOpenEntityPanel,\n onOpenRecentActivity,\n onSuggestedActionFeedback: _onSuggestedActionFeedback,\n onScoreFeedback: _onScoreFeedback,\n onSignalApprove,\n getSignalApprovalState,\n signalLabels,\n hideApproveButton,\n signalBriefCopy,\n briefStyleVariant = \"default\",\n renderDetailExtra,\n renderBeforeScore,\n renderAfterScore,\n lastActivityTime,\n renderTitleExtra,\n renderTitleActionRow,\n renderTitleSubtext,\n renderMetadataExtra,\n accountDetailsButtonLabel,\n getAccountDetailsButtonAriaLabel,\n onOpenSignalBucket,\n approveButtonIconUrl,\n opportunityPreview,\n onRequestApproval,\n attentionCount,\n timelineSystemEventsConfig: configProp,\n timelineSystemEventsToggleLabel,\n timelineSystemEventsStorageKey,\n timelineSystemEventsDefaultVisible,\n timelineSystemEventsHiddenHint,\n timelineSystemEventsVisibleHint,\n}: DetailViewProps) {\n // Resolve system-events config: prefer the config object, fall back to deprecated individual props.\n const sysEvtConfig = React.useMemo<TimelineSystemEventsConfig | undefined>(() => {\n if (configProp) return configProp\n // Build from deprecated individual props if any are provided\n if (\n timelineSystemEventsToggleLabel ||\n timelineSystemEventsStorageKey ||\n timelineSystemEventsDefaultVisible !== undefined ||\n timelineSystemEventsHiddenHint ||\n timelineSystemEventsVisibleHint\n ) {\n return {\n toggleLabel: timelineSystemEventsToggleLabel,\n storageKey: timelineSystemEventsStorageKey,\n defaultVisible: timelineSystemEventsDefaultVisible,\n hiddenHint: timelineSystemEventsHiddenHint,\n visibleHint: timelineSystemEventsVisibleHint,\n }\n }\n return undefined\n }, [\n configProp,\n timelineSystemEventsToggleLabel,\n timelineSystemEventsStorageKey,\n timelineSystemEventsDefaultVisible,\n timelineSystemEventsHiddenHint,\n timelineSystemEventsVisibleHint,\n ])\n\n const [showTimeline, setShowTimeline] = React.useState(false)\n const [extraActions, setExtraActions] = React.useState<SuggestedAction[]>([])\n\n // ---- System-noise toggle state ----\n const sysEvtDefaultVisible = sysEvtConfig?.defaultVisible ?? false\n const sysEvtStorageKey = sysEvtConfig?.storageKey\n const [showSystemEvents, setShowSystemEvents] = React.useState(sysEvtDefaultVisible)\n const initialReadDoneRef = React.useRef(false)\n\n // Read persisted value from localStorage on mount\n React.useEffect(() => {\n if (!sysEvtStorageKey) {\n initialReadDoneRef.current = true\n return\n }\n try {\n const stored = localStorage.getItem(sysEvtStorageKey)\n if (stored !== null) {\n setShowSystemEvents(stored === \"true\")\n }\n } catch {\n // localStorage unavailable — ignore\n }\n initialReadDoneRef.current = true\n }, [sysEvtStorageKey])\n\n // Write to localStorage when the toggle changes (skip initial if matching default)\n React.useEffect(() => {\n if (!sysEvtStorageKey) return\n if (!initialReadDoneRef.current) return\n try {\n localStorage.setItem(sysEvtStorageKey, String(showSystemEvents))\n } catch {\n // localStorage unavailable — ignore\n }\n }, [showSystemEvents, sysEvtStorageKey])\n\n React.useEffect(() => {\n setShowTimeline(false)\n setExtraActions([])\n }, [item.id])\n\n const signalData = React.useMemo(\n () => getSignalScore(item.company, item),\n [getSignalScore, item],\n )\n\n const suggestedActions = React.useMemo(\n () => [...buildSuggestedActions(item), ...extraActions],\n [buildSuggestedActions, item, extraActions],\n )\n const timelineEvents = React.useMemo(\n () => getTimelineEvents?.(item) ?? [],\n [getTimelineEvents, item],\n )\n\n const handleDuplicate = React.useCallback(\n (id: number | string) => {\n const base = suggestedActions.find((a) => a.id === id)\n if (!base || base.type !== \"email\") return\n const clone: SuggestedAction = {\n ...base,\n id: `${base.id}-dup-${Date.now()}`,\n emailMeta: base.emailMeta ? { ...base.emailMeta, to: undefined } : undefined,\n }\n setExtraActions((prev) => [...prev, clone])\n },\n [suggestedActions],\n )\n\n return (\n <SignalApproval.Root\n key={item.id}\n companyName={item.company}\n labels={signalLabels}\n hideApproveButton={hideApproveButton}\n approveButtonIconUrl={approveButtonIconUrl}\n opportunityPreview={opportunityPreview}\n onRequestApproval={onRequestApproval}\n initialApprovalState={getSignalApprovalState?.(item)}\n onApprove={(draft) => onSignalApprove?.(item, draft)}\n onApproveFeedback={(reasons, detail) => {\n signalData.onApproveFeedback?.(reasons, detail)\n console.log(\"Approval feedback:\", { taskId: item.id, company: item.company, reasons, detail })\n }}\n onDismiss={(reasons, detail, subReason) => {\n signalData.onDismissFeedback?.(reasons, detail, subReason)\n }}\n >\n <div className=\"mx-auto w-full max-w-3xl p-6 pb-12 md:p-8\">\n <div className=\"pb-8\">\n {/* Header */}\n <div className=\"mb-4 flex items-center gap-2\">\n <button\n type=\"button\"\n className=\"flex items-center gap-1.5 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground\"\n >\n <ArrowLeft className=\"h-3.5 w-3.5\" />\n Back\n </button>\n <span className=\"text-muted-foreground/40\">·</span>\n <span className=\"text-xs text-muted-foreground\">{item.company}</span>\n </div>\n\n <div className=\"mb-3 space-y-3\">\n <div className=\"flex flex-wrap items-start gap-x-3 gap-y-2\">\n <div className=\"min-w-0 flex-1\">\n <h1 className=\"text-2xl font-bold tracking-tight text-foreground\">{item.title}</h1>\n {renderTitleSubtext?.(item)}\n </div>\n {renderTitleExtra?.(item)}\n </div>\n {renderTitleActionRow ? (\n <div className=\"flex w-full flex-wrap items-center gap-2\">\n {renderTitleActionRow(item)}\n </div>\n ) : null}\n </div>\n\n <div className=\"mb-6 flex flex-wrap items-center gap-2\">\n <SignalPriorityPopover\n score={signalData.score}\n urgencyLabel={signalData.urgencyLabel}\n urgencyExplanation={signalData.urgencyExplanation ?? signalData.signalBrief}\n scoreDisplay={signalData.priorityScoreDisplay}\n formulaLabel={signalData.priorityFormulaLabel}\n factors={signalData.priorityFactors ?? []}\n metaText={undefined}\n feedbackChips={signalData.priorityFeedbackChips}\n onFeedbackSubmit={signalData.onPriorityFeedback}\n initialFactorFeedback={signalData.initialFactorPopoverFeedback}\n onFactorFeedback={signalData.onFactorFeedback}\n initialPriorityFeedback={signalData.initialPriorityFeedback}\n />\n {signalData.timeChipLabel && (\n <Badge\n variant=\"outline\"\n title={signalData.timeChipDetail ?? undefined}\n className=\"transition-colors hover:bg-muted/50\"\n >\n {signalData.timeChipLabel}\n </Badge>\n )}\n <TooltipProvider delayDuration={300}>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={onOpenEntityPanel}\n className=\"group/account ml-1 inline-flex max-w-full items-center gap-2 rounded-md border border-border/60 bg-background px-2 py-1 transition-colors hover:border-border hover:bg-muted/50\"\n aria-label={getAccountDetailsButtonAriaLabel?.(item) ?? `View account details for ${item.company}`}\n >\n <span className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded bg-foreground text-[9px] font-semibold uppercase leading-none text-background\">\n {getCompanyInitials(item.company)}\n </span>\n {accountDetailsButtonLabel ? (\n <span className=\"inline-flex min-w-0 items-center gap-1.5 text-xs font-medium text-foreground\">\n {accountDetailsButtonLabel(item)}\n </span>\n ) : (\n <span className=\"truncate text-xs font-medium text-foreground\">{item.company}</span>\n )}\n <span className=\"flex shrink-0 items-center gap-1.5\">\n <span\n aria-hidden\n className={`h-1.5 w-1.5 shrink-0 rounded-full ${STATUS_DOT_CLASS[item.statusColor] ?? \"bg-muted-foreground/40\"}`}\n />\n {/* \"View account\" expands in on hover via an animated grid column */}\n <span className=\"-ml-1.5 grid grid-cols-[0fr] transition-all duration-200 ease-out group-hover/account:ml-0 group-hover/account:grid-cols-[1fr]\">\n <span className=\"overflow-hidden\">\n <span className=\"block whitespace-nowrap text-xs font-medium text-muted-foreground/80\">\n View account\n </span>\n </span>\n </span>\n <ChevronRight className=\"h-3 w-3 shrink-0 text-muted-foreground/50 transition-transform duration-150 group-hover/account:translate-x-0.5 group-hover/account:text-muted-foreground\" />\n </span>\n </button>\n </TooltipTrigger>\n <TooltipContent>Open account panel</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n {renderMetadataExtra?.(item)}\n </div>\n\n {/* Signal Brief */}\n {sections.signalBrief && (() => {\n const briefHeading = signalBriefCopy?.heading ?? \"Signal brief\"\n const introOpt = signalBriefCopy?.intro\n const briefIntro =\n introOpt === null\n ? null\n : typeof introOpt === \"function\"\n ? introOpt(item)\n : introOpt ?? `Signals indicate a potential opportunity for ${item.company}.`\n const isProminent = briefStyleVariant === \"prominent\";\n return (\n <div className=\"mb-8\">\n {briefHeading ? (\n <h3 className=\"text-xs font-bold text-muted-foreground uppercase tracking-wider mb-3\">{briefHeading}</h3>\n ) : null}\n {briefIntro && !signalData.signalBrief ? (\n <p className={isProminent\n ? \"text-sm text-foreground/70 leading-relaxed mb-2\"\n : \"text-sm text-muted-foreground leading-relaxed mb-2\"\n }>\n {briefIntro}\n </p>\n ) : null}\n {signalData.signalBrief ? (\n <p className={isProminent\n ? \"text-base text-foreground leading-relaxed mb-4\"\n : \"text-sm text-foreground/90 leading-relaxed mb-4\"\n }>\n {signalData.signalBrief}\n </p>\n ) : (\n <p className={isProminent\n ? \"text-base text-foreground leading-relaxed mb-4\"\n : \"text-sm text-foreground/90 leading-relaxed mb-4\"\n }>\n {signalData.whyNow}\n </p>\n )}\n\n {/* Before-score content slot (e.g. \"Signals on Case\" chips) */}\n {renderBeforeScore?.(item)}\n\n <ScoreWhyChips\n item={item}\n signalData={signalData}\n onOpenSignalBucket={onOpenSignalBucket}\n />\n <div className=\"mt-4\">\n <SignalApproval.Actions />\n </div>\n </div>\n )\n })()}\n\n {/* After-score content slot (e.g. OpportunityPanel) */}\n {renderAfterScore?.(item)}\n\n {/* Activity Timeline */}\n {sections.timeline && timelineEvents.length > 0 && (\n <TimelineSection\n timelineEvents={timelineEvents}\n showTimeline={showTimeline}\n setShowTimeline={setShowTimeline}\n showSystemEvents={showSystemEvents}\n setShowSystemEvents={setShowSystemEvents}\n attentionCount={attentionCount}\n sysEvtConfig={sysEvtConfig}\n lastActivityTime={lastActivityTime}\n />\n )}\n </div>\n\n {/* Suggested Actions */}\n {sections.suggestedActions && (\n <SignalApproval.Gate>\n <SuggestedActions\n actions={suggestedActions}\n accountContacts={accountContacts}\n signature={emailSignature}\n iconMap={iconMap}\n onDismiss={(id) => console.log(\"Dismiss action:\", id)}\n onSend={(id) => console.log(\"Send action:\", id)}\n onSaveDraft={(id) => console.log(\"Save draft:\", id)}\n onDuplicate={handleDuplicate}\n onOpenAccountDetails={onOpenEntityPanel}\n onOpenRecentActivity={onOpenRecentActivity}\n onMarkComplete={(id) => console.log(\"Mark complete:\", id)}\n onDispatchAgent={(id) => console.log(\"Dispatch agent:\", id)}\n />\n </SignalApproval.Gate>\n )}\n {renderDetailExtra?.(item)}\n </div>\n </SignalApproval.Root>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Main Component\n// ---------------------------------------------------------------------------\n\nexport function PrototypeInboxView({\n items,\n filterCategories,\n detailSections,\n accountContacts = [],\n buildAccountContacts,\n emailSignature = \"\",\n buildSuggestedActions: buildSuggestedActionsProp,\n buildSourceItems: buildSourceItemsProp,\n getSignalScore: getSignalScoreProp,\n getTimelineEvents,\n iconMap = {},\n hideToolbarActions,\n hideHoverActions,\n onSuggestedActionFeedback,\n onScoreFeedback,\n onOpenSignalBucket,\n headerActions,\n onOpenEntityPanel,\n onOpenRecentActivity,\n onItemSelect,\n defaultViewMode,\n buildEntityChips,\n quickFilterTabs,\n hideAccountsButton,\n accountDetailsLabel,\n onSignalApprove,\n getSignalApprovalState,\n signalLabels,\n hideApproveButton,\n signalBriefCopy,\n briefStyleVariant,\n renderDetailExtra,\n renderBeforeScore,\n renderAfterScore,\n lastActivityTime,\n timelineSystemEventsConfig,\n attentionCount,\n renderTitleExtra,\n renderTitleActionRow,\n renderTitleSubtext,\n accountDetailsButtonLabel,\n getAccountDetailsButtonAriaLabel,\n sortOptions,\n activeSortId,\n onSortChange,\n}: PrototypeInboxViewProps) {\n const [inboxViewMode, setInboxViewMode] = React.useState<\"inbox\" | \"list\" | \"detail\">(\n defaultViewMode === \"list\" ? \"list\" : defaultViewMode === \"split\" ? \"inbox\" : \"inbox\"\n )\n const [previousViewMode, setPreviousViewMode] = React.useState<\"inbox\" | \"list\">(\"inbox\")\n const [selectedTask, setSelectedTask] = React.useState(items[0])\n const [inboxAssignee, setInboxAssignee] = React.useState<AssigneeFilter>(\"me\")\n const [inboxFilters, setInboxFilters] = React.useState<Record<string, string>>({})\n const [activeQuickFilter, setActiveQuickFilter] = React.useState<string>(\"all\")\n const [splitViewSearch, setSplitViewSearch] = React.useState(\"\")\n\n const sections = React.useMemo(\n () => ({ ...DEFAULT_DETAIL_SECTIONS, ...detailSections }),\n [detailSections],\n )\n\n const resolvedFilterCategories: InboxFilterCategory[] = React.useMemo(\n () =>\n filterCategories ?? [\n {\n id: \"category\",\n label: \"Category\",\n icon: <Tag className=\"h-3.5 w-3.5 text-muted-foreground\" />,\n options: [...new Set(items.map((i) => i.tag1))],\n },\n {\n id: \"account\",\n label: \"Account\",\n icon: <Building className=\"h-3.5 w-3.5 text-muted-foreground\" />,\n options: [...new Set(items.map((i) => i.company))],\n },\n ],\n [filterCategories, items],\n )\n\n const buildSuggestedActions = React.useMemo(\n () => buildSuggestedActionsProp ?? (() => []),\n [buildSuggestedActionsProp],\n )\n\n const buildSourceItems = React.useMemo(\n () => buildSourceItemsProp ?? (() => []),\n [buildSourceItemsProp],\n )\n\n const getSignalScore = React.useMemo(\n () => getSignalScoreProp ?? (() => DEFAULT_SIGNAL_SCORE),\n [getSignalScoreProp],\n )\n\n // Build a map from filter category id → QueueItem field for targeted filtering.\n // Known category ids are mapped explicitly; unknown categories fall back to a\n // broad search across display fields so consumer-defined filters still work.\n const filterFieldMap = React.useMemo<\n Record<string, (item: QueueItem, value: string) => boolean>\n >(() => {\n const map: Record<string, (item: QueueItem, value: string) => boolean> = {}\n for (const cat of resolvedFilterCategories) {\n switch (cat.id) {\n case \"category\":\n case \"signalType\":\n map[cat.id] = (item, v) => item.tag1.toLowerCase() === v.toLowerCase()\n break\n case \"account\":\n map[cat.id] = (item, v) => item.company.toLowerCase() === v.toLowerCase()\n break\n default:\n // Fallback: check all display fields\n map[cat.id] = (item, v) => {\n const lv = v.toLowerCase()\n return (\n item.tag1.toLowerCase() === lv ||\n item.company.toLowerCase() === lv ||\n item.title.toLowerCase().includes(lv) ||\n item.details.toLowerCase().includes(lv)\n )\n }\n }\n }\n return map\n }, [resolvedFilterCategories])\n\n // Filter items for list view based on toolbar filters\n const filteredItems = React.useMemo(() => {\n const activeFilters = Object.entries(inboxFilters).filter(\n ([, value]) => value && value !== \"all\"\n )\n if (activeFilters.length === 0) return items\n return items.filter((item) =>\n activeFilters.every(([key, value]) => {\n const matcher = filterFieldMap[key]\n return matcher ? matcher(item, value) : true\n })\n )\n }, [items, inboxFilters, filterFieldMap])\n\n // Resolve quick filter tabs once — used by both the split view filter and\n // the tab bar render. Each tab's `matchValue` (falling back to `label`) is\n // compared against `item.tag1` so consumer labels can differ from data values.\n type QuickFilterTab = { id: string; label: string; matchValue?: string; count?: number }\n const resolvedQuickFilterTabs = React.useMemo<QuickFilterTab[]>(() => {\n if (quickFilterTabs) return quickFilterTabs\n // Derive default tabs from the actual item tag1 values\n const uniqueTags = [...new Set(items.map((i) => i.tag1))]\n return uniqueTags.map((tag) => ({\n id: tag.toLowerCase().replace(/\\s+/g, \"-\"),\n label: tag,\n }))\n }, [quickFilterTabs, items])\n\n // Compute per-tab counts once so they can be displayed in the tab bar\n const quickFilterTabCounts = React.useMemo(() => {\n const counts: Record<string, number> = {}\n for (const tab of resolvedQuickFilterTabs) {\n const match = (tab.matchValue ?? tab.label).toLowerCase()\n counts[tab.id] = items.filter((i) => i.tag1.toLowerCase() === match).length\n }\n return counts\n }, [resolvedQuickFilterTabs, items])\n\n // Filter items for split view based on quick filter tabs and search\n const splitViewItems = React.useMemo(() => {\n let filtered = items\n // Apply quick filter tab\n if (activeQuickFilter !== \"all\") {\n const activeTab = resolvedQuickFilterTabs.find((t) => t.id === activeQuickFilter)\n if (activeTab) {\n const match = (activeTab.matchValue ?? activeTab.label).toLowerCase()\n filtered = filtered.filter(\n (item) => item.tag1.toLowerCase() === match\n )\n }\n }\n // Apply search input\n if (splitViewSearch.trim()) {\n const q = splitViewSearch.trim().toLowerCase()\n filtered = filtered.filter(\n (item) =>\n item.tag1.toLowerCase().includes(q) ||\n item.company.toLowerCase().includes(q) ||\n item.title.toLowerCase().includes(q)\n )\n }\n return filtered\n }, [items, activeQuickFilter, resolvedQuickFilterTabs, splitViewSearch])\n\n // Grouped items for list view — one group per severity tier so items\n // are labelled correctly (e.g. \"Urgent\", \"High\", \"Active\").\n const inboxGroups = React.useMemo<GroupedListGroup<QueueItem>[]>(() => {\n const urgent = filteredItems.filter((i) => i.statusColor === \"red\")\n const high = filteredItems.filter((i) => i.statusColor === \"orange\")\n const active = filteredItems.filter((i) => i.statusColor !== \"red\" && i.statusColor !== \"orange\")\n return [\n { key: \"urgent\", label: \"Urgent\", items: urgent },\n { key: \"high\", label: \"High\", items: high },\n { key: \"active\", label: \"Active\", items: active },\n ].filter((g) => g.items.length > 0)\n }, [filteredItems])\n\n const renderInboxRow = React.useCallback(\n (item: QueueItem) => (\n <>\n <span className={`h-2 w-2 shrink-0 rounded-full ${dotColorClass(item.statusColor)}`} />\n <span className=\"w-[80px] shrink-0 font-mono text-xs text-muted-foreground/80\">{item.id}</span>\n <span className=\"shrink-0 rounded-md border border-border bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground whitespace-nowrap\">{item.tag1}</span>\n <span className=\"min-w-0 flex-1 truncate text-sm font-semibold text-foreground\">{item.title}</span>\n <span className=\"w-[120px] shrink-0 truncate text-xs font-medium text-foreground\">{item.company}</span>\n <span className=\"w-[80px] shrink-0 text-right text-xs text-muted-foreground\">{item.time}</span>\n </>\n ),\n [],\n )\n\n const handleInboxItemSelect = React.useCallback(\n (item: QueueItem) => {\n setSelectedTask(item)\n if (onItemSelect) {\n onItemSelect(item)\n } else if (inboxViewMode === \"list\") {\n setPreviousViewMode(\"list\")\n setInboxViewMode(\"detail\")\n }\n },\n [inboxViewMode, onItemSelect],\n )\n\n const handleBackFromDetail = React.useCallback(() => {\n setInboxViewMode(previousViewMode)\n }, [previousViewMode])\n\n const handleViewModeChange = React.useCallback((id: string) => {\n const mode = id as \"inbox\" | \"list\" | \"detail\"\n if (mode !== \"detail\") {\n setPreviousViewMode(mode)\n }\n setInboxViewMode(mode)\n }, [])\n\n React.useEffect(() => {\n const mql = window.matchMedia(\"(max-width: 768px)\")\n function handleChange(e: MediaQueryListEvent | MediaQueryList) {\n if (e.matches && inboxViewMode === \"inbox\") {\n setPreviousViewMode(\"inbox\")\n setInboxViewMode(\"detail\")\n }\n }\n handleChange(mql)\n mql.addEventListener(\"change\", handleChange)\n return () => mql.removeEventListener(\"change\", handleChange)\n }, [inboxViewMode])\n\n const detailViewProps: DetailViewProps = {\n item: selectedTask,\n sections,\n getSignalScore,\n buildSuggestedActions,\n buildSourceItems,\n getTimelineEvents,\n accountContacts: buildAccountContacts?.(selectedTask) ?? accountContacts,\n emailSignature,\n iconMap,\n onOpenEntityPanel,\n onOpenRecentActivity,\n onSuggestedActionFeedback,\n onScoreFeedback,\n onSignalApprove,\n getSignalApprovalState,\n signalLabels,\n hideApproveButton,\n signalBriefCopy,\n briefStyleVariant,\n renderDetailExtra,\n renderBeforeScore,\n renderAfterScore,\n lastActivityTime,\n timelineSystemEventsConfig,\n attentionCount,\n renderTitleExtra,\n renderTitleActionRow,\n renderTitleSubtext,\n accountDetailsButtonLabel,\n getAccountDetailsButtonAriaLabel,\n onOpenSignalBucket,\n }\n\n return (\n <div className=\"flex h-full w-full flex-col\">\n {/* Toolbar */}\n <div className=\"flex items-center justify-between border-b border-border bg-background px-4 py-3 shrink-0\">\n <div className=\"flex items-center gap-3\">\n {inboxViewMode === \"detail\" ? (\n <button\n type=\"button\"\n onClick={handleBackFromDetail}\n className=\"flex items-center gap-2 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n Back\n </button>\n ) : null}\n <h2 className=\"text-lg font-semibold text-foreground\">Inbox</h2>\n <Badge variant=\"secondary\" className=\"bg-muted text-muted-foreground hover:bg-muted font-medium text-[11px] px-2 py-0.5 rounded-md\">\n {items.length}\n </Badge>\n </div>\n <div className=\"flex items-center gap-3\">\n <ViewModeToggle\n modes={[\n { id: \"inbox\", icon: <Columns2 className=\"h-3.5 w-3.5\" />, label: \"Split View\" },\n { id: \"list\", icon: <LayoutList className=\"h-3.5 w-3.5\" />, label: \"List View\" },\n { id: \"detail\", icon: <Square className=\"h-3.5 w-3.5\" />, label: \"Detail View\" },\n ]}\n activeMode={inboxViewMode}\n onModeChange={handleViewModeChange}\n />\n {headerActions}\n </div>\n </div>\n\n {/* View modes */}\n {inboxViewMode === \"detail\" ? (\n <div className=\"flex h-full flex-1 flex-col overflow-hidden bg-background\">\n <div className=\"flex-1 overflow-y-auto\">\n <DetailView {...detailViewProps} />\n </div>\n </div>\n ) : inboxViewMode === \"list\" ? (\n <div className=\"flex-1 overflow-y-auto bg-background\">\n <InboxToolbar\n assignee={inboxAssignee}\n onAssigneeChange={setInboxAssignee}\n filterCategories={resolvedFilterCategories}\n selectedFilters={inboxFilters}\n onFilterChange={(catId, val) =>\n setInboxFilters((prev) => ({ ...prev, [catId]: val }))\n }\n onClearFilters={() => setInboxFilters({})}\n />\n <GroupedListView<QueueItem>\n groups={inboxGroups}\n renderRow={renderInboxRow}\n getItemKey={(item) => item.id}\n selectedKey={selectedTask.id}\n onItemClick={handleInboxItemSelect}\n emptyMessage=\"No inbox items\"\n />\n </div>\n ) : (\n /* Split view */\n <div className=\"flex h-full min-h-0 w-full flex-1\">\n <div className=\"flex h-full min-w-[380px] w-[380px] flex-col border-r border-border bg-background shadow-sm z-10\">\n <div className=\"flex flex-col gap-4 border-b border-border p-4 shrink-0\">\n {!hideToolbarActions && (\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-1\">\n <Button variant=\"outline\" size=\"icon\" className=\"h-8 w-8 text-muted-foreground\"><Eye className=\"w-4 h-4\" /></Button>\n <Button variant=\"outline\" size=\"icon\" className=\"h-8 w-8 text-muted-foreground\"><FileText className=\"w-4 h-4\" /></Button>\n <Button variant=\"outline\" size=\"icon\" className=\"h-8 w-8 text-muted-foreground\"><Clock className=\"w-4 h-4\" /></Button>\n <Button variant=\"outline\" size=\"icon\" className=\"h-8 w-8 text-muted-foreground\"><CheckSquare className=\"w-4 h-4\" /></Button>\n </div>\n <Button size=\"sm\" className=\"h-8 px-4 bg-foreground text-background hover:bg-foreground/90 text-xs font-semibold gap-1.5 rounded-md\">\n <Plus className=\"w-4 h-4\" /> Add Task\n </Button>\n </div>\n )}\n <div className=\"flex items-center gap-2\">\n <div className=\"relative flex-1\">\n <Filter className=\"absolute left-2.5 top-1.5 w-4 h-4 text-muted-foreground\" />\n <Input\n className=\"h-8 pl-8 text-xs bg-background border-border rounded-md shadow-none\"\n placeholder=\"Filter by category...\"\n value={splitViewSearch}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setSplitViewSearch(e.target.value)}\n />\n </div>\n {sortOptions && sortOptions.length > 0 && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" size=\"sm\" className=\"h-8 text-xs font-medium rounded-md shadow-none gap-1.5\">\n <ArrowUpDown className=\"w-3.5 h-3.5\" />\n {sortOptions.find(o => o.id === activeSortId)?.label ?? 'Sort'}\n <ChevronDown className=\"w-3 h-3\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuRadioGroup value={activeSortId ?? ''} onValueChange={(val) => onSortChange?.(val)}>\n {sortOptions.map(option => (\n <DropdownMenuRadioItem key={option.id} value={option.id}>\n {option.label}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n {!hideAccountsButton && (\n <Button variant=\"outline\" size=\"sm\" className=\"h-8 text-xs font-medium rounded-md shadow-none\">\n <Building className=\"w-3.5 h-3.5 mr-1.5\" /> {accountDetailsLabel ?? \"Accounts\"}\n </Button>\n )}\n </div>\n <div className=\"flex items-center gap-1.5 overflow-x-auto pb-1 mt-1 scrollbar-hide\">\n <Button\n size=\"sm\"\n variant={activeQuickFilter === \"all\" ? \"default\" : \"outline\"}\n className={`h-7 rounded-full px-3.5 text-[11px] font-semibold shadow-none ${\n activeQuickFilter === \"all\"\n ? \"bg-foreground text-background hover:bg-foreground/90\"\n : \"bg-transparent border-border text-muted-foreground hover:text-foreground\"\n }`}\n onClick={() => setActiveQuickFilter(\"all\")}\n >\n All\n </Button>\n {resolvedQuickFilterTabs.map((tab) => {\n const count = tab.count ?? quickFilterTabCounts[tab.id]\n return (\n <Button\n key={tab.id}\n size=\"sm\"\n variant={activeQuickFilter === tab.id ? \"default\" : \"outline\"}\n className={`h-7 rounded-full px-3.5 text-[11px] font-medium shadow-none ${\n activeQuickFilter === tab.id\n ? \"bg-foreground text-background hover:bg-foreground/90\"\n : \"bg-transparent border-border text-muted-foreground hover:text-foreground\"\n }`}\n onClick={() => setActiveQuickFilter(tab.id)}\n >\n {tab.label}{count != null && count > 0 ? ` (${count})` : \"\"}\n </Button>\n )\n })}\n </div>\n </div>\n\n <div className=\"flex-1 overflow-y-auto\">\n {splitViewItems.map((item) => (\n <div\n key={item.id}\n onClick={() => { setSelectedTask(item); onItemSelect?.(item) }}\n className={`cursor-pointer border-b border-border p-4 transition-colors group relative border-l-2 ${\n selectedTask.id === item.id\n ? \"bg-muted/30 border-l-brand-purple\"\n : \"bg-transparent border-l-transparent hover:bg-muted/10\"\n }`}\n >\n <div className=\"mb-1.5 flex items-center gap-2\">\n <span className=\"min-w-0 truncate text-[13px] font-semibold text-foreground leading-tight\">{item.title}</span>\n {selectedTask.id !== item.id && item.tag1 && (\n <span className=\"shrink-0 rounded-md border border-border bg-muted/60 px-2 py-0.5 text-[10px] font-medium text-muted-foreground\">\n {item.tag1}\n </span>\n )}\n <span className=\"ml-auto shrink-0 text-[10px] font-medium text-muted-foreground/80\">{item.time}</span>\n </div>\n <div className=\"flex items-start gap-2 mt-2\">\n <span className={`w-1.5 h-1.5 rounded-full shrink-0 mt-1.5 ${dotColorClass(item.statusColor)}`} />\n <span className=\"text-xs text-muted-foreground leading-tight\">{item.details}</span>\n </div>\n {buildEntityChips && (() => {\n const chips = buildEntityChips(item)\n if (!chips.length) return null\n return (\n <div className=\"flex items-center gap-1.5 mt-2 flex-wrap\">\n {chips.map((chip) => (\n <button\n key={chip.id}\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); chip.onClick?.() }}\n className=\"inline-flex items-center gap-1 rounded-md border border-border/60 bg-muted/30 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground\"\n >\n <span className=\"flex h-3.5 w-3.5 items-center justify-center rounded bg-muted-foreground/10 text-[8px] font-semibold\">{chip.avatarLetter}</span>\n {chip.label}\n </button>\n ))}\n </div>\n )\n })()}\n {!hideHoverActions && (\n <div className={`absolute right-4 bottom-4 flex items-center gap-1.5 bg-background shadow-sm rounded-md px-1 py-0.5 border border-border ${\n selectedTask.id === item.id ? \"opacity-100\" : \"opacity-0 group-hover:opacity-100 transition-opacity\"\n }`}>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-6 w-6 rounded text-muted-foreground hover:text-foreground\"><CheckSquare className=\"w-3.5 h-3.5\" /></Button>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-6 w-6 rounded text-muted-foreground hover:text-foreground\"><Clock className=\"w-3.5 h-3.5\" /></Button>\n </div>\n )}\n </div>\n ))}\n <div className=\"p-4\">\n <Button variant=\"outline\" size=\"sm\" className=\"h-8 text-xs font-semibold rounded-md shadow-none\">See more</Button>\n </div>\n </div>\n </div>\n\n <div className=\"flex h-full flex-1 flex-col overflow-hidden bg-background\">\n <div className=\"flex-1 overflow-y-auto\">\n <DetailView {...detailViewProps} />\n </div>\n </div>\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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","names":["_a"]}
|
|
1
|
+
{"version":3,"sources":["../../src/prototype/prototype-inbox-view.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport {\n ArrowLeft,\n ArrowUpDown,\n ChevronDown,\n ChevronRight,\n Filter,\n FileText,\n Clock,\n CheckSquare,\n Eye,\n Plus,\n\n Building,\n LayoutList,\n Columns2,\n Square,\n Tag,\n} from \"lucide-react\"\n\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuTrigger,\n} from \"../components/dropdown-menu\"\nimport { Button } from \"../components/button\"\nimport { Badge } from \"../components/badge\"\nimport { Input } from \"../components/input\"\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"../components/tooltip\"\nimport { ViewModeToggle } from \"../components/view-mode-toggle\"\nimport {\n InboxToolbar,\n type AssigneeFilter,\n type InboxFilterCategory,\n} from \"../components/inbox-toolbar\"\nimport { GroupedListView, type GroupedListGroup } from \"../components/item-list\"\nimport { SignalApproval, type ApprovalState, type OpportunityDraft, type OpportunityPreview } from \"../components/signal-feedback-inline\"\nimport { ScoreWhyChips } from \"../components/score-why-chips\"\nimport { SignalPriorityPopover } from \"../components/signal-priority-popover\"\nimport { type SourceDef } from \"../components/detail-view\"\nimport {\n SuggestedActions,\n type SuggestedAction,\n type SuggestedContact,\n} from \"../components/suggested-actions\"\nimport { TimelineActivity, type TimelineEvent } from \"../components/timeline-activity\"\nimport type {\n QueueItem,\n InboxViewConfig,\n InboxDetailSections,\n SignalScoreData,\n BriefStyleVariant,\n TimelineSystemEventsConfig,\n} from \"./prototype-config\"\n\n// ---------------------------------------------------------------------------\n// Dot color utility — maps statusColor to a Tailwind background class.\n// Centralised here so the list row and split-view card stay in sync and\n// future color additions are a single-edit change.\n// ---------------------------------------------------------------------------\n\nfunction dotColorClass(statusColor: string): string {\n if (statusColor === \"red\") return \"bg-[#f43f5e]\"\n if (statusColor === \"yellow\" || statusColor === \"amber\" || statusColor === \"orange\") return \"bg-[#eab308]\"\n if (statusColor === \"green\") return \"bg-[#22c55e]\"\n return \"bg-[#9ca3af]\"\n}\n\n// ---------------------------------------------------------------------------\n// Props\n// ---------------------------------------------------------------------------\n\nexport interface PrototypeInboxViewProps extends InboxViewConfig {\n /** Extra ReactNode rendered at the end of the header bar (e.g. exit button). */\n headerActions?: React.ReactNode\n onOpenEntityPanel?: () => void\n onOpenRecentActivity?: () => void\n onNavigateToInbox?: () => void\n onItemSelect?: (item: QueueItem) => void\n defaultViewMode?: \"list\" | \"split\"\n}\n\n// ---------------------------------------------------------------------------\n// Default detail sections\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_DETAIL_SECTIONS: InboxDetailSections = {\n signalBrief: true,\n suggestedActions: true,\n timeline: true,\n}\n\nconst DEFAULT_SIGNAL_SCORE: SignalScoreData = {\n score: 65,\n factors: [\n { key: \"trigger\", label: \"Trigger strength\", score: 70, why: \"Moderate signal detected based on account activity\" },\n { key: \"fit\", label: \"Company fit\", score: 65, why: \"Reasonable fit based on company profile\" },\n { key: \"timing\", label: \"Timing\", score: 58, why: \"Within general evaluation window\" },\n ],\n whyNow: \"Moderate signals detected that warrant review and potential outreach.\",\n evidence: [\n \"Activity patterns suggest potential opportunity\",\n \"Company profile aligns with target segment\",\n ],\n confidence: 72,\n}\n\n// ---------------------------------------------------------------------------\n// Detail View\n// ---------------------------------------------------------------------------\n\n/** Up to 2-character uppercase initials for a company name (e.g. \"Northwind Systems\" -> \"NW\"). */\nfunction getCompanyInitials(company: string): string {\n const words = company.trim().split(/\\s+/).filter(Boolean)\n if (words.length === 0) return \"?\"\n if (words.length === 1) return words[0].slice(0, 2).toUpperCase()\n return (words[0][0] + words[1][0]).toUpperCase()\n}\n\n/** Maps a QueueItem.statusColor to a Tailwind dot background class. */\nconst STATUS_DOT_CLASS: Record<string, string> = {\n red: \"bg-red-500\",\n orange: \"bg-orange-500\",\n amber: \"bg-amber-500\",\n yellow: \"bg-yellow-500\",\n green: \"bg-emerald-500\",\n emerald: \"bg-emerald-500\",\n blue: \"bg-blue-500\",\n gray: \"bg-gray-300\",\n grey: \"bg-gray-300\",\n}\n\nexport interface DetailViewProps {\n item: QueueItem\n sections: InboxDetailSections\n getSignalScore: (company: string, item?: QueueItem) => SignalScoreData\n buildSuggestedActions: (item: QueueItem) => SuggestedAction[]\n buildSourceItems: (item: QueueItem) => SourceDef[]\n getTimelineEvents?: (item: QueueItem) => TimelineEvent[]\n accountContacts: SuggestedContact[]\n emailSignature: string | React.ReactNode\n iconMap: Record<string, string>\n onOpenEntityPanel?: () => void\n onOpenRecentActivity?: () => void\n onSuggestedActionFeedback?: (actionId: number | string, feedback: string, actionTitle?: string) => void\n /** @deprecated The compact score UX no longer renders score-level thumbs by default. */\n onScoreFeedback?: (type: \"up\" | \"down\", pills: string[], detail: string) => void\n onSignalApprove?: (item: QueueItem, draft?: OpportunityDraft) => void | Promise<boolean>\n getSignalApprovalState?: (item: QueueItem) => ApprovalState | undefined\n signalLabels?: InboxViewConfig[\"signalLabels\"]\n hideApproveButton?: boolean\n signalBriefCopy?: InboxViewConfig[\"signalBriefCopy\"]\n briefStyleVariant?: BriefStyleVariant\n renderDetailExtra?: (item: QueueItem) => React.ReactNode\n /** Render content between the signal brief text and the signal score bar (e.g. \"Signals on Case\" chips). */\n renderBeforeScore?: (item: QueueItem) => React.ReactNode\n /** Render content between the signal score section and the activity timeline. */\n renderAfterScore?: (item: QueueItem) => React.ReactNode\n lastActivityTime?: string\n /** Render extra content inline with the detail title. */\n renderTitleExtra?: (item: QueueItem) => React.ReactNode\n /** Render a full-width action row below the detail title row. */\n renderTitleActionRow?: (item: QueueItem) => React.ReactNode\n /** Render supporting content below the detail title. */\n renderTitleSubtext?: (item: QueueItem) => React.ReactNode\n /** Render extra metadata chips (e.g. assignee) inside the chips row below the title. */\n renderMetadataExtra?: (item: QueueItem) => React.ReactNode\n /**\n * Where the metadata chips row (priority · deadline · account · renderMetadataExtra) sits.\n * - \"default\": above the signal brief (legacy layout, unchanged for existing consumers).\n * - \"below-brief\": moved beneath the brief text, just before `renderBeforeScore`\n * (case-panel redesign — chips + owners read as one block under the brief).\n */\n metadataLayout?: \"default\" | \"below-brief\"\n /** Override the built-in account details metadata button label. */\n accountDetailsButtonLabel?: (item: QueueItem) => React.ReactNode\n /** Accessible label for the built-in account details metadata button. */\n getAccountDetailsButtonAriaLabel?: (item: QueueItem) => string\n onOpenSignalBucket?: (args: { item: QueueItem; bucketKey: string; signalId: string }) => void\n approveButtonIconUrl?: string\n opportunityPreview?: OpportunityPreview\n onRequestApproval?: () => Promise<void>\n /** Number of important/attention-worthy events to highlight on the collapsed timeline header. */\n attentionCount?: number\n /** Configuration for the system-noise events toggle (score changes, etc.). */\n timelineSystemEventsConfig?: TimelineSystemEventsConfig\n\n // ── Deprecated individual props (use timelineSystemEventsConfig instead) ──\n /** @deprecated Use `timelineSystemEventsConfig.toggleLabel`. */\n timelineSystemEventsToggleLabel?: string\n /** @deprecated Use `timelineSystemEventsConfig.storageKey`. */\n timelineSystemEventsStorageKey?: string\n /** @deprecated Use `timelineSystemEventsConfig.defaultVisible`. */\n timelineSystemEventsDefaultVisible?: boolean\n /** @deprecated Use `timelineSystemEventsConfig.hiddenHint`. */\n timelineSystemEventsHiddenHint?: string\n /** @deprecated Use `timelineSystemEventsConfig.visibleHint`. */\n timelineSystemEventsVisibleHint?: string\n}\n\n// ---------------------------------------------------------------------------\n// TimelineSection — extracted from the IIFE in DetailView for readability\n// ---------------------------------------------------------------------------\n\nfunction TimelineSection({\n timelineEvents,\n showTimeline,\n setShowTimeline,\n showSystemEvents,\n setShowSystemEvents,\n attentionCount,\n sysEvtConfig,\n lastActivityTime,\n}: {\n timelineEvents: TimelineEvent[]\n showTimeline: boolean\n setShowTimeline: React.Dispatch<React.SetStateAction<boolean>>\n showSystemEvents: boolean\n setShowSystemEvents: React.Dispatch<React.SetStateAction<boolean>>\n attentionCount?: number\n sysEvtConfig?: TimelineSystemEventsConfig\n lastActivityTime?: string\n}) {\n // Single-pass partition: compute visibleEvents and hiddenCount together\n const visibleEvents: TimelineEvent[] = []\n let hiddenCount = 0\n for (const e of timelineEvents) {\n if (e.isSystemNoise) hiddenCount++\n if (!e.isSystemNoise || showSystemEvents) visibleEvents.push(e)\n }\n const hasSystemNoise = hiddenCount > 0\n\n // The toggle renders whenever there are system-noise events — even if no\n // config was provided — so consumers that emit `isSystemNoise: true` always\n // give users a way to reveal those events.\n const toggleLabel = sysEvtConfig?.toggleLabel ?? \"System events\"\n\n // Derive \"Last activity\" from the first *visible* event so the collapsed\n // header never points at a hidden score-update. The caller-supplied\n // `lastActivityTime` is only used when system-noise filtering is NOT active\n // (i.e. all events are visible) since it may come from an unfiltered source\n // such as `case.last_activity_at`.\n const firstVisibleTime =\n (!hasSystemNoise || showSystemEvents) && lastActivityTime\n ? lastActivityTime\n : visibleEvents.length > 0\n ? visibleEvents[0].time\n : \"\"\n\n const visibleCount = visibleEvents.length\n const eventCountLabel = `${visibleCount} ${visibleCount === 1 ? \"event\" : \"events\"}`\n\n return (\n <div className=\"mb-8\">\n {/* Header — outer non-interactive container */}\n <div\n className=\"group/timeline flex w-full items-center justify-between gap-2 py-2 rounded-md transition-colors hover:bg-muted/40 -mx-2 px-2\"\n data-testid=\"timeline-header\"\n >\n {/* Left: collapse/expand button */}\n <button\n type=\"button\"\n onClick={() => setShowTimeline((prev) => !prev)}\n className=\"flex items-center gap-2 cursor-pointer bg-transparent border-0 p-0\"\n data-testid=\"timeline-collapse-btn\"\n >\n <h3 className=\"text-xs font-bold text-muted-foreground uppercase tracking-wider group-hover/timeline:text-foreground transition-colors\">Activity timeline</h3>\n {!showTimeline && attentionCount != null && attentionCount > 0 && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-destructive/10 px-1.5 py-0.5 text-[10px] font-semibold text-destructive border border-destructive/20\">\n {attentionCount} new\n </span>\n )}\n {!showTimeline && firstVisibleTime && (\n <span className=\"text-[11px] text-muted-foreground/60\" data-testid=\"last-activity-hint\">\n · Last activity {firstVisibleTime}\n </span>\n )}\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-[11px] font-medium text-muted-foreground\" data-testid=\"event-count\">{eventCountLabel}</span>\n <ChevronDown className={`h-3.5 w-3.5 text-muted-foreground transition-transform duration-200 ${showTimeline ? \"rotate-180\" : \"\"}`} />\n </div>\n </button>\n\n {/* Right: system-events toggle — always rendered when noise events exist */}\n {hasSystemNoise && (\n <button\n type=\"button\"\n onClick={() => setShowSystemEvents((prev) => !prev)}\n className=\"flex shrink-0 items-center gap-1.5 rounded-full border border-border bg-background px-2.5 py-1 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-muted/40 hover:text-foreground cursor-pointer\"\n aria-pressed={showSystemEvents}\n data-testid=\"system-events-toggle\"\n >\n {toggleLabel}\n <span\n className=\"inline-flex items-center justify-center rounded-full bg-muted px-1.5 text-[10px] font-semibold min-w-[18px] tabular-nums\"\n data-testid=\"hidden-count-badge\"\n >\n {hiddenCount}\n </span>\n </button>\n )}\n </div>\n\n {/* Timeline body */}\n {showTimeline && visibleEvents.length > 0 && (\n <div className=\"mt-3\">\n <TimelineActivity events={visibleEvents} />\n </div>\n )}\n\n {/* Footer hint */}\n {showTimeline && !showSystemEvents && sysEvtConfig?.hiddenHint && hasSystemNoise && (\n <p className=\"mt-2 text-[11px] text-muted-foreground/60 border-t border-dashed border-border pt-2\" data-testid=\"timeline-footer-hint\">\n {sysEvtConfig.hiddenHint}\n </p>\n )}\n {showTimeline && showSystemEvents && sysEvtConfig?.visibleHint && hasSystemNoise && (\n <p className=\"mt-2 text-[11px] text-muted-foreground/60 border-t border-dashed border-border pt-2\" data-testid=\"timeline-footer-hint\">\n {sysEvtConfig.visibleHint.replace(\"{count}\", String(hiddenCount))}\n </p>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Detail View\n// ---------------------------------------------------------------------------\n\nexport function DetailView({\n item,\n sections,\n getSignalScore,\n buildSuggestedActions,\n buildSourceItems: _buildSourceItems,\n getTimelineEvents,\n accountContacts,\n emailSignature,\n iconMap,\n onOpenEntityPanel,\n onOpenRecentActivity,\n onSuggestedActionFeedback: _onSuggestedActionFeedback,\n onScoreFeedback: _onScoreFeedback,\n onSignalApprove,\n getSignalApprovalState,\n signalLabels,\n hideApproveButton,\n signalBriefCopy,\n briefStyleVariant = \"default\",\n renderDetailExtra,\n renderBeforeScore,\n renderAfterScore,\n lastActivityTime,\n renderTitleExtra,\n renderTitleActionRow,\n renderTitleSubtext,\n renderMetadataExtra,\n metadataLayout = \"default\",\n accountDetailsButtonLabel,\n getAccountDetailsButtonAriaLabel,\n onOpenSignalBucket,\n approveButtonIconUrl,\n opportunityPreview,\n onRequestApproval,\n attentionCount,\n timelineSystemEventsConfig: configProp,\n timelineSystemEventsToggleLabel,\n timelineSystemEventsStorageKey,\n timelineSystemEventsDefaultVisible,\n timelineSystemEventsHiddenHint,\n timelineSystemEventsVisibleHint,\n}: DetailViewProps) {\n // Resolve system-events config: prefer the config object, fall back to deprecated individual props.\n const sysEvtConfig = React.useMemo<TimelineSystemEventsConfig | undefined>(() => {\n if (configProp) return configProp\n // Build from deprecated individual props if any are provided\n if (\n timelineSystemEventsToggleLabel ||\n timelineSystemEventsStorageKey ||\n timelineSystemEventsDefaultVisible !== undefined ||\n timelineSystemEventsHiddenHint ||\n timelineSystemEventsVisibleHint\n ) {\n return {\n toggleLabel: timelineSystemEventsToggleLabel,\n storageKey: timelineSystemEventsStorageKey,\n defaultVisible: timelineSystemEventsDefaultVisible,\n hiddenHint: timelineSystemEventsHiddenHint,\n visibleHint: timelineSystemEventsVisibleHint,\n }\n }\n return undefined\n }, [\n configProp,\n timelineSystemEventsToggleLabel,\n timelineSystemEventsStorageKey,\n timelineSystemEventsDefaultVisible,\n timelineSystemEventsHiddenHint,\n timelineSystemEventsVisibleHint,\n ])\n\n const [showTimeline, setShowTimeline] = React.useState(false)\n const [extraActions, setExtraActions] = React.useState<SuggestedAction[]>([])\n\n // ---- System-noise toggle state ----\n const sysEvtDefaultVisible = sysEvtConfig?.defaultVisible ?? false\n const sysEvtStorageKey = sysEvtConfig?.storageKey\n const [showSystemEvents, setShowSystemEvents] = React.useState(sysEvtDefaultVisible)\n const initialReadDoneRef = React.useRef(false)\n\n // Read persisted value from localStorage on mount\n React.useEffect(() => {\n if (!sysEvtStorageKey) {\n initialReadDoneRef.current = true\n return\n }\n try {\n const stored = localStorage.getItem(sysEvtStorageKey)\n if (stored !== null) {\n setShowSystemEvents(stored === \"true\")\n }\n } catch {\n // localStorage unavailable — ignore\n }\n initialReadDoneRef.current = true\n }, [sysEvtStorageKey])\n\n // Write to localStorage when the toggle changes (skip initial if matching default)\n React.useEffect(() => {\n if (!sysEvtStorageKey) return\n if (!initialReadDoneRef.current) return\n try {\n localStorage.setItem(sysEvtStorageKey, String(showSystemEvents))\n } catch {\n // localStorage unavailable — ignore\n }\n }, [showSystemEvents, sysEvtStorageKey])\n\n React.useEffect(() => {\n setShowTimeline(false)\n setExtraActions([])\n }, [item.id])\n\n const signalData = React.useMemo(\n () => getSignalScore(item.company, item),\n [getSignalScore, item],\n )\n\n const suggestedActions = React.useMemo(\n () => [...buildSuggestedActions(item), ...extraActions],\n [buildSuggestedActions, item, extraActions],\n )\n const timelineEvents = React.useMemo(\n () => getTimelineEvents?.(item) ?? [],\n [getTimelineEvents, item],\n )\n\n const handleDuplicate = React.useCallback(\n (id: number | string) => {\n const base = suggestedActions.find((a) => a.id === id)\n if (!base || base.type !== \"email\") return\n const clone: SuggestedAction = {\n ...base,\n id: `${base.id}-dup-${Date.now()}`,\n emailMeta: base.emailMeta ? { ...base.emailMeta, to: undefined } : undefined,\n }\n setExtraActions((prev) => [...prev, clone])\n },\n [suggestedActions],\n )\n\n // Deadline chip tone (case-panel redesign): amber as the deadline nears, red when due/overdue.\n const timeChipToneClass =\n signalData.timeChipTone === \"red\"\n ? \"border-red-300 bg-red-50 text-red-700 hover:bg-red-50\"\n : signalData.timeChipTone === \"amber\"\n ? \"border-amber-300 bg-amber-50 text-amber-700 hover:bg-amber-50\"\n : \"hover:bg-muted/50\"\n\n // The metadata chips row (priority · deadline · account · renderMetadataExtra). Rendered above\n // the brief by default, or beneath it when `metadataLayout === \"below-brief\"` (case-panel redesign).\n const metadataChips = (\n <>\n <SignalPriorityPopover\n score={signalData.score}\n urgencyLabel={signalData.urgencyLabel}\n urgencyExplanation={signalData.urgencyExplanation ?? signalData.signalBrief}\n scoreDisplay={signalData.priorityScoreDisplay}\n formulaLabel={signalData.priorityFormulaLabel}\n factors={signalData.priorityFactors ?? []}\n metaText={undefined}\n feedbackChips={signalData.priorityFeedbackChips}\n onFeedbackSubmit={signalData.onPriorityFeedback}\n initialFactorFeedback={signalData.initialFactorPopoverFeedback}\n onFactorFeedback={signalData.onFactorFeedback}\n initialPriorityFeedback={signalData.initialPriorityFeedback}\n />\n {signalData.timeChipLabel && (\n <Badge\n variant=\"outline\"\n title={signalData.timeChipDetail ?? undefined}\n className={`transition-colors ${timeChipToneClass}`}\n >\n {signalData.timeChipLabel}\n </Badge>\n )}\n <TooltipProvider delayDuration={300}>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={onOpenEntityPanel}\n className=\"group/account ml-1 inline-flex max-w-full items-center gap-2 rounded-md border border-border/60 bg-background px-2 py-1 transition-colors hover:border-border hover:bg-muted/50\"\n aria-label={getAccountDetailsButtonAriaLabel?.(item) ?? `View account details for ${item.company}`}\n >\n <span className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded bg-foreground text-[9px] font-semibold uppercase leading-none text-background\">\n {getCompanyInitials(item.company)}\n </span>\n {accountDetailsButtonLabel ? (\n <span className=\"inline-flex min-w-0 items-center gap-1.5 text-xs font-medium text-foreground\">\n {accountDetailsButtonLabel(item)}\n </span>\n ) : (\n <span className=\"truncate text-xs font-medium text-foreground\">{item.company}</span>\n )}\n <span className=\"flex shrink-0 items-center gap-1.5\">\n <span\n aria-hidden\n className={`h-1.5 w-1.5 shrink-0 rounded-full ${STATUS_DOT_CLASS[item.statusColor] ?? \"bg-muted-foreground/40\"}`}\n />\n {/* \"View account\" expands in on hover via an animated grid column */}\n <span className=\"-ml-1.5 grid grid-cols-[0fr] transition-all duration-200 ease-out group-hover/account:ml-0 group-hover/account:grid-cols-[1fr]\">\n <span className=\"overflow-hidden\">\n <span className=\"block whitespace-nowrap text-xs font-medium text-muted-foreground/80\">\n View account\n </span>\n </span>\n </span>\n <ChevronRight className=\"h-3 w-3 shrink-0 text-muted-foreground/50 transition-transform duration-150 group-hover/account:translate-x-0.5 group-hover/account:text-muted-foreground\" />\n </span>\n </button>\n </TooltipTrigger>\n <TooltipContent>Open account panel</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n {renderMetadataExtra?.(item)}\n </>\n )\n\n return (\n <SignalApproval.Root\n key={item.id}\n companyName={item.company}\n labels={signalLabels}\n hideApproveButton={hideApproveButton}\n approveButtonIconUrl={approveButtonIconUrl}\n opportunityPreview={opportunityPreview}\n onRequestApproval={onRequestApproval}\n initialApprovalState={getSignalApprovalState?.(item)}\n onApprove={(draft) => onSignalApprove?.(item, draft)}\n onApproveFeedback={(reasons, detail) => {\n signalData.onApproveFeedback?.(reasons, detail)\n console.log(\"Approval feedback:\", { taskId: item.id, company: item.company, reasons, detail })\n }}\n onDismiss={(reasons, detail, subReason) => {\n signalData.onDismissFeedback?.(reasons, detail, subReason)\n }}\n >\n <div className=\"mx-auto w-full max-w-3xl p-6 pb-12 md:p-8\">\n <div className=\"pb-8\">\n {/* Header */}\n <div className=\"mb-4 flex items-center gap-2\">\n <span className=\"text-xs text-muted-foreground\">{item.company}</span>\n </div>\n\n <div className=\"mb-3 space-y-3\">\n <div className=\"flex flex-wrap items-start gap-x-3 gap-y-2\">\n <div className=\"min-w-0 flex-1\">\n <h1 className=\"text-2xl font-bold tracking-tight text-foreground\">{item.title}</h1>\n {renderTitleSubtext?.(item)}\n </div>\n {renderTitleExtra?.(item)}\n </div>\n {renderTitleActionRow ? (\n <div className=\"flex w-full flex-wrap items-center gap-2\">\n {renderTitleActionRow(item)}\n </div>\n ) : null}\n </div>\n\n {metadataLayout === \"default\" ? (\n <div className=\"mb-6 flex flex-wrap items-center gap-2\">{metadataChips}</div>\n ) : null}\n\n {/* Signal Brief */}\n {sections.signalBrief && (() => {\n const briefHeading = signalBriefCopy?.heading ?? \"Signal brief\"\n const introOpt = signalBriefCopy?.intro\n const briefIntro =\n introOpt === null\n ? null\n : typeof introOpt === \"function\"\n ? introOpt(item)\n : introOpt ?? `Signals indicate a potential opportunity for ${item.company}.`\n const isProminent = briefStyleVariant === \"prominent\";\n return (\n <div className=\"mb-8\">\n {briefHeading ? (\n <h3 className=\"text-xs font-bold text-muted-foreground uppercase tracking-wider mb-3\">{briefHeading}</h3>\n ) : null}\n {briefIntro && !signalData.signalBrief ? (\n <p className={isProminent\n ? \"text-sm text-foreground/70 leading-relaxed mb-2\"\n : \"text-sm text-muted-foreground leading-relaxed mb-2\"\n }>\n {briefIntro}\n </p>\n ) : null}\n {signalData.signalBrief ? (\n <p className={isProminent\n ? \"text-base text-foreground leading-relaxed mb-4\"\n : \"text-sm text-foreground/90 leading-relaxed mb-4\"\n }>\n {signalData.signalBrief}\n </p>\n ) : (\n <p className={isProminent\n ? \"text-base text-foreground leading-relaxed mb-4\"\n : \"text-sm text-foreground/90 leading-relaxed mb-4\"\n }>\n {signalData.whyNow}\n </p>\n )}\n\n {/* Metadata chips relocated beneath the brief (case-panel redesign). */}\n {metadataLayout === \"below-brief\" ? (\n <div className=\"mb-4 flex flex-wrap items-center gap-2\">{metadataChips}</div>\n ) : null}\n\n {/* Before-score content slot (e.g. \"Signals on Case\" chips) */}\n {renderBeforeScore?.(item)}\n\n <ScoreWhyChips\n item={item}\n signalData={signalData}\n onOpenSignalBucket={onOpenSignalBucket}\n />\n <div className=\"mt-4\">\n <SignalApproval.Actions />\n </div>\n </div>\n )\n })()}\n\n {/* After-score content slot (e.g. OpportunityPanel) */}\n {renderAfterScore?.(item)}\n\n {/* Activity Timeline */}\n {sections.timeline && timelineEvents.length > 0 && (\n <TimelineSection\n timelineEvents={timelineEvents}\n showTimeline={showTimeline}\n setShowTimeline={setShowTimeline}\n showSystemEvents={showSystemEvents}\n setShowSystemEvents={setShowSystemEvents}\n attentionCount={attentionCount}\n sysEvtConfig={sysEvtConfig}\n lastActivityTime={lastActivityTime}\n />\n )}\n </div>\n\n {/* Suggested Actions */}\n {sections.suggestedActions && (\n <SignalApproval.Gate>\n <SuggestedActions\n actions={suggestedActions}\n accountContacts={accountContacts}\n signature={emailSignature}\n iconMap={iconMap}\n onDismiss={(id) => console.log(\"Dismiss action:\", id)}\n onSend={(id) => console.log(\"Send action:\", id)}\n onSaveDraft={(id) => console.log(\"Save draft:\", id)}\n onDuplicate={handleDuplicate}\n onOpenAccountDetails={onOpenEntityPanel}\n onOpenRecentActivity={onOpenRecentActivity}\n onMarkComplete={(id) => console.log(\"Mark complete:\", id)}\n onDispatchAgent={(id) => console.log(\"Dispatch agent:\", id)}\n />\n </SignalApproval.Gate>\n )}\n {renderDetailExtra?.(item)}\n </div>\n </SignalApproval.Root>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Main Component\n// ---------------------------------------------------------------------------\n\nexport function PrototypeInboxView({\n items,\n filterCategories,\n detailSections,\n accountContacts = [],\n buildAccountContacts,\n emailSignature = \"\",\n buildSuggestedActions: buildSuggestedActionsProp,\n buildSourceItems: buildSourceItemsProp,\n getSignalScore: getSignalScoreProp,\n getTimelineEvents,\n iconMap = {},\n hideToolbarActions,\n hideHoverActions,\n onSuggestedActionFeedback,\n onScoreFeedback,\n onOpenSignalBucket,\n headerActions,\n onOpenEntityPanel,\n onOpenRecentActivity,\n onItemSelect,\n defaultViewMode,\n buildEntityChips,\n quickFilterTabs,\n hideAccountsButton,\n accountDetailsLabel,\n onSignalApprove,\n getSignalApprovalState,\n signalLabels,\n hideApproveButton,\n signalBriefCopy,\n briefStyleVariant,\n renderDetailExtra,\n renderBeforeScore,\n renderAfterScore,\n lastActivityTime,\n timelineSystemEventsConfig,\n attentionCount,\n renderTitleExtra,\n renderTitleActionRow,\n renderTitleSubtext,\n accountDetailsButtonLabel,\n getAccountDetailsButtonAriaLabel,\n sortOptions,\n activeSortId,\n onSortChange,\n}: PrototypeInboxViewProps) {\n const [inboxViewMode, setInboxViewMode] = React.useState<\"inbox\" | \"list\" | \"detail\">(\n defaultViewMode === \"list\" ? \"list\" : defaultViewMode === \"split\" ? \"inbox\" : \"inbox\"\n )\n const [previousViewMode, setPreviousViewMode] = React.useState<\"inbox\" | \"list\">(\"inbox\")\n const [selectedTask, setSelectedTask] = React.useState(items[0])\n const [inboxAssignee, setInboxAssignee] = React.useState<AssigneeFilter>(\"me\")\n const [inboxFilters, setInboxFilters] = React.useState<Record<string, string>>({})\n const [activeQuickFilter, setActiveQuickFilter] = React.useState<string>(\"all\")\n const [splitViewSearch, setSplitViewSearch] = React.useState(\"\")\n\n const sections = React.useMemo(\n () => ({ ...DEFAULT_DETAIL_SECTIONS, ...detailSections }),\n [detailSections],\n )\n\n const resolvedFilterCategories: InboxFilterCategory[] = React.useMemo(\n () =>\n filterCategories ?? [\n {\n id: \"category\",\n label: \"Category\",\n icon: <Tag className=\"h-3.5 w-3.5 text-muted-foreground\" />,\n options: [...new Set(items.map((i) => i.tag1))],\n },\n {\n id: \"account\",\n label: \"Account\",\n icon: <Building className=\"h-3.5 w-3.5 text-muted-foreground\" />,\n options: [...new Set(items.map((i) => i.company))],\n },\n ],\n [filterCategories, items],\n )\n\n const buildSuggestedActions = React.useMemo(\n () => buildSuggestedActionsProp ?? (() => []),\n [buildSuggestedActionsProp],\n )\n\n const buildSourceItems = React.useMemo(\n () => buildSourceItemsProp ?? (() => []),\n [buildSourceItemsProp],\n )\n\n const getSignalScore = React.useMemo(\n () => getSignalScoreProp ?? (() => DEFAULT_SIGNAL_SCORE),\n [getSignalScoreProp],\n )\n\n // Build a map from filter category id → QueueItem field for targeted filtering.\n // Known category ids are mapped explicitly; unknown categories fall back to a\n // broad search across display fields so consumer-defined filters still work.\n const filterFieldMap = React.useMemo<\n Record<string, (item: QueueItem, value: string) => boolean>\n >(() => {\n const map: Record<string, (item: QueueItem, value: string) => boolean> = {}\n for (const cat of resolvedFilterCategories) {\n switch (cat.id) {\n case \"category\":\n case \"signalType\":\n map[cat.id] = (item, v) => item.tag1.toLowerCase() === v.toLowerCase()\n break\n case \"account\":\n map[cat.id] = (item, v) => item.company.toLowerCase() === v.toLowerCase()\n break\n default:\n // Fallback: check all display fields\n map[cat.id] = (item, v) => {\n const lv = v.toLowerCase()\n return (\n item.tag1.toLowerCase() === lv ||\n item.company.toLowerCase() === lv ||\n item.title.toLowerCase().includes(lv) ||\n item.details.toLowerCase().includes(lv)\n )\n }\n }\n }\n return map\n }, [resolvedFilterCategories])\n\n // Filter items for list view based on toolbar filters\n const filteredItems = React.useMemo(() => {\n const activeFilters = Object.entries(inboxFilters).filter(\n ([, value]) => value && value !== \"all\"\n )\n if (activeFilters.length === 0) return items\n return items.filter((item) =>\n activeFilters.every(([key, value]) => {\n const matcher = filterFieldMap[key]\n return matcher ? matcher(item, value) : true\n })\n )\n }, [items, inboxFilters, filterFieldMap])\n\n // Resolve quick filter tabs once — used by both the split view filter and\n // the tab bar render. Each tab's `matchValue` (falling back to `label`) is\n // compared against `item.tag1` so consumer labels can differ from data values.\n type QuickFilterTab = { id: string; label: string; matchValue?: string; count?: number }\n const resolvedQuickFilterTabs = React.useMemo<QuickFilterTab[]>(() => {\n if (quickFilterTabs) return quickFilterTabs\n // Derive default tabs from the actual item tag1 values\n const uniqueTags = [...new Set(items.map((i) => i.tag1))]\n return uniqueTags.map((tag) => ({\n id: tag.toLowerCase().replace(/\\s+/g, \"-\"),\n label: tag,\n }))\n }, [quickFilterTabs, items])\n\n // Compute per-tab counts once so they can be displayed in the tab bar\n const quickFilterTabCounts = React.useMemo(() => {\n const counts: Record<string, number> = {}\n for (const tab of resolvedQuickFilterTabs) {\n const match = (tab.matchValue ?? tab.label).toLowerCase()\n counts[tab.id] = items.filter((i) => i.tag1.toLowerCase() === match).length\n }\n return counts\n }, [resolvedQuickFilterTabs, items])\n\n // Filter items for split view based on quick filter tabs and search\n const splitViewItems = React.useMemo(() => {\n let filtered = items\n // Apply quick filter tab\n if (activeQuickFilter !== \"all\") {\n const activeTab = resolvedQuickFilterTabs.find((t) => t.id === activeQuickFilter)\n if (activeTab) {\n const match = (activeTab.matchValue ?? activeTab.label).toLowerCase()\n filtered = filtered.filter(\n (item) => item.tag1.toLowerCase() === match\n )\n }\n }\n // Apply search input\n if (splitViewSearch.trim()) {\n const q = splitViewSearch.trim().toLowerCase()\n filtered = filtered.filter(\n (item) =>\n item.tag1.toLowerCase().includes(q) ||\n item.company.toLowerCase().includes(q) ||\n item.title.toLowerCase().includes(q)\n )\n }\n return filtered\n }, [items, activeQuickFilter, resolvedQuickFilterTabs, splitViewSearch])\n\n // Grouped items for list view — one group per severity tier so items\n // are labelled correctly (e.g. \"Urgent\", \"High\", \"Active\").\n const inboxGroups = React.useMemo<GroupedListGroup<QueueItem>[]>(() => {\n const urgent = filteredItems.filter((i) => i.statusColor === \"red\")\n const high = filteredItems.filter((i) => i.statusColor === \"orange\")\n const active = filteredItems.filter((i) => i.statusColor !== \"red\" && i.statusColor !== \"orange\")\n return [\n { key: \"urgent\", label: \"Urgent\", items: urgent },\n { key: \"high\", label: \"High\", items: high },\n { key: \"active\", label: \"Active\", items: active },\n ].filter((g) => g.items.length > 0)\n }, [filteredItems])\n\n const renderInboxRow = React.useCallback(\n (item: QueueItem) => (\n <>\n <span className={`h-2 w-2 shrink-0 rounded-full ${dotColorClass(item.statusColor)}`} />\n <span className=\"w-[80px] shrink-0 font-mono text-xs text-muted-foreground/80\">{item.id}</span>\n <span className=\"shrink-0 rounded-md border border-border bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground whitespace-nowrap\">{item.tag1}</span>\n <span className=\"min-w-0 flex-1 truncate text-sm font-semibold text-foreground\">{item.title}</span>\n <span className=\"w-[120px] shrink-0 truncate text-xs font-medium text-foreground\">{item.company}</span>\n <span className=\"w-[80px] shrink-0 text-right text-xs text-muted-foreground\">{item.time}</span>\n </>\n ),\n [],\n )\n\n const handleInboxItemSelect = React.useCallback(\n (item: QueueItem) => {\n setSelectedTask(item)\n if (onItemSelect) {\n onItemSelect(item)\n } else if (inboxViewMode === \"list\") {\n setPreviousViewMode(\"list\")\n setInboxViewMode(\"detail\")\n }\n },\n [inboxViewMode, onItemSelect],\n )\n\n const handleBackFromDetail = React.useCallback(() => {\n setInboxViewMode(previousViewMode)\n }, [previousViewMode])\n\n const handleViewModeChange = React.useCallback((id: string) => {\n const mode = id as \"inbox\" | \"list\" | \"detail\"\n if (mode !== \"detail\") {\n setPreviousViewMode(mode)\n }\n setInboxViewMode(mode)\n }, [])\n\n React.useEffect(() => {\n const mql = window.matchMedia(\"(max-width: 768px)\")\n function handleChange(e: MediaQueryListEvent | MediaQueryList) {\n if (e.matches && inboxViewMode === \"inbox\") {\n setPreviousViewMode(\"inbox\")\n setInboxViewMode(\"detail\")\n }\n }\n handleChange(mql)\n mql.addEventListener(\"change\", handleChange)\n return () => mql.removeEventListener(\"change\", handleChange)\n }, [inboxViewMode])\n\n const detailViewProps: DetailViewProps = {\n item: selectedTask,\n sections,\n getSignalScore,\n buildSuggestedActions,\n buildSourceItems,\n getTimelineEvents,\n accountContacts: buildAccountContacts?.(selectedTask) ?? accountContacts,\n emailSignature,\n iconMap,\n onOpenEntityPanel,\n onOpenRecentActivity,\n onSuggestedActionFeedback,\n onScoreFeedback,\n onSignalApprove,\n getSignalApprovalState,\n signalLabels,\n hideApproveButton,\n signalBriefCopy,\n briefStyleVariant,\n renderDetailExtra,\n renderBeforeScore,\n renderAfterScore,\n lastActivityTime,\n timelineSystemEventsConfig,\n attentionCount,\n renderTitleExtra,\n renderTitleActionRow,\n renderTitleSubtext,\n accountDetailsButtonLabel,\n getAccountDetailsButtonAriaLabel,\n onOpenSignalBucket,\n }\n\n return (\n <div className=\"flex h-full w-full flex-col\">\n {/* Toolbar */}\n <div className=\"flex items-center justify-between border-b border-border bg-background px-4 py-3 shrink-0\">\n <div className=\"flex items-center gap-3\">\n {inboxViewMode === \"detail\" ? (\n <button\n type=\"button\"\n onClick={handleBackFromDetail}\n className=\"flex items-center gap-2 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n Back\n </button>\n ) : null}\n <h2 className=\"text-lg font-semibold text-foreground\">Inbox</h2>\n <Badge variant=\"secondary\" className=\"bg-muted text-muted-foreground hover:bg-muted font-medium text-[11px] px-2 py-0.5 rounded-md\">\n {items.length}\n </Badge>\n </div>\n <div className=\"flex items-center gap-3\">\n <ViewModeToggle\n modes={[\n { id: \"inbox\", icon: <Columns2 className=\"h-3.5 w-3.5\" />, label: \"Split View\" },\n { id: \"list\", icon: <LayoutList className=\"h-3.5 w-3.5\" />, label: \"List View\" },\n { id: \"detail\", icon: <Square className=\"h-3.5 w-3.5\" />, label: \"Detail View\" },\n ]}\n activeMode={inboxViewMode}\n onModeChange={handleViewModeChange}\n />\n {headerActions}\n </div>\n </div>\n\n {/* View modes */}\n {inboxViewMode === \"detail\" ? (\n <div className=\"flex h-full flex-1 flex-col overflow-hidden bg-background\">\n <div className=\"flex-1 overflow-y-auto\">\n <DetailView {...detailViewProps} />\n </div>\n </div>\n ) : inboxViewMode === \"list\" ? (\n <div className=\"flex-1 overflow-y-auto bg-background\">\n <InboxToolbar\n assignee={inboxAssignee}\n onAssigneeChange={setInboxAssignee}\n filterCategories={resolvedFilterCategories}\n selectedFilters={inboxFilters}\n onFilterChange={(catId, val) =>\n setInboxFilters((prev) => ({ ...prev, [catId]: val }))\n }\n onClearFilters={() => setInboxFilters({})}\n />\n <GroupedListView<QueueItem>\n groups={inboxGroups}\n renderRow={renderInboxRow}\n getItemKey={(item) => item.id}\n selectedKey={selectedTask.id}\n onItemClick={handleInboxItemSelect}\n emptyMessage=\"No inbox items\"\n />\n </div>\n ) : (\n /* Split view */\n <div className=\"flex h-full min-h-0 w-full flex-1\">\n <div className=\"flex h-full min-w-[380px] w-[380px] flex-col border-r border-border bg-background shadow-sm z-10\">\n <div className=\"flex flex-col gap-4 border-b border-border p-4 shrink-0\">\n {!hideToolbarActions && (\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-1\">\n <Button variant=\"outline\" size=\"icon\" className=\"h-8 w-8 text-muted-foreground\"><Eye className=\"w-4 h-4\" /></Button>\n <Button variant=\"outline\" size=\"icon\" className=\"h-8 w-8 text-muted-foreground\"><FileText className=\"w-4 h-4\" /></Button>\n <Button variant=\"outline\" size=\"icon\" className=\"h-8 w-8 text-muted-foreground\"><Clock className=\"w-4 h-4\" /></Button>\n <Button variant=\"outline\" size=\"icon\" className=\"h-8 w-8 text-muted-foreground\"><CheckSquare className=\"w-4 h-4\" /></Button>\n </div>\n <Button size=\"sm\" className=\"h-8 px-4 bg-foreground text-background hover:bg-foreground/90 text-xs font-semibold gap-1.5 rounded-md\">\n <Plus className=\"w-4 h-4\" /> Add Task\n </Button>\n </div>\n )}\n <div className=\"flex items-center gap-2\">\n <div className=\"relative flex-1\">\n <Filter className=\"absolute left-2.5 top-1.5 w-4 h-4 text-muted-foreground\" />\n <Input\n className=\"h-8 pl-8 text-xs bg-background border-border rounded-md shadow-none\"\n placeholder=\"Filter by category...\"\n value={splitViewSearch}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setSplitViewSearch(e.target.value)}\n />\n </div>\n {sortOptions && sortOptions.length > 0 && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" size=\"sm\" className=\"h-8 text-xs font-medium rounded-md shadow-none gap-1.5\">\n <ArrowUpDown className=\"w-3.5 h-3.5\" />\n {sortOptions.find(o => o.id === activeSortId)?.label ?? 'Sort'}\n <ChevronDown className=\"w-3 h-3\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuRadioGroup value={activeSortId ?? ''} onValueChange={(val) => onSortChange?.(val)}>\n {sortOptions.map(option => (\n <DropdownMenuRadioItem key={option.id} value={option.id}>\n {option.label}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n {!hideAccountsButton && (\n <Button variant=\"outline\" size=\"sm\" className=\"h-8 text-xs font-medium rounded-md shadow-none\">\n <Building className=\"w-3.5 h-3.5 mr-1.5\" /> {accountDetailsLabel ?? \"Accounts\"}\n </Button>\n )}\n </div>\n <div className=\"flex items-center gap-1.5 overflow-x-auto pb-1 mt-1 scrollbar-hide\">\n <Button\n size=\"sm\"\n variant={activeQuickFilter === \"all\" ? \"default\" : \"outline\"}\n className={`h-7 rounded-full px-3.5 text-[11px] font-semibold shadow-none ${\n activeQuickFilter === \"all\"\n ? \"bg-foreground text-background hover:bg-foreground/90\"\n : \"bg-transparent border-border text-muted-foreground hover:text-foreground\"\n }`}\n onClick={() => setActiveQuickFilter(\"all\")}\n >\n All\n </Button>\n {resolvedQuickFilterTabs.map((tab) => {\n const count = tab.count ?? quickFilterTabCounts[tab.id]\n return (\n <Button\n key={tab.id}\n size=\"sm\"\n variant={activeQuickFilter === tab.id ? \"default\" : \"outline\"}\n className={`h-7 rounded-full px-3.5 text-[11px] font-medium shadow-none ${\n activeQuickFilter === tab.id\n ? \"bg-foreground text-background hover:bg-foreground/90\"\n : \"bg-transparent border-border text-muted-foreground hover:text-foreground\"\n }`}\n onClick={() => setActiveQuickFilter(tab.id)}\n >\n {tab.label}{count != null && count > 0 ? ` (${count})` : \"\"}\n </Button>\n )\n })}\n </div>\n </div>\n\n <div className=\"flex-1 overflow-y-auto\">\n {splitViewItems.map((item) => (\n <div\n key={item.id}\n onClick={() => { setSelectedTask(item); onItemSelect?.(item) }}\n className={`cursor-pointer border-b border-border p-4 transition-colors group relative border-l-2 ${\n selectedTask.id === item.id\n ? \"bg-muted/30 border-l-brand-purple\"\n : \"bg-transparent border-l-transparent hover:bg-muted/10\"\n }`}\n >\n <div className=\"mb-1.5 flex items-center gap-2\">\n <span className=\"min-w-0 truncate text-[13px] font-semibold text-foreground leading-tight\">{item.title}</span>\n {selectedTask.id !== item.id && item.tag1 && (\n <span className=\"shrink-0 rounded-md border border-border bg-muted/60 px-2 py-0.5 text-[10px] font-medium text-muted-foreground\">\n {item.tag1}\n </span>\n )}\n <span className=\"ml-auto shrink-0 text-[10px] font-medium text-muted-foreground/80\">{item.time}</span>\n </div>\n <div className=\"flex items-start gap-2 mt-2\">\n <span className={`w-1.5 h-1.5 rounded-full shrink-0 mt-1.5 ${dotColorClass(item.statusColor)}`} />\n <span className=\"text-xs text-muted-foreground leading-tight\">{item.details}</span>\n </div>\n {buildEntityChips && (() => {\n const chips = buildEntityChips(item)\n if (!chips.length) return null\n return (\n <div className=\"flex items-center gap-1.5 mt-2 flex-wrap\">\n {chips.map((chip) => (\n <button\n key={chip.id}\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); chip.onClick?.() }}\n className=\"inline-flex items-center gap-1 rounded-md border border-border/60 bg-muted/30 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground\"\n >\n <span className=\"flex h-3.5 w-3.5 items-center justify-center rounded bg-muted-foreground/10 text-[8px] font-semibold\">{chip.avatarLetter}</span>\n {chip.label}\n </button>\n ))}\n </div>\n )\n })()}\n {!hideHoverActions && (\n <div className={`absolute right-4 bottom-4 flex items-center gap-1.5 bg-background shadow-sm rounded-md px-1 py-0.5 border border-border ${\n selectedTask.id === item.id ? \"opacity-100\" : \"opacity-0 group-hover:opacity-100 transition-opacity\"\n }`}>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-6 w-6 rounded text-muted-foreground hover:text-foreground\"><CheckSquare className=\"w-3.5 h-3.5\" /></Button>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-6 w-6 rounded text-muted-foreground hover:text-foreground\"><Clock className=\"w-3.5 h-3.5\" /></Button>\n </div>\n )}\n </div>\n ))}\n <div className=\"p-4\">\n <Button variant=\"outline\" size=\"sm\" className=\"h-8 text-xs font-semibold rounded-md shadow-none\">See more</Button>\n </div>\n </div>\n </div>\n\n <div className=\"flex h-full flex-1 flex-col overflow-hidden bg-background\">\n <div className=\"flex-1 overflow-y-auto\">\n <DetailView {...detailViewProps} />\n </div>\n </div>\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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","names":["_a"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { h as InsightsViewConfig } from '../signal-priority-popover-
|
|
2
|
+
import { h as InsightsViewConfig } from '../signal-priority-popover-Cg9XPJsp.js';
|
|
3
3
|
import '../components/feedback-primitives.js';
|
|
4
4
|
import '../components/quick-action-sidebar-nav.js';
|
|
5
5
|
import '../components/quick-action-modal.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { j as PrototypeConfig } from '../signal-priority-popover-
|
|
2
|
+
import { j as PrototypeConfig } from '../signal-priority-popover-Cg9XPJsp.js';
|
|
3
3
|
import '../components/feedback-primitives.js';
|
|
4
4
|
import '../components/quick-action-sidebar-nav.js';
|
|
5
5
|
import '../components/quick-action-modal.js';
|
package/dist/{signal-priority-popover-CZitE9xq.d.ts → signal-priority-popover-Cg9XPJsp.d.ts}
RENAMED
|
@@ -137,6 +137,11 @@ interface SignalScoreData {
|
|
|
137
137
|
timeChipLabel?: string;
|
|
138
138
|
/** Expanded detail for time chip popover (e.g., "Day 2 of 14 · Event detected on May 1"). */
|
|
139
139
|
timeChipDetail?: string;
|
|
140
|
+
/**
|
|
141
|
+
* Visual urgency tone for the deadline chip. The consumer computes this from the live deadline
|
|
142
|
+
* (e.g. amber when a few days remain, red when due/overdue). Defaults to neutral when omitted.
|
|
143
|
+
*/
|
|
144
|
+
timeChipTone?: "neutral" | "amber" | "red";
|
|
140
145
|
}
|
|
141
146
|
interface InboxSortOption {
|
|
142
147
|
id: string;
|
package/package.json
CHANGED
|
@@ -82,7 +82,7 @@ describe("ConversationPanel", () => {
|
|
|
82
82
|
expect(screen.getByText("Draft ready")).toBeDefined();
|
|
83
83
|
expect(screen.getByText("Draft ready on 1 thread")).toBeDefined();
|
|
84
84
|
expect(screen.queryByText("Awaiting response")).toBeNull();
|
|
85
|
-
expect(screen.getAllByText("Draft")).
|
|
85
|
+
expect(screen.getAllByText("Draft").length).toBeGreaterThan(0);
|
|
86
86
|
expect(screen.getByText("Draft copy")).toBeDefined();
|
|
87
87
|
});
|
|
88
88
|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { cleanup, render, screen } from "@testing-library/react"
|
|
2
|
+
import { afterEach, describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import { DetailView } from "../prototype-inbox-view"
|
|
5
|
+
import type { DetailViewProps } from "../prototype-inbox-view"
|
|
6
|
+
import type { SignalScoreData } from "../prototype-config"
|
|
7
|
+
|
|
8
|
+
const baseItem = {
|
|
9
|
+
id: "case-1",
|
|
10
|
+
title: "Churn risk case title",
|
|
11
|
+
details: "Case details",
|
|
12
|
+
statusColor: "red",
|
|
13
|
+
time: "1h ago",
|
|
14
|
+
company: "Acme Corp",
|
|
15
|
+
tag1: "Signal",
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
cleanup()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
function renderDetailView(
|
|
23
|
+
overrides: Partial<DetailViewProps> = {},
|
|
24
|
+
scoreOverrides: Partial<SignalScoreData> = {},
|
|
25
|
+
) {
|
|
26
|
+
const props: DetailViewProps = {
|
|
27
|
+
item: baseItem,
|
|
28
|
+
sections: { signalBrief: true, suggestedActions: false, timeline: false },
|
|
29
|
+
getSignalScore: () => ({
|
|
30
|
+
score: 72,
|
|
31
|
+
factors: [],
|
|
32
|
+
whyNow: "Why now",
|
|
33
|
+
evidence: [],
|
|
34
|
+
confidence: 80,
|
|
35
|
+
urgencyLabel: "High",
|
|
36
|
+
urgencyExplanation: "High priority",
|
|
37
|
+
signalBrief: "BRIEF BODY TEXT",
|
|
38
|
+
timeChipLabel: "3 days left",
|
|
39
|
+
...scoreOverrides,
|
|
40
|
+
}),
|
|
41
|
+
buildSuggestedActions: () => [],
|
|
42
|
+
buildSourceItems: () => [],
|
|
43
|
+
accountContacts: [],
|
|
44
|
+
emailSignature: "",
|
|
45
|
+
iconMap: {},
|
|
46
|
+
renderMetadataExtra: () => <span data-testid="metadata-extra">Owner: Lee</span>,
|
|
47
|
+
...overrides,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return render(<DetailView {...props} />)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const PRECEDES = Node.DOCUMENT_POSITION_PRECEDING
|
|
54
|
+
const FOLLOWS = Node.DOCUMENT_POSITION_FOLLOWING
|
|
55
|
+
|
|
56
|
+
describe("DetailView metadataLayout", () => {
|
|
57
|
+
it("renders the metadata chips above the brief by default", () => {
|
|
58
|
+
renderDetailView()
|
|
59
|
+
|
|
60
|
+
const brief = screen.getByText("BRIEF BODY TEXT")
|
|
61
|
+
const meta = screen.getByTestId("metadata-extra")
|
|
62
|
+
// metadata-extra comes before the brief body in document order
|
|
63
|
+
expect(brief.compareDocumentPosition(meta) & PRECEDES).toBeTruthy()
|
|
64
|
+
expect(screen.getByTestId("priority-popover-trigger")).toBeTruthy()
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it("relocates the metadata chips below the brief when metadataLayout='below-brief'", () => {
|
|
68
|
+
renderDetailView({ metadataLayout: "below-brief" })
|
|
69
|
+
|
|
70
|
+
const brief = screen.getByText("BRIEF BODY TEXT")
|
|
71
|
+
const meta = screen.getByTestId("metadata-extra")
|
|
72
|
+
// metadata-extra now follows the brief body
|
|
73
|
+
expect(brief.compareDocumentPosition(meta) & FOLLOWS).toBeTruthy()
|
|
74
|
+
// chips themselves (priority + account + deadline) render exactly once
|
|
75
|
+
expect(screen.getAllByTestId("priority-popover-trigger")).toHaveLength(1)
|
|
76
|
+
expect(screen.getByText("3 days left")).toBeTruthy()
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
describe("DetailView deadline chip tone", () => {
|
|
81
|
+
it("applies the red tone when timeChipTone='red'", () => {
|
|
82
|
+
renderDetailView({}, { timeChipTone: "red" })
|
|
83
|
+
expect(screen.getByText("3 days left").className).toContain("text-red-700")
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it("applies the amber tone when timeChipTone='amber'", () => {
|
|
87
|
+
renderDetailView({}, { timeChipTone: "amber" })
|
|
88
|
+
expect(screen.getByText("3 days left").className).toContain("text-amber-700")
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it("uses a neutral tone when timeChipTone is omitted", () => {
|
|
92
|
+
renderDetailView()
|
|
93
|
+
const chip = screen.getByText("3 days left")
|
|
94
|
+
expect(chip.className).not.toContain("text-red-700")
|
|
95
|
+
expect(chip.className).not.toContain("text-amber-700")
|
|
96
|
+
})
|
|
97
|
+
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { render, screen } from "@testing-library/react"
|
|
2
|
-
import { describe, expect, it, vi } from "vitest"
|
|
1
|
+
import { cleanup, render, screen } from "@testing-library/react"
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from "vitest"
|
|
3
3
|
|
|
4
4
|
import { DetailView } from "../prototype-inbox-view"
|
|
5
5
|
import type { DetailViewProps } from "../prototype-inbox-view"
|
|
@@ -14,6 +14,10 @@ const baseItem = {
|
|
|
14
14
|
tag1: "Signal",
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
cleanup()
|
|
19
|
+
})
|
|
20
|
+
|
|
17
21
|
function renderDetailView(overrides: Partial<DetailViewProps> = {}) {
|
|
18
22
|
const props: DetailViewProps = {
|
|
19
23
|
item: baseItem,
|
|
@@ -39,6 +43,30 @@ function renderDetailView(overrides: Partial<DetailViewProps> = {}) {
|
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
describe("DetailView title slots", () => {
|
|
46
|
+
it("does not render the inert detail Back button while preserving title and metadata slots", () => {
|
|
47
|
+
renderDetailView({
|
|
48
|
+
renderTitleActionRow: () => (
|
|
49
|
+
<button type="button">Full-width quick action</button>
|
|
50
|
+
),
|
|
51
|
+
renderMetadataExtra: () => <span data-testid="metadata-extra">Owner: Lee</span>,
|
|
52
|
+
accountDetailsButtonLabel: (item) => (
|
|
53
|
+
<>
|
|
54
|
+
<span>View account details</span>
|
|
55
|
+
<span>{item.company}</span>
|
|
56
|
+
</>
|
|
57
|
+
),
|
|
58
|
+
getAccountDetailsButtonAriaLabel: (item) => `View account details for ${item.company}`,
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
expect(screen.queryByRole("button", { name: "Back" })).toBeNull()
|
|
62
|
+
expect(screen.getByRole("heading", { name: "Churn risk case title" })).toBeTruthy()
|
|
63
|
+
expect(screen.getAllByText("Acme Corp").length).toBeGreaterThan(0)
|
|
64
|
+
expect(screen.getByRole("button", { name: "Full-width quick action" })).toBeTruthy()
|
|
65
|
+
expect(screen.getByTestId("metadata-extra").textContent).toBe("Owner: Lee")
|
|
66
|
+
expect(screen.getByTestId("priority-popover-trigger")).toBeTruthy()
|
|
67
|
+
expect(screen.getByRole("button", { name: "View account details for Acme Corp" })).toBeTruthy()
|
|
68
|
+
})
|
|
69
|
+
|
|
42
70
|
it("renders supporting title text below the main title", () => {
|
|
43
71
|
renderDetailView({
|
|
44
72
|
renderTitleSubtext: (item) => <p data-testid="title-subtext">Full title: {item.title}</p>,
|
|
@@ -142,6 +142,11 @@ export interface SignalScoreData {
|
|
|
142
142
|
timeChipLabel?: string
|
|
143
143
|
/** Expanded detail for time chip popover (e.g., "Day 2 of 14 · Event detected on May 1"). */
|
|
144
144
|
timeChipDetail?: string
|
|
145
|
+
/**
|
|
146
|
+
* Visual urgency tone for the deadline chip. The consumer computes this from the live deadline
|
|
147
|
+
* (e.g. amber when a few days remain, red when due/overdue). Defaults to neutral when omitted.
|
|
148
|
+
*/
|
|
149
|
+
timeChipTone?: "neutral" | "amber" | "red"
|
|
145
150
|
}
|
|
146
151
|
|
|
147
152
|
// ---------------------------------------------------------------------------
|
|
@@ -169,6 +169,13 @@ export interface DetailViewProps {
|
|
|
169
169
|
renderTitleSubtext?: (item: QueueItem) => React.ReactNode
|
|
170
170
|
/** Render extra metadata chips (e.g. assignee) inside the chips row below the title. */
|
|
171
171
|
renderMetadataExtra?: (item: QueueItem) => React.ReactNode
|
|
172
|
+
/**
|
|
173
|
+
* Where the metadata chips row (priority · deadline · account · renderMetadataExtra) sits.
|
|
174
|
+
* - "default": above the signal brief (legacy layout, unchanged for existing consumers).
|
|
175
|
+
* - "below-brief": moved beneath the brief text, just before `renderBeforeScore`
|
|
176
|
+
* (case-panel redesign — chips + owners read as one block under the brief).
|
|
177
|
+
*/
|
|
178
|
+
metadataLayout?: "default" | "below-brief"
|
|
172
179
|
/** Override the built-in account details metadata button label. */
|
|
173
180
|
accountDetailsButtonLabel?: (item: QueueItem) => React.ReactNode
|
|
174
181
|
/** Accessible label for the built-in account details metadata button. */
|
|
@@ -352,6 +359,7 @@ export function DetailView({
|
|
|
352
359
|
renderTitleActionRow,
|
|
353
360
|
renderTitleSubtext,
|
|
354
361
|
renderMetadataExtra,
|
|
362
|
+
metadataLayout = "default",
|
|
355
363
|
accountDetailsButtonLabel,
|
|
356
364
|
getAccountDetailsButtonAriaLabel,
|
|
357
365
|
onOpenSignalBucket,
|
|
@@ -465,6 +473,84 @@ export function DetailView({
|
|
|
465
473
|
[suggestedActions],
|
|
466
474
|
)
|
|
467
475
|
|
|
476
|
+
// Deadline chip tone (case-panel redesign): amber as the deadline nears, red when due/overdue.
|
|
477
|
+
const timeChipToneClass =
|
|
478
|
+
signalData.timeChipTone === "red"
|
|
479
|
+
? "border-red-300 bg-red-50 text-red-700 hover:bg-red-50"
|
|
480
|
+
: signalData.timeChipTone === "amber"
|
|
481
|
+
? "border-amber-300 bg-amber-50 text-amber-700 hover:bg-amber-50"
|
|
482
|
+
: "hover:bg-muted/50"
|
|
483
|
+
|
|
484
|
+
// The metadata chips row (priority · deadline · account · renderMetadataExtra). Rendered above
|
|
485
|
+
// the brief by default, or beneath it when `metadataLayout === "below-brief"` (case-panel redesign).
|
|
486
|
+
const metadataChips = (
|
|
487
|
+
<>
|
|
488
|
+
<SignalPriorityPopover
|
|
489
|
+
score={signalData.score}
|
|
490
|
+
urgencyLabel={signalData.urgencyLabel}
|
|
491
|
+
urgencyExplanation={signalData.urgencyExplanation ?? signalData.signalBrief}
|
|
492
|
+
scoreDisplay={signalData.priorityScoreDisplay}
|
|
493
|
+
formulaLabel={signalData.priorityFormulaLabel}
|
|
494
|
+
factors={signalData.priorityFactors ?? []}
|
|
495
|
+
metaText={undefined}
|
|
496
|
+
feedbackChips={signalData.priorityFeedbackChips}
|
|
497
|
+
onFeedbackSubmit={signalData.onPriorityFeedback}
|
|
498
|
+
initialFactorFeedback={signalData.initialFactorPopoverFeedback}
|
|
499
|
+
onFactorFeedback={signalData.onFactorFeedback}
|
|
500
|
+
initialPriorityFeedback={signalData.initialPriorityFeedback}
|
|
501
|
+
/>
|
|
502
|
+
{signalData.timeChipLabel && (
|
|
503
|
+
<Badge
|
|
504
|
+
variant="outline"
|
|
505
|
+
title={signalData.timeChipDetail ?? undefined}
|
|
506
|
+
className={`transition-colors ${timeChipToneClass}`}
|
|
507
|
+
>
|
|
508
|
+
{signalData.timeChipLabel}
|
|
509
|
+
</Badge>
|
|
510
|
+
)}
|
|
511
|
+
<TooltipProvider delayDuration={300}>
|
|
512
|
+
<Tooltip>
|
|
513
|
+
<TooltipTrigger asChild>
|
|
514
|
+
<button
|
|
515
|
+
type="button"
|
|
516
|
+
onClick={onOpenEntityPanel}
|
|
517
|
+
className="group/account ml-1 inline-flex max-w-full items-center gap-2 rounded-md border border-border/60 bg-background px-2 py-1 transition-colors hover:border-border hover:bg-muted/50"
|
|
518
|
+
aria-label={getAccountDetailsButtonAriaLabel?.(item) ?? `View account details for ${item.company}`}
|
|
519
|
+
>
|
|
520
|
+
<span className="flex h-5 w-5 shrink-0 items-center justify-center rounded bg-foreground text-[9px] font-semibold uppercase leading-none text-background">
|
|
521
|
+
{getCompanyInitials(item.company)}
|
|
522
|
+
</span>
|
|
523
|
+
{accountDetailsButtonLabel ? (
|
|
524
|
+
<span className="inline-flex min-w-0 items-center gap-1.5 text-xs font-medium text-foreground">
|
|
525
|
+
{accountDetailsButtonLabel(item)}
|
|
526
|
+
</span>
|
|
527
|
+
) : (
|
|
528
|
+
<span className="truncate text-xs font-medium text-foreground">{item.company}</span>
|
|
529
|
+
)}
|
|
530
|
+
<span className="flex shrink-0 items-center gap-1.5">
|
|
531
|
+
<span
|
|
532
|
+
aria-hidden
|
|
533
|
+
className={`h-1.5 w-1.5 shrink-0 rounded-full ${STATUS_DOT_CLASS[item.statusColor] ?? "bg-muted-foreground/40"}`}
|
|
534
|
+
/>
|
|
535
|
+
{/* "View account" expands in on hover via an animated grid column */}
|
|
536
|
+
<span className="-ml-1.5 grid grid-cols-[0fr] transition-all duration-200 ease-out group-hover/account:ml-0 group-hover/account:grid-cols-[1fr]">
|
|
537
|
+
<span className="overflow-hidden">
|
|
538
|
+
<span className="block whitespace-nowrap text-xs font-medium text-muted-foreground/80">
|
|
539
|
+
View account
|
|
540
|
+
</span>
|
|
541
|
+
</span>
|
|
542
|
+
</span>
|
|
543
|
+
<ChevronRight className="h-3 w-3 shrink-0 text-muted-foreground/50 transition-transform duration-150 group-hover/account:translate-x-0.5 group-hover/account:text-muted-foreground" />
|
|
544
|
+
</span>
|
|
545
|
+
</button>
|
|
546
|
+
</TooltipTrigger>
|
|
547
|
+
<TooltipContent>Open account panel</TooltipContent>
|
|
548
|
+
</Tooltip>
|
|
549
|
+
</TooltipProvider>
|
|
550
|
+
{renderMetadataExtra?.(item)}
|
|
551
|
+
</>
|
|
552
|
+
)
|
|
553
|
+
|
|
468
554
|
return (
|
|
469
555
|
<SignalApproval.Root
|
|
470
556
|
key={item.id}
|
|
@@ -488,14 +574,6 @@ export function DetailView({
|
|
|
488
574
|
<div className="pb-8">
|
|
489
575
|
{/* Header */}
|
|
490
576
|
<div className="mb-4 flex items-center gap-2">
|
|
491
|
-
<button
|
|
492
|
-
type="button"
|
|
493
|
-
className="flex items-center gap-1.5 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground"
|
|
494
|
-
>
|
|
495
|
-
<ArrowLeft className="h-3.5 w-3.5" />
|
|
496
|
-
Back
|
|
497
|
-
</button>
|
|
498
|
-
<span className="text-muted-foreground/40">·</span>
|
|
499
577
|
<span className="text-xs text-muted-foreground">{item.company}</span>
|
|
500
578
|
</div>
|
|
501
579
|
|
|
@@ -514,71 +592,9 @@ export function DetailView({
|
|
|
514
592
|
) : null}
|
|
515
593
|
</div>
|
|
516
594
|
|
|
517
|
-
|
|
518
|
-
<
|
|
519
|
-
|
|
520
|
-
urgencyLabel={signalData.urgencyLabel}
|
|
521
|
-
urgencyExplanation={signalData.urgencyExplanation ?? signalData.signalBrief}
|
|
522
|
-
scoreDisplay={signalData.priorityScoreDisplay}
|
|
523
|
-
formulaLabel={signalData.priorityFormulaLabel}
|
|
524
|
-
factors={signalData.priorityFactors ?? []}
|
|
525
|
-
metaText={undefined}
|
|
526
|
-
feedbackChips={signalData.priorityFeedbackChips}
|
|
527
|
-
onFeedbackSubmit={signalData.onPriorityFeedback}
|
|
528
|
-
initialFactorFeedback={signalData.initialFactorPopoverFeedback}
|
|
529
|
-
onFactorFeedback={signalData.onFactorFeedback}
|
|
530
|
-
initialPriorityFeedback={signalData.initialPriorityFeedback}
|
|
531
|
-
/>
|
|
532
|
-
{signalData.timeChipLabel && (
|
|
533
|
-
<Badge
|
|
534
|
-
variant="outline"
|
|
535
|
-
title={signalData.timeChipDetail ?? undefined}
|
|
536
|
-
className="transition-colors hover:bg-muted/50"
|
|
537
|
-
>
|
|
538
|
-
{signalData.timeChipLabel}
|
|
539
|
-
</Badge>
|
|
540
|
-
)}
|
|
541
|
-
<TooltipProvider delayDuration={300}>
|
|
542
|
-
<Tooltip>
|
|
543
|
-
<TooltipTrigger asChild>
|
|
544
|
-
<button
|
|
545
|
-
type="button"
|
|
546
|
-
onClick={onOpenEntityPanel}
|
|
547
|
-
className="group/account ml-1 inline-flex max-w-full items-center gap-2 rounded-md border border-border/60 bg-background px-2 py-1 transition-colors hover:border-border hover:bg-muted/50"
|
|
548
|
-
aria-label={getAccountDetailsButtonAriaLabel?.(item) ?? `View account details for ${item.company}`}
|
|
549
|
-
>
|
|
550
|
-
<span className="flex h-5 w-5 shrink-0 items-center justify-center rounded bg-foreground text-[9px] font-semibold uppercase leading-none text-background">
|
|
551
|
-
{getCompanyInitials(item.company)}
|
|
552
|
-
</span>
|
|
553
|
-
{accountDetailsButtonLabel ? (
|
|
554
|
-
<span className="inline-flex min-w-0 items-center gap-1.5 text-xs font-medium text-foreground">
|
|
555
|
-
{accountDetailsButtonLabel(item)}
|
|
556
|
-
</span>
|
|
557
|
-
) : (
|
|
558
|
-
<span className="truncate text-xs font-medium text-foreground">{item.company}</span>
|
|
559
|
-
)}
|
|
560
|
-
<span className="flex shrink-0 items-center gap-1.5">
|
|
561
|
-
<span
|
|
562
|
-
aria-hidden
|
|
563
|
-
className={`h-1.5 w-1.5 shrink-0 rounded-full ${STATUS_DOT_CLASS[item.statusColor] ?? "bg-muted-foreground/40"}`}
|
|
564
|
-
/>
|
|
565
|
-
{/* "View account" expands in on hover via an animated grid column */}
|
|
566
|
-
<span className="-ml-1.5 grid grid-cols-[0fr] transition-all duration-200 ease-out group-hover/account:ml-0 group-hover/account:grid-cols-[1fr]">
|
|
567
|
-
<span className="overflow-hidden">
|
|
568
|
-
<span className="block whitespace-nowrap text-xs font-medium text-muted-foreground/80">
|
|
569
|
-
View account
|
|
570
|
-
</span>
|
|
571
|
-
</span>
|
|
572
|
-
</span>
|
|
573
|
-
<ChevronRight className="h-3 w-3 shrink-0 text-muted-foreground/50 transition-transform duration-150 group-hover/account:translate-x-0.5 group-hover/account:text-muted-foreground" />
|
|
574
|
-
</span>
|
|
575
|
-
</button>
|
|
576
|
-
</TooltipTrigger>
|
|
577
|
-
<TooltipContent>Open account panel</TooltipContent>
|
|
578
|
-
</Tooltip>
|
|
579
|
-
</TooltipProvider>
|
|
580
|
-
{renderMetadataExtra?.(item)}
|
|
581
|
-
</div>
|
|
595
|
+
{metadataLayout === "default" ? (
|
|
596
|
+
<div className="mb-6 flex flex-wrap items-center gap-2">{metadataChips}</div>
|
|
597
|
+
) : null}
|
|
582
598
|
|
|
583
599
|
{/* Signal Brief */}
|
|
584
600
|
{sections.signalBrief && (() => {
|
|
@@ -620,6 +636,11 @@ export function DetailView({
|
|
|
620
636
|
</p>
|
|
621
637
|
)}
|
|
622
638
|
|
|
639
|
+
{/* Metadata chips relocated beneath the brief (case-panel redesign). */}
|
|
640
|
+
{metadataLayout === "below-brief" ? (
|
|
641
|
+
<div className="mb-4 flex flex-wrap items-center gap-2">{metadataChips}</div>
|
|
642
|
+
) : null}
|
|
643
|
+
|
|
623
644
|
{/* Before-score content slot (e.g. "Signals on Case" chips) */}
|
|
624
645
|
{renderBeforeScore?.(item)}
|
|
625
646
|
|