186 lines
No EOL
6.6 KiB
TypeScript
186 lines
No EOL
6.6 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { useAuth } from '../../contexts/AuthContext';
|
|
|
|
interface CardCounts {
|
|
MTG?: number;
|
|
POKEMON?: number;
|
|
LORCANA?: number;
|
|
total?: number;
|
|
}
|
|
|
|
interface LoadingResults {
|
|
mtg?: number;
|
|
pokemon?: number;
|
|
lorcana?: number;
|
|
}
|
|
|
|
const CardLoader: React.FC = () => {
|
|
const { user, token } = useAuth();
|
|
const [cardCounts, setCardCounts] = useState<CardCounts>({});
|
|
const [loading, setLoading] = useState(false);
|
|
const [loadingResults, setLoadingResults] = useState<LoadingResults>({});
|
|
const [selectedGame, setSelectedGame] = useState<string>('ALL');
|
|
const [message, setMessage] = useState<string>('');
|
|
|
|
// Fetch current card counts
|
|
const fetchCardCounts = async () => {
|
|
try {
|
|
const response = await fetch('https://tcg-vault.vercel.app/api/admin?action=card-counts', {
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
setCardCounts(data.counts || {});
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching card counts:', error);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
fetchCardCounts();
|
|
}, []);
|
|
|
|
// Load cards from external APIs
|
|
const loadCards = async (game: string) => {
|
|
setLoading(true);
|
|
setMessage(`Loading ${game} cards...`);
|
|
setLoadingResults({});
|
|
|
|
try {
|
|
const response = await fetch(`https://tcg-vault.vercel.app/api/admin?action=load-cards`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`,
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({ game })
|
|
});
|
|
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
setLoadingResults(data.results || {});
|
|
setMessage(`Successfully loaded cards! ${data.message}`);
|
|
|
|
// Refresh card counts
|
|
setTimeout(() => {
|
|
fetchCardCounts();
|
|
}, 1000);
|
|
} else {
|
|
const errorData = await response.json();
|
|
setMessage(`Error loading cards: ${errorData.error}`);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading cards:', error);
|
|
setMessage('Error loading cards. Please try again.');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleLoadCards = () => {
|
|
loadCards(selectedGame);
|
|
};
|
|
|
|
return (
|
|
<div className="bg-white rounded-lg shadow-md p-6">
|
|
<h2 className="text-2xl font-bold text-gray-800 mb-6">Card Database Loader</h2>
|
|
|
|
{/* Current Card Counts */}
|
|
<div className="mb-6">
|
|
<h3 className="text-lg font-semibold text-gray-700 mb-3">Current Database Status</h3>
|
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<div className="bg-blue-50 p-4 rounded-lg">
|
|
<div className="text-2xl font-bold text-blue-600">{cardCounts.MTG || 0}</div>
|
|
<div className="text-sm text-blue-500">MTG Cards</div>
|
|
</div>
|
|
<div className="bg-yellow-50 p-4 rounded-lg">
|
|
<div className="text-2xl font-bold text-yellow-600">{cardCounts.POKEMON || 0}</div>
|
|
<div className="text-sm text-yellow-500">Pokémon Cards</div>
|
|
</div>
|
|
<div className="bg-purple-50 p-4 rounded-lg">
|
|
<div className="text-2xl font-bold text-purple-600">{cardCounts.LORCANA || 0}</div>
|
|
<div className="text-sm text-purple-500">Lorcana Cards</div>
|
|
</div>
|
|
<div className="bg-green-50 p-4 rounded-lg">
|
|
<div className="text-2xl font-bold text-green-600">{cardCounts.total || 0}</div>
|
|
<div className="text-sm text-green-500">Total Cards</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Load Cards Section */}
|
|
<div className="mb-6">
|
|
<h3 className="text-lg font-semibold text-gray-700 mb-3">Load Cards from External APIs</h3>
|
|
|
|
<div className="flex flex-col sm:flex-row gap-4 mb-4">
|
|
<select
|
|
value={selectedGame}
|
|
onChange={(e) => setSelectedGame(e.target.value)}
|
|
className="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
>
|
|
<option value="ALL">All Games (MTG, Pokémon, Lorcana)</option>
|
|
<option value="MTG">Magic: The Gathering</option>
|
|
<option value="POKEMON">Pokémon</option>
|
|
<option value="LORCANA">Disney Lorcana</option>
|
|
</select>
|
|
|
|
<button
|
|
onClick={handleLoadCards}
|
|
disabled={loading}
|
|
className="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors"
|
|
>
|
|
{loading ? 'Loading...' : 'Load Cards'}
|
|
</button>
|
|
</div>
|
|
|
|
{/* Loading Results */}
|
|
{Object.keys(loadingResults).length > 0 && (
|
|
<div className="bg-gray-50 p-4 rounded-lg">
|
|
<h4 className="font-semibold text-gray-700 mb-2">Loading Results:</h4>
|
|
<div className="space-y-2">
|
|
{loadingResults.mtg !== undefined && (
|
|
<div className="text-blue-600">MTG: {loadingResults.mtg} cards loaded</div>
|
|
)}
|
|
{loadingResults.pokemon !== undefined && (
|
|
<div className="text-yellow-600">Pokémon: {loadingResults.pokemon} cards loaded</div>
|
|
)}
|
|
{loadingResults.lorcana !== undefined && (
|
|
<div className="text-purple-600">Lorcana: {loadingResults.lorcana} cards loaded</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Message */}
|
|
{message && (
|
|
<div className={`mt-4 p-3 rounded-lg ${
|
|
message.includes('Error')
|
|
? 'bg-red-50 text-red-700 border border-red-200'
|
|
: 'bg-green-50 text-green-700 border border-green-200'
|
|
}`}>
|
|
{message}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Instructions */}
|
|
<div className="bg-gray-50 p-4 rounded-lg">
|
|
<h3 className="text-lg font-semibold text-gray-700 mb-2">Instructions</h3>
|
|
<ul className="text-sm text-gray-600 space-y-1">
|
|
<li>• This will load cards from external APIs into your database</li>
|
|
<li>• MTG cards come from Scryfall API</li>
|
|
<li>• Pokémon cards come from Pokémon TCG API</li>
|
|
<li>• Lorcana cards come from Lorcana API and Lorcast API</li>
|
|
<li>• Loading may take several minutes for large datasets</li>
|
|
<li>• Cards are deduplicated automatically</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default CardLoader;
|