import { NextRequest, NextResponse } from "next/server"; import { prisma } from "@/lib/prisma"; import { requireAuth } from "@/lib/auth"; // GET /api/souq/orders/[id] — order detail export async function GET( request: NextRequest, { params }: { params: Promise<{ id: string }> } ) { try { const auth = await requireAuth(request); if (!auth) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const { id } = await params; const order = await prisma.purchase.findUnique({ where: { id }, include: { listing: { select: { id: true, title: true, category: true, subcategory: true, priceFlh: true, description: true, deliveryDays: true }, }, buyer: { select: { id: true, name: true, email: true, avatar: true }, }, seller: { select: { id: true, name: true, email: true, avatar: true }, }, }, }); if (!order) { return NextResponse.json( { error: "Order not found" }, { status: 404 } ); } // Verify user is either the buyer or seller if (order.buyerId !== auth.userId && order.sellerId !== auth.userId) { return NextResponse.json( { error: "Forbidden: you are not a party to this order" }, { status: 403 } ); } // Check if the current user (buyer) has already reviewed this order let hasReviewed = false; if (order.status === "completed" && order.buyerId === auth.userId) { const existingReview = await prisma.review.findFirst({ where: { purchaseId: order.id, reviewerId: auth.userId }, select: { id: true }, }); hasReviewed = !!existingReview; } // Parse JSON fields const data = order as any; return NextResponse.json({ order: { ...data, messages: data.messages ? JSON.parse(data.messages) : [], deliveryFiles: data.deliveryFiles ? JSON.parse(data.deliveryFiles) : [], }, hasReviewed, }); } catch (error) { console.error("GET /api/souq/orders/[id] error:", error); return NextResponse.json( { error: "Internal server error" }, { status: 500 } ); } } // PATCH /api/souq/orders/[id] — update order status or add messages export async function PATCH( request: NextRequest, { params }: { params: Promise<{ id: string }> } ) { try { const auth = await requireAuth(request); if (!auth) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const { id } = await params; const order = await prisma.purchase.findUnique({ where: { id }, }); if (!order) { return NextResponse.json( { error: "Order not found" }, { status: 404 } ); } // Verify user is either the buyer or seller if (order.buyerId !== auth.userId && order.sellerId !== auth.userId) { return NextResponse.json( { error: "Forbidden: you are not a party to this order" }, { status: 403 } ); } const body = await request.json(); const { status: newStatus, message, deliveryFiles } = body; const updateData: Record = {}; // Update status if provided if (newStatus) { const validStatuses = [ "pending", "paid", "in_progress", "delivered", "completed", "disputed", "cancelled", ]; if (!validStatuses.includes(newStatus)) { return NextResponse.json( { error: `Invalid status. Must be one of: ${validStatuses.join(", ")}`, }, { status: 400 } ); } // Validate status transitions const validTransitions: Record = { paid: ["in_progress", "cancelled"], in_progress: ["delivered", "disputed"], delivered: ["completed", "disputed"], completed: [], disputed: ["completed", "cancelled"], cancelled: [], pending: ["paid", "cancelled"], }; const allowed = validTransitions[order.status] || []; if (!allowed.includes(newStatus)) { return NextResponse.json( { error: `Cannot transition from "${order.status}" to "${newStatus}"`, }, { status: 400 } ); } // Only seller can mark as in_progress or delivered if ( (newStatus === "in_progress" || newStatus === "delivered") && auth.userId !== order.sellerId ) { return NextResponse.json( { error: "Only the seller can update to this status" }, { status: 403 } ); } // Only buyer can mark as completed if (newStatus === "completed" && auth.userId !== order.buyerId) { return NextResponse.json( { error: "Only the buyer can mark an order as completed" }, { status: 403 } ); } updateData.status = newStatus; } // Add a message if provided if (message) { if (typeof message !== "string" || message.trim().length === 0) { return NextResponse.json( { error: "Message must be a non-empty string" }, { status: 400 } ); } const existingMessages = order.messages ? (JSON.parse(order.messages) as Array>) : []; const newMessage = { from: auth.userId, text: message.trim(), timestamp: new Date().toISOString(), }; existingMessages.push(newMessage); updateData.messages = JSON.stringify(existingMessages); } // Update delivery files if provided if (deliveryFiles) { if (!Array.isArray(deliveryFiles)) { return NextResponse.json( { error: "deliveryFiles must be an array" }, { status: 400 } ); } updateData.deliveryFiles = JSON.stringify(deliveryFiles); } if (Object.keys(updateData).length === 0) { return NextResponse.json( { error: "No fields to update. Provide status, message, or deliveryFiles." }, { status: 400 } ); } const updated = await prisma.purchase.update({ where: { id }, data: updateData, include: { listing: { select: { id: true, title: true, category: true }, }, buyer: { select: { id: true, name: true, email: true, avatar: true }, }, seller: { select: { id: true, name: true, email: true, avatar: true }, }, }, }); const data = updated as any; return NextResponse.json({ order: { ...data, messages: data.messages ? JSON.parse(data.messages) : [], deliveryFiles: data.deliveryFiles ? JSON.parse(data.deliveryFiles) : [], }, }); } catch (error) { console.error("PATCH /api/souq/orders/[id] error:", error); return NextResponse.json( { error: "Internal server error" }, { status: 500 } ); } }