108 lines
3.1 KiB
TypeScript
108 lines
3.1 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server"
|
|
import prisma from "@/lib/prisma"
|
|
import { createEventSchema } from "@/lib/validators"
|
|
import { resolveOrgId } from "@/lib/org"
|
|
|
|
interface PledgeSummary {
|
|
amountPence: number
|
|
status: string
|
|
}
|
|
|
|
interface EventRow {
|
|
id: string
|
|
name: string
|
|
slug: string
|
|
eventDate: Date | null
|
|
location: string | null
|
|
goalAmount: number | null
|
|
status: string
|
|
createdAt: Date
|
|
_count: { pledges: number; qrSources: number }
|
|
pledges: PledgeSummary[]
|
|
}
|
|
|
|
// GET all events for org (TODO: auth middleware)
|
|
export async function GET(request: NextRequest) {
|
|
try {
|
|
if (!prisma) {
|
|
return NextResponse.json([])
|
|
}
|
|
const orgId = await resolveOrgId(request.headers.get("x-org-id"))
|
|
if (!orgId) {
|
|
return NextResponse.json({ error: "Organization not found" }, { status: 404 })
|
|
}
|
|
|
|
const events = await prisma.event.findMany({
|
|
where: { organizationId: orgId },
|
|
include: {
|
|
_count: { select: { pledges: true, qrSources: true } },
|
|
pledges: {
|
|
select: { amountPence: true, status: true },
|
|
},
|
|
},
|
|
orderBy: { createdAt: "desc" },
|
|
}) as EventRow[]
|
|
|
|
const formatted = events.map((e: EventRow) => ({
|
|
id: e.id,
|
|
name: e.name,
|
|
slug: e.slug,
|
|
eventDate: e.eventDate,
|
|
location: e.location,
|
|
goalAmount: e.goalAmount,
|
|
status: e.status,
|
|
pledgeCount: e._count.pledges,
|
|
qrSourceCount: e._count.qrSources,
|
|
totalPledged: e.pledges.reduce((sum: number, p: PledgeSummary) => sum + p.amountPence, 0),
|
|
totalCollected: e.pledges
|
|
.filter((p: PledgeSummary) => p.status === "paid")
|
|
.reduce((sum: number, p: PledgeSummary) => sum + p.amountPence, 0),
|
|
createdAt: e.createdAt,
|
|
}))
|
|
|
|
return NextResponse.json(formatted)
|
|
} catch (error) {
|
|
console.error("Events GET error:", error)
|
|
return NextResponse.json({ error: "Internal error" }, { status: 500 })
|
|
}
|
|
}
|
|
|
|
// POST create event
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
if (!prisma) {
|
|
return NextResponse.json({ error: "Database not configured" }, { status: 503 })
|
|
}
|
|
const orgId = await resolveOrgId(request.headers.get("x-org-id"))
|
|
if (!orgId) {
|
|
return NextResponse.json({ error: "Organization not found" }, { status: 404 })
|
|
}
|
|
const body = await request.json()
|
|
|
|
const parsed = createEventSchema.safeParse(body)
|
|
if (!parsed.success) {
|
|
return NextResponse.json({ error: "Invalid data", details: parsed.error.flatten() }, { status: 400 })
|
|
}
|
|
|
|
const slug = parsed.data.name
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9]+/g, "-")
|
|
.replace(/^-|-$/g, "")
|
|
.slice(0, 50)
|
|
|
|
const event = await prisma.event.create({
|
|
data: {
|
|
...parsed.data,
|
|
slug: slug + "-" + Date.now().toString(36),
|
|
eventDate: parsed.data.eventDate ? new Date(parsed.data.eventDate) : null,
|
|
organizationId: orgId,
|
|
},
|
|
})
|
|
|
|
return NextResponse.json(event, { status: 201 })
|
|
} catch (error) {
|
|
console.error("Event creation error:", error)
|
|
return NextResponse.json({ error: "Internal error" }, { status: 500 })
|
|
}
|
|
}
|