83 lines
2.4 KiB
TypeScript
83 lines
2.4 KiB
TypeScript
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<GameItem[]>([]);
|
|
const [search, setSearch] = useState("");
|
|
const containerRef = useRef<HTMLDivElement>(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<string, GameItem[]> = {};
|
|
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 (
|
|
<div className={styles.container} ref={containerRef}>
|
|
<input
|
|
className={styles.searchInput}
|
|
type="text"
|
|
placeholder="Search items or type to filter..."
|
|
value={search}
|
|
onChange={(e) => setSearch(e.target.value)}
|
|
autoFocus
|
|
/>
|
|
<div className={styles.dropdown}>
|
|
{Object.entries(groups).map(([groupName, groupItems]) => (
|
|
<div key={groupName} className={styles.group}>
|
|
<div className={styles.groupLabel}>{groupName}</div>
|
|
{groupItems.map((item) => (
|
|
<div
|
|
key={item.id}
|
|
className={styles.item}
|
|
onClick={() => onSelect(item)}
|
|
>
|
|
<span className={styles.itemName}>{item.name}</span>
|
|
<span className={styles.itemMeta}>
|
|
{item.slot_count > 0 ? `${item.slot_count} slot` : "—"}
|
|
</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
))}
|
|
<div className={styles.customOption} onClick={onCustom}>
|
|
Custom item...
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|