265 lines
No EOL
7.6 KiB
JavaScript
265 lines
No EOL
7.6 KiB
JavaScript
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
|
|
});
|
|
}
|
|
}
|