diff --git a/src/components/FilterBar/FilterBar.jsx b/src/components/FilterBar/FilterBar.jsx new file mode 100644 index 0000000..195e3bb --- /dev/null +++ b/src/components/FilterBar/FilterBar.jsx @@ -0,0 +1,45 @@ +import React from 'react'; + +const TYPES = ['All', 'Monster', 'Spell', 'Trap']; + +function FilterBar({ typeFilter, setTypeFilter, ownedOnly, setOwnedOnly, sortBy, setSortBy }) { + return ( +
Loading cards...
; - if (error) returnError: {error}
; + const getCardTotal = useCallback((card) => + card.printings?.reduce((sum, p) => { + const key = `${p.set_id}-${p.rarity_id}`; + return sum + (ownedAmounts[card.id]?.[key] ?? p.amount_owned ?? 0); + }, 0) ?? 0 + , [ownedAmounts]); + + const stats = useMemo(() => ({ + totalCards: cards.length, + ownedUnique: cards.filter(c => getCardTotal(c) > 0).length, + totalCopies: cards.reduce((sum, c) => sum + getCardTotal(c), 0), + }), [cards, getCardTotal]); + + const filteredCards = useMemo(() => { + let result = cards; + + if (debouncedSearchTerm) { + const lower = debouncedSearchTerm.toLowerCase(); + result = result.filter(c => c.name.toLowerCase().includes(lower)); + } + + if (typeFilter !== 'All') { + const lower = typeFilter.toLowerCase(); + result = result.filter(c => c.type.toLowerCase().includes(lower)); + } + + if (ownedOnly) { + result = result.filter(c => getCardTotal(c) > 0); + } + + const sorted = [...result]; + if (sortBy === 'owned') { + sorted.sort((a, b) => getCardTotal(b) - getCardTotal(a)); + } else { + sorted.sort((a, b) => a.name.localeCompare(b.name)); + } + + return sorted; + }, [cards, debouncedSearchTerm, typeFilter, ownedOnly, sortBy, getCardTotal]); + + if (loading) returnLoading cards...
; + if (error) returnError: {error}
; const expandedCard = cards.find(c => c.id === expandedCardId); - // Filter + sort using debounced search - const filteredCards = cards - .filter(card => - card.name.toLowerCase().includes(debouncedSearchTerm.toLowerCase()) - ) - .sort((a, b) => a.name.localeCompare(b.name)); - return (Loading image...
- ) + <> + {cardImages[expandedCardId] ? ( +Loading image...
+ )} ++ {expandedCard.type} + {expandedCard.race && ` · ${expandedCard.race}`} + {expandedCard.attribute && ` · ${expandedCard.attribute}`} +
+ {expandedCard.level != null && ( ++ {'★'.repeat(Math.min(expandedCard.level, 13))} Lv.{expandedCard.level} +
+ )} + {expandedCard.link_val != null && ( ++ Link {expandedCard.link_val} +
+ )} + > ) : ( -Click a card to see its image
+Click a card to see details
)}