import { useState } from 'react'; import { Check, ListChecks, Loader2, Sparkles } from 'lucide-react'; import { Badge } from './ui/badge'; import { Button } from './ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './ui/card'; import StatBar from './StatBar'; import { cn } from '@/lib/utils'; import { EVENT_COLORS, RELATION_COLORS } from '@/lib/colors'; import { relationFromScore, type TemplateMeta, type WorldDraft, type WorldNation } from '@shared/scenario'; interface Props { /** The era template the draft was generated from (name/year for the header). */ template: TemplateMeta; /** The free-text description the user wrote (shown as the world's context). */ description: string; /** The effective start year (template default or the user's override). */ year: number; /** The step-1 draft world to review and finalize. */ world: WorldDraft; /** The advisor's proposed checkpoints (all approved by default). */ checkpoints: string[]; /** A finalize (LLM) call is in flight — disables the controls. */ busy?: boolean; /** Back to the scenario form (a fresh attempt — the form's state resets). */ onBack: () => void; /** Step 2: finalize with the approved checkpoints + the chosen nation to lead. */ onFinalize: (approvedCheckpoints: string[], playerNationId: string) => void; } const STAT_BARS: Array<{ key: keyof WorldNation['stats']; label: string }> = [ { key: 'military', label: 'Military' }, { key: 'economy', label: 'Economy' }, { key: 'stability', label: 'Stability' }, { key: 'population', label: 'Population' }, ]; /** * "Create scenario" — step 2 of the dynamic path (v0.31, #52). Shows the * generated world (each nation's stats, territory country codes, and * relations; plus any backstory events) and the advisor's proposed * checkpoints as an approve/remove checklist (approved by default — the * approved ones bind the finalize step). The player then picks which nation * to lead (the nation cards mirror NationSelect's pick screen; the draft's * nations are not a static Preset, so they are rendered here directly) and * finalizes. On success the app navigates into the new game; on failure it * toasts and stays here with the current selections intact. */ export default function CheckpointReview({ template, description, year, world, checkpoints, busy = false, onBack, onFinalize, }: Props) { // Approve/remove per checkpoint (approved by default — the advisor's list is // a starting point the player prunes, not a form they fill in). const [approved, setApproved] = useState(() => checkpoints.map(() => true)); // The nation the player will lead (none until explicitly picked). const [selectedId, setSelectedId] = useState(null); const nameOf = (id: string) => world.nations.find((n) => n.id === id)?.name ?? id; const approvedCount = approved.filter(Boolean).length; const selected = selectedId ? world.nations.find((n) => n.id === selectedId) : undefined; const toggle = (i: number) => setApproved((prev) => prev.map((v, j) => (j === i ? !v : v))); const finalize = () => { if (!selectedId) return; onFinalize( checkpoints.filter((_, i) => approved[i]), selectedId, ); }; return (

{template.name}

{year}
{description && (

{description}

)} {/* --- The generated world --- */}

The generated world

{world.nations.map((n) => (
{n.name} {n.type ?? 'major'} {n.territory.length > 0 && ( {n.territory.join(' · ')} )}
{STAT_BARS.map(({ key, label }) => ( ))}
{Object.keys(n.relations).length > 0 && (
{Object.entries(n.relations).map(([otherId, score]) => { const status = relationFromScore(score); return ( {nameOf(otherId)} {score > 0 ? `+${score}` : score} ); })}
)}
))} {(world.events ?? []).length > 0 && (
Backstory
    {(world.events ?? []).map((e, i) => (
  • {nameOf(e.nation)}:{' '} {e.title} — {e.text}
  • ))}
)}
{/* --- Advisor checkpoints (approve / remove) --- */}

Advisor checkpoints

{approvedCount} of {checkpoints.length} approved

The advisor’s opening read of this world’s live strategic threads. Keep the ones the final world should respect — removed checkpoints are dropped.

    {checkpoints.map((c, i) => (
  • {approved[i] && } {c}
  • ))}
{/* --- Choose your nation (cards mirror NationSelect's pick screen) --- */}

Choose your nation

{world.nations.map((n) => { const isSel = n.id === selectedId; return ( {n.name} {isSel && } {n.type ?? 'major'} · {n.territory.length} territory unit {n.territory.length === 1 ? '' : 's'} ({n.territory.join(', ')}) {STAT_BARS.map(({ key, label }) => ( ))} ); })}
{/* --- Finalize --- */}
{selected ? `Finalizing as ${selected.name} with ${approvedCount} of ${checkpoints.length} checkpoints approved.` : 'Pick the nation you will lead, then finalize the scenario.'}
); }