Add user cards API endpoints - fix Cards page error by implementing missing /api/user-cards endpoints
This commit is contained in:
parent
d9ed0e911e
commit
40928bbbda
2 changed files with 711 additions and 0 deletions
429
api/user-cards.js
Normal file
429
api/user-cards.js
Normal file
|
|
@ -0,0 +1,429 @@
|
||||||
|
import { NextResponse } from 'next/server';
|
||||||
|
import { sql } from '@vercel/postgres';
|
||||||
|
import { verifyToken } from './setup-auth.js';
|
||||||
|
|
||||||
|
// GET /api/user-cards - Get user's cards with optional filters
|
||||||
|
export async function GET(request) {
|
||||||
|
try {
|
||||||
|
const token = request.headers.get('authorization')?.replace('Bearer ', '');
|
||||||
|
const user = await verifyToken(token);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { searchParams } = new URL(request.url);
|
||||||
|
const game = searchParams.get('game');
|
||||||
|
const rarity = searchParams.get('rarity');
|
||||||
|
const status = searchParams.get('status');
|
||||||
|
const search = searchParams.get('search');
|
||||||
|
|
||||||
|
let query = `
|
||||||
|
SELECT
|
||||||
|
uc.id,
|
||||||
|
uc.user_id,
|
||||||
|
uc.card_id,
|
||||||
|
uc.status,
|
||||||
|
uc.quantity,
|
||||||
|
uc.condition,
|
||||||
|
uc.notes,
|
||||||
|
uc.acquired_date,
|
||||||
|
uc.acquired_price,
|
||||||
|
uc.acquired_from,
|
||||||
|
uc.created_at,
|
||||||
|
uc.updated_at,
|
||||||
|
c.name,
|
||||||
|
c.set_name,
|
||||||
|
c.set_code,
|
||||||
|
c.card_number,
|
||||||
|
c.rarity,
|
||||||
|
c.game,
|
||||||
|
c.card_type,
|
||||||
|
c.mana_cost,
|
||||||
|
c.cmc,
|
||||||
|
c.colors,
|
||||||
|
c.oracle_text,
|
||||||
|
c.power,
|
||||||
|
c.toughness,
|
||||||
|
c.image_url,
|
||||||
|
c.stock_image_url,
|
||||||
|
c.current_price,
|
||||||
|
c.market_price,
|
||||||
|
c.verified,
|
||||||
|
c.created_at as card_created_at,
|
||||||
|
c.updated_at as card_updated_at
|
||||||
|
FROM user_cards uc
|
||||||
|
JOIN cards c ON uc.card_id = c.id
|
||||||
|
WHERE uc.user_id = $1
|
||||||
|
`;
|
||||||
|
|
||||||
|
const params = [user.id];
|
||||||
|
let paramIndex = 2;
|
||||||
|
|
||||||
|
if (game) {
|
||||||
|
query += ` AND c.game = $${paramIndex}`;
|
||||||
|
params.push(game);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rarity) {
|
||||||
|
query += ` AND c.rarity = $${paramIndex}`;
|
||||||
|
params.push(rarity);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status && status !== 'all') {
|
||||||
|
query += ` AND uc.status = $${paramIndex}`;
|
||||||
|
params.push(status);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (search) {
|
||||||
|
query += ` AND (c.name ILIKE $${paramIndex} OR c.set_name ILIKE $${paramIndex})`;
|
||||||
|
params.push(`%${search}%`);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
query += ` ORDER BY uc.created_at DESC`;
|
||||||
|
|
||||||
|
const result = await sql.query(query, params);
|
||||||
|
|
||||||
|
const userCards = result.rows.map(row => ({
|
||||||
|
id: row.id,
|
||||||
|
userId: row.user_id,
|
||||||
|
cardId: row.card_id,
|
||||||
|
status: row.status,
|
||||||
|
quantity: row.quantity,
|
||||||
|
condition: row.condition,
|
||||||
|
notes: row.notes,
|
||||||
|
acquiredDate: row.acquired_date,
|
||||||
|
acquiredPrice: row.acquired_price,
|
||||||
|
acquiredFrom: row.acquired_from,
|
||||||
|
createdAt: row.created_at,
|
||||||
|
updatedAt: row.updated_at,
|
||||||
|
card: {
|
||||||
|
id: row.card_id,
|
||||||
|
name: row.name,
|
||||||
|
set_name: row.set_name,
|
||||||
|
set_code: row.set_code,
|
||||||
|
card_number: row.card_number,
|
||||||
|
rarity: row.rarity,
|
||||||
|
game: row.game,
|
||||||
|
card_type: row.card_type,
|
||||||
|
mana_cost: row.mana_cost,
|
||||||
|
cmc: row.cmc,
|
||||||
|
colors: row.colors ? JSON.parse(row.colors) : [],
|
||||||
|
oracle_text: row.oracle_text,
|
||||||
|
power: row.power,
|
||||||
|
toughness: row.toughness,
|
||||||
|
image_url: row.image_url,
|
||||||
|
stock_image_url: row.stock_image_url,
|
||||||
|
current_price: row.current_price,
|
||||||
|
market_price: row.market_price,
|
||||||
|
verified: row.verified,
|
||||||
|
createdAt: row.card_created_at,
|
||||||
|
updatedAt: row.card_updated_at,
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
data: userCards,
|
||||||
|
message: `Found ${userCards.length} cards`
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching user cards:', error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Failed to fetch user cards' },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/user-cards - Add card to user collection
|
||||||
|
export async function POST(request) {
|
||||||
|
try {
|
||||||
|
const token = request.headers.get('authorization')?.replace('Bearer ', '');
|
||||||
|
const user = await verifyToken(token);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = await request.json();
|
||||||
|
const {
|
||||||
|
cardId,
|
||||||
|
status = 'owned',
|
||||||
|
quantity = 1,
|
||||||
|
condition,
|
||||||
|
notes,
|
||||||
|
acquiredDate,
|
||||||
|
acquiredPrice,
|
||||||
|
acquiredFrom,
|
||||||
|
collectionIds = [],
|
||||||
|
deckIds = []
|
||||||
|
} = body;
|
||||||
|
|
||||||
|
if (!cardId) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Card ID is required' },
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if card exists
|
||||||
|
const cardResult = await sql.query(
|
||||||
|
'SELECT id FROM cards WHERE id = $1',
|
||||||
|
[cardId]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (cardResult.rows.length === 0) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Card not found' },
|
||||||
|
{ status: 404 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user already has this card
|
||||||
|
const existingResult = await sql.query(
|
||||||
|
'SELECT id FROM user_cards WHERE user_id = $1 AND card_id = $2',
|
||||||
|
[user.id, cardId]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingResult.rows.length > 0) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Card already in collection' },
|
||||||
|
{ status: 409 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add card to user collection
|
||||||
|
const result = await sql.query(
|
||||||
|
`INSERT INTO user_cards (
|
||||||
|
user_id, card_id, status, quantity, condition, notes,
|
||||||
|
acquired_date, acquired_price, acquired_from, created_at, updated_at
|
||||||
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, NOW(), NOW())
|
||||||
|
RETURNING *`,
|
||||||
|
[
|
||||||
|
user.id, cardId, status, quantity, condition, notes,
|
||||||
|
acquiredDate, acquiredPrice, acquiredFrom
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
const userCard = result.rows[0];
|
||||||
|
|
||||||
|
// Add to collections if specified
|
||||||
|
if (collectionIds.length > 0) {
|
||||||
|
for (const collectionId of collectionIds) {
|
||||||
|
await sql.query(
|
||||||
|
'INSERT INTO collection_cards (collection_id, user_card_id) VALUES ($1, $2)',
|
||||||
|
[collectionId, userCard.id]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to decks if specified
|
||||||
|
if (deckIds.length > 0) {
|
||||||
|
for (const deckId of deckIds) {
|
||||||
|
await sql.query(
|
||||||
|
'INSERT INTO deck_cards (deck_id, user_card_id, quantity, board) VALUES ($1, $2, $3, $4)',
|
||||||
|
[deckId, userCard.id, quantity, 'mainboard']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
id: userCard.id,
|
||||||
|
userId: userCard.user_id,
|
||||||
|
cardId: userCard.card_id,
|
||||||
|
status: userCard.status,
|
||||||
|
quantity: userCard.quantity,
|
||||||
|
condition: userCard.condition,
|
||||||
|
notes: userCard.notes,
|
||||||
|
acquiredDate: userCard.acquired_date,
|
||||||
|
acquiredPrice: userCard.acquired_price,
|
||||||
|
acquiredFrom: userCard.acquired_from,
|
||||||
|
createdAt: userCard.created_at,
|
||||||
|
updatedAt: userCard.updated_at,
|
||||||
|
},
|
||||||
|
message: 'Card added to collection'
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error adding card to collection:', error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Failed to add card to collection' },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT /api/user-cards/[id] - Update user card
|
||||||
|
export async function PUT(request, { params }) {
|
||||||
|
try {
|
||||||
|
const token = request.headers.get('authorization')?.replace('Bearer ', '');
|
||||||
|
const user = await verifyToken(token);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id } = params;
|
||||||
|
const body = await request.json();
|
||||||
|
|
||||||
|
// Check if user owns this card
|
||||||
|
const ownershipResult = await sql.query(
|
||||||
|
'SELECT id FROM user_cards WHERE id = $1 AND user_id = $2',
|
||||||
|
[id, user.id]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ownershipResult.rows.length === 0) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Card not found or not owned by user' },
|
||||||
|
{ status: 404 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build update query dynamically
|
||||||
|
const updateFields = [];
|
||||||
|
const updateValues = [];
|
||||||
|
let paramIndex = 1;
|
||||||
|
|
||||||
|
if (body.status !== undefined) {
|
||||||
|
updateFields.push(`status = $${paramIndex}`);
|
||||||
|
updateValues.push(body.status);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.quantity !== undefined) {
|
||||||
|
updateFields.push(`quantity = $${paramIndex}`);
|
||||||
|
updateValues.push(body.quantity);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.condition !== undefined) {
|
||||||
|
updateFields.push(`condition = $${paramIndex}`);
|
||||||
|
updateValues.push(body.condition);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.notes !== undefined) {
|
||||||
|
updateFields.push(`notes = $${paramIndex}`);
|
||||||
|
updateValues.push(body.notes);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.acquiredDate !== undefined) {
|
||||||
|
updateFields.push(`acquired_date = $${paramIndex}`);
|
||||||
|
updateValues.push(body.acquiredDate);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.acquiredPrice !== undefined) {
|
||||||
|
updateFields.push(`acquired_price = $${paramIndex}`);
|
||||||
|
updateValues.push(body.acquiredPrice);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.acquiredFrom !== undefined) {
|
||||||
|
updateFields.push(`acquired_from = $${paramIndex}`);
|
||||||
|
updateValues.push(body.acquiredFrom);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateFields.length === 0) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'No fields to update' },
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFields.push(`updated_at = NOW()`);
|
||||||
|
updateValues.push(id);
|
||||||
|
|
||||||
|
const query = `
|
||||||
|
UPDATE user_cards
|
||||||
|
SET ${updateFields.join(', ')}
|
||||||
|
WHERE id = $${paramIndex}
|
||||||
|
RETURNING *
|
||||||
|
`;
|
||||||
|
|
||||||
|
const result = await sql.query(query, updateValues);
|
||||||
|
const userCard = result.rows[0];
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
id: userCard.id,
|
||||||
|
userId: userCard.user_id,
|
||||||
|
cardId: userCard.card_id,
|
||||||
|
status: userCard.status,
|
||||||
|
quantity: userCard.quantity,
|
||||||
|
condition: userCard.condition,
|
||||||
|
notes: userCard.notes,
|
||||||
|
acquiredDate: userCard.acquired_date,
|
||||||
|
acquiredPrice: userCard.acquired_price,
|
||||||
|
acquiredFrom: userCard.acquired_from,
|
||||||
|
createdAt: userCard.created_at,
|
||||||
|
updatedAt: userCard.updated_at,
|
||||||
|
},
|
||||||
|
message: 'Card updated successfully'
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error updating user card:', error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Failed to update card' },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE /api/user-cards/[id] - Delete user card
|
||||||
|
export async function DELETE(request, { params }) {
|
||||||
|
try {
|
||||||
|
const token = request.headers.get('authorization')?.replace('Bearer ', '');
|
||||||
|
const user = await verifyToken(token);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id } = params;
|
||||||
|
|
||||||
|
// Check if user owns this card
|
||||||
|
const ownershipResult = await sql.query(
|
||||||
|
'SELECT id FROM user_cards WHERE id = $1 AND user_id = $2',
|
||||||
|
[id, user.id]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ownershipResult.rows.length === 0) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Card not found or not owned by user' },
|
||||||
|
{ status: 404 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete from collections and decks first
|
||||||
|
await sql.query('DELETE FROM collection_cards WHERE user_card_id = $1', [id]);
|
||||||
|
await sql.query('DELETE FROM deck_cards WHERE user_card_id = $1', [id]);
|
||||||
|
|
||||||
|
// Delete the user card
|
||||||
|
await sql.query('DELETE FROM user_cards WHERE id = $1', [id]);
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
message: 'Card removed from collection'
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting user card:', error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Failed to delete card' },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
282
api/user-cards/[id].js
Normal file
282
api/user-cards/[id].js
Normal file
|
|
@ -0,0 +1,282 @@
|
||||||
|
import { NextResponse } from 'next/server';
|
||||||
|
import { sql } from '@vercel/postgres';
|
||||||
|
import { verifyToken } from '../setup-auth.js';
|
||||||
|
|
||||||
|
// GET /api/user-cards/[id] - Get single user card
|
||||||
|
export async function GET(request, { params }) {
|
||||||
|
try {
|
||||||
|
const token = request.headers.get('authorization')?.replace('Bearer ', '');
|
||||||
|
const user = await verifyToken(token);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id } = params;
|
||||||
|
|
||||||
|
const result = await sql.query(
|
||||||
|
`SELECT
|
||||||
|
uc.id,
|
||||||
|
uc.user_id,
|
||||||
|
uc.card_id,
|
||||||
|
uc.status,
|
||||||
|
uc.quantity,
|
||||||
|
uc.condition,
|
||||||
|
uc.notes,
|
||||||
|
uc.acquired_date,
|
||||||
|
uc.acquired_price,
|
||||||
|
uc.acquired_from,
|
||||||
|
uc.created_at,
|
||||||
|
uc.updated_at,
|
||||||
|
c.name,
|
||||||
|
c.set_name,
|
||||||
|
c.set_code,
|
||||||
|
c.card_number,
|
||||||
|
c.rarity,
|
||||||
|
c.game,
|
||||||
|
c.card_type,
|
||||||
|
c.mana_cost,
|
||||||
|
c.cmc,
|
||||||
|
c.colors,
|
||||||
|
c.oracle_text,
|
||||||
|
c.power,
|
||||||
|
c.toughness,
|
||||||
|
c.image_url,
|
||||||
|
c.stock_image_url,
|
||||||
|
c.current_price,
|
||||||
|
c.market_price,
|
||||||
|
c.verified,
|
||||||
|
c.created_at as card_created_at,
|
||||||
|
c.updated_at as card_updated_at
|
||||||
|
FROM user_cards uc
|
||||||
|
JOIN cards c ON uc.card_id = c.id
|
||||||
|
WHERE uc.id = $1 AND uc.user_id = $2`,
|
||||||
|
[id, user.id]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.rows.length === 0) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Card not found or not owned by user' },
|
||||||
|
{ status: 404 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const row = result.rows[0];
|
||||||
|
const userCard = {
|
||||||
|
id: row.id,
|
||||||
|
userId: row.user_id,
|
||||||
|
cardId: row.card_id,
|
||||||
|
status: row.status,
|
||||||
|
quantity: row.quantity,
|
||||||
|
condition: row.condition,
|
||||||
|
notes: row.notes,
|
||||||
|
acquiredDate: row.acquired_date,
|
||||||
|
acquiredPrice: row.acquired_price,
|
||||||
|
acquiredFrom: row.acquired_from,
|
||||||
|
createdAt: row.created_at,
|
||||||
|
updatedAt: row.updated_at,
|
||||||
|
card: {
|
||||||
|
id: row.card_id,
|
||||||
|
name: row.name,
|
||||||
|
set_name: row.set_name,
|
||||||
|
set_code: row.set_code,
|
||||||
|
card_number: row.card_number,
|
||||||
|
rarity: row.rarity,
|
||||||
|
game: row.game,
|
||||||
|
card_type: row.card_type,
|
||||||
|
mana_cost: row.mana_cost,
|
||||||
|
cmc: row.cmc,
|
||||||
|
colors: row.colors ? JSON.parse(row.colors) : [],
|
||||||
|
oracle_text: row.oracle_text,
|
||||||
|
power: row.power,
|
||||||
|
toughness: row.toughness,
|
||||||
|
image_url: row.image_url,
|
||||||
|
stock_image_url: row.stock_image_url,
|
||||||
|
current_price: row.current_price,
|
||||||
|
market_price: row.market_price,
|
||||||
|
verified: row.verified,
|
||||||
|
createdAt: row.card_created_at,
|
||||||
|
updatedAt: row.card_updated_at,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
data: userCard
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching user card:', error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Failed to fetch user card' },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT /api/user-cards/[id] - Update user card
|
||||||
|
export async function PUT(request, { params }) {
|
||||||
|
try {
|
||||||
|
const token = request.headers.get('authorization')?.replace('Bearer ', '');
|
||||||
|
const user = await verifyToken(token);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id } = params;
|
||||||
|
const body = await request.json();
|
||||||
|
|
||||||
|
// Check if user owns this card
|
||||||
|
const ownershipResult = await sql.query(
|
||||||
|
'SELECT id FROM user_cards WHERE id = $1 AND user_id = $2',
|
||||||
|
[id, user.id]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ownershipResult.rows.length === 0) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Card not found or not owned by user' },
|
||||||
|
{ status: 404 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build update query dynamically
|
||||||
|
const updateFields = [];
|
||||||
|
const updateValues = [];
|
||||||
|
let paramIndex = 1;
|
||||||
|
|
||||||
|
if (body.status !== undefined) {
|
||||||
|
updateFields.push(`status = $${paramIndex}`);
|
||||||
|
updateValues.push(body.status);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.quantity !== undefined) {
|
||||||
|
updateFields.push(`quantity = $${paramIndex}`);
|
||||||
|
updateValues.push(body.quantity);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.condition !== undefined) {
|
||||||
|
updateFields.push(`condition = $${paramIndex}`);
|
||||||
|
updateValues.push(body.condition);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.notes !== undefined) {
|
||||||
|
updateFields.push(`notes = $${paramIndex}`);
|
||||||
|
updateValues.push(body.notes);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.acquiredDate !== undefined) {
|
||||||
|
updateFields.push(`acquired_date = $${paramIndex}`);
|
||||||
|
updateValues.push(body.acquiredDate);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.acquiredPrice !== undefined) {
|
||||||
|
updateFields.push(`acquired_price = $${paramIndex}`);
|
||||||
|
updateValues.push(body.acquiredPrice);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.acquiredFrom !== undefined) {
|
||||||
|
updateFields.push(`acquired_from = $${paramIndex}`);
|
||||||
|
updateValues.push(body.acquiredFrom);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateFields.length === 0) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'No fields to update' },
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFields.push(`updated_at = NOW()`);
|
||||||
|
updateValues.push(id);
|
||||||
|
|
||||||
|
const query = `
|
||||||
|
UPDATE user_cards
|
||||||
|
SET ${updateFields.join(', ')}
|
||||||
|
WHERE id = $${paramIndex}
|
||||||
|
RETURNING *
|
||||||
|
`;
|
||||||
|
|
||||||
|
const result = await sql.query(query, updateValues);
|
||||||
|
const userCard = result.rows[0];
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
id: userCard.id,
|
||||||
|
userId: userCard.user_id,
|
||||||
|
cardId: userCard.card_id,
|
||||||
|
status: userCard.status,
|
||||||
|
quantity: userCard.quantity,
|
||||||
|
condition: userCard.condition,
|
||||||
|
notes: userCard.notes,
|
||||||
|
acquiredDate: userCard.acquired_date,
|
||||||
|
acquiredPrice: userCard.acquired_price,
|
||||||
|
acquiredFrom: userCard.acquired_from,
|
||||||
|
createdAt: userCard.created_at,
|
||||||
|
updatedAt: userCard.updated_at,
|
||||||
|
},
|
||||||
|
message: 'Card updated successfully'
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error updating user card:', error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Failed to update card' },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE /api/user-cards/[id] - Delete user card
|
||||||
|
export async function DELETE(request, { params }) {
|
||||||
|
try {
|
||||||
|
const token = request.headers.get('authorization')?.replace('Bearer ', '');
|
||||||
|
const user = await verifyToken(token);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id } = params;
|
||||||
|
|
||||||
|
// Check if user owns this card
|
||||||
|
const ownershipResult = await sql.query(
|
||||||
|
'SELECT id FROM user_cards WHERE id = $1 AND user_id = $2',
|
||||||
|
[id, user.id]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ownershipResult.rows.length === 0) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Card not found or not owned by user' },
|
||||||
|
{ status: 404 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete from collections and decks first
|
||||||
|
await sql.query('DELETE FROM collection_cards WHERE user_card_id = $1', [id]);
|
||||||
|
await sql.query('DELETE FROM deck_cards WHERE user_card_id = $1', [id]);
|
||||||
|
|
||||||
|
// Delete the user card
|
||||||
|
await sql.query('DELETE FROM user_cards WHERE id = $1', [id]);
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
message: 'Card removed from collection'
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting user card:', error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Failed to delete card' },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue