import { useState } from 'react';
import { ChevronDown, FileText, RefreshCw, TriangleAlert } from 'lucide-react';
import { cn } from '../../lib/cn';
import { Avatar } from '../core/Avatar';
import { ReasoningBody } from './ReasoningBody';
import type { Decision } from '../../types';
export interface AIDecisionStreamProps {
decisions: Decision[];
loading?: boolean;
/** Manual refresh handler. Shown as a refresh button in the header. */
onRefresh?: () => void;
/** Autonomy threshold. @default 0.7 */
threshold?: number;
className?: string;
}
/**
* AI DECISION STREAM — the stacked-decision view.
* A single-open accordion: each row is a scannable summary (employee, activity,
* confidence, one-line reasoning); expanding reveals the full reasoning in a
* height-capped, scrollable box so a wall of text never blows out the column.
*/
export function AIDecisionStream({
decisions,
loading = false,
onRefresh,
threshold = 0.7,
className,
}: AIDecisionStreamProps) {
// Single-open accordion; all collapsed by default (-1 = none open).
const [openIdx, setOpenIdx] = useState(-1);
const escalations = decisions.filter((d) => d.confidence < threshold);
return (
AI decision stream
{decisions.length} action{decisions.length === 1 ? '' : 's'}
{onRefresh && (
)}
{escalations.length > 0 && (
{escalations.length} escalation{escalations.length > 1 ? 's' : ''} need you
{escalations[0].employee} · confidence {Math.round(escalations[0].confidence * 100)}%.
)}
{/* Placeholder only on first load; a manual refresh keeps the list visible
(the header button spins) so the stream never blanks out. */}
{loading && decisions.length === 0 && (
Loading decisions…
)}
{!loading && decisions.length === 0 && (
No AI decisions for this lead yet.
)}
{decisions.length > 0 && (
{decisions.map((d, i) => (
setOpenIdx((cur) => (cur === i ? -1 : i))}
/>
))}
)}
);
}
function DecisionRow({
decision: d,
threshold,
open,
onToggle,
}: {
decision: Decision;
threshold: number;
open: boolean;
onToggle: () => void;
}) {
const autonomous = d.confidence >= threshold;
const accent = autonomous ? 'var(--status-autonomous)' : 'var(--status-escalated)';
const accentSoft = autonomous ? 'var(--status-autonomous-soft)' : 'var(--status-escalated-soft)';
const pct = Math.round(d.confidence * 100);
return (
{/* accent rail on the open row */}
{open && (
)}
{d.employee}
{/* confidence chip */}
{pct}%
{d.activity}
{d.time && · {d.time} }
{d.summary}
{open && (d.reasoning || d.citations.length > 0) && (
{d.reasoning && (
)}
{d.citations.length > 0 && (
Cited knowledge
{d.citations.map((c, i) => (
{c}
))}
)}
)}
);
}