deckhearth/pages/api/collections/[id].js
Randall Stillwell 72de168fc6 🎯 Complete Testing Workflow Setup
 Database & API Fixes:
- Fixed collection detail API to use correct column names (card_type, market_price, image_url)
- Removed all mock data and fallbacks
- Updated field mappings throughout collection detail page
- Fixed hero section to use real collection data with proper image support

�� Test Users Created:
- admin@tcgvault.com / admin123 (Admin)
- alice@tcgvault.com / alice123 (User)
- bob@tcgvault.com / bob123 (User)

🃏 Sample Cards Added:
- Lightning Bolt (MTG) - $2.50
- Black Lotus (MTG) - $25,000
- Pikachu (Pokemon) - $8.50
- Charizard (Pokemon) - $350
- Mickey Mouse (Lorcana) - $45
- Elsa (Lorcana) - $15.75

🔧 Collaboration Features:
- Added CollaborationManager to collection detail page
- Integrated real user permissions (isOwner check)
- Updated hero section with real stats and creator info

🔍 Card Management:
- Created cards search API (/api/cards/search)
- Implemented quick add functionality in empty state
- Real-time card search with dropdown results
- Add cards directly to collection with quantity

�� Ready for Testing:
1. Login as any user to see only their collections
2. Create collections with real data
3. Add cards using search functionality
4. Invite collaborators via email system
5. Switch users to test collaboration workflow

Complete end-to-end testing environment ready! 🚀
2025-07-25 10:42:00 -05:00

132 lines
No EOL
3.8 KiB
JavaScript

import { sql } from '@vercel/postgres';
import { withCollectionPermission, getUserFromRequest, logCollectionActivity } from '../../../lib/permission-middleware';
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') {
// GET requests use the permission from middleware
const collection = req.permission.collection;
const userRole = req.permission.role;
try {
// Get detailed collection info with creator
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}
`;
const collectionDetails = collectionResult.rows[0];
// Get cards in the collection
const cardsResult = await sql`
SELECT
cc.*,
cards.name,
cards.set_name,
cards.rarity,
cards.card_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: {
...collectionDetails,
totalCards,
totalValue,
userRole
},
cards
});
} catch (error) {
console.error('Error fetching collection:', error);
res.status(500).json({ error: 'Internal server error' });
}
} else if (req.method === 'PUT') {
// Update collection - requires editor permissions
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 *
`;
// Log activity
await logCollectionActivity(id, req.user.userId, 'collection_updated', {
name,
description,
isPublic
});
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 - requires owner permissions
try {
// Log activity before deletion
await logCollectionActivity(id, req.user.userId, 'collection_deleted', {});
// Delete collection (cascade will handle related records)
const result = await sql`DELETE FROM collections WHERE id = ${id} RETURNING *`;
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' });
}
}
// Apply permission middleware based on method
export default async function(req, res) {
let requiredPermission = 'viewer'; // Default for GET
if (req.method === 'PUT') {
requiredPermission = 'editor';
} else if (req.method === 'DELETE') {
requiredPermission = 'owner';
}
return withCollectionPermission(requiredPermission)(handler)(req, res);
};