feat: add improved pi agent with observatory, dashboard, and pledge-now-pay-later

This commit is contained in:
Azreen Jamal
2026-03-01 23:41:24 +08:00
parent ae242436c9
commit f832b913d5
99 changed files with 20949 additions and 74 deletions

View File

@@ -0,0 +1,79 @@
import { NextRequest, NextResponse } from "next/server"
import prisma from "@/lib/prisma"
import { formatWebhookPayload } from "@/lib/exports"
interface ReminderWithPledge {
id: string
pledgeId: string
step: number
channel: string
scheduledAt: Date
payload: unknown
pledge: {
donorName: string | null
donorEmail: string | null
donorPhone: string | null
reference: string
amountPence: number
rail: string
event: { name: string }
organization: { name: string }
}
}
// GET pending webhook events (for external polling)
export async function GET(request: NextRequest) {
try {
if (!prisma) {
return NextResponse.json([])
}
const since = request.nextUrl.searchParams.get("since")
const limit = parseInt(request.nextUrl.searchParams.get("limit") || "50")
const reminders = await prisma.reminder.findMany({
where: {
status: "pending",
scheduledAt: { lte: new Date() },
...(since ? { scheduledAt: { gte: new Date(since) } } : {}),
},
include: {
pledge: {
include: {
event: { select: { name: true } },
organization: { select: { name: true } },
},
},
},
take: limit,
orderBy: { scheduledAt: "asc" },
}) as ReminderWithPledge[]
const events = reminders.map((r: ReminderWithPledge) =>
formatWebhookPayload("reminder.due", {
reminderId: r.id,
pledgeId: r.pledgeId,
step: r.step,
channel: r.channel,
scheduledAt: r.scheduledAt,
donor: {
name: r.pledge.donorName,
email: r.pledge.donorEmail,
phone: r.pledge.donorPhone,
},
pledge: {
reference: r.pledge.reference,
amount: r.pledge.amountPence,
rail: r.pledge.rail,
},
event: r.pledge.event.name,
organization: r.pledge.organization.name,
payload: r.payload,
})
)
return NextResponse.json({ events, count: events.length })
} catch (error) {
console.error("Webhooks error:", error)
return NextResponse.json({ error: "Internal error" }, { status: 500 })
}
}