Files
mb-grid-solutions.com/app/api/contact/route.ts
Marc Mintel 55cb073a6d
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 4s
Build & Deploy / 🧪 QA (push) Successful in 2m55s
Build & Deploy / 🏗️ Build (push) Successful in 11m40s
Build & Deploy / 🚀 Deploy (push) Failing after 8s
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 1s
feat(cms): migrate from directus to payloadcms
2026-02-27 12:56:35 +01:00

169 lines
5.2 KiB
TypeScript

import { NextResponse } from "next/server";
import { getPayload } from "payload";
import configPromise from "@payload-config";
import { getServerAppServices } from "@/lib/services/create-services.server";
import {
render,
ContactFormNotification,
ConfirmationMessage,
} from "@mintel/mail";
import React from "react";
export async function POST(req: Request) {
const services = getServerAppServices();
const logger = services.logger.child({ action: "contact_submission" });
// Set analytics context from request headers for high-fidelity server-side tracking
if (services.analytics.setServerContext) {
services.analytics.setServerContext({
userAgent: req.headers.get("user-agent") || undefined,
language: req.headers.get("accept-language")?.split(",")[0] || undefined,
referrer: req.headers.get("referer") || undefined,
ip: req.headers.get("x-forwarded-for")?.split(",")[0] || undefined,
});
}
try {
const { name, email, company, message, website } = await req.json();
// Track attempt
services.analytics.track("contact-form-attempt");
// Honeypot check
if (website) {
logger.info("Spam detected (honeypot)");
return NextResponse.json({ message: "Ok" });
}
// Validation
if (!name || name.length < 2 || name.length > 100) {
return NextResponse.json({ error: "Ungültiger Name" }, { status: 400 });
}
if (!email || !/^\S+@\S+\.\S+$/.test(email)) {
return NextResponse.json({ error: "Ungültige E-Mail" }, { status: 400 });
}
if (!message || message.length < 20) {
return NextResponse.json({ error: "message_too_short" }, { status: 400 });
}
if (message.length > 4000) {
return NextResponse.json({ error: "message_too_long" }, { status: 400 });
}
const payload = await getPayload({ config: configPromise });
// 1. Payload save
let payloadSaved = false;
try {
await payload.create({
collection: "form-submissions",
data: {
name,
email,
company: company || "Nicht angegeben",
message,
},
});
logger.info("Contact submission saved to PayloadCMS");
payloadSaved = true;
} catch (payloadError) {
const errorMessage =
payloadError instanceof Error
? payloadError.message
: String(payloadError);
logger.error("Failed to save to Payload", {
error: errorMessage,
details: payloadError,
});
services.errors.captureException(payloadError, { phase: "payload_save" });
}
// 2. Email sending via Payload (which uses configured nodemailer)
try {
const { config } = await import("@/lib/config");
const clientName = "MB Grid Solutions";
// 2a. Notification to MB Grid
const notificationHtml = await render(
React.createElement(ContactFormNotification, {
name,
email,
message,
company,
}),
);
await payload.sendEmail({
from: config.mail.from,
to:
config.mail.recipients.join(",") ||
process.env.CONTACT_RECIPIENT ||
"info@mb-grid-solutions.com",
replyTo: email,
subject: `Kontaktanfrage von ${name}`,
html: notificationHtml,
});
// 2b. Confirmation to the User
try {
const confirmationHtml = await render(
React.createElement(ConfirmationMessage, {
name,
clientName,
}),
);
await payload.sendEmail({
from: config.mail.from,
to: email,
subject: `Ihre Kontaktanfrage bei ${clientName}`,
html: confirmationHtml,
});
} catch (confirmError) {
logger.warn(
"Failed to send confirmation email, but notification was sent",
{ error: confirmError },
);
}
logger.info("Emails sent successfully");
// Notify success for important leads
await services.notifications.notify({
title: "📩 Neue Kontaktanfrage",
message: `Anfrage von ${name} (${email}) erhalten.\nFirma: ${company || "Nicht angegeben"}`,
priority: 5,
});
} catch (smtpError) {
logger.error("SMTP Error", { error: smtpError });
services.errors.captureException(smtpError, { phase: "smtp_send" });
if (!payloadSaved) {
return NextResponse.json(
{ error: "Systemfehler (Speicherung und Versand fehlgeschlagen)" },
{ status: 500 },
);
}
await services.notifications.notify({
title: "🚨 SMTP Fehler (Kontaktformular)",
message: `Anfrage von ${name} (${email}) in Payload gespeichert, aber E-Mail-Versand fehlgeschlagen: ${smtpError instanceof Error ? smtpError.message : String(smtpError)}`,
priority: 8,
});
}
// Track success
services.analytics.track("contact-form-success", {
has_company: Boolean(company),
});
return NextResponse.json({ message: "Ok" });
} catch (error) {
logger.error("Global API Error", { error });
services.errors.captureException(error, { phase: "api_global" });
return NextResponse.json(
{ error: "Interner Serverfehler" },
{ status: 500 },
);
}
}