import { useState, type ReactElement } from 'react' import { MAX_CRITERIA, progressText, slug, VERDICTS, type Criterion, type Run, type RunSnapshot, type Screen, type Verdict } from './screener' // The qualitative stage's bar: the criteria in words, the button that has every company on the list // read against them, and where that run is. A run costs model calls for every company, so it starts // on the button (or on the orchestrator's word, which is the same write), never on a criterion alone. interface Props { criteria: Criterion[] onCriteria: (next: Criterion[]) => void run: Run | null snapshot: RunSnapshot | null screen: Screen | null /** The server's session holds the list on screen and no screen call is out, so a run would freeze the right list. */ settled: boolean verdicts: Verdict[] onVerdicts: (next: Verdict[]) => void onRun: () => void onRetry: () => void onClear: () => void } export function QualitativeBar(props: Props): ReactElement { const { criteria, onCriteria, run, snapshot, screen, settled, verdicts, onVerdicts, onRun, onRetry, onClear } = props const [question, setQuestion] = useState('') const [problem, setProblem] = useState('') const busy = run !== null && run.status !== 'done' && run.status !== 'error' function add(): void { const typed = question.trim() // The server's own bounds on a criterion, said before it has to refuse. if (typed.length < 5 || typed.length > 500) { setProblem('A criterion is a question of 5 to 500 characters.') return } onCriteria([...criteria, { id: slug(typed, criteria.map((c) => c.id)), question: typed }]) setQuestion('') setProblem('') } return (