import { NextRequest, NextResponse } from "next/server"; import { prisma } from "@/lib/prisma"; import { requireAuth } from "@/lib/auth"; // POST /api/souq/reviews — create a review export async function POST(request: NextRequest) { try { const auth = await requireAuth(request); if (!auth) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const { listingId, orderId, rating, title, text } = await request.json(); // ── Validate fields ── if (!listingId || !orderId) { return NextResponse.json( { error: "Missing required fields: listingId, orderId" }, { status: 400 } ); } if (!rating || typeof rating !== "number" || rating < 1 || rating > 5 || !Number.isInteger(rating)) { return NextResponse.json( { error: "Rating must be an integer between 1 and 5" }, { status: 400 } ); } // ── Ensure the order exists and belongs to this user ── const order = await prisma.purchase.findUnique({ where: { id: orderId }, include: { listing: { select: { id: true, sellerId: true } } }, }); if (!order) { return NextResponse.json({ error: "Order not found" }, { status: 404 }); } if (order.buyerId !== auth.userId) { return NextResponse.json( { error: "Only the buyer can review this order" }, { status: 403 } ); } if (order.status !== "completed") { return NextResponse.json( { error: "Can only review completed orders" }, { status: 400 } ); } if (order.listingId !== listingId) { return NextResponse.json( { error: "Listing does not match this order" }, { status: 400 } ); } // ── Check if user already reviewed this purchase ── const existing = await prisma.review.findFirst({ where: { purchaseId: orderId, reviewerId: auth.userId }, }); if (existing) { return NextResponse.json( { error: "You have already reviewed this order" }, { status: 409 } ); } // ── Create the review and update listing stats in a transaction ── const [review] = await prisma.$transaction(async (tx) => { const created = await tx.review.create({ data: { listingId, purchaseId: orderId, reviewerId: auth.userId, sellerId: order.listing.sellerId, rating, title: title || null, text: text ?? "", }, }); // Recalculate listing average rating and count const agg = await tx.review.aggregate({ where: { listingId }, _avg: { rating: true }, _count: { rating: true }, }); await tx.listing.update({ where: { id: listingId }, data: { rating: agg._avg.rating ?? 0, reviewCount: agg._count.rating, }, }); return [created]; }); return NextResponse.json({ review }, { status: 201 }); } catch (error) { console.error("POST /api/souq/reviews error:", error); return NextResponse.json( { error: "Internal server error" }, { status: 500 } ); } }