76 lines
3.5 KiB
TypeScript
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 });
|
|
}
|