import { useState, useEffect, useRef } from 'react'; import { useRouter } from 'next/router'; import Link from 'next/link'; import Layout from '../components/Layout'; import CardItem from '../components/CardItem'; import BulkSelectionToolbar from '../components/BulkSelectionToolbar'; import CollectionSelectionModal from '../components/CollectionSelectionModal'; import ProtectedRoute from '../components/ProtectedRoute'; import { ManaCost, ColorFilterSymbol } from '../components/ManaSymbols'; import ManaSymbolSettings from '../components/ManaSymbolSettings'; import { useAuth } from '../lib/use-auth'; // Public fallback component for non-authenticated users function PublicCardsView() { return (
{/* Header with login prompt */}

Browse Trading Cards

Discover thousands of trading cards from popular TCGs

Sign Up to Unlock Full Features

Create collections, mark favorites, add cards to your inventory, and more!

Create Free Account Sign In
{/* Basic card browser would go here - simplified version */}

Full Card Browser Coming Soon

Sign up now to get early access to our complete card database and collection tools.

); } function AuthenticatedCards() { const router = useRouter(); const { user, loading: authLoading } = useAuth(); const [cards, setCards] = useState([]); const [loading, setLoading] = useState(true); const [loadingMore, setLoadingMore] = useState(false); const [searchQuery, setSearchQuery] = useState(''); const [selectedTCG, setSelectedTCG] = useState('all'); const [selectedRarity, setSelectedRarity] = useState('all'); const [selectedSet, setSelectedSet] = useState('all'); const [selectedValueRange, setSelectedValueRange] = useState('all'); const [viewMode, setViewMode] = useState('grid'); // grid or list const [pagination, setPagination] = useState({ page: 1, limit: 50, total: 0, pages: 0 }); const [filters, setFilters] = useState({ games: [], rarities: [], sets: [] }); const [hasMore, setHasMore] = useState(true); const loadingMoreRef = useRef(false); const hasMoreRef = useRef(true); // Bulk selection state const [selectedCards, setSelectedCards] = useState([]); const [favoritedCards, setFavoritedCards] = useState(new Set()); // Modal states const [showCollectionModal, setShowCollectionModal] = useState(false); const [cardsToAdd, setCardsToAdd] = useState([]); // Mana symbol settings const [manaSymbolSettings, setManaSymbolSettings] = useState({ useSVG: false }); // Fetch cards from database const fetchCards = async (isLoadMore = false) => { try { if (isLoadMore) { setLoadingMore(true); loadingMoreRef.current = true; } else { setLoading(true); } const params = new URLSearchParams({ query: searchQuery, game: selectedTCG, rarity: selectedRarity, set: selectedSet, minPrice: selectedValueRange === 'under-50' ? '0' : selectedValueRange === '50-100' ? '50' : selectedValueRange === '100-500' ? '100' : selectedValueRange === '500-1000' ? '500' : selectedValueRange === 'over-1000' ? '1000' : '', maxPrice: selectedValueRange === '50-100' ? '100' : selectedValueRange === '100-500' ? '500' : selectedValueRange === '500-1000' ? '1000' : '', page: pagination.page.toString(), limit: pagination.limit.toString() }); const response = await fetch(`/api/cards/search?${params}`); const data = await response.json(); if (data.success) { if (isLoadMore) { setCards(prevCards => [...prevCards, ...data.cards]); } else { setCards(data.cards); } setPagination(data.pagination); setFilters(data.filters); const hasMoreCards = data.pagination.page < data.pagination.pages; setHasMore(hasMoreCards); hasMoreRef.current = hasMoreCards; } else { console.error('Failed to fetch cards:', data.error); if (!isLoadMore) { setCards([]); } } } catch (error) { console.error('Error fetching cards:', error); if (!isLoadMore) { setCards([]); } } finally { setLoading(false); setLoadingMore(false); loadingMoreRef.current = false; } }; // Load user's favorited cards const loadFavoritedCards = async () => { try { const token = localStorage.getItem('auth_token'); if (!token) return; const response = await fetch('/api/favorites?type=card', { headers: { 'Authorization': `Bearer ${token}` } }); if (response.ok) { const data = await response.json(); const favoriteIds = new Set(data.favorites.map(fav => parseInt(fav.item_id))); setFavoritedCards(favoriteIds); } } catch (error) { console.error('Error loading favorited cards:', error); } }; // Initial load useEffect(() => { setPagination(prev => ({ ...prev, page: 1 })); setCards([]); setHasMore(true); hasMoreRef.current = true; fetchCards(false); loadFavoritedCards(); // Load user's favorites }, [selectedTCG, selectedRarity, selectedSet, selectedValueRange]); // Handle search with debounce const [searchTimeout, setSearchTimeout] = useState(null); const handleSearchChange = (value) => { setSearchQuery(value); // Clear existing timeout if (searchTimeout) { clearTimeout(searchTimeout); } // Set new timeout for search const newTimeout = setTimeout(() => { setPagination(prev => ({ ...prev, page: 1 })); setCards([]); setHasMore(true); hasMoreRef.current = true; fetchCards(false); }, 500); // 500ms delay setSearchTimeout(newTimeout); }; // Cleanup timeout on unmount useEffect(() => { return () => { if (searchTimeout) { clearTimeout(searchTimeout); } }; }, [searchTimeout]); // Load more cards const loadMoreCards = async () => { if (!loadingMoreRef.current && hasMoreRef.current) { const nextPage = pagination.page + 1; setPagination(prev => ({ ...prev, page: nextPage })); // Use the next page number directly in the fetch try { setLoadingMore(true); loadingMoreRef.current = true; const params = new URLSearchParams({ query: searchQuery, game: selectedTCG, rarity: selectedRarity, set: selectedSet, minPrice: selectedValueRange === 'under-50' ? '0' : selectedValueRange === '50-100' ? '50' : selectedValueRange === '100-500' ? '100' : selectedValueRange === '500-1000' ? '500' : selectedValueRange === 'over-1000' ? '1000' : '', maxPrice: selectedValueRange === '50-100' ? '100' : selectedValueRange === '100-500' ? '500' : selectedValueRange === '500-1000' ? '1000' : '', page: nextPage.toString(), limit: pagination.limit.toString() }); const response = await fetch(`/api/cards/search?${params}`); const data = await response.json(); if (data.success) { setCards(prevCards => [...prevCards, ...data.cards]); setPagination(data.pagination); setFilters(data.filters); const hasMoreCards = data.pagination.page < data.pagination.pages; setHasMore(hasMoreCards); hasMoreRef.current = hasMoreCards; } else { console.error('Failed to fetch more cards:', data.error); } } catch (error) { console.error('Error fetching more cards:', error); } finally { setLoadingMore(false); loadingMoreRef.current = false; } } }; // Update refs when state changes useEffect(() => { hasMoreRef.current = hasMore; loadingMoreRef.current = loadingMore; }, [hasMore, loadingMore]); // Intersection Observer for infinite scroll useEffect(() => { const observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting && hasMoreRef.current && !loadingMoreRef.current) { loadMoreCards(); } }); }, { rootMargin: '50px', threshold: 0.1 } ); const setupObserver = () => { const sentinel = document.getElementById('infinite-scroll-sentinel'); if (sentinel) { observer.observe(sentinel); } else { setTimeout(setupObserver, 100); } }; setupObserver(); return () => { const sentinel = document.getElementById('infinite-scroll-sentinel'); if (sentinel) { observer.unobserve(sentinel); } }; }, []); const getRarityColor = (rarity) => { // Map database rarity values to colors const rarityColorMap = { 'common': '#6B7280', 'uncommon': '#10B981', 'rare': '#F59E0B', 'mythic': '#FFD700', 'holographic': '#FF6B6B', 'enchanted': '#A855F7', 'secret rare': '#FF6B6B', 'ultra rare': '#A855F7' }; return rarityColorMap[rarity?.toLowerCase()] || '#6B7280'; }; const tcgOptions = [ { value: 'MTG', label: 'Magic: The Gathering', color: 'purple', icon: '🔮' }, { value: 'Pokemon', label: 'Pokemon', color: 'blue', icon: '⚡' }, { value: 'Lorcana', label: 'Disney Lorcana', color: 'pink', icon: '✨' } ]; const rarityOptions = [ { value: 'all', label: 'All Rarities' }, { value: 'common', label: 'Common' }, { value: 'uncommon', label: 'Uncommon' }, { value: 'rare', label: 'Rare' }, { value: 'mythic', label: 'Mythic' }, { value: 'enchanted', label: 'Enchanted' }, ...filters.rarities.filter(rarity => !['all', 'common', 'uncommon', 'rare', 'mythic', 'enchanted'].includes(rarity) ).map(rarity => ({ value: rarity, label: rarity, color: getRarityColor(rarity) })) ]; const setOptions = [ { value: 'all', label: 'All Sets' }, ...filters.sets.map(set => ({ value: set, label: set })) ]; const valueRangeOptions = [ { value: 'all', label: 'All Values' }, { value: 'under-50', label: 'Under $50' }, { value: '50-100', label: '$50 - $100' }, { value: '100-500', label: '$100 - $500' }, { value: '500-1000', label: '$500 - $1,000' }, { value: 'over-1000', label: 'Over $1,000' } ]; const formatCurrency = (amount) => { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount); }; const getRarityLabel = (rarity) => { const rarityOption = rarityOptions.find(option => option.value === rarity); return rarityOption ? rarityOption.label : rarity; }; // Bulk selection handlers const handleToggleSelect = (card) => { setSelectedCards(prev => { const isSelected = prev.some(c => c.id === card.id); if (isSelected) { return prev.filter(c => c.id !== card.id); } else { return [...prev, card]; } }); }; const handleClearSelection = () => { setSelectedCards([]); }; const handleToggleFavorite = async (card) => { try { const isFavorited = favoritedCards.has(card.id); const method = isFavorited ? 'DELETE' : 'POST'; const response = await fetch('/api/favorites', { method, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('auth_token')}` }, body: JSON.stringify({ itemType: 'card', itemId: card.id }) }); if (response.ok) { setFavoritedCards(prev => { const newSet = new Set(prev); if (isFavorited) { newSet.delete(card.id); } else { newSet.add(card.id); } return newSet; }); } } catch (error) { console.error('Error toggling favorite:', error); } }; // Bulk action handlers const handleBulkAddToCollection = (cards) => { setCardsToAdd(cards); setShowCollectionModal(true); }; const handleBulkAddToDeck = (cards) => { console.log('Adding to deck:', cards); alert(`Adding ${cards.length} cards to deck (functionality coming soon)`); }; const handleBulkMarkAsOwned = async (cards) => { try { const token = localStorage.getItem('auth_token'); if (!token) { alert('Please log in to mark cards as owned'); return; } let successCount = 0; for (const card of cards) { try { const response = await fetch(`/api/cards/${card.id}/ownership`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ quantity: 1 }) }); if (response.ok) { successCount++; } } catch (error) { console.error(`Error marking card ${card.id} as owned:`, error); } } if (successCount === cards.length) { alert(`Successfully marked ${cards.length} cards as owned!`); } else { alert(`Marked ${successCount} out of ${cards.length} cards as owned. Some operations may have failed.`); } // Clear selection after successful operation setSelectedCards([]); } catch (error) { console.error('Error in bulk mark as owned:', error); alert('Failed to mark cards as owned. Please try again.'); } }; const handleBulkRemoveFromOwned = async (cards) => { try { const token = localStorage.getItem('auth_token'); if (!token) { alert('Please log in to remove cards from owned'); return; } let successCount = 0; for (const card of cards) { try { const response = await fetch(`/api/cards/${card.id}/ownership`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ quantity: 0 }) }); if (response.ok) { successCount++; } } catch (error) { console.error(`Error removing card ${card.id} from owned:`, error); } } if (successCount === cards.length) { alert(`Successfully removed ${cards.length} cards from owned!`); } else { alert(`Removed ${successCount} out of ${cards.length} cards from owned. Some operations may have failed.`); } // Clear selection after successful operation setSelectedCards([]); } catch (error) { console.error('Error in bulk remove from owned:', error); alert('Failed to remove cards from owned. Please try again.'); } }; const handleBulkFavorite = async (cards) => { try { for (const card of cards) { if (!favoritedCards.has(card.id)) { await fetch('/api/favorites', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('auth_token')}` }, body: JSON.stringify({ itemType: 'card', itemId: card.id }) }); } } setFavoritedCards(prev => { const newSet = new Set(prev); cards.forEach(card => newSet.add(card.id)); return newSet; }); alert(`Added ${cards.length} cards to favorites`); } catch (error) { console.error('Error bulk favoriting:', error); } }; const handleBulkDelete = (cards) => { console.log('Bulk delete:', cards); alert(`Bulk delete functionality coming soon for ${cards.length} cards`); }; // Collection modal handlers const handleAddToCollections = (results, selectedCollectionIds, cards) => { const successCount = results.filter(r => r.success).length; const totalAttempts = results.length; if (successCount === totalAttempts) { alert(`Successfully added ${cards.length} card${cards.length !== 1 ? 's' : ''} to ${selectedCollectionIds.length} collection${selectedCollectionIds.length !== 1 ? 's' : ''}!`); } else { alert(`Added ${successCount} out of ${totalAttempts} cards. Some additions may have failed.`); } // Clear selection after successful addition setSelectedCards([]); }; if (loading && cards.length === 0) { return (
); } return ( {/* Header */}

Cards

Browse and manage your card collection

{/* Quick Filters */}

Quick Filters

{tcgOptions.map(option => ( ))}
{/* Advanced Filters */}
handleSearchChange(e.target.value)} onKeyPress={(e) => { if (e.key === 'Enter') { setPagination(prev => ({ ...prev, page: 1 })); setCards([]); setHasMore(true); hasMoreRef.current = true; fetchCards(false); } }} />
{/* Active Filters Display */} {(selectedTCG !== 'all' || selectedRarity !== 'all' || selectedSet !== 'all' || selectedValueRange !== 'all') && (
{selectedTCG !== 'all' && ( {tcgOptions.find(opt => opt.value === selectedTCG)?.label} )} {selectedRarity !== 'all' && ( {rarityOptions.find(opt => opt.value === selectedRarity)?.label} )} {selectedSet !== 'all' && ( {setOptions.find(opt => opt.value === selectedSet)?.label} )} {selectedValueRange !== 'all' && ( {valueRangeOptions.find(opt => opt.value === selectedValueRange)?.label} )}
)}
{/* Cards Display */}
{cards.length === 0 ? (
🃏

No cards found

Try adjusting your search or filters

) : ( <>
{cards.map((card) => ( c.id === card.id)} onToggleSelect={handleToggleSelect} onAddToCollection={(card) => handleBulkAddToCollection([card])} onAddToDeck={handleBulkAddToDeck} onToggleFavorite={handleToggleFavorite} isFavorited={favoritedCards.has(card.id)} /> ))}
{/* Infinite Scroll Loading Indicator */} {loadingMore && (
Loading more cards...
)} {/* Infinite Scroll Sentinel */}
{/* Load More Button */} {hasMore && !loadingMore && (
)} {/* End of results indicator */} {!hasMore && cards.length > 0 && (
No more cards to load
)} )}
{/* Bulk Selection Toolbar */} {/* Collection Selection Modal */} setShowCollectionModal(false)} cards={cardsToAdd} onAddToCollections={handleAddToCollections} /> ); } export default function Cards() { return ( } > ); } // 3D Card Component function Card3D({ card, viewMode, getRarityLabel, getRarityColor }) { const [isHovered, setIsHovered] = useState(false); const [cardPosition, setCardPosition] = useState({ x: 0, y: 0, width: 0, height: 0 }); const [isFavorited, setIsFavorited] = useState(false); const handleMouseMove = (e) => { const rect = e.currentTarget.getBoundingClientRect(); setCardPosition({ x: rect.left, y: rect.top, width: rect.width, height: rect.height }); }; const handleMouseLeave = () => { setIsHovered(false); }; const handleMouseEnter = () => { setIsHovered(true); }; const getTCGColor = (game) => { const colors = { 'MTG': '#8B5CF6', // purple 'Pokemon': '#3B82F6', // blue 'Lorcana': '#EC4899' // pink }; return colors[game] || '#6B7280'; }; const getSetColor = (setName) => { // Generate a consistent color based on set name const hash = setName.split('').reduce((a, b) => { a = ((a << 5) - a) + b.charCodeAt(0); return a & a; }, 0); const hue = Math.abs(hash) % 360; return `hsl(${hue}, 70%, 60%)`; }; const formatCurrency = (amount) => { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount); }; const getRarityGradient = (rarity) => { const gradients = { common: 'from-gray-400 to-gray-500', uncommon: 'from-green-400 to-emerald-500', rare: 'from-yellow-400 to-orange-500', mythic: 'from-yellow-400 to-orange-500', holographic: 'from-red-400 to-pink-500', enchanted: 'from-purple-400 to-indigo-500', ultra: 'from-blue-400 to-cyan-500' }; return gradients[rarity] || 'from-gray-400 to-gray-500'; }; const getRarityGlow = (rarity) => { const glows = { common: '0 0 15px rgba(156, 163, 175, 0.4)', uncommon: '0 0 15px rgba(34, 197, 94, 0.4)', rare: '0 0 20px rgba(251, 191, 36, 0.5)', mythic: '0 0 20px rgba(255, 215, 0, 0.4), 0 0 40px rgba(255, 215, 0, 0.2), 0 0 60px rgba(255, 215, 0, 0.1)', holographic: '0 0 25px rgba(239, 68, 68, 0.6)', enchanted: '0 0 20px rgba(168, 85, 247, 0.4), 0 0 40px rgba(168, 85, 247, 0.2), 0 0 60px rgba(168, 85, 247, 0.1)', ultra: '0 0 25px rgba(59, 130, 246, 0.6)' }; return glows[rarity] || '0 0 15px rgba(156, 163, 175, 0.4)'; }; if (viewMode === 'list') { return (
{card.game}

