import { NextRequest, NextResponse } from "next/server"; import { prisma } from "@/lib/prisma"; export const dynamic = "force-dynamic"; export const revalidate = 0; export async function GET(req: NextRequest) { const url = new URL(req.url); const limit = Math.min(parseInt(url.searchParams.get("limit") ?? "25"), 100); // Aggregate total donated per user const rows = await prisma.donation.groupBy({ by: ["userId"], where: { userId: { not: null }, status: "succeeded" }, _sum: { amountUsdCents: true }, _count: { id: true }, orderBy: { _sum: { amountUsdCents: "desc" } }, take: limit, }); // Fetch display names const userIds = rows.map((r) => r.userId).filter((id): id is string => id != null); const users = await prisma.user.findMany({ where: { id: { in: userIds } }, select: { id: true, name: true, email: true }, }); const userMap = new Map(users.map(u => [u.id, u])); const leaderboard = rows.map((row, idx) => { const uid = row.userId!; const user = userMap.get(uid); // Show name if present, else obfuscate email let displayName = user?.name ?? "Anonymous"; // Ghost donors have emails ending in leaderboard.local — show name only // Real donors: show first name + last initial, or truncated email const email = user?.email ?? ""; if (!user?.name && !email.endsWith("leaderboard.local")) { const [local] = email.split("@"); displayName = local.slice(0, 3) + "***"; } return { rank: idx + 1, displayName, totalUsdCents: row._sum.amountUsdCents ?? 0, donationCount: row._count.id, }; }); return NextResponse.json({ leaderboard }); }