import { NextRequest, NextResponse } from "next/server"; import { prisma } from "@/lib/db"; import { deleteObject } from "@/lib/storage"; import { fireIntegrationEvent } from "@/lib/integrations"; import { logActivity, diffCardFields } from "@/lib/activity-log"; import { getOrCreateUser, RoleError } from "@/lib/auth"; export async function GET( _request: NextRequest, { params }: { params: Promise<{ id: string }> } ) { try { const { id } = await params; const card = await prisma.responseCard.findUnique({ where: { id }, }); if (!card) { return NextResponse.json({ error: "Card not found" }, { status: 404 }); } const frontImageUrl = card.frontImagePath ? `/api/images/${card.frontImagePath}` : null; const backImageUrl = card.backImagePath ? `/api/images/${card.backImagePath}` : null; return NextResponse.json({ ...card, frontImageUrl, backImageUrl, }); } catch (error) { console.error("[cards/[id] GET]", error); return NextResponse.json( { error: "Failed to fetch card" }, { status: 500 } ); } } export async function PUT( request: NextRequest, { params }: { params: Promise<{ id: string }> } ) { try { const user = await getOrCreateUser(request.headers); const { id } = await params; const card = await prisma.responseCard.findUnique({ where: { id }, }); if (!card) { return NextResponse.json({ error: "Card not found" }, { status: 404 }); } if (user) { if (user.role === "viewer") { return NextResponse.json({ error: "Viewers cannot edit cards" }, { status: 403 }); } if (user.role === "reviewer" && card.assignedToId !== user.id) { return NextResponse.json({ error: "You can only edit cards assigned to you" }, { status: 403 }); } } const body = await request.json().catch(() => ({})); const data: Record = {}; const stringFields = [ "name", "gender", "dateOfBirth", "maritalStatus", "maritalStatusOther", "visitType", "cellPhone", "homePhone", "email", "address", "aptNumber", "city", "state", "zip", "prayerRequests", "messageTopicsOther", "attendanceDuration", "campusPreferenceOther", "howHeardOther", "serviceAttended", "followUp", "notes", "serviceTime", "planningCenter", "ocrStatus", "reviewStatus", "ocrError", "reviewNotes", ]; for (const field of stringFields) { if (body[field] != null) data[field] = String(body[field]); } if (body.prayerForTeam != null) data.prayerForTeam = Boolean(body.prayerForTeam); if (body.prayerConfidential != null) data.prayerConfidential = Boolean(body.prayerConfidential); if (body.iSaidYesBookSent != null) data.iSaidYesBookSent = Boolean(body.iSaidYesBookSent); if (body.ftGuestLetterSent != null) data.ftGuestLetterSent = Boolean(body.ftGuestLetterSent); for (const dateField of ["firstTimeGuestDate", "salvationDate", "assignedAt", "reviewedAt"] as const) { if (body[dateField] !== undefined) { data[dateField] = body[dateField] ? new Date(body[dateField]) : null; } } if (body.ocrConfidence != null) data.ocrConfidence = Number(body.ocrConfidence); if (body.messageTopics != null) data.messageTopics = body.messageTopics; if (body.nextStep != null) data.nextStep = body.nextStep; if (body.campusPreference != null) data.campusPreference = body.campusPreference; if (body.howHeard != null) data.howHeard = body.howHeard; if (body.rawOcrResponse != null) data.rawOcrResponse = body.rawOcrResponse; for (const assignField of ["assignedToId", "assignedById", "reviewedById"] as const) { if (body[assignField] !== undefined) { data[assignField] = body[assignField] || null; } } if (body.reviewStatus === "in_review" && card.reviewStatus === "assigned") { data.reviewStatus = "in_review"; } if (body.reviewStatus === "reviewed" && user) { data.reviewedById = user.id; data.reviewedAt = new Date(); } const oldCard = card as unknown as Record; const updated = await prisma.responseCard.update({ where: { id }, data: data as Parameters[0]["data"], }); const newCard = updated as unknown as Record; const changes = diffCardFields(oldCard, newCard); if (changes.length > 0) { logActivity( id, "manual_edit", "user", `${changes.length} field(s) updated manually`, changes, user?.id ).catch(() => {}); } const oldStatus = card.reviewStatus; const newStatus = updated.reviewStatus; if (oldStatus !== newStatus) { if (newStatus === "reviewed") { fireIntegrationEvent("card_reviewed", id, { oldCard }).catch(() => {}); } else if (newStatus === "exported") { fireIntegrationEvent("card_exported", id, { oldCard }).catch(() => {}); } } return NextResponse.json(updated); } catch (error) { if (error instanceof RoleError) { return NextResponse.json({ error: error.message }, { status: 403 }); } console.error("[cards/[id] PUT]", error); return NextResponse.json( { error: "Failed to update card" }, { status: 500 } ); } } export async function DELETE( request: NextRequest, { params }: { params: Promise<{ id: string }> } ) { try { const user = await getOrCreateUser(request.headers); if (user && user.role !== "admin") { return NextResponse.json({ error: "Only admins can delete cards" }, { status: 403 }); } const { id } = await params; const card = await prisma.responseCard.findUnique({ where: { id }, }); if (!card) { return NextResponse.json({ error: "Card not found" }, { status: 404 }); } fireIntegrationEvent("card_deleted", id).catch(() => {}); const deletePromises: Promise[] = []; if (card.frontImagePath) deletePromises.push(deleteObject(card.frontImagePath)); if (card.backImagePath) deletePromises.push(deleteObject(card.backImagePath)); await Promise.allSettled(deletePromises); await prisma.responseCard.delete({ where: { id }, }); return NextResponse.json({ success: true }); } catch (error) { console.error("[cards/[id] DELETE]", error); return NextResponse.json( { error: "Failed to delete card" }, { status: 500 } ); } }