import { useState } from 'react'; import { Link, useParams } from 'react-router-dom'; import { ArrowLeft, Brain, Download, Radar } from 'lucide-react'; import { useQuery, useZino } from '../api/provider'; import { ACT, FINDING_KIND, NEEDS_HUMAN, RECORD_VIEW, STAGES, STAGE_TONE, actionsFor, stageStep, } from '../api/config'; import { Badge, Button, ErrorNote, Facts, Spinner } from '../components/core'; import { ActivityForm } from '../components/ActivityForm'; import { AvaLive } from '../components/AvaLive'; import { Disclosure, FullStory, Recheck, Recommendations, SqlEvidence, Verdict } from '../components/Findings'; import { Briefing, BriefingSkeleton } from '../components/Briefing'; import { loadBriefing, sliceOf } from '../api/charts'; import type { Action } from '../api/config'; import { dateTime, num, prose, str } from '../format'; /** * One investigation, for a person with ninety seconds. * * ORDER IS THE DESIGN. What happened (one sentence, large) → how much (three * numbers) → what she wants approved → the buttons. That is the whole * above-the-fold. The full analysis, her evidence and the live trace sit * behind disclosures underneath, for the reviewer who wants to check and the * sceptic who wants to see the SQL. * * The exception is while Ava is still working: then the live trace IS the * page, because there is nothing else to show yet and watching her query is * the demo. * * POLLING is on while she owns the case (Investigating / Monitoring); when it * is with a person nothing moves, so the poll stops. */ export function CaseScreen() { const { id } = useParams(); const { client, user } = useZino(); const [form, setForm] = useState(null); const [showWork, setShowWork] = useState(false); const [exporting, setExporting] = useState(false); const cases = useQuery( () => client.rows(RECORD_VIEW, { limit: 1, filters: [{ field_key: 'instance_id', value: String(id), data_type: 'number' }], }), [id], true, 6000, ); const row = cases.data?.[0]; const state = str(row?.current_state_name); const aiOwned = state === 'Investigating' || state === 'Monitoring'; const scanned = str(row?.scanned_summary); const flagged = num(row?.flagged_count); const kind = str(row?.finding_kind); const quiet = flagged === 0 && !str(row?.summary); const hasFindings = !!str(row?.summary); const slice = row ? sliceOf(row) : null; // Chart rows come from six Databricks views through the record-view API. Loaded // once there are findings to picture; the slice keys decide which weekly line // and which recovery breakdown are drawn. const asOf = str(row?.review_to || row?.review_as_of).slice(0, 10) || null; // The anchor behind "expiring within 14 days". It is the review's own // ceiling date when the reviewer set one, otherwise the lakehouse's latest // service date — read from the stats view, NOT from the briefing: the charts // take seconds to load and a link rendered without the anchor would silently // drop the deadline window and open thousands of rows instead of hundreds. const lake = useQuery(() => client.rows('dni-rv-lakehouse-tables', { limit: 10 }), [], !asOf && hasFindings); const anchor = asOf ?? str(lake.data?.find((r) => str(r.table_name) === 'claims')?.to_date).slice(0, 10) ?? null; const briefing = useQuery( () => loadBriefing(client, slice, { kind, asOf }), [id, slice?.payer, slice?.department, slice?.code, kind, asOf], hasFindings, ); async function exportDeck() { if (!row || !briefing.data) return; setExporting(true); try { // pptxgenjs is ~700 KB; nobody pays for it until they ask for slides. const { buildDeck } = await import('../lib/slides'); await buildDeck(row, briefing.data, slice, kind); } finally { setExporting(false); } } const trace = useQuery(() => client.avaTrace(String(id)), [id], true, aiOwned ? 4000 : 0); const decisions = useQuery(() => client.avaDecisions(String(id)), [id], true, aiOwned ? 8000 : 0); const actions = actionsFor(state, user?.roles); function refresh() { cases.refetch(); trace.refetch(); decisions.refetch(); } if (cases.loading && !cases.data) return ; if (cases.error) return {cases.error}; if (!row) return Case {id} not found.; const work = ; return (
Back Case #{str(row.instance_id)} {quiet ? 'No findings' : state} {kind && FINDING_KIND[kind] && {FINDING_KIND[kind]}} Daily review · opened {dateTime(row.created_at)} {str(row.review_as_of) ? ` · as of ${str(row.review_as_of).slice(0, 10)}` : ''} {hasFindings && ( )}
{/* ---------- Ava still working: the trace is the page ---------- */} {aiOwned && !hasFindings && ( <>

Review in progress

Checking all payers, departments and front desks against the 8-week baseline.

Typical duration 4–5 minutes. If no change clears the materiality threshold, the case closes with no findings.

{work} )} {/* ---------- A quiet morning ---------- */} {quiet && (

Review complete

No findings. No material change across payers, departments or front desks.

{scanned &&

{scanned}

}
)} {/* ---------- Needs a human ---------- */} {state === NEEDS_HUMAN && (

Escalated — requires a decision

{prose(row.escalation_reason) || 'No reason recorded.'}

)} {/* ---------- The findings: what happened, how much, what to approve ---------- */} {hasFindings && ( <> {briefing.data ? ( ) : ( )} )} {/* ---------- The decision ---------- */} {actions.length > 0 && (

Review decision

{actions.map((a) => (
{a.hint &&

{a.hint}

}
))}
)} {/* ---------- For the reader who wants to check ---------- */} {hasFindings && ( <> {!aiOwned && ( setShowWork(!showWork)} icon={} title="Activity trace" hint="Step-by-step execution log for this review" tone="ai" >
{work}
)} {aiOwned && work} )} {quiet && ( <> setShowWork(!showWork)} icon={} title="Activity trace" hint="Step-by-step execution log — the checks performed for this no-findings result" tone="ai" >
{work}
)} {/* ---------- Provenance ---------- */}
{form && ( setForm(null)} activityUid={form.activity} instanceId={str(row.instance_id)} title={form.label} subtitle={form.hint} submitLabel={form.label} danger={form.kind === 'danger'} prefill={form.activity === ACT.APPROVE ? { approval_note: defaultApprovalNote(row) } : undefined} onDone={refresh} /> )}
); } /** The five states, as a rail. Needs Human is off the rail on purpose: it is * not a step forward, it is the case leaving the track. */ function Rail({ state }: { state: string }) { if (state === NEEDS_HUMAN) return null; const at = stageStep(state); return (
    {STAGES.map((s, i) => { const done = at > i; const here = at === i; return (
  1. {s} {i < STAGES.length - 1 &&
  2. ); })}
); } function defaultApprovalNote(row: Record): string { const recoverable = row.recoverable_amount; return recoverable ? `Approved. Proceed with the recommended appeals and process changes. Expected recovery $${Number(recoverable).toLocaleString('en-US')}.` : 'Approved. Proceed with the recommended actions.'; }