feat: Erinnerungs-Checkboxen, Anbieterlogos via Logo.dev, Kontakte in Einstellungen

This commit is contained in:
opencode committed 2026-10-18 12:25:56 +02:00
1 parent 11bef8748f
commit a1195223e0
18 files changed
+381 -50

No files matched your search

+15
View File
@@ -0,0 +1,15 @@
import { NextRequest, NextResponse } from "next/server";
import { searchLogos } from "@/lib/logo";
export async function GET(req: NextRequest) {
const q = req.nextUrl.searchParams.get("q") ?? "";
if (!q.trim()) return NextResponse.json([]);
try {
const candidates = await searchLogos(q);
return NextResponse.json(candidates);
} catch (err) {
const message = err instanceof Error ? err.message : "Logosuche fehlgeschlagen";
const status = message.includes("LOGO_DEV_SECRET_KEY") ? 503 : 502;
return NextResponse.json({ error: message }, { status });
}
}
+2 -1
View File
@@ -1,5 +1,6 @@
import { NextRequest, NextResponse } from "next/server";
import { getDb } from "@/lib/db";
import { withLogoUrl } from "@/lib/logo";
export async function GET(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
@@ -8,7 +9,7 @@ export async function GET(_req: NextRequest, { params }: { params: Promise<{ id:
const db = getDb();
const v = await db.voucher.findUnique({ where: { id: numId }, include: { contacts: { include: { contact: true } } } });
if (!v) return NextResponse.json({ error: "not found" }, { status: 404 });
return NextResponse.json(v);
return NextResponse.json(withLogoUrl(v));
}
export async function POST(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
+12 -4
View File
@@ -3,6 +3,7 @@ import { getDb } from "@/lib/db";
import { getVoucherStatus } from "@/lib/voucher-status";
import { validateVoucher, isExpiringSoon } from "@/lib/vouchers";
import { parseReminderDays } from "@/lib/reminders";
import { normalizeDomain, withLogoUrl } from "@/lib/logo";
export async function GET(req: NextRequest) {
const filter = req.nextUrl.searchParams.get("filter");
@@ -16,7 +17,7 @@ export async function GET(req: NextRequest) {
if (filter === "aktiv") return s === "aktiv";
return true;
});
return NextResponse.json(filtered);
return NextResponse.json(filtered.map(withLogoUrl));
}
export async function POST(req: NextRequest) {
@@ -43,15 +44,21 @@ export async function POST(req: NextRequest) {
return NextResponse.json({ errors: ["contactIds"] }, { status: 400 });
}
}
const providerDomain = normalizeDomain(
body.providerDomain === undefined || body.providerDomain === null ? null : String(body.providerDomain)
);
if (body.providerDomain !== undefined && body.providerDomain !== null && String(body.providerDomain).trim() !== "" && !providerDomain) {
return NextResponse.json({ errors: ["providerDomain"] }, { status: 400 });
}
const reminderRaw =
typeof body.reminderDays === "string"
? body.reminderDays
: Array.isArray(body.reminderDays)
? body.reminderDays.join(",")
? body.reminderDays
: undefined;
const reminderProvided = reminderRaw !== undefined && reminderRaw.trim() !== "";
const explicitNone = Array.isArray(body.reminderDays) && body.reminderDays.length === 0;
const reminderDays = parseReminderDays(reminderRaw);
if (reminderProvided && reminderDays.length === 0) {
if (!explicitNone && reminderRaw !== undefined && (typeof reminderRaw !== "string" || reminderRaw.trim() !== "") && reminderDays.length === 0) {
return NextResponse.json({ errors: ["reminderDays"] }, { status: 400 });
}
const created = await db.voucher.create({
@@ -64,6 +71,7 @@ export async function POST(req: NextRequest) {
codeText: input.codeText,
kategorie: input.kategorie,
notiz: input.notiz,
providerDomain,
contacts: contactIds.length ? { create: contactIds.map((contactId) => ({ contactId })) } : undefined,
rules: {
create: reminderDays.map((tageVorher) => ({ tageVorher })),