import { useState, useEffect } from 'react'; import { useRouter } from 'next/router'; import Layout from '../../components/Layout'; export default function CardEditor() { const router = useRouter(); const { id } = router.query; const user = { email: 'admin@tcgvault.com', role: 'admin' }; const [card, setCard] = useState(null); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [message, setMessage] = useState(''); const [searchQuery, setSearchQuery] = useState(''); const [searchResults, setSearchResults] = useState([]); const [searchLoading, setSearchLoading] = useState(false); // Form state const [formData, setFormData] = useState({ name: '', set_name: '', set_code: '', card_number: '', rarity: '', game: '', mana_cost: '', cmc: '', card_type: '', colors: [], oracle_text: '', power: '', toughness: '', image_url: '', stock_image_url: '', current_price: '', market_price: '' }); // Load card data if ID is provided useEffect(() => { if (id) { fetchCard(id); } else { setLoading(false); } }, [id]); const fetchCard = async (cardId) => { try { const response = await fetch(`/api/cards/${cardId}`); if (response.ok) { const cardData = await response.json(); setCard(cardData); setFormData({ name: cardData.name || '', set_name: cardData.set_name || '', set_code: cardData.set_code || '', card_number: cardData.card_number || '', rarity: cardData.rarity || '', game: cardData.game || '', mana_cost: cardData.mana_cost || '', cmc: cardData.cmc || '', card_type: cardData.card_type || '', colors: Array.isArray(cardData.colors) ? cardData.colors : [], oracle_text: cardData.oracle_text || '', power: cardData.power || '', toughness: cardData.toughness || '', image_url: cardData.image_url || '', stock_image_url: cardData.stock_image_url || '', current_price: cardData.current_price || '', market_price: cardData.market_price || '' }); } else { setMessage('Card not found'); } } catch (error) { setMessage('Error loading card: ' + error.message); } finally { setLoading(false); } }; const searchCards = async (query) => { if (!query.trim()) { setSearchResults([]); return; } setSearchLoading(true); try { const response = await fetch(`/api/cards/search?query=${encodeURIComponent(query)}&limit=20`); if (response.ok) { const data = await response.json(); setSearchResults(data.cards || []); } } catch (error) { console.error('Search error:', error); } finally { setSearchLoading(false); } }; const handleInputChange = (field, value) => { setFormData(prev => ({ ...prev, [field]: value })); }; const handleColorChange = (color, checked) => { setFormData(prev => ({ ...prev, colors: checked ? [...prev.colors, color] : prev.colors.filter(c => c !== color) })); }; const handleSave = async () => { if (!card?.id) { setMessage('No card selected to edit'); return; } setSaving(true); setMessage(''); try { const response = await fetch(`/api/cards/${card.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ ...formData, cmc: formData.cmc ? parseInt(formData.cmc) : null, current_price: formData.current_price ? parseFloat(formData.current_price) : null, market_price: formData.market_price ? parseFloat(formData.market_price) : null }) }); if (response.ok) { const updatedCard = await response.json(); setCard(updatedCard); setMessage('Card updated successfully!'); // Clear message after 3 seconds setTimeout(() => setMessage(''), 3000); } else { const errorData = await response.json(); setMessage('Error updating card: ' + (errorData.error || 'Unknown error')); } } catch (error) { setMessage('Error updating card: ' + error.message); } finally { setSaving(false); } }; const selectCard = (selectedCard) => { router.push(`/admin/card-editor?id=${selectedCard.id}`); }; const rarityOptions = [ 'common', 'uncommon', 'rare', 'mythic', 'legendary', 'holographic', 'enchanted', 'super rare', 'ultra rare' ]; const gameOptions = ['MTG', 'Pokemon', 'Lorcana']; const colorOptions = ['White', 'Blue', 'Black', 'Red', 'Green', 'Colorless']; if (loading) { return (
); } return (
{/* Admin Navigation */}

Admin Tools

Admin Card Editor

Search for a card to edit its details, or continue editing the selected card.

{/* Card Search */}

Find Card to Edit

{ setSearchQuery(e.target.value); searchCards(e.target.value); }} className="w-full p-3 rounded-lg border transition-all duration-200" style={{ backgroundColor: 'var(--bg-primary)', borderColor: 'var(--border)', color: 'var(--text-primary)' }} />
{/* Search Results */} {searchLoading && (
)} {searchResults.length > 0 && (
{searchResults.map((searchCard) => (
selectCard(searchCard)} className="p-4 rounded-lg border cursor-pointer transition-all duration-200 hover:shadow-lg hover:scale-105" style={{ backgroundColor: 'var(--bg-primary)', borderColor: 'var(--border)' }} >
{searchCard.image_url ? ( {searchCard.name} ) : (
{searchCard.game}
)}

{searchCard.name}

{searchCard.set_name} • {searchCard.game}

{searchCard.rarity}

))}
)}
{/* Card Editor Form */} {card && (
{/* Card Preview */}

Card Preview

{formData.image_url ? ( {formData.name} { e.target.style.display = 'none'; e.target.nextSibling.style.display = 'flex'; }} /> ) : null}
🃏
{formData.name || 'Card Name'}
{formData.set_name || 'Set Name'}

{formData.name || 'Card Name'}

{formData.set_name} • {formData.game}

{formData.rarity} • {formData.card_type}

{formData.current_price && (

${parseFloat(formData.current_price).toFixed(2)}

)}
{/* Editor Form */}

Edit Card Details

{message && (
{message}
)}
{/* Basic Information */}

Basic Information

handleInputChange('name', e.target.value)} className="w-full p-3 rounded-lg border transition-all duration-200" style={{ backgroundColor: 'var(--bg-primary)', borderColor: 'var(--border)', color: 'var(--text-primary)' }} />
handleInputChange('set_name', e.target.value)} className="w-full p-3 rounded-lg border transition-all duration-200" style={{ backgroundColor: 'var(--bg-primary)', borderColor: 'var(--border)', color: 'var(--text-primary)' }} />
handleInputChange('set_code', e.target.value)} className="w-full p-3 rounded-lg border transition-all duration-200" style={{ backgroundColor: 'var(--bg-primary)', borderColor: 'var(--border)', color: 'var(--text-primary)' }} />
handleInputChange('card_number', e.target.value)} className="w-full p-3 rounded-lg border transition-all duration-200" style={{ backgroundColor: 'var(--bg-primary)', borderColor: 'var(--border)', color: 'var(--text-primary)' }} />
{/* Game Mechanics */}

