Files
democratic-money/src/app/api/rewards/redeem/route.ts
root a3f08242fe first commit
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 19:20:03 +00:00

80 lines
2.2 KiB
TypeScript

import { NextResponse } from "next/server";
import { z } from "zod";
import { auth } from "@/auth";
import { isAdminRole } from "@/lib/admin";
import { prisma } from "@/lib/prisma";
const bodySchema = z.object({
slug: z.string().min(1),
});
export async function POST(req: Request) {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
try {
const json = await req.json();
const { slug } = bodySchema.parse(json);
const sku = await prisma.prizeSku.findUnique({ where: { slug } });
if (!sku) {
return NextResponse.json({ error: "Not found" }, { status: 404 });
}
const admin = isAdminRole(session.user!.role);
const result = await prisma.$transaction(async (tx) => {
if (!admin) {
const wallet = await tx.wallet.findUnique({ where: { userId: session.user!.id } });
if (!wallet || wallet.balanceCredits < sku.costCredits) {
throw new Error("INSUFFICIENT_CREDITS");
}
}
const redemption = await tx.redemption.create({
data: {
userId: session.user!.id,
prizeSkuId: sku.id,
creditsSpent: admin ? 0 : sku.costCredits,
},
});
if (!admin) {
await tx.ledgerEntry.create({
data: {
userId: session.user!.id,
delta: -sku.costCredits,
type: "DEBIT_SPEND",
redemptionId: redemption.id,
memo: `Redeem: ${sku.title}`,
},
});
await tx.wallet.update({
where: { userId: session.user!.id },
data: { balanceCredits: { decrement: sku.costCredits } },
});
}
return redemption.id;
});
return NextResponse.json({
ok: true,
redemptionId: result,
adminBypass: admin,
});
} catch (e) {
if (e instanceof z.ZodError) {
return NextResponse.json({ error: "Invalid input", issues: e.issues }, { status: 400 });
}
if (e instanceof Error && e.message === "INSUFFICIENT_CREDITS") {
return NextResponse.json({ error: "Insufficient BLW (Blue Wave)" }, { status: 402 });
}
console.error(e);
return NextResponse.json({ error: "Redeem failed" }, { status: 500 });
}
}