import { useState, useEffect } from 'react';
import { useRouter } from 'next/router';
import Layout from '../components/Layout';
import CameraScanner from '../components/CameraScanner';
import OCRSettings from '../components/OCRSettings';
import { ManaCost, ColorIdentity } from '../components/ManaSymbols';
import ManaSymbolSettings from '../components/ManaSymbolSettings';
import { useAuth } from '../lib/use-auth';
export default function Scanner() {
const { user, loading: authLoading } = useAuth();
const router = useRouter();
const [scannedCards, setScannedCards] = useState([]);
const [collections, setCollections] = useState([]);
const [decks, setDecks] = useState([]);
const [showCreateCollection, setShowCreateCollection] = useState(false);
const [newCollectionName, setNewCollectionName] = useState('');
const [showOCRSettings, setShowOCRSettings] = useState(false);
// Bulk action states
const [selectedCards, setSelectedCards] = useState(new Set());
const [bulkAction, setBulkAction] = useState(''); // 'owned', 'collection', 'deck'
const [bulkTarget, setBulkTarget] = useState('');
const [isProcessing, setIsProcessing] = useState(false);
// Mana symbol settings
const [manaSymbolSettings, setManaSymbolSettings] = useState({ useSVG: false });
// Redirect to login if not authenticated (wait for verify to finish)
useEffect(() => {
if (!authLoading && !user) {
router.push('/login');
}
}, [authLoading, user, router]);
// Load collections and decks
useEffect(() => {
if (user) {
loadCollections();
loadDecks();
}
}, [user]);
const loadCollections = async () => {
try {
const response = await fetch('/api/collections', {
headers: {
'Authorization': `Bearer ${localStorage.getItem('auth_token')}`
}
});
if (response.ok) {
const data = await response.json();
// Filter out system collections (like "All My Cards")
const userCollections = data.filter(collection => !collection.is_system_collection);
setCollections(userCollections);
}
} catch (error) {
console.error('Error loading collections:', error);
}
};
const loadDecks = async () => {
try {
const response = await fetch('/api/decks', {
headers: {
'Authorization': `Bearer ${localStorage.getItem('auth_token')}`
}
});
if (response.ok) {
const data = await response.json();
setDecks(data);
}
} catch (error) {
console.error('Error loading decks:', error);
}
};
const handleCardScanned = async (cardData) => {
console.log('Card scanned:', cardData);
console.log('Looking for existing card with name:', cardData.name, 'set:', cardData.set);
// Check if this card already exists in the queue
setScannedCards(prev => {
console.log('Current queue:', prev.map(c => ({ name: c.name, set: c.set, processed: c.processed })));
const existingCardIndex = prev.findIndex(existing =>
existing.name === cardData.name &&
existing.set === cardData.set &&
!existing.processed
);
if (existingCardIndex !== -1) {
console.log(`📈 Incrementing quantity for existing card: ${cardData.name}`);
// Increment quantity of existing card
const updatedCards = [...prev];
updatedCards[existingCardIndex] = {
...updatedCards[existingCardIndex],
quantity: (updatedCards[existingCardIndex].quantity || 1) + 1,
timestamp: new Date().toISOString() // Update timestamp
};
return updatedCards;
} else {
console.log(`🆕 Adding new card to queue: ${cardData.name}`);
// Add new card to queue
const scannedCard = {
...cardData,
id: Date.now() + Math.random(), // More unique ID for the queue
name: cardData.name,
set: cardData.set,
quantity: 1,
timestamp: new Date().toISOString(),
processed: false
};
return [scannedCard, ...prev];
}
});
};
// Quantity management functions
const incrementCardQuantity = (cardId) => {
setScannedCards(prev => prev.map(card =>
card.id === cardId
? { ...card, quantity: (card.quantity || 1) + 1 }
: card
));
};
const decrementCardQuantity = (cardId) => {
setScannedCards(prev => prev.map(card =>
card.id === cardId
? { ...card, quantity: Math.max(1, (card.quantity || 1) - 1) }
: card
));
};
const handleError = (error) => {
console.error('Scanner error:', error);
// You could show a toast notification here
};
// Individual card actions
const addSingleCardToOwned = async (card) => {
try {
await addToOwnedCards(card);
markCardAsProcessed(card.id, 'owned');
} catch (error) {
console.error('Error adding card to owned:', error);
}
};
const addSingleCardToCollection = async (card, collectionId) => {
try {
await addToCollection(card, collectionId);
markCardAsProcessed(card.id, 'collection');
} catch (error) {
console.error('Error adding card to collection:', error);
}
};
const addSingleCardToDeck = async (card, deckId) => {
try {
await addToDeck(card, deckId);
markCardAsProcessed(card.id, 'deck');
} catch (error) {
console.error('Error adding card to deck:', error);
}
};
// Bulk actions
const handleBulkAction = async () => {
if (!bulkAction || selectedCards.size === 0) return;
setIsProcessing(true);
try {
const cardsToProcess = scannedCards.filter(card => selectedCards.has(card.id));
for (const card of cardsToProcess) {
if (bulkAction === 'owned') {
await addToOwnedCards(card);
} else if (bulkAction === 'collection' && bulkTarget) {
await addToCollection(card, bulkTarget);
} else if (bulkAction === 'deck' && bulkTarget) {
await addToDeck(card, bulkTarget);
}
markCardAsProcessed(card.id, bulkAction);
}
// Clear selections and reset bulk action state
setSelectedCards(new Set());
setBulkAction('');
setBulkTarget('');
} catch (error) {
console.error('Error processing bulk action:', error);
} finally {
setIsProcessing(false);
}
};
const markCardAsProcessed = (cardId, action) => {
setScannedCards(prev => prev.map(card =>
card.id === cardId
? { ...card, processed: true, processedAction: action }
: card
));
};
// Helper functions for API calls
const addToOwnedCards = async (cardData) => {
const response = await fetch('/api/user-cards', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('auth_token')}`
},
body: JSON.stringify({
cardId: cardData.databaseId,
quantity: 1,
condition: 'NM'
})
});
if (!response.ok) {
throw new Error('Failed to add to owned cards');
}
};
const addToCollection = async (cardData, collectionId) => {
const response = await fetch(`/api/collections/${collectionId}/cards`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('auth_token')}`
},
body: JSON.stringify({
cardId: cardData.databaseId,
quantity: 1
})
});
if (!response.ok) {
throw new Error('Failed to add to collection');
}
};
const addToDeck = async (cardData, deckId) => {
const response = await fetch(`/api/decks/${deckId}/cards`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('auth_token')}`
},
body: JSON.stringify({
cardId: cardData.databaseId,
quantity: 1
})
});
if (!response.ok) {
throw new Error('Failed to add to deck');
}
};
const createCollection = async () => {
if (!newCollectionName.trim()) return;
try {
const response = await fetch('/api/collections', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('auth_token')}`
},
body: JSON.stringify({
name: newCollectionName,
description: 'Created from card scanner',
is_public: false
})
});
if (response.ok) {
const newCollection = await response.json();
setCollections(prev => [newCollection, ...prev]);
setBulkTarget(newCollection.id.toString());
setNewCollectionName('');
setShowCreateCollection(false);
}
} catch (error) {
console.error('Error creating collection:', error);
}
};
const clearScannedCards = () => {
setScannedCards([]);
setSelectedCards(new Set());
};
const removeScannedCard = (cardId) => {
setScannedCards(prev => prev.filter(card => card.id !== cardId));
setSelectedCards(prev => {
const newSet = new Set(prev);
newSet.delete(cardId);
return newSet;
});
};
const toggleCardSelection = (cardId) => {
setSelectedCards(prev => {
const newSet = new Set(prev);
if (newSet.has(cardId)) {
newSet.delete(cardId);
} else {
newSet.add(cardId);
}
return newSet;
});
};
const selectAllCards = () => {
const unprocessedCards = scannedCards.filter(card => !card.processed);
setSelectedCards(new Set(unprocessedCards.map(card => card.id)));
};
const deselectAllCards = () => {
setSelectedCards(new Set());
};
if (authLoading) {
return (
Scan cards to identify them, then choose what to do with your collection