diff --git a/src/components/Collection.tsx b/src/components/Collection.tsx index 690cd28..1dfcac9 100644 --- a/src/components/Collection.tsx +++ b/src/components/Collection.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect, useRef, useCallback } from 'react'; import { Search, Loader2, Trash2, CheckCircle, XCircle, RefreshCw, Plus, Minus, X } from 'lucide-react'; import { Card } from '../types'; -import { getUserCollectionPaginated, getCardsByIds, addCardToCollection } from '../services/api'; +import { getUserCollectionPaginated, getCardsByIds, addCardToCollection, getCollectionTotalValue } from '../services/api'; import { useAuth } from '../contexts/AuthContext'; import { supabase } from '../lib/supabase'; import ConfirmModal from './ConfirmModal'; @@ -18,6 +18,8 @@ export default function Collection() { const [hasMore, setHasMore] = useState(false); const [offset, setOffset] = useState(0); const [totalCount, setTotalCount] = useState(0); + const [totalCollectionValue, setTotalCollectionValue] = useState(0); + const [isLoadingTotalValue, setIsLoadingTotalValue] = useState(true); const [hoveredCard, setHoveredCard] = useState(null); const [selectedCard, setSelectedCard] = useState<{ card: Card; quantity: number } | null>(null); const [cardFaceIndex, setCardFaceIndex] = useState>(new Map()); @@ -69,6 +71,30 @@ export default function Collection() { }); }; + // Calculate total collection value (lightweight query from database) + useEffect(() => { + const calculateTotalValue = async () => { + if (!user) { + setIsLoadingTotalValue(false); + return; + } + + try { + setIsLoadingTotalValue(true); + // Get total value directly from database (no need to fetch all cards!) + const totalValue = await getCollectionTotalValue(user.id); + setTotalCollectionValue(totalValue); + } catch (error) { + console.error('Error calculating total collection value:', error); + setTotalCollectionValue(0); + } finally { + setIsLoadingTotalValue(false); + } + }; + + calculateTotalValue(); + }, [user]); + // Load user's collection from Supabase on mount useEffect(() => { const loadCollection = async () => { @@ -287,12 +313,22 @@ export default function Collection() { {/* Collection Value Summary */}
-
Total Collection Value
+
+ {searchQuery ? 'Filtered Value' : 'Total Collection Value'} +
- ${(searchQuery ? filteredCollection : collection).reduce((total, { card, quantity }) => { - const price = card.prices?.usd ? parseFloat(card.prices.usd) : 0; - return total + (price * quantity); - }, 0).toFixed(2)} + {isLoadingTotalValue ? ( + + ) : searchQuery ? ( + // For search results, calculate from filtered collection + `$${filteredCollection.reduce((total, { card, quantity }) => { + const price = card.prices?.usd ? parseFloat(card.prices.usd) : 0; + return total + (price * quantity); + }, 0).toFixed(2)}` + ) : ( + // For full collection, use pre-calculated total + `$${totalCollectionValue.toFixed(2)}` + )}
diff --git a/src/components/Community.tsx b/src/components/Community.tsx index 92c1593..07aa58c 100644 --- a/src/components/Community.tsx +++ b/src/components/Community.tsx @@ -23,7 +23,7 @@ import { Trade, TradeItem, } from '../services/tradesService'; -import { getUserCollection, getUserCollectionPaginated, getCardsByIds } from '../services/api'; +import { getUserCollectionPaginated, getCardsByIds, getCollectionTotalValue } from '../services/api'; import { Card } from '../types'; import TradeCreator from './TradeCreator'; import TradeDetail from './TradeDetail'; @@ -68,6 +68,8 @@ export default function Community() { const [hasMoreUserCards, setHasMoreUserCards] = useState(false); const [userCollectionOffset, setUserCollectionOffset] = useState(0); const [userCollectionTotalCount, setUserCollectionTotalCount] = useState(0); + const [userCollectionTotalValue, setUserCollectionTotalValue] = useState(0); + const [isLoadingUserTotalValue, setIsLoadingUserTotalValue] = useState(true); const [showTradeCreator, setShowTradeCreator] = useState(false); const [userCollectionSearch, setUserCollectionSearch] = useState(''); const [hoveredUserCard, setHoveredUserCard] = useState(null); @@ -305,15 +307,20 @@ export default function Community() { const loadUserCollection = async (userId: string) => { setLoadingCollection(true); + setIsLoadingUserTotalValue(true); setSelectedUserCollection([]); setUserCollectionOffset(0); + try { + // Load paginated collection for display const result = await getUserCollectionPaginated(userId, PAGE_SIZE, 0); setUserCollectionTotalCount(result.totalCount); setHasMoreUserCards(result.hasMore); if (result.items.size === 0) { setSelectedUserCollection([]); + setUserCollectionTotalValue(0); + setIsLoadingUserTotalValue(false); return; } @@ -324,11 +331,17 @@ export default function Community() { quantity: result.items.get(card.id) || 0, }))); setUserCollectionOffset(PAGE_SIZE); + + // Calculate total value (lightweight query from database) + const totalValue = await getCollectionTotalValue(userId); + setUserCollectionTotalValue(totalValue); } catch (error) { console.error('Error loading collection:', error); setSelectedUserCollection([]); + setUserCollectionTotalValue(0); } finally { setLoadingCollection(false); + setIsLoadingUserTotalValue(false); } }; @@ -700,12 +713,22 @@ export default function Community() { {/* Collection Value Summary */}
-
Total Collection Value
+
+ {userCollectionSearch ? 'Filtered Value' : 'Total Collection Value'} +
- ${(userCollectionSearch ? filteredUserCollection : selectedUserCollection).reduce((total, { card, quantity }) => { - const price = card.prices?.usd ? parseFloat(card.prices.usd) : 0; - return total + (price * quantity); - }, 0).toFixed(2)} + {isLoadingUserTotalValue ? ( + + ) : userCollectionSearch ? ( + // For search results, calculate from filtered collection + `$${filteredUserCollection.reduce((total, { card, quantity }) => { + const price = card.prices?.usd ? parseFloat(card.prices.usd) : 0; + return total + (price * quantity); + }, 0).toFixed(2)}` + ) : ( + // For full collection, use pre-calculated total + `$${userCollectionTotalValue.toFixed(2)}` + )}