Game Mechanics

handleInputChange('card_type', e.target.value)} placeholder="e.g., Creature, Instant, Pokemon, Character" className="w-full p-3 rounded-lg border transition-all duration-200" style={{ backgroundColor: 'var(--bg-primary)', borderColor: 'var(--border)', color: 'var(--text-primary)' }} />
handleInputChange('mana_cost', e.target.value)} placeholder="e.g., {2}{U}{U}, 3, etc." className="w-full p-3 rounded-lg border transition-all duration-200" style={{ backgroundColor: 'var(--bg-primary)', borderColor: 'var(--border)', color: 'var(--text-primary)' }} />
handleInputChange('cmc', e.target.value)} className="w-full p-3 rounded-lg border transition-all duration-200" style={{ backgroundColor: 'var(--bg-primary)', borderColor: 'var(--border)', color: 'var(--text-primary)' }} />
handleInputChange('power', e.target.value)} placeholder="e.g., 2, *, X" className="w-full p-3 rounded-lg border transition-all duration-200" style={{ backgroundColor: 'var(--bg-primary)', borderColor: 'var(--border)', color: 'var(--text-primary)' }} />
handleInputChange('toughness', e.target.value)} placeholder="e.g., 2, *, X" className="w-full p-3 rounded-lg border transition-all duration-200" style={{ backgroundColor: 'var(--bg-primary)', borderColor: 'var(--border)', color: 'var(--text-primary)' }} />
{/* Colors */}
{colorOptions.map(color => ( ))}
{/* Card Text */}

Card Text