import { useMemo, useState } from "react"; import { useCategories } from "../hooks/useCategories"; import { useFormatters } from "../hooks/useFormatters"; import { useItems } from "../hooks/useItems"; import { useTotals } from "../hooks/useTotals"; import { LucideIcon } from "../lib/iconData"; import { useUIStore } from "../stores/uiStore"; import { CategoryFilterDropdown } from "./CategoryFilterDropdown"; import { CategoryHeader } from "./CategoryHeader"; import { ItemCard } from "./ItemCard"; export function CollectionView() { const { data: items, isLoading: itemsLoading } = useItems(); const { data: totals } = useTotals(); const { data: categories } = useCategories(); const { weight, price } = useFormatters(); const openAddPanel = useUIStore((s) => s.openAddPanel); const [searchText, setSearchText] = useState(""); const [categoryFilter, setCategoryFilter] = useState(null); const filteredItems = useMemo(() => { if (!items) return []; return items.filter((item) => { const matchesSearch = searchText === "" || item.name.toLowerCase().includes(searchText.toLowerCase()); const matchesCategory = categoryFilter === null || item.categoryId === categoryFilter; return matchesSearch && matchesCategory; }); }, [items, searchText, categoryFilter]); const hasActiveFilters = searchText !== "" || categoryFilter !== null; if (itemsLoading) { return (
{[1, 2, 3].map((i) => (
))}
); } if (!items || items.length === 0) { return (

Your collection is empty

Start cataloging your gear by adding your first item. Track weight, price, and organize by category.

); } // Build category totals lookup const categoryTotalsMap = new Map< number, { totalWeight: number; totalCost: number; itemCount: number } >(); if (totals?.categories) { for (const ct of totals.categories) { categoryTotalsMap.set(ct.categoryId, { totalWeight: ct.totalWeight, totalCost: ct.totalCost, itemCount: ct.itemCount, }); } } // Group filtered items by categoryId (used when no active filters) const groupedItems = new Map< number, { items: typeof filteredItems; categoryName: string; categoryIcon: string; } >(); for (const item of filteredItems) { const group = groupedItems.get(item.categoryId); if (group) { group.items.push(item); } else { groupedItems.set(item.categoryId, { items: [item], categoryName: item.categoryName, categoryIcon: item.categoryIcon, }); } } return ( <> {/* Collection stats card */} {totals?.global && (
Items {totals.global.itemCount}
Total Weight {weight(totals.global.totalWeight)}
Total Spent {price(totals.global.totalCost)}
)} {/* Search/filter toolbar */}
setSearchText(e.target.value)} className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-gray-400 focus:border-transparent" /> {searchText && ( )}
{hasActiveFilters && (

Showing {filteredItems.length} of {items.length} items

)}
{/* Filtered results */} {hasActiveFilters ? ( filteredItems.length === 0 ? (

No items match your search

) : (
{filteredItems.map((item) => ( ))}
) ) : ( Array.from(groupedItems.entries()).map( ([ categoryId, { items: categoryItems, categoryName, categoryIcon }, ]) => { const catTotals = categoryTotalsMap.get(categoryId); return (
{categoryItems.map((item) => ( ))}
); }, ) )} ); }