import { useState, useEffect, useRef } from "react"; import { getGameItems } from "../api"; import type { GameItem } from "../types"; import styles from "./ItemPicker.module.css"; interface ItemPickerProps { onSelect: (item: GameItem) => void; onCustom: () => void; onClose: () => void; } export default function ItemPicker({ onSelect, onCustom, onClose, }: ItemPickerProps) { const [items, setItems] = useState([]); const [search, setSearch] = useState(""); const containerRef = useRef(null); useEffect(() => { getGameItems().then(setItems); }, []); useEffect(() => { function handleClickOutside(e: MouseEvent) { if ( containerRef.current && !containerRef.current.contains(e.target as Node) ) { onClose(); } } document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, [onClose]); const filtered = search ? items.filter((i) => i.name.toLowerCase().includes(search.toLowerCase())) : items; const groups: Record = {}; for (const item of filtered) { const key = item.type.charAt(0).toUpperCase() + item.type.slice(1) + "s"; if (!groups[key]) groups[key] = []; groups[key].push(item); } return (
setSearch(e.target.value)} autoFocus />
{Object.entries(groups).map(([groupName, groupItems]) => (
{groupName}
{groupItems.map((item) => (
onSelect(item)} > {item.name} {item.slot_count > 0 ? `${item.slot_count} slot` : "—"}
))}
))}
Custom item...
); }