import { useState } from 'react'; import { Check, Loader2, PenLine, X } from 'lucide-react'; import { Button } from './ui/button'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from './ui/dialog'; import { Input } from './ui/input'; import { Badge } from './ui/badge'; import type { GameState } from '@shared/types'; import type { NationOp, RenameOp } from '@shared/protocol'; interface Props { game: GameState; open: boolean; onOpenChange: (open: boolean) => void; /** A confirm/reject request is in flight — disable the per-op controls. */ opBusy: boolean; /** Apply a pending op; `edits.name` optionally overrides a rename's target name. */ onConfirm: (index: number, edits?: { name?: string }) => void; /** Drop a pending op (reject / dismiss). */ onReject: (index: number) => void; } /** A short, display-safe description of a pending nation op. */ function describeOp(op: NationOp, name: (ref: string) => string): string { if (op.kind === 'rename') return `Rename ${name(op.nationRef)} to “${op.to}”`; if (op.kind === 'split') return `Split ${name(op.nationRef)} into ${op.parts.length} nations (${op.parts .map((p) => p.name) .join(', ')})`; return `Merge ${op.nationRefs.map(name).join(' + ')} into “${op.into}”`; } /** * Reviews the nation ops the LLM has proposed (stored in `pendingNationOps`) * and lets the player apply ("LLM proposes, player confirms") or drop each one. * A rename shows the model's proposed name in an editable field (so the player * can tweak it before confirming); split and merge are declared but not yet * applied (P4b) — they can be dismissed but not confirmed. */ export default function NationOpDialog({ game, open, onOpenChange, opBusy, onConfirm, onReject, }: Props) { const ops = game.pendingNationOps; const name = (ref: string) => game.nations[ref]?.name ?? ref; // The player's edit to a rename's target name, keyed by pending-op index. // An unset entry means "use the model's proposed name" (`op.to`). const [edits, setEdits] = useState>({}); return ( Nation proposals The model proposed changes to nations. Confirm to apply them (you can edit a rename) or reject to leave the world as it is. {ops.length === 0 ? (

Nothing pending — the model hasn’t proposed any nation changes.

) : (
    {ops.map((op, i) => { const isRename = op.kind === 'rename'; const finalName = isRename ? (edits[i] ?? (op as RenameOp).to).trim() : ''; return (
  • {op.kind} {describeOp(op, name)}
    {isRename ? (
    setEdits((p) => ({ ...p, [i]: e.target.value }))} placeholder="New name…" data-testid="nation-op-name-input" />
    ) : (
    {op.kind === 'split' ? 'Split' : 'Merge'} isn’t available yet — dismiss to ignore it.
    )}
  • ); })}
)}
); }