import { NextRequest, NextResponse } from 'next/server'; import { getServerSession } from 'next-auth'; import { authOptions } from '@/lib/auth'; import { db } from '@/lib/db'; import { cookies } from 'next/headers'; export async function GET( request: NextRequest, { params }: { params: Promise<{ id: string }> } ) { try { let userId: string | undefined; // Try NextAuth session first const session = await getServerSession(authOptions); if (session?.user?.id) { userId = session.user.id; } else { // Fallback: Check raw userId cookie (like /api/user does) const cookieStore = await cookies(); userId = cookieStore.get('userId')?.value; } if (!userId) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const { id } = await params; const { searchParams } = new URL(request.url); const page = parseInt(searchParams.get('page') || '1'); const limit = parseInt(searchParams.get('limit') || '20'); const skip = (page - 1) * limit; // Verify QR ownership and type const qrCode = await db.qRCode.findUnique({ where: { id, userId: userId }, select: { id: true, contentType: true }, }); if (!qrCode) { return NextResponse.json({ error: 'QR code not found' }, { status: 404 }); } // Check if consistent with schema (Prisma enum mismatch fix) // @ts-ignore - Temporary ignore until client regeneration catches up fully in all envs if (qrCode.contentType !== 'FEEDBACK') { return NextResponse.json({ error: 'Not a feedback QR code' }, { status: 400 }); } // Fetch feedback entries (stored as QRScans with ipHash='feedback') const [feedbackEntries, totalCount] = await Promise.all([ db.qRScan.findMany({ where: { qrId: id, ipHash: 'feedback' }, orderBy: { ts: 'desc' }, skip, take: limit, select: { id: true, userAgent: true, ts: true }, }), db.qRScan.count({ where: { qrId: id, ipHash: 'feedback' }, }), ]); // Parse feedback data from userAgent field const feedbacks = feedbackEntries.map((entry) => { const parsed = parseFeedback(entry.userAgent || ''); return { id: entry.id, rating: parsed.rating, comment: parsed.comment, date: entry.ts, }; }); // Calculate stats const allRatings = await db.qRScan.findMany({ where: { qrId: id, ipHash: 'feedback' }, select: { userAgent: true }, }); const ratings = allRatings.map((e) => parseFeedback(e.userAgent || '').rating).filter((r) => r > 0); const avgRating = ratings.length > 0 ? ratings.reduce((a, b) => a + b, 0) / ratings.length : 0; // Rating distribution const distribution = { 5: ratings.filter((r) => r === 5).length, 4: ratings.filter((r) => r === 4).length, 3: ratings.filter((r) => r === 3).length, 2: ratings.filter((r) => r === 2).length, 1: ratings.filter((r) => r === 1).length, }; return NextResponse.json({ feedbacks, stats: { total: totalCount, avgRating: Math.round(avgRating * 10) / 10, distribution, }, pagination: { page, limit, totalPages: Math.ceil(totalCount / limit), hasMore: skip + limit < totalCount, }, }); } catch (error) { console.error('Error fetching feedback:', error); return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } } function parseFeedback(userAgent: string): { rating: number; comment: string } { // Format: "rating:4|comment:Great service!" const ratingMatch = userAgent.match(/rating:(\d)/); const commentMatch = userAgent.match(/comment:(.+)/); return { rating: ratingMatch ? parseInt(ratingMatch[1]) : 0, comment: commentMatch ? commentMatch[1] : '', }; }