import React, { useState, useCallback, useMemo } from 'react'; import { useInventoryStore } from '../store/inventoryStore'; import { formatItemName, getItemEmoji, formatCount, ITEM_CATEGORIES, getItemCategory } from '../utils/itemUtils'; import ItemIcon from './ItemIcon'; import './InventoryGrid.css'; function InventoryGrid() { const inventory = useInventoryStore((state) => state.inventory); const searchQuery = useInventoryStore((state) => state.searchQuery); const setSearchQuery = useInventoryStore((state) => state.setSearchQuery); const getFilteredItems = useInventoryStore((state) => state.getFilteredItems); const orderItem = useInventoryStore((state) => state.orderItem); const dropperNicknames = useInventoryStore((state) => state.dropperNicknames) || {}; const [selectedItemName, setSelectedItemName] = useState(null); const [orderAmount, setOrderAmount] = useState(1); const [sortBy, setSortBy] = useState('count'); const [activeCategory, setActiveCategory] = useState('all'); const [selectedDropper, setSelectedDropper] = useState(''); // Derive selectedItem from live inventory so count always reflects real-time data const selectedItem = useMemo(() => { if (!selectedItemName) return null; const items = inventory.itemList || []; return items.find((i) => i.name === selectedItemName) || null; }, [selectedItemName, inventory.itemList]); const droppers = inventory.droppers || []; const items = getFilteredItems(); const filteredByCategory = useMemo(() => { if (activeCategory === 'all') return items; return items.filter((item) => getItemCategory(item.name) === activeCategory); }, [items, activeCategory]); const sortedItems = useMemo(() => { return [...filteredByCategory].sort((a, b) => { if (sortBy === 'count') return (b.count || 0) - (a.count || 0); if (sortBy === 'name') return (a.displayName || a.name || '').localeCompare(b.displayName || b.name || ''); return 0; }); }, [filteredByCategory, sortBy]); const handleOrder = useCallback(async () => { if (!selectedItem || orderAmount <= 0) return; await orderItem(selectedItem.name, orderAmount, selectedDropper || undefined); }, [selectedItem, orderAmount, orderItem, selectedDropper]); const handleItemClick = (item) => { setSelectedItemName(item.name); setOrderAmount(1); }; // Count items per category for badges const categoryCounts = useMemo(() => { const counts = { all: items.length }; for (const cat of ITEM_CATEGORIES) { if (cat.id !== 'all') { counts[cat.id] = items.filter((item) => getItemCategory(item.name) === cat.id).length; } } return counts; }, [items]); return (
{/* Search & controls bar */}
๐Ÿ” setSearchQuery(e.target.value)} className="search-input" /> {searchQuery && ( )}
{sortedItems.length} types ยท {(inventory.grandTotal || 0).toLocaleString()} items
{/* Creative inventory category tabs */}
{ITEM_CATEGORIES.map((cat) => ( ))}
{/* Item grid */}
{sortedItems.map((item) => (
handleItemClick(item)} > {formatCount(item.count)} {/* Minecraft-style tooltip */}
{formatItemName(item.name)}
{(item.count || 0).toLocaleString()} items
{item.name}
))} {sortedItems.length === 0 && (
{searchQuery ? `No items matching "${searchQuery}"` : activeCategory !== 'all' ? 'No items in this category' : 'No items in storage'}
)}
{/* Item detail / order panel */} {selectedItem && (

{formatItemName(selectedItem.name || '')}

{selectedItem.name || ''}
Total {(selectedItem.count || 0).toLocaleString()}
Stacks {Math.ceil((selectedItem.count || 0) / 64)}

๐Ÿ“ค Order Items

{droppers.length >= 1 && (
)}
setOrderAmount(Math.max(1, parseInt(e.target.value) || 1))} min="1" max={selectedItem.count || 1} />
)}
); } export default InventoryGrid;