{card.name}

{card.set_name} • {getRarityLabel(card.rarity)}

{card.oracle_text || card.card_type}

{formatCurrency(card.current_price || 0)}

{getRarityLabel(card.rarity)}
); } return (
{/* Card Container with proper ratio and rarity glow */}
{/* Particle Effects for All Rarities */} {card.rarity !== 'common' && (
{/* Get particle count and colors based on rarity */} {(() => { const rarityConfig = { 'mythic': { particleCount: 16, sparkleCount: 10, particleColor: '#FFD700', sparkleColor: '#FFA500', glowColor: '#FFD700' }, 'enchanted': { particleCount: 14, sparkleCount: 8, particleColor: '#A855F7', sparkleColor: '#EC4899', glowColor: '#A855F7' }, 'rare': { particleCount: 10, sparkleCount: 6, particleColor: '#3B82F6', sparkleColor: '#60A5FA', glowColor: '#3B82F6' }, 'uncommon': { particleCount: 6, sparkleCount: 4, particleColor: '#10B981', sparkleColor: '#34D399', glowColor: '#10B981' } }; const config = rarityConfig[card.rarity]; if (!config) return null; return ( <> {/* Floating Particles - Edge framing */}
{[...Array(config.particleCount)].map((_, i) => { // Position particles around the card edges let left, top; const edgeIndex = i % 4; // 4 edges const positionOnEdge = Math.floor(i / 4); if (edgeIndex === 0) { // Top edge left = `${10 + (positionOnEdge * 20)}%`; top = '2%'; } else if (edgeIndex === 1) { // Right edge left = '98%'; top = `${10 + (positionOnEdge * 20)}%`; } else if (edgeIndex === 2) { // Bottom edge left = `${10 + (positionOnEdge * 20)}%`; top = '98%'; } else { // Left edge left = '2%'; top = `${10 + (positionOnEdge * 20)}%`; } return (
); })}
{/* Sparkle Effects - Corner highlights */}
{[...Array(config.sparkleCount)].map((_, i) => { // Position sparkles in the corners and edge centers let left, top; if (i < 2) { // Top corners left = i === 0 ? '5%' : '95%'; top = '5%'; } else if (i < 4) { // Bottom corners left = i === 2 ? '5%' : '95%'; top = '95%'; } else if (i < 6) { // Edge centers left = i === 4 ? '50%' : '50%'; top = i === 4 ? '5%' : '95%'; } else { // Side centers left = i === 6 ? '5%' : '95%'; top = '50%'; } return (
); })}
{/* Rarity Aura - Blend with overall glow */}
); })()}
)} {/* Card Image */}
{card.image_url ? ( {card.name} { e.target.style.display = 'none'; e.target.nextSibling.style.display = 'flex'; }} /> ) : null} {/* Card Back placeholder when no image */}
{/* Owned Quantity Chip - Only show if owned */} {card.quantity > 0 && (
{card.quantity}
)} {/* Favorite Button */}
{/* Hover Details Panel */} {isHovered && (
{/* Card Title */}
{card.name}
{/* Top Section - TCG, Set, Type, HP in 2x2 grid */}
TCG
{card.game}
Set
{card.set_name}
{card.type && (
Type
{card.game === 'Pokemon' && card.type === 'Lightning' && ( )} {card.type}
)} {card.hp && (
HP
{card.hp}
)}
{/* Card Type and Form */}
Card type
{card.card_type || 'Card'}
{card.form && (
Form
{card.form}
)}
{/* Cost to Play */} {card.mana_cost && (
Cost to Play
)} {/* Card Rule Section */} {card.game === 'Pokemon' && card.form && card.form.includes('V') && (
Card rule
V rule: When your Pokémon V is Knocked Out, your opponent takes 2 Prize cards.
)} {/* Abilities/Attacks/Moves Section */} {card.oracle_text && (
Card Text
{card.oracle_text}
)} {/* Quote Section */} {card.flavor_text && (
Quote
"{card.flavor_text}"
)} {/* Current Price */} {card.current_price && (
Current Price
{formatCurrency(card.current_price)}
)} {/* Bottom Section - Weaknesses and Retreat */}
{card.weakness && (
Weaknesses
{card.game === 'Pokemon' && ( 👊 )} {card.weakness}
)} {card.retreat_cost && (
Retreat
{card.game === 'Pokemon' && ( <> )} {card.retreat_cost}
)}
{/* Decks and Collections */} {(card.decks && card.decks.length > 0) || (card.collections && card.collections.length > 0) && (
Included In
{card.decks && card.decks.length > 0 && (
Decks: {card.decks.join(', ')}
)} {card.collections && card.collections.length > 0 && (
Collections: {card.collections.join(', ')}
)}
)}
)}
); } // Card Back Component for placeholders function CardBack({ game }) { const getCardBackImage = () => { switch (game) { case 'MTG': return 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE0MyIgdmlld0JveD0iMCAwIDIwMCAxNDMiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyMDAiIGhlaWdodD0iMTQzIiBmaWxsPSIjOEI0NTEzIi8+CjxyZWN0IHg9IjEwIiB5PSIxMCIgd2lkdGg9IjE4MCIgaGVpZ2h0PSIxMjMiIGZpbGw9IiNBMDUyMkQiIHJ4PSI4Ii8+Cjx0ZXh0IHg9IjEwMCIgeT0iMzAiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIyNCIgZm9udC13ZWlnaHQ9ImJvbGQiIGZpbGw9IiM0QTkwRTIiIHRleHQtYW5jaG9yPSJtaWRkbGUiPk1BR0lDPC90ZXh0Pgo8dGV4dCB4PSIxMDAiIHk9IjQ1IiBmb250LWZhbWlseT0iQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGZpbGw9IndoaXRlIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5UaGUgR2F0aGVyaW5nPC90ZXh0Pgo8Y2lyY2xlIGN4PSI3MCIgY3k9IjcwIiByPSI0IiBmaWxsPSJ3aGl0ZSIvPgo8Y2lyY2xlIGN4PSIxMzAiIGN4PSI3MCIgcj0iNCIgZmlsbD0iI0Y1OTlFMEIiLz4KPGNpcmNsZSBjeD0iMTAwIiBjeT0iODAiIHI9IjQiIGZpbGw9IiM0QTkwRTIiLz4KPGNpcmNsZSBjeD0iNzAiIGN5PSI5MCIgcj0iNCIgZmlsbD0iIzEwQjk4MSIvPgo8Y2lyY2xlIGN4PSIxMzAiIGN5PSI5MCIgcj0iNCIgZmlsbD0iYmxhY2siLz4KPHRleHQgeD0iMTAwIiB5PSIxMjAiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMCIgZm9udC13ZWlnaHQ9ImJvbGQiIGZpbGw9IiMyMEIyQUEiIHRleHQtYW5jaG9yPSJtaWRkbGUiPkRFQ0tNQVNURVI8L3RleHQ+Cjwvc3ZnPgo='; case 'Pokemon': return 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE0MyIgdmlld0JveD0iMCAwIDIwMCAxNDMiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyMDAiIGhlaWdodD0iMTQzIiBmaWxsPSIjRkY2QjZCIi8+CjxyZWN0IHg9IjEwIiB5PSIxMCIgd2lkdGg9IjE4MCIgaGVpZ2h0PSIxMjMiIGZpbGw9IiNGRjhFOEUiIHJ4PSI4Ii8+Cjx0ZXh0IHg9IjEwMCIgeT0iMzAiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIyNCIgZm9udC13ZWlnaHQ9ImJvbGQiIGZpbGw9IiNGRkQ3MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPlBPS0VNT048L3RleHQ+Cjx0ZXh0IHg9IjEwMCIgeT0iNDUiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgZmlsbD0id2hpdGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiPlRyYWRpbmcgQ2FyZCBHYW1lPC90ZXh0Pgo8Y2lyY2xlIGN4PSIxMDAiIGN5PSI3MCIgcj0iMjAiIGZpbGw9IndoaXRlIi8+Cjx0ZXh0IHg9IjEwMCIgeT0iNzgiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIyNCIgZmlsbD0iIzFGN0Y3RiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+4pePPC90ZXh0Pgo8dGV4dCB4PSIxMDAiIHk9IjEyMCIgZm9udC1mYW1pbHk9IkFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjEwIiBmb250LXdlaWdodD0iYm9sZCIgZmlsbD0iI0ZGRDcwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+R0FNRSBGUkVBSzwvdGV4dD4KPC9zdmc+Cg=='; case 'Lorcana': return 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE0MyIgdmlld0JveD0iMCAwIDIwMCAxNDMiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyMDAiIGhlaWdodD0iMTQzIiBmaWxsPSIjRUM0ODk5Ii8+CjxyZWN0IHg9IjEwIiB5PSIxMCIgd2lkdGg9IjE4MCIgaGVpZ2h0PSIxMjMiIGZpbGw9IiNGNDcyQjYiIHJ4PSI4Ii8+Cjx0ZXh0IHg9IjEwMCIgeT0iMzAiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIyNCIgZm9udC13ZWlnaHQ9ImJvbGQiIGZpbGw9IiNGQkJGMjQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPkRJU05FWTwvdGV4dD4KPHRleHQgeD0iMTAwIiB5PSI0NSIgZm9udC1mYW1pbHk9IkFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBmaWxsPSJ3aGl0ZSIgdGV4dC1hbmNob3I9Im1pZGRsZSI+TG9yY2FuYTwvdGV4dD4KPGNpcmNsZSBjeD0iMTAwIiBjeT0iNzAiIHI9IjIwIiBmaWxsPSJ3aGl0ZSIvPgo8dGV4dCB4PSIxMDAiIHk9Ijc4IiBmb250LWZhbWlseT0iQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjQiIGZpbGw9IiMxRjdGN0YiIHRleHQtYW5jaG9yPSJtaWRkbGUiPvCfkqQ8L3RleHQ+Cjx0ZXh0IHg9IjEwMCIgeT0iMTIwIiBmb250LWZhbWlseT0iQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTAiIGZvbnQtd2VpZ2h0PSJib2xkIiBmaWxsPSIjRjU5RTBCIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5SQVZFTlNERVJHPzwvdGV4dD4KPC9zdmc+Cg=='; default: return 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE0MyIgdmlld0JveD0iMCAwIDIwMCAxNDMiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyMDAiIGhlaWdodD0iMTQzIiBmaWxsPSIjNkI3MjgwIi8+CjxyZWN0IHg9IjEwIiB5PSIxMCIgd2lkdGg9IjE4MCIgaGVpZ2h0PSIxMjMiIGZpbGw9IiM5Q0EzQUYiIHJ4PSI4Ii8+Cjx0ZXh0IHg9IjEwMCIgeT0iMzAiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIyNCIgZm9udC13ZWlnaHQ9ImJvbGQiIGZpbGw9IndoaXRlIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5UQ0c8L3RleHQ+Cjx0ZXh0IHg9IjEwMCIgeT0iNDUiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgZmlsbD0id2hpdGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiPlRyYWRpbmcgQ2FyZDwvdGV4dD4KPGNpcmNsZSBjeD0iMTAwIiBjeT0iNzAiIHI9IjIwIiBmaWxsPSJ3aGl0ZSIvPgo8dGV4dCB4PSIxMDAiIHk9Ijc4IiBmb250LWZhbWlseT0iQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjQiIGZpbGw9IiMxRjdGN0YiIHRleHQtYW5jaG9yPSJtaWRkbGUiPvCfkqQ8L3RleHQ+Cjx0ZXh0IHg9IjEwMCIgeT0iMTIwIiBmb250LWZhbWlseT0iQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTAiIGZvbnQtd2VpZ2h0PSJib2xkIiBmaWxsPSIjNkI3MjgwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5DQVJEPC90ZXh0Pgo8L3N2Zz4K'; } }; return (
{`${game}
); }