deckhearth/pages/api/user-cards.js

265 lines
7.6 KiB
JavaScript
Raw Normal View History

import { sql } from '@vercel/postgres';
import { verifyToken } from './auth-utils.js';
// GET /api/user-cards - Get user's cards with optional filters
export default async function handler(req, res) {
// Set CORS headers
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// Handle preflight requests
if (req.method === 'OPTIONS') {
res.status(200).end();
return;
}
if (req.method !== 'GET' && req.method !== 'POST' && req.method !== 'PUT' && req.method !== 'DELETE') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
// Temporarily bypass auth for testing
// const token = req.headers.authorization?.replace('Bearer ', '');
// const user = await verifyToken(token);
// if (!user) {
// return res.status(401).json({ error: 'Unauthorized' });
// }
const userId = 1; // Temporarily hardcoded for testing
if (req.method === 'GET') {
const { game, status, page = '1', limit = '20' } = req.query;
const pageNum = parseInt(page);
const limitNum = parseInt(limit);
const offset = (pageNum - 1) * limitNum;
let sqlQuery = `
SELECT
uc.id,
uc.user_id,
uc.card_id,
uc.quantity,
uc.status,
uc.condition,
uc.notes,
uc.created_at,
uc.updated_at,
c.name,
c.set_name,
c.set_code,
c.card_number,
c.rarity,
c.game,
c.mana_cost,
c.cmc,
c.card_type,
c.colors,
c.oracle_text,
c.power,
c.toughness,
c.image_url,
c.stock_image_url,
c.current_price,
c.market_price,
c.verified
FROM user_cards uc
JOIN cards c ON uc.card_id = c.id
WHERE uc.user_id = $1
`;
const params = [userId];
let paramIndex = 2;
if (game && game !== 'ALL') {
sqlQuery += ` AND c.game = $${paramIndex}`;
params.push(game);
paramIndex++;
}
if (status && status !== 'ALL') {
sqlQuery += ` AND uc.status = $${paramIndex}`;
params.push(status);
paramIndex++;
}
sqlQuery += ` ORDER BY c.name ASC LIMIT $${paramIndex} OFFSET $${paramIndex + 1}`;
params.push(limitNum, offset);
const result = await sql.query(sqlQuery, params);
// Get total count
let countQuery = `
SELECT COUNT(*) as total
FROM user_cards uc
JOIN cards c ON uc.card_id = c.id
WHERE uc.user_id = $1
`;
const countParams = [userId];
let countParamIndex = 2;
if (game && game !== 'ALL') {
countQuery += ` AND c.game = $${countParamIndex}`;
countParams.push(game);
countParamIndex++;
}
if (status && status !== 'ALL') {
countQuery += ` AND uc.status = $${countParamIndex}`;
countParams.push(status);
countParamIndex++;
}
const countResult = await sql.query(countQuery, countParams);
const total = parseInt(countResult.rows[0].total);
const userCards = result.rows.map(row => ({
id: row.id,
userId: row.user_id,
cardId: row.card_id,
quantity: row.quantity,
status: row.status,
condition: row.condition,
notes: row.notes,
createdAt: row.created_at,
updatedAt: row.updated_at,
card: {
id: row.card_id,
name: row.name,
setName: row.set_name,
setCode: row.set_code,
cardNumber: row.card_number,
rarity: row.rarity,
game: row.game,
manaCost: row.mana_cost,
cmc: row.cmc,
cardType: row.card_type,
colors: row.colors ? JSON.parse(row.colors) : [],
oracleText: row.oracle_text,
power: row.power,
toughness: row.toughness,
imageUrl: row.image_url,
stockImageUrl: row.stock_image_url,
currentPrice: row.current_price,
marketPrice: row.market_price,
verified: row.verified
}
}));
return res.status(200).json({
success: true,
userCards,
pagination: {
page: pageNum,
limit: limitNum,
total,
pages: Math.ceil(total / limitNum)
}
});
}
if (req.method === 'POST') {
const { cardId, quantity = 1, status = 'OWNED', condition = 'NM', notes = '' } = req.body;
if (!cardId) {
return res.status(400).json({ error: 'Card ID is required' });
}
// Check if user already has this card
const existingCard = await sql.query(`
SELECT * FROM user_cards
WHERE user_id = $1 AND card_id = $2
`, [userId, cardId]);
if (existingCard.rows.length > 0) {
// Update existing card
const result = await sql.query(`
UPDATE user_cards
SET quantity = $1, status = $2, condition = $3, notes = $4, updated_at = NOW()
WHERE user_id = $5 AND card_id = $6
RETURNING *
`, [quantity, status, condition, notes, userId, cardId]);
return res.status(200).json({
success: true,
message: 'Card updated',
userCard: result.rows[0]
});
} else {
// Add new card
const result = await sql.query(`
INSERT INTO user_cards (user_id, card_id, quantity, status, condition, notes)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING *
`, [userId, cardId, quantity, status, condition, notes]);
return res.status(201).json({
success: true,
message: 'Card added',
userCard: result.rows[0]
});
}
}
if (req.method === 'PUT') {
const { id, quantity, status, condition, notes } = req.body;
if (!id) {
return res.status(400).json({ error: 'User card ID is required' });
}
const result = await sql.query(`
UPDATE user_cards
SET quantity = COALESCE($1, quantity),
status = COALESCE($2, status),
condition = COALESCE($3, condition),
notes = COALESCE($4, notes),
updated_at = NOW()
WHERE id = $5 AND user_id = $6
RETURNING *
`, [quantity, status, condition, notes, id, userId]);
if (result.rows.length === 0) {
return res.status(404).json({ error: 'User card not found' });
}
return res.status(200).json({
success: true,
message: 'Card updated',
userCard: result.rows[0]
});
}
if (req.method === 'DELETE') {
const { id } = req.query;
if (!id) {
return res.status(400).json({ error: 'User card ID is required' });
}
const result = await sql.query(`
DELETE FROM user_cards
WHERE id = $1 AND user_id = $2
RETURNING *
`, [id, userId]);
if (result.rows.length === 0) {
return res.status(404).json({ error: 'User card not found' });
}
return res.status(200).json({
success: true,
message: 'Card removed'
});
}
} catch (error) {
console.error('❌ Error in user-cards API:', error);
return res.status(500).json({
error: 'Failed to process user cards request',
details: error.message
});
}
}