darkwatch/client/src/components/ItemPicker.tsx

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>
);
}