import { NextRequest, NextResponse } from "next/server" import prisma from "@/lib/prisma" import { updatePledgeStatusSchema } from "@/lib/validators" import { logActivity } from "@/lib/activity-log" import { requirePermission } from "@/lib/session" export async function GET( request: NextRequest, { params }: { params: Promise<{ id: string }> } ) { try { if (!prisma) { return NextResponse.json({ error: "Database not configured" }, { status: 503 }) } const { id } = await params const pledge = await prisma.pledge.findUnique({ where: { id }, include: { event: { select: { name: true } } }, }) if (!pledge) { return NextResponse.json({ error: "Not found" }, { status: 404 }) } return NextResponse.json({ id: pledge.id, reference: pledge.reference, amountPence: pledge.amountPence, rail: pledge.rail, status: pledge.status, donorName: pledge.donorName, donorEmail: pledge.donorEmail, eventName: pledge.event.name, }) } catch (error) { console.error("Pledge GET error:", error) return NextResponse.json({ error: "Internal error" }, { status: 500 }) } } export async function PATCH( request: NextRequest, { params }: { params: Promise<{ id: string }> } ) { try { if (!prisma) { return NextResponse.json({ error: "Database not configured" }, { status: 503 }) } // Only admins can change pledge statuses const allowed = await requirePermission("pledges.write") if (!allowed) return NextResponse.json({ error: "Admin access required" }, { status: 403 }) const { id } = await params const body = await request.json() const parsed = updatePledgeStatusSchema.safeParse(body) if (!parsed.success) { return NextResponse.json({ error: "Invalid data" }, { status: 400 }) } const existing = await prisma.pledge.findUnique({ where: { id } }) if (!existing) { return NextResponse.json({ error: "Pledge not found" }, { status: 404 }) } // Build update data — only include fields that were provided const updateData: Record = {} if (parsed.data.status !== undefined) updateData.status = parsed.data.status if (parsed.data.notes !== undefined) updateData.notes = parsed.data.notes if (parsed.data.amountPence !== undefined) updateData.amountPence = parsed.data.amountPence if (parsed.data.donorName !== undefined) updateData.donorName = parsed.data.donorName if (parsed.data.donorEmail !== undefined) updateData.donorEmail = parsed.data.donorEmail if (parsed.data.donorPhone !== undefined) updateData.donorPhone = parsed.data.donorPhone if (parsed.data.rail !== undefined) updateData.rail = parsed.data.rail if (parsed.data.status === "paid") { updateData.paidAt = new Date() } if (parsed.data.status === "cancelled") { updateData.cancelledAt = new Date() } const pledge = await prisma.pledge.update({ where: { id }, data: updateData, }) // If paid or cancelled, skip remaining reminders if (parsed.data.status && ["paid", "cancelled"].includes(parsed.data.status)) { await prisma.reminder.updateMany({ where: { pledgeId: id, status: "pending" }, data: { status: "skipped" }, }) } // A/B conversion tracking: when paid, credit the template variant that was last sent if (parsed.data.status === "paid") { try { const lastSentReminder = await prisma.reminder.findFirst({ where: { pledgeId: id, status: "sent" }, orderBy: { sentAt: "desc" }, }) const payload = lastSentReminder?.payload as Record | null if (payload?.templateId) { await prisma.messageTemplate.update({ where: { id: payload.templateId }, data: { convertedCount: { increment: 1 } }, }) } } catch { /* conversion tracking is best-effort */ } } // Log activity const changes = Object.keys(updateData).filter(k => k !== "paidAt" && k !== "cancelledAt") await logActivity({ action: parsed.data.status === "paid" ? "pledge.marked_paid" : parsed.data.status === "cancelled" ? "pledge.cancelled" : "pledge.updated", entityType: "pledge", entityId: id, orgId: existing.organizationId, metadata: { changes, previousStatus: existing.status, newStatus: parsed.data.status }, }) return NextResponse.json(pledge) } catch (error) { console.error("Pledge update error:", error) return NextResponse.json({ error: "Internal error" }, { status: 500 }) } }