MBO-Tech-IT-Webseite/modules/02-admin-auth/files/app/api/admin/anfragen-action/route.ts

166 lines
4.8 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { createServiceClient } from "@/lib/supabase";
import { verifyActionToken } from "@/lib/admin-auth";
import { markActionTokenUsed } from "@/lib/token-blacklist";
import { sendeKundenStatusEmail, getKalenderTage } from "@/lib/mailer";
// Verfügbarkeit aktualisieren wenn Status sich ändert
async function aktualisiereVerfuegbarkeit(
db: ReturnType<typeof createServiceClient>,
anfrageId: string,
neuerStatus: string
) {
if (neuerStatus === "bestaetigt") {
await db
.from("verfuegbarkeit")
.update({ status: "belegt" })
.eq("anfrage_id", anfrageId);
} else if (neuerStatus === "abgelehnt") {
await db
.from("verfuegbarkeit")
.delete()
.eq("anfrage_id", anfrageId);
}
}
export async function GET(req: NextRequest) {
const token = req.nextUrl.searchParams.get("token");
if (!token) {
return NextResponse.json(
{ error: "Token erforderlich" },
{ status: 400 }
);
}
// Token validieren
const actionToken = await verifyActionToken(token);
if (!actionToken) {
return NextResponse.json(
{ error: "Token ungültig oder abgelaufen" },
{ status: 400 }
);
}
const { anfrageId, status } = actionToken;
const appUrl = process.env.APP_URL ?? "https://www.mietparkhahn.de";
const ipAddr = req.headers.get("x-forwarded-for") || req.headers.get("x-real-ip") || "unknown";
// ✅ Token als verwendet markieren (One-Time-Use)
const [, tokenSig] = token.split(".");
await markActionTokenUsed(tokenSig, anfrageId, status, ipAddr);
try {
const db = createServiceClient();
// Aktuellen Status laden (vor dem Update) für Audit Log
const { data: currentData } = await db
.from("anfragen")
.select("status")
.eq("id", anfrageId)
.single();
const alterStatus = currentData?.status || null;
// Status aktualisieren
const { error } = await db
.from("anfragen")
.update({ status })
.eq("id", anfrageId);
if (error) {
console.error(`[Action] Fehler beim Update von Anfrage ${anfrageId}:`, error);
return NextResponse.json(
{ error: "Statusaktualisierung fehlgeschlagen" },
{ status: 500 }
);
}
// Status-Änderung ins Audit Log schreiben
if (alterStatus !== status) {
const { error: auditError } = await db
.from("anfrage_status_audit")
.insert({
anfrage_id: anfrageId,
status_von: alterStatus,
status_zu: status,
bearbeitet_von: "action-link",
notizen: null,
});
if (auditError) {
console.error(`[Action] Fehler beim Schreiben des Status-Audit-Logs für Anfrage ${anfrageId}:`, auditError);
}
}
// Verfügbarkeit aktualisieren
await aktualisiereVerfuegbarkeit(db, anfrageId, status);
// Anfrage-Daten + Positionen für E-Mail laden
const { data: anfrage } = await db
.from("anfragen")
.select("firma, email, notizen")
.eq("id", anfrageId)
.single();
if (anfrage?.email) {
let positionen: any[] = [];
// Positionen laden
const { data: posData, error: posError } = await db
.from("anfragen_positionen")
.select("*")
.eq("anfrage_id", anfrageId)
.order("mietbeginn");
if (posError) {
console.error(
`[Action] Fehler beim Laden von Positionen für Anfrage ${anfrageId}:`,
posError
);
}
// Positionen formatieren für Email-Template
positionen = (posData ?? []).map((p: any) => ({
maschineName: p.maschine_name || "Unbekannte Maschine",
mietbeginn: p.mietbeginn,
mietende: p.mietende,
gesamtTage: p.gesamt_tage || getKalenderTage(p.mietbeginn, p.mietende),
lieferung: p.lieferung || false,
lieferadresse: p.lieferadresse || "",
anmerkung: p.anmerkung || "",
tagessatz: p.tagessatz,
preisStufe: null,
zubehoer: [],
}));
console.log(
`[Action] Anfrage ${anfrageId}: ${positionen.length} Positionen geladen`
);
// Kunden-Status-Email versenden
sendeKundenStatusEmail({
anfrageId,
firma: anfrage.firma,
email: anfrage.email,
neuerStatus: status as "bestaetigt" | "abgelehnt" | "abgeschlossen",
notizen: anfrage.notizen || undefined,
positionen: positionen.length > 0 ? positionen : undefined,
}).catch((err) =>
console.error("[Action] Fehler beim Versand der Status-Email:", err)
);
}
// Redirect zum Admin-Panel mit Success-Indicator
return NextResponse.redirect(
`${appUrl}/admin/anfragen/${anfrageId}?action=done`
);
} catch (err) {
console.error("[Action] Unerwarteter Fehler:", err);
return NextResponse.json(
{ error: "Ein Fehler ist aufgetreten" },
{ status: 500 }
);
}
}