166 lines
4.8 KiB
TypeScript
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 }
|
|
);
|
|
}
|
|
}
|