import React, { useState, useEffect } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import cardDataService from '../../services/cardDataSources'; import type { Card } from '../../types'; interface CardDatabaseBrowserProps { isOpen: boolean; onClose: () => void; onCardSelect?: (card: Card) => void; } const CardDatabaseBrowser: React.FC = ({ isOpen, onClose, onCardSelect }) => { const [searchTerm, setSearchTerm] = useState(''); const [debouncedSearch, setDebouncedSearch] = useState(''); const [selectedGame, setSelectedGame] = useState(''); const [selectedCard, setSelectedCard] = useState(null); const [showCardManager, setShowCardManager] = useState(false); const [isSearching, setIsSearching] = useState(false); const queryClient = useQueryClient(); // Debounce search input useEffect(() => { const timer = setTimeout(() => { setDebouncedSearch(searchTerm); }, 500); return () => clearTimeout(timer); }, [searchTerm]); // Search external APIs const { data: externalCards = [], isLoading: isSearchingExternal } = useQuery({ queryKey: ['external-cards', debouncedSearch, selectedGame], queryFn: async () => { if (!debouncedSearch.trim()) return []; setIsSearching(true); try { const cards = await cardDataService.searchCards(debouncedSearch, selectedGame || undefined); console.log(`Found ${cards.length} cards for search "${debouncedSearch}" in game "${selectedGame}"`); return cards; } catch (error) { console.error('Error searching external cards:', error); return []; } finally { setIsSearching(false); } }, enabled: !!debouncedSearch.trim() && isOpen, staleTime: 5 * 60 * 1000, // 5 minutes retry: 2, }); // Get random cards for discovery const { data: randomCards = [] } = useQuery({ queryKey: ['random-cards', selectedGame], queryFn: async () => { try { const cards = await cardDataService.getRandomCards(20, selectedGame || undefined); console.log(`Found ${cards.length} random cards for game "${selectedGame}"`); return cards; } catch (error) { console.error('Error fetching random cards:', error); return []; } }, enabled: isOpen && !debouncedSearch.trim(), staleTime: 10 * 60 * 1000, // 10 minutes retry: 2, }); // Add card to database mutation const addToDatabaseMutation = useMutation({ mutationFn: async (card: Card) => { // First, try to add the card to our database const response = await fetch('/api/cards/find-or-create', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('tcg-vault-token')}`, }, body: JSON.stringify({ name: card.name, game: card.game, setName: card.set_name, setCode: card.set_code, rarity: card.rarity, cardType: card.card_type, manaCost: card.mana_cost, imageUrl: card.stock_image_url, }), }); if (!response.ok) { throw new Error('Failed to add card to database'); } const result = await response.json(); return result.card; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['cards'] }); }, }); const handleCardClick = async (card: Card) => { if (onCardSelect) { onCardSelect(card); onClose(); } else { setSelectedCard(card); setShowCardManager(true); } }; const handleAddToDatabase = async (card: Card) => { try { await addToDatabaseMutation.mutateAsync(card); // Show success message alert(`${card.name} has been added to the database!`); } catch (error) { console.error('Error adding card to database:', error); alert('Failed to add card to database. Please try again.'); } }; const getGameBadgeColor = (game: string) => { switch (game) { case 'MTG': return 'bg-orange-100 text-orange-800 dark:bg-orange-900/30 dark:text-orange-300'; case 'POKEMON': return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-300'; case 'LORCANA': return 'bg-purple-100 text-purple-800 dark:bg-purple-900/30 dark:text-purple-300'; case 'YUGIOH': return 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300'; default: return 'bg-surface-100 text-surface-800 dark:bg-surface-700 dark:text-surface-300'; } }; const getRarityBadgeColor = (rarity: string) => { switch (rarity?.toLowerCase()) { case 'common': return 'bg-surface-100 text-surface-800 dark:bg-surface-700 dark:text-surface-300'; case 'uncommon': return 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300'; case 'rare': return 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300'; case 'super rare': return 'bg-purple-100 text-purple-800 dark:bg-purple-900/30 dark:text-purple-300'; case 'legendary': return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-300'; case 'mythic': return 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300'; default: return 'bg-surface-100 text-surface-800 dark:bg-surface-700 dark:text-surface-300'; } }; if (!isOpen) return null; const displayCards = debouncedSearch.trim() ? externalCards : randomCards; const isLoading = isSearchingExternal || isSearching; // Debug logging console.log('CardDatabaseBrowser state:', { isOpen, searchTerm, debouncedSearch, selectedGame, externalCards: externalCards.length, randomCards: randomCards.length, displayCards: displayCards.length, isLoading }); return ( <>
e.stopPropagation()} >
{/* Header */}

Card Database Browser

{/* Search Bar */}
setSearchTerm(e.target.value)} onKeyDown={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()} placeholder="Search cards from external databases..." className="w-full pl-10 pr-4 py-3 bg-surface-50 dark:bg-surface-700 border border-surface-300 dark:border-surface-600 rounded-xl text-surface-900 dark:text-white placeholder-surface-500 dark:placeholder-surface-400 focus:outline-none focus:ring-2 focus:ring-primary-500 transition-colors" />
{/* Game Filter */}
{/* Content */}
{isLoading ? (
Searching external databases...
) : displayCards.length === 0 ? (
🔍

{debouncedSearch.trim() ? 'No cards found' : 'Discover Cards'}

{debouncedSearch.trim() ? 'Try adjusting your search terms or game filter' : 'Search for cards to see results from external databases' }

) : (
{displayCards.map((card) => (
{/* Card Image */}
{card.stock_image_url ? ( {card.name} ) : ( )}
{/* Card Info */}

{card.name}

{card.set_name} • {card.card_number}

{/* Badges */}
{card.game} {card.rarity && ( {card.rarity} )} {card.current_price && ( ${card.current_price} )}
{/* Actions */}
))}
)}
{/* Card Manager Modal */} {selectedCard && showCardManager && (
{/* This would render the CardManager component */}
setShowCardManager(false)}>

Add {selectedCard.name} to your collection

This card will be added to your collection with the details you specify.

)} ); }; export default CardDatabaseBrowser;