diff --git a/src/components/Collection.tsx b/src/components/Collection.tsx index 4d24083..c000b53 100644 --- a/src/components/Collection.tsx +++ b/src/components/Collection.tsx @@ -1,44 +1,112 @@ -import React, { useState } from 'react'; -import { Search, Plus } from 'lucide-react'; +import React, { useState, useEffect } from 'react'; +import { Search, Plus, Loader2, Trash2, CheckCircle, XCircle } from 'lucide-react'; import { Card } from '../types'; -import { searchCards } from '../services/api'; +import { searchCards, getUserCollection, addCardToCollection, getCardsByIds } from '../services/api'; +import { useAuth } from '../contexts/AuthContext'; +import MagicCard from './MagicCard'; export default function Collection() { + const { user } = useAuth(); const [searchQuery, setSearchQuery] = useState(''); const [searchResults, setSearchResults] = useState([]); const [collection, setCollection] = useState<{ card: Card; quantity: number }[]>([]); + const [isLoadingCollection, setIsLoadingCollection] = useState(true); + const [isAddingCard, setIsAddingCard] = useState(null); + const [snackbar, setSnackbar] = useState<{ message: string; type: 'success' | 'error' } | null>(null); + + // Load user's collection from Supabase on mount + useEffect(() => { + const loadCollection = async () => { + if (!user) { + setIsLoadingCollection(false); + return; + } + + try { + setIsLoadingCollection(true); + // Get collection from Supabase (returns Map) + const collectionMap = await getUserCollection(user.id); + + if (collectionMap.size === 0) { + setCollection([]); + return; + } + + // Get the actual card data from Scryfall for all cards in collection + const cardIds = Array.from(collectionMap.keys()); + const cards = await getCardsByIds(cardIds); + + // Combine card data with quantities + const collectionWithCards = cards.map(card => ({ + card, + quantity: collectionMap.get(card.id) || 0, + })); + + setCollection(collectionWithCards); + } catch (error) { + console.error('Error loading collection:', error); + setSnackbar({ message: 'Failed to load collection', type: 'error' }); + } finally { + setIsLoadingCollection(false); + } + }; + + loadCollection(); + }, [user]); const handleSearch = async (e: React.FormEvent) => { e.preventDefault(); if (!searchQuery.trim()) return; - + try { const cards = await searchCards(searchQuery); setSearchResults(cards); } catch (error) { console.error('Failed to search cards:', error); + setSnackbar({ message: 'Failed to search cards', type: 'error' }); } }; - const addToCollection = (card: Card) => { - setCollection(prev => { - const existing = prev.find(c => c.card.id === card.id); - if (existing) { - return prev.map(c => - c.card.id === card.id - ? { ...c, quantity: c.quantity + 1 } - : c - ); - } - return [...prev, { card, quantity: 1 }]; - }); + const addToCollection = async (card: Card) => { + if (!user) { + setSnackbar({ message: 'Please log in to add cards to your collection', type: 'error' }); + return; + } + + try { + setIsAddingCard(card.id); + + // Add card to Supabase + await addCardToCollection(user.id, card.id, 1); + + // Update local state + setCollection(prev => { + const existing = prev.find(c => c.card.id === card.id); + if (existing) { + return prev.map(c => + c.card.id === card.id + ? { ...c, quantity: c.quantity + 1 } + : c + ); + } + return [...prev, { card, quantity: 1 }]; + }); + + setSnackbar({ message: 'Card added to collection!', type: 'success' }); + } catch (error) { + console.error('Error adding card to collection:', error); + setSnackbar({ message: 'Failed to add card to collection', type: 'error' }); + } finally { + setIsAddingCard(null); + setTimeout(() => setSnackbar(null), 3000); + } }; return (

My Collection

- + {/* Search */}
@@ -65,57 +133,113 @@ export default function Collection() {

Search Results

- {searchResults.map(card => ( -
- {card.image_uris?.normal && ( - {card.name} - )} -
-

{card.name}

- + {searchResults.map(card => { + const inCollection = collection.find(c => c.card.id === card.id); + + return ( +
+ +
+

{card.name}

+ {inCollection && ( +
+ + In collection (x{inCollection.quantity}) +
+ )} + {card.prices?.usd && ( +
${card.prices.usd}
+ )} + +
-
- ))} + ); + })}
)} {/* Collection */}
-

My Cards

-
- {collection.map(({ card, quantity }) => ( -
- {card.image_uris?.normal && ( - {card.name} - )} -
-
-

{card.name}

- - x{quantity} - +

+ My Cards ({collection.length} unique cards, {collection.reduce((acc, c) => acc + c.quantity, 0)} total) +

+ + {isLoadingCollection ? ( +
+ +
+ ) : collection.length === 0 ? ( +
+

Your collection is empty

+

Search for cards above to add them to your collection

+
+ ) : ( +
+ {collection.map(({ card, quantity }) => ( +
+ +
+
+

{card.name}

+ + x{quantity} + +
+ {card.prices?.usd && ( +
+ ${card.prices.usd} each + + (${(parseFloat(card.prices.usd) * quantity).toFixed(2)} total) + +
+ )}
-
- ))} -
+ ))} +
+ )}
+ + {/* Snackbar */} + {snackbar && ( +
+
+
+ {snackbar.type === 'success' ? ( + + ) : ( + + )} + {snackbar.message} +
+ +
+
+ )}
); -} +}