Files
gutscheintracker/app/api/vouchers/route.ts
T

76 lines
3.5 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { getDb } from "@/lib/db";
import { getVoucherStatus } from "@/lib/voucher-status";
import { validateVoucher, isExpiringSoon, parseVoucherFields } from "@/lib/vouchers";
import { withLogoUrl } from "@/lib/logo";
import { getViewer } from "@/lib/viewer";
import { canAccess, contactUsableIn, resolveTarget, scopeWhere } from "@/lib/access";
export async function GET(req: NextRequest) {
const viewer = await getViewer();
if (!viewer) return NextResponse.json({ error: "unauthorized" }, { status: 401 });
const filter = req.nextUrl.searchParams.get("filter");
const scopeParam = req.nextUrl.searchParams.get("bestand") ?? (viewer.householdId !== null ? "household" : "private");
const db = getDb();
const scoped = await db.voucher.findMany({ where: scopeWhere(viewer), orderBy: { createdAt: "desc" } });
const all = scopeParam === "household" && viewer.householdId !== null
? scoped.filter((v) => v.householdId === viewer.householdId)
: scopeParam === "private"
? scoped.filter((v) => v.householdId === null)
: scoped;
const filtered = all.filter((v) => {
const s = getVoucherStatus(v);
if (filter === "eingeloest") return s === "eingeloest";
if (filter === "abgelaufen") return s === "abgelaufen";
if (filter === "bald") return s === "aktiv" && isExpiringSoon(v.ablaufdatum);
if (filter === "aktiv") return s === "aktiv";
return true;
});
return NextResponse.json(await Promise.all(filtered.map(withLogoUrl)));
}
export async function POST(req: NextRequest) {
const viewer = await getViewer();
if (!viewer) return NextResponse.json({ error: "unauthorized" }, { status: 401 });
const body = await req.json();
const target = resolveTarget(viewer, body.scope ?? body.ziel);
if (!target.ok) return NextResponse.json({ errors: ["scope"], message: target.error }, { status: 400 });
const { fields, errors: parseErrors } = parseVoucherFields(body);
const errs = [...parseErrors, ...validateVoucher(fields)];
if (errs.length) return NextResponse.json({ errors: errs }, { status: 400 });
const db = getDb();
if (fields.contactIds.length) {
const found = await db.contact.findMany({ where: { id: { in: fields.contactIds } } });
if (found.length !== new Set(fields.contactIds).size) {
return NextResponse.json({ errors: ["contactIds"] }, { status: 400 });
}
const unusable = found.filter((c) => !contactUsableIn(viewer, target.householdId, c));
if (unusable.length) return NextResponse.json({ errors: ["contactIds"] }, { status: 403 });
}
const created = await db.voucher.create({
data: {
name: fields.name.trim(),
anbieter: fields.anbieter.trim(),
wertTyp: fields.wertTyp,
wertCents: fields.wertCents,
restCents: fields.restCents,
prozentWert: fields.prozentWert,
mindestbestellwertCents: fields.mindestbestellwertCents,
ablaufdatum: fields.ablaufdatum ? new Date(fields.ablaufdatum) : null,
codeText: fields.codeText,
kategorie: fields.kategorie,
notiz: fields.notiz,
providerDomain: fields.providerDomain,
createdBy: viewer.name,
shopUrl: fields.shopUrl,
ownerId: viewer.id,
householdId: target.householdId,
contacts: fields.contactIds.length ? { create: fields.contactIds.map((contactId) => ({ contactId })) } : undefined,
rules: {
create: fields.reminderDays.map((tageVorher) => ({ tageVorher })),
},
},
});
return NextResponse.json(created, { status: 201 });
}