import { NextRequest, NextResponse } from 'next/server'; import pool from '@/lib/db'; import { verifyToken, TokenPayload } from '@/lib/auth'; import { RowDataPacket, ResultSetHeader } from 'mysql2'; import { sendEmail, sendMessageNotification } from '@/lib/email'; function getUserFromRequest(request: NextRequest): TokenPayload | null { const authHeader = request.headers.get('authorization'); if (!authHeader?.startsWith('Bearer ')) return null; const token = authHeader.substring(7); try { return verifyToken(token); } catch { return null; } } interface RouteParams { params: Promise<{ id: string }>; } // GET /api/conversations/[id] - Get conversation with messages export async function GET(request: NextRequest, { params }: RouteParams) { try { const user = getUserFromRequest(request); if (!user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const { id } = await params; const [convRows] = await pool.query( `SELECT c.*, u.full_name as user_name, u.email as user_email, p.name as product_name FROM conversations c JOIN users u ON c.user_id = u.id LEFT JOIN products p ON c.product_id = p.id WHERE c.id = ?`, [id] ); if (convRows.length === 0) { return NextResponse.json({ error: 'Conversation not found' }, { status: 404 }); } const conversation = convRows[0]; if (user.role !== 'admin' && conversation.user_id !== user.userId) { return NextResponse.json({ error: 'Forbidden' }, { status: 403 }); } const [messages] = await pool.query( `SELECT m.*, u.full_name as sender_name FROM messages m JOIN users u ON m.sender_id = u.id WHERE m.conversation_id = ? ORDER BY m.created_at ASC`, [id] ); const readRole = user.role === 'admin' ? 'customer' : 'admin'; await pool.query( `UPDATE messages SET is_read = TRUE WHERE conversation_id = ? AND sender_role = ? AND is_read = FALSE`, [id, readRole] ); return NextResponse.json({ conversation, messages }); } catch (error) { console.error('Error fetching conversation:', error); return NextResponse.json({ error: 'Server error' }, { status: 500 }); } } // POST /api/conversations/[id] - Add message to conversation export async function POST(request: NextRequest, { params }: RouteParams) { try { const user = getUserFromRequest(request); if (!user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const { id } = await params; const body = await request.json(); const { content } = body; if (!content) { return NextResponse.json({ error: 'Message content required' }, { status: 400 }); } const [convRows] = await pool.query( `SELECT c.*, u.full_name as user_name, u.email as user_email FROM conversations c JOIN users u ON c.user_id = u.id WHERE c.id = ?`, [id] ); if (convRows.length === 0) { return NextResponse.json({ error: 'Conversation not found' }, { status: 404 }); } const conversation = convRows[0]; if (user.role !== 'admin' && conversation.user_id !== user.userId) { return NextResponse.json({ error: 'Forbidden' }, { status: 403 }); } const senderRole = user.role === 'admin' ? 'admin' : 'customer'; await pool.query( `INSERT INTO messages (conversation_id, sender_id, sender_role, content) VALUES (?, ?, ?, ?)`, [id, user.userId, senderRole, content] ); // Fetch sender's expanded details for the email const [senderDetails] = await pool.query( `SELECT full_name, email, mobile, personnummer FROM users WHERE id = ?`, [user.userId] ); const sender = senderDetails[0]; await pool.query( `UPDATE conversations SET updated_at = CURRENT_TIMESTAMP WHERE id = ?`, [id] ); // Send email notification based on recipient's online status if (user.role === 'admin') { // Admin replying to customer const [sessions] = await pool.query( `SELECT COUNT(*) as count FROM user_sessions WHERE user_id = ? AND expires_at > NOW()`, [conversation.user_id] ); const isCustomerOnline = sessions[0].count > 0; if (!isCustomerOnline) { await sendMessageNotification( conversation.user_email, `Nytt svar: ${conversation.subject}`, 'Nordic Storium Support', process.env.SMTP_FROM || 'support@nordicstorium.com', null, null, content, `${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'}/messages`, 'Se konversation' ); } } else { // Customer replying to admins const [admins] = await pool.query( `SELECT id, email FROM users WHERE role = 'admin'` ); for (const admin of admins) { const [sessions] = await pool.query( `SELECT COUNT(*) as count FROM user_sessions WHERE user_id = ? AND expires_at > NOW()`, [admin.id] ); const isAdminOnline = sessions[0].count > 0; if (!isAdminOnline) { await sendMessageNotification( admin.email, `Nytt meddelande: ${conversation.subject}`, sender.full_name, sender.email, sender.mobile, sender.personnummer, content, `${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'}/admin/messages`, 'Svara i Adminpanelen' ); } } } return NextResponse.json({ success: true }); } catch (error) { console.error('Error sending message:', error); return NextResponse.json({ error: 'Server error' }, { status: 500 }); } } // DELETE /api/conversations/[id] - Delete conversation export async function DELETE(request: NextRequest, { params }: RouteParams) { try { const user = getUserFromRequest(request); if (!user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const { id } = await params; const [convRows] = await pool.query( `SELECT * FROM conversations WHERE id = ?`, [id] ); if (convRows.length === 0) { return NextResponse.json({ error: 'Conversation not found' }, { status: 404 }); } const conversation = convRows[0]; // Only admin can delete completely, customers can only delete their own if (user.role !== 'admin' && conversation.user_id !== user.userId) { return NextResponse.json({ error: 'Forbidden' }, { status: 403 }); } // Delete the conversation (cascades to messages) await pool.query(`DELETE FROM conversations WHERE id = ?`, [id]); return NextResponse.json({ success: true, message: 'Conversation deleted' }); } catch (error) { console.error('Error deleting conversation:', error); return NextResponse.json({ error: 'Server error' }, { status: 500 }); } } // PATCH /api/conversations/[id] - Resolve conversation (admin only) export async function PATCH(request: NextRequest, { params }: RouteParams) { try { const user = getUserFromRequest(request); if (!user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } if (user.role !== 'admin') { return NextResponse.json({ error: 'Admin only' }, { status: 403 }); } const { id } = await params; const body = await request.json(); const { action } = body; if (action === 'resolve') { // Get conversation info for email const [convRows] = await pool.query( `SELECT c.*, u.email as user_email, u.full_name as user_name FROM conversations c JOIN users u ON c.user_id = u.id WHERE c.id = ?`, [id] ); if (convRows.length === 0) { return NextResponse.json({ error: 'Conversation not found' }, { status: 404 }); } const conversation = convRows[0]; // Update status to closed await pool.query( `UPDATE conversations SET status = 'closed' WHERE id = ?`, [id] ); // Send resolution email to customer await sendEmail( conversation.user_email, `Ärende löst: ${conversation.subject}`, `

Ditt ärende har markerats som löst

Hej ${conversation.user_name || 'kund'},

Vi har markerat ditt ärende "${conversation.subject}" som löst.

Om du fortfarande har frågor eller känner att ärendet inte är helt löst, tveka inte att kontakta oss igen.

Med vänliga hälsningar,
Nordic Storium Support

` ); return NextResponse.json({ success: true, message: 'Conversation resolved' }); } return NextResponse.json({ error: 'Invalid action' }, { status: 400 }); } catch (error) { console.error('Error resolving conversation:', error); return NextResponse.json({ error: 'Server error' }, { status: 500 }); } }