{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "training-report",
  "title": "Training report",
  "description": "Your drill accuracy by stack depth and preflop spot, with your biggest leak called out. Needs your API key.",
  "registryDependencies": [
    "https://www.pokerstudy.ai/r/poker-core.json",
    "https://www.pokerstudy.ai/r/pokerstudy-api.json"
  ],
  "files": [
    {
      "path": "src/components/pokerstudy/training-report.tsx",
      "content": "\"use client\";\n\nimport { PokerStudyStatus, usePokerStudy } from \"@/components/pokerstudy/use-pokerstudy\";\nimport { GRADE_COLORS, GRADE_LABELS, type Grade, type TrainerStats } from \"@/lib/pokerstudy/poker\";\n\nconst GRADES: Grade[] = [\"perfect\", \"correct\", \"inaccuracy\", \"mistake\", \"blunder\"];\n/** Below this many drilled hands a spot's accuracy is too noisy to call a leak. */\nconst MIN_HANDS = 10;\n\nfunction TallyBar({ tally }: { tally: Record<Grade, number> }) {\n  return (\n    <span className=\"flex h-2 w-full overflow-hidden rounded-full bg-white/5\">\n      {GRADES.map((g) =>\n        tally[g] > 0 ? <span key={g} style={{ flexGrow: tally[g], backgroundColor: GRADE_COLORS[g] }} /> : null,\n      )}\n    </span>\n  );\n}\n\n/** Drill accuracy by stack depth and spot, with the weakest spot called out. */\nexport function TrainingReportView({ data }: { data: TrainerStats }) {\n  const spots = data.buckets.flatMap((b) =>\n    b.scenarios.filter((s) => s.hands >= MIN_HANDS).map((s) => ({ ...s, bucket: b.label })),\n  );\n  const worst = spots.length > 0 ? spots.reduce((a, b) => (b.correctPct < a.correctPct ? b : a)) : null;\n\n  return (\n    <div className=\"flex w-full max-w-[560px] flex-col gap-5\">\n      <div className=\"flex flex-wrap items-end justify-between gap-3\">\n        <div className=\"flex flex-col\">\n          <span className=\"font-mono text-3xl font-semibold tabular-nums text-foreground\">{data.overall.correctPct}%</span>\n          <span className=\"text-xs text-muted-foreground\">correct over {data.overall.hands} drilled hands</span>\n        </div>\n        {worst ? (\n          <div className=\"rounded-md border border-amber-400/30 bg-amber-400/10 px-3 py-2 text-sm\">\n            <span className=\"text-amber-200\">Biggest leak: </span>\n            <span className=\"font-medium text-foreground\">\n              {worst.label}, {worst.bucket}\n            </span>\n            <span className=\"font-mono text-amber-200\"> {worst.correctPct}%</span>\n          </div>\n        ) : null}\n      </div>\n      <TallyBar tally={data.overall.tally} />\n      <div className=\"flex flex-wrap gap-x-3 gap-y-1 text-[11px]\">\n        {GRADES.map((g) => (\n          <span key={g} className=\"flex items-center gap-1.5 text-muted-foreground\">\n            <span aria-hidden className=\"size-2 rounded-[2px]\" style={{ backgroundColor: GRADE_COLORS[g] }} />\n            {GRADE_LABELS[g]} <span className=\"font-mono tabular-nums text-foreground\">{data.overall.tally[g]}</span>\n          </span>\n        ))}\n      </div>\n      {data.buckets\n        .filter((b) => b.hands > 0)\n        .map((b) => (\n          <div key={b.key} className=\"flex flex-col gap-2\">\n            <span className=\"text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n              {b.label} · {b.correctPct}%\n            </span>\n            <ul className=\"flex flex-col gap-1.5\">\n              {b.scenarios\n                .filter((s) => s.hands > 0)\n                .map((s) => (\n                  <li key={s.key} className=\"grid grid-cols-[7rem_1fr_3rem] items-center gap-3 text-sm\">\n                    <span className={worst?.key === s.key && worst.bucket === b.label ? \"font-semibold text-amber-200\" : \"text-foreground\"}>\n                      {s.label}\n                    </span>\n                    <TallyBar tally={s.tally} />\n                    <span className=\"text-right font-mono text-xs tabular-nums text-muted-foreground\">{s.correctPct}%</span>\n                  </li>\n                ))}\n            </ul>\n          </div>\n        ))}\n    </div>\n  );\n}\n\n/**\n * How you're doing in Poker Study AI's preflop drills, and where you lose the\n * most. Private data: see `authorizePrivate`.\n */\nexport function TrainingReport({\n  endpoint = \"/api/pokerstudy\",\n  initialData,\n}: {\n  endpoint?: string;\n  initialData?: TrainerStats;\n}) {\n  const state = usePokerStudy<TrainerStats>(`${endpoint}/trainer-stats`, { initialData });\n  if (state.status !== \"ready\") return <PokerStudyStatus state={state} />;\n  if (state.data.overall.hands === 0) {\n    return <p className=\"text-sm text-muted-foreground\">No drills yet. Train at pokerstudy.ai/train to fill this in.</p>;\n  }\n  return <TrainingReportView data={state.data} />;\n}\n",
      "type": "registry:component",
      "target": "components/pokerstudy/training-report.tsx"
    }
  ],
  "type": "registry:block"
}