Ship all P0/P1/P2 gaps + 11 AI features
P0 Critical (7): - STOP/UNSUBSCRIBE keyword → CANCEL (PECR compliance) - Rate limiting on pledge creation (10/IP/5min) - Terms of Service + Privacy Policy pages - WhatsApp onboarding gate (persistent dashboard banner) - Demo account seeding (demo@pnpl.app) - Footer legal links - Basic accessibility (aria labels on donor flow) P1 Within 2 Weeks (8): - Pledge editing by staff (PATCH amount, name, email, phone, rail) - Donor self-cancel page (/p/cancel) + API - Donor 'My Pledges' lookup page (/p/my-pledges) - Bulk QR code download (print-ready HTML) - Public event progress bar (/e/[slug]/progress) - Email-only donor handling (honest status + WhatsApp fallback) - Email verification (format + disposable domain blocking) - Organisations page rewrite (multi-campaign, not multi-org) P2 Within First Month (10): - Event cloning with QR sources - Account deletion (GDPR Article 17) - Daily digest cron via WhatsApp - AI-6 Smart reminder timing (due date anchoring, cultural sensitivity) - H1 Duplicate donor detection (email, phone, Jaro-Winkler name) - H5 Bank CSV format presets (10 UK banks) - H16 Partial payment matching (underpay, overpay, instalment) - H10 Activity logging (audit trail for staff actions) - AI nudge endpoint + AI column mapping + AI event setup wizard - AI anomaly detection wired into daily digest AI Features (11): smart reconciliation, social proof, auto column mapper, daily digest, impact storyteller, smart timing, nudge composer, event wizard, NLU concierge, anomaly detection, bank presets 22 new files, 15 modified files, 0 TypeScript errors, clean build.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { NextRequest, NextResponse } from "next/server"
|
||||
import prisma from "@/lib/prisma"
|
||||
import { updatePledgeStatusSchema } from "@/lib/validators"
|
||||
import { logActivity } from "@/lib/activity-log"
|
||||
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
@@ -55,10 +56,15 @@ export async function PATCH(
|
||||
return NextResponse.json({ error: "Pledge not found" }, { status: 404 })
|
||||
}
|
||||
|
||||
const updateData: Record<string, unknown> = {
|
||||
status: parsed.data.status,
|
||||
notes: parsed.data.notes,
|
||||
}
|
||||
// Build update data — only include fields that were provided
|
||||
const updateData: Record<string, unknown> = {}
|
||||
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()
|
||||
@@ -73,13 +79,25 @@ export async function PATCH(
|
||||
})
|
||||
|
||||
// If paid or cancelled, skip remaining reminders
|
||||
if (["paid", "cancelled"].includes(parsed.data.status)) {
|
||||
if (parsed.data.status && ["paid", "cancelled"].includes(parsed.data.status)) {
|
||||
await prisma.reminder.updateMany({
|
||||
where: { pledgeId: id, status: "pending" },
|
||||
data: { status: "skipped" },
|
||||
})
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
Reference in New Issue
Block a user