🔧 Gemini AI Integration: - Added Google Gemini API as default OCR service - Auto-configures from GEMINI_AI_API_KEY environment variable - Fixed Puter.js authentication issues - Enhanced OCR settings with connection testing 🎨 Redesigned Scanner Queue: - New thumbnail + content layout with checkbox overlay - Smart quantity management (duplicates increment quantity) - Complete card information display from database - Two-row action layout (primary/secondary actions) - Floating bottom toolbar for bulk actions - Real card images from database �� Enhanced User Experience: - Fixed Canvas2D performance warnings - Better error handling and fallbacks - Improved responsive design - Database confirmation indicators - Professional card scanning workflow 📱 Mobile Ready: - Optimized layouts for mobile scanning - Touch-friendly controls and interactions - Improved visual feedback and status indicators
110 lines
No EOL
3.3 KiB
JavaScript
110 lines
No EOL
3.3 KiB
JavaScript
import { sql } from '@vercel/postgres';
|
|
import { getUserFromRequest } from '../../../../lib/permission-middleware';
|
|
|
|
export default async function handler(req, res) {
|
|
try {
|
|
const user = await getUserFromRequest(req);
|
|
if (!user) {
|
|
return res.status(401).json({ error: 'Authentication required' });
|
|
}
|
|
|
|
const { id: deckId } = req.query;
|
|
|
|
// Verify user owns this deck
|
|
const deckResult = await sql`
|
|
SELECT * FROM decks WHERE id = ${deckId} AND user_id = ${user.userId}
|
|
`;
|
|
|
|
if (deckResult.rows.length === 0) {
|
|
return res.status(404).json({ error: 'Deck not found or access denied' });
|
|
}
|
|
|
|
if (req.method === 'POST') {
|
|
const { cardId, quantity = 1 } = req.body;
|
|
|
|
if (!cardId) {
|
|
return res.status(400).json({ error: 'Card ID is required' });
|
|
}
|
|
|
|
// Check if card already exists in deck
|
|
const existingResult = await sql`
|
|
SELECT * FROM deck_cards
|
|
WHERE deck_id = ${deckId} AND card_id = ${cardId}
|
|
`;
|
|
|
|
if (existingResult.rows.length > 0) {
|
|
// Update quantity
|
|
const newQuantity = existingResult.rows[0].quantity + quantity;
|
|
await sql`
|
|
UPDATE deck_cards
|
|
SET quantity = ${newQuantity}, updated_at = CURRENT_TIMESTAMP
|
|
WHERE deck_id = ${deckId} AND card_id = ${cardId}
|
|
`;
|
|
} else {
|
|
// Insert new record
|
|
await sql`
|
|
INSERT INTO deck_cards (deck_id, card_id, quantity)
|
|
VALUES (${deckId}, ${cardId}, ${quantity})
|
|
`;
|
|
}
|
|
|
|
return res.status(200).json({ message: 'Card added to deck' });
|
|
|
|
} else if (req.method === 'GET') {
|
|
// Get cards in deck
|
|
const result = await sql`
|
|
SELECT dc.*, c.name, c.set_name, c.rarity, c.game, c.image_url, c.mana_cost, c.cmc, c.card_type, c.colors
|
|
FROM deck_cards dc
|
|
JOIN cards c ON dc.card_id = c.id
|
|
WHERE dc.deck_id = ${deckId}
|
|
ORDER BY c.name ASC
|
|
`;
|
|
|
|
return res.status(200).json(result.rows);
|
|
|
|
} else if (req.method === 'DELETE') {
|
|
const { cardId, quantity = 1 } = req.body;
|
|
|
|
if (!cardId) {
|
|
return res.status(400).json({ error: 'Card ID is required' });
|
|
}
|
|
|
|
// Check if card exists in deck
|
|
const existingResult = await sql`
|
|
SELECT * FROM deck_cards
|
|
WHERE deck_id = ${deckId} AND card_id = ${cardId}
|
|
`;
|
|
|
|
if (existingResult.rows.length === 0) {
|
|
return res.status(404).json({ error: 'Card not found in deck' });
|
|
}
|
|
|
|
const currentQuantity = existingResult.rows[0].quantity;
|
|
const newQuantity = currentQuantity - quantity;
|
|
|
|
if (newQuantity <= 0) {
|
|
// Remove card entirely
|
|
await sql`
|
|
DELETE FROM deck_cards
|
|
WHERE deck_id = ${deckId} AND card_id = ${cardId}
|
|
`;
|
|
} else {
|
|
// Update quantity
|
|
await sql`
|
|
UPDATE deck_cards
|
|
SET quantity = ${newQuantity}, updated_at = CURRENT_TIMESTAMP
|
|
WHERE deck_id = ${deckId} AND card_id = ${cardId}
|
|
`;
|
|
}
|
|
|
|
return res.status(200).json({ message: 'Card removed from deck' });
|
|
|
|
} else {
|
|
return res.status(405).json({ error: 'Method not allowed' });
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Error in deck cards API:', error);
|
|
return res.status(500).json({ error: 'Internal server error' });
|
|
}
|
|
}
|