deckhearth/pages/api/collections/[id].js
Randall Stillwell 00853fe499 Enhanced collections with detailed view and card management
- Created comprehensive collection detail page (/collection/[id]) with:
  * Hero section with collection metadata (name, creator, format, cost)
  * Action buttons (copy link, share, print proxies, save deck)
  * Collection statistics (total cards, value, views, favorites)
  * Advanced filtering and search functionality
  * Grid and list view modes for cards
  * Real-time card filtering by rarity, type, and search terms

- Added complete API endpoints for collection management:
  * GET/PUT/DELETE /api/collections/[id] - collection CRUD operations
  * POST/PUT/DELETE /api/collections/[id]/cards - card management
  * Enhanced /api/collections with database integration

- Features matching deck builder interface from image:
  * Beautiful hero section with background image
  * Metadata display (creator, format, cost, play guide)
  * Copy/share/save functionality
  * Comprehensive filtering system
  * Responsive card grid and list views
  * Real-time statistics and card counting

- Updated collections listing page to link to detailed views
- Proper error handling and loading states throughout
- Mobile-responsive design with modern UI/UX
2025-07-25 07:44:23 -05:00

118 lines
No EOL
3.3 KiB
JavaScript

import { sql } from '@vercel/postgres';
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;
}
const { id } = req.query;
if (req.method === 'GET') {
try {
// Get collection details
const collectionResult = await sql`
SELECT
c.*,
u.email as creator_email
FROM collections c
LEFT JOIN users u ON c.user_id = u.id
WHERE c.id = ${id}
`;
if (collectionResult.rows.length === 0) {
return res.status(404).json({ error: 'Collection not found' });
}
const collection = collectionResult.rows[0];
// Get cards in the collection
const cardsResult = await sql`
SELECT
cc.*,
cards.name,
cards.set_name,
cards.rarity,
cards.type,
cards.image_url,
cards.market_price
FROM collection_cards cc
JOIN cards ON cc.card_id = cards.id
WHERE cc.collection_id = ${id}
ORDER BY cc.created_at ASC
`;
const cards = cardsResult.rows;
// Calculate collection stats
const totalCards = cards.reduce((sum, card) => sum + card.quantity, 0);
const totalValue = cards.reduce((sum, card) => sum + (card.market_price * card.quantity), 0);
res.status(200).json({
collection: {
...collection,
totalCards,
totalValue
},
cards
});
} catch (error) {
console.error('Error fetching collection:', error);
res.status(500).json({ error: 'Internal server error' });
}
} else if (req.method === 'PUT') {
// Update collection
try {
const { name, description, isPublic } = req.body;
const result = await sql`
UPDATE collections
SET
name = ${name},
description = ${description},
is_public = ${isPublic},
updated_at = NOW()
WHERE id = ${id}
RETURNING *
`;
if (result.rows.length === 0) {
return res.status(404).json({ error: 'Collection not found' });
}
res.status(200).json(result.rows[0]);
} catch (error) {
console.error('Error updating collection:', error);
res.status(500).json({ error: 'Internal server error' });
}
} else if (req.method === 'DELETE') {
// Delete collection
try {
// First delete all cards in the collection
await sql`DELETE FROM collection_cards WHERE collection_id = ${id}`;
// Then delete the collection
const result = await sql`DELETE FROM collections WHERE id = ${id} RETURNING *`;
if (result.rows.length === 0) {
return res.status(404).json({ error: 'Collection not found' });
}
res.status(200).json({ message: 'Collection deleted successfully' });
} catch (error) {
console.error('Error deleting collection:', error);
res.status(500).json({ error: 'Internal server error' });
}
} else {
res.status(405).json({ error: 'Method not allowed' });
}
}