import type { PlayerCharacter } from "@initiative/domain"; import { X } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { ColorPalette } from "./color-palette"; import { IconGrid } from "./icon-grid"; import { Button } from "./ui/button"; import { Input } from "./ui/input"; interface CreatePlayerModalProps { open: boolean; onClose: () => void; onSave: ( name: string, ac: number, maxHp: number, color: string | undefined, icon: string | undefined, ) => void; playerCharacter?: PlayerCharacter; } export function CreatePlayerModal({ open, onClose, onSave, playerCharacter, }: Readonly) { const dialogRef = useRef(null); const [name, setName] = useState(""); const [ac, setAc] = useState("10"); const [maxHp, setMaxHp] = useState("10"); const [color, setColor] = useState("blue"); const [icon, setIcon] = useState("sword"); const [error, setError] = useState(""); const isEdit = !!playerCharacter; useEffect(() => { if (open) { if (playerCharacter) { setName(playerCharacter.name); setAc(String(playerCharacter.ac)); setMaxHp(String(playerCharacter.maxHp)); setColor(playerCharacter.color ?? ""); setIcon(playerCharacter.icon ?? ""); } else { setName(""); setAc("10"); setMaxHp("10"); setColor(""); setIcon(""); } setError(""); } }, [open, playerCharacter]); useEffect(() => { const dialog = dialogRef.current; if (!dialog) return; if (open && !dialog.open) { dialog.showModal(); } else if (!open && dialog.open) { dialog.close(); } }, [open]); useEffect(() => { const dialog = dialogRef.current; if (!dialog) return; function handleCancel(e: Event) { e.preventDefault(); onClose(); } function handleBackdropClick(e: MouseEvent) { if (e.target === dialog) onClose(); } dialog.addEventListener("cancel", handleCancel); dialog.addEventListener("mousedown", handleBackdropClick); return () => { dialog.removeEventListener("cancel", handleCancel); dialog.removeEventListener("mousedown", handleBackdropClick); }; }, [onClose]); const handleSubmit = (e: React.SubmitEvent) => { e.preventDefault(); const trimmed = name.trim(); if (trimmed === "") { setError("Name is required"); return; } const acNum = Number.parseInt(ac, 10); if (Number.isNaN(acNum) || acNum < 0) { setError("AC must be a non-negative number"); return; } const hpNum = Number.parseInt(maxHp, 10); if (Number.isNaN(hpNum) || hpNum < 1) { setError("Max HP must be at least 1"); return; } onSave(trimmed, acNum, hpNum, color || undefined, icon || undefined); onClose(); }; return (

{isEdit ? "Edit Player" : "Create Player"}

Name { setName(e.target.value); setError(""); }} placeholder="Character name" aria-label="Name" autoFocus /> {!!error &&

{error}

}
AC setAc(e.target.value)} placeholder="AC" aria-label="AC" className="text-center" />
Max HP setMaxHp(e.target.value)} placeholder="Max HP" aria-label="Max HP" className="text-center" />
Color
Icon
); }