ValuationOS
ValuationOS β€” initial commit (Phases 1–5)
d31acaa
import type { AnalystLoadRow } from "@/types/api";
export function AnalystLoad({ rows }: { rows: AnalystLoadRow[] }) {
const maxCases = Math.max(1, ...rows.map((r) => r.open_cases));
return (
<div className="panel">
<div className="px-4 py-3 border-b border-border flex items-center justify-between">
<div className="heading">Analyst load</div>
<div className="text-xs text-muted">{rows.length}</div>
</div>
<div className="p-4 space-y-2.5">
{rows.length === 0 && <div className="text-sm text-muted">No open cases.</div>}
{rows.map((r) => {
const isUnassigned = r.analyst === "Unassigned";
return (
<div
key={r.analyst}
className="grid grid-cols-[120px,1fr,90px] items-center gap-3 text-sm"
>
<div className={isUnassigned ? "text-warning" : "text-text"}>
{r.analyst}
</div>
<div className="relative h-5 rounded-sm bg-panel2 overflow-hidden border border-border">
<div
className={isUnassigned ? "absolute inset-y-0 left-0 bg-warning/50" : "absolute inset-y-0 left-0 bg-accent/70"}
style={{ width: `${(r.open_cases / maxCases) * 100}%` }}
/>
<div className="absolute inset-0 flex items-center px-2 text-[11px] num">
{r.open_cases} {r.open_cases === 1 ? "case" : "cases"}
</div>
</div>
<div className="num text-xs text-muted text-right">
{r.avg_materiality_bps != null
? `${r.avg_materiality_bps.toFixed(1)} bps avg`
: "β€”"}
</div>
</div>
);
})}
</div>
</div>
);
}