import { sql } from '@vercel/postgres'; import { getUserFromRequest } from '../../../lib/permission-middleware'; export default async function handler(req, res) { // Set CORS headers res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, PUT, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); // Handle preflight requests if (req.method === 'OPTIONS') { res.status(200).end(); return; } try { // Get authenticated user const user = await getUserFromRequest(req); if (!user) { return res.status(401).json({ error: 'Authentication required' }); } if (req.method === 'GET') { // Get user and settings const result = await sql` SELECT id, email, role, first_name, last_name, username, collection_visibility, preferred_currency, cards_per_page, default_view, notifications_email, notifications_marketing, two_factor_enabled, theme, language, created_at, updated_at FROM users WHERE id = ${user.userId} `; if (result.rows.length === 0) { return res.status(404).json({ error: 'User not found' }); } const userData = result.rows[0]; // Structure response const response = { user: { id: userData.id, email: userData.email, role: userData.role, first_name: userData.first_name, last_name: userData.last_name, username: userData.username }, settings: { // Account Settings collection_visibility: userData.collection_visibility || 'private', preferred_currency: userData.preferred_currency || 'USD', cards_per_page: userData.cards_per_page || 50, default_view: userData.default_view || 'grid', // Security Settings two_factor_enabled: userData.two_factor_enabled || false, // Notification Settings notifications_email: userData.notifications_email !== false, // Default to true notifications_marketing: userData.notifications_marketing || false, // Display Settings theme: userData.theme || 'system', language: userData.language || 'en' } }; res.status(200).json(response); } else if (req.method === 'PUT') { // Update user settings const { collection_visibility, preferred_currency, cards_per_page, default_view, two_factor_enabled, notifications_email, notifications_marketing, theme, language } = req.body; // Validate enum values const validVisibility = ['private', 'public', 'unlisted']; const validCurrency = ['USD', 'EUR', 'GBP', 'CAD', 'JPY']; const validCardsPerPage = [25, 50, 100]; const validView = ['grid', 'list']; const validTheme = ['light', 'dark', 'system']; const validLanguage = ['en', 'es', 'fr', 'de', 'ja']; // Validate inputs if (collection_visibility && !validVisibility.includes(collection_visibility)) { return res.status(400).json({ error: 'Invalid collection visibility' }); } if (preferred_currency && !validCurrency.includes(preferred_currency)) { return res.status(400).json({ error: 'Invalid preferred currency' }); } if (cards_per_page && !validCardsPerPage.includes(cards_per_page)) { return res.status(400).json({ error: 'Invalid cards per page value' }); } if (default_view && !validView.includes(default_view)) { return res.status(400).json({ error: 'Invalid default view' }); } if (theme && !validTheme.includes(theme)) { return res.status(400).json({ error: 'Invalid theme' }); } if (language && !validLanguage.includes(language)) { return res.status(400).json({ error: 'Invalid language' }); } // Build update query dynamically const updateFields = []; const updateValues = []; let paramIndex = 1; if (collection_visibility !== undefined) { updateFields.push(`collection_visibility = $${paramIndex}`); updateValues.push(collection_visibility); paramIndex++; } if (preferred_currency !== undefined) { updateFields.push(`preferred_currency = $${paramIndex}`); updateValues.push(preferred_currency); paramIndex++; } if (cards_per_page !== undefined) { updateFields.push(`cards_per_page = $${paramIndex}`); updateValues.push(cards_per_page); paramIndex++; } if (default_view !== undefined) { updateFields.push(`default_view = $${paramIndex}`); updateValues.push(default_view); paramIndex++; } if (two_factor_enabled !== undefined) { updateFields.push(`two_factor_enabled = $${paramIndex}`); updateValues.push(two_factor_enabled); paramIndex++; } if (notifications_email !== undefined) { updateFields.push(`notifications_email = $${paramIndex}`); updateValues.push(notifications_email); paramIndex++; } if (notifications_marketing !== undefined) { updateFields.push(`notifications_marketing = $${paramIndex}`); updateValues.push(notifications_marketing); paramIndex++; } if (theme !== undefined) { updateFields.push(`theme = $${paramIndex}`); updateValues.push(theme); paramIndex++; } if (language !== undefined) { updateFields.push(`language = $${paramIndex}`); updateValues.push(language); paramIndex++; } if (updateFields.length === 0) { return res.status(400).json({ error: 'No settings to update' }); } // Add updated_at and user_id updateFields.push('updated_at = CURRENT_TIMESTAMP'); updateValues.push(user.userId); // Execute update const updateQuery = ` UPDATE users SET ${updateFields.join(', ')} WHERE id = $${paramIndex} RETURNING id, email, role, first_name, last_name, username, collection_visibility, preferred_currency, cards_per_page, default_view, notifications_email, notifications_marketing, two_factor_enabled, theme, language, created_at, updated_at `; const result = await sql.query(updateQuery, updateValues); if (result.rows.length === 0) { return res.status(404).json({ error: 'User not found' }); } const userData = result.rows[0]; // Structure response const response = { user: { id: userData.id, email: userData.email, role: userData.role, first_name: userData.first_name, last_name: userData.last_name, username: userData.username }, settings: { collection_visibility: userData.collection_visibility, preferred_currency: userData.preferred_currency, cards_per_page: userData.cards_per_page, default_view: userData.default_view, two_factor_enabled: userData.two_factor_enabled, notifications_email: userData.notifications_email, notifications_marketing: userData.notifications_marketing, theme: userData.theme, language: userData.language } }; res.status(200).json(response); } else { res.status(405).json({ error: 'Method not allowed' }); } } catch (error) { console.error('Settings API error:', error); res.status(500).json({ error: 'Internal server error' }); } }