diff --git a/app/api/contact/route.ts b/app/api/contact/route.ts
new file mode 100644
index 0000000..6153063
--- /dev/null
+++ b/app/api/contact/route.ts
@@ -0,0 +1,33 @@
+import { NextResponse } from "next/server";
+import { sendeKontaktEmail } from "@/lib/mailer";
+
+export async function POST(request: Request) {
+ let body: Record;
+ try {
+ body = await request.json();
+ } catch {
+ return NextResponse.json({ ok: false, error: "Ungültige Anfrage" }, { status: 400 });
+ }
+
+ const { name, email, betreff, nachricht, telefon } = body;
+ if (!name?.trim() || !email?.trim() || !betreff?.trim()) {
+ return NextResponse.json({ ok: false, error: "Pflichtfelder fehlen" }, { status: 400 });
+ }
+
+ const result = await sendeKontaktEmail({ name, email, betreff, nachricht, telefon });
+
+ if (!result.sent && !result.queued) {
+ console.error(
+ `[Contact] UNZUSTELLBAR – Anfrage konnte weder gesendet noch in Queue gespeichert werden:\n` +
+ ` Zeit: ${new Date().toISOString()}\n` +
+ ` Name: ${name}\n` +
+ ` E-Mail: ${email}\n` +
+ ` Telefon: ${telefon ?? "(nicht angegeben)"}\n` +
+ ` Betreff: ${betreff}\n` +
+ ` Nachricht: ${nachricht ?? "(keine)"}`
+ );
+ return NextResponse.json({ ok: false, error: "Mail konnte nicht gesendet werden" }, { status: 500 });
+ }
+
+ return NextResponse.json({ ok: true, queued: result.queued });
+}
diff --git a/components/Contact.tsx b/components/Contact.tsx
index 1f37602..d031829 100644
--- a/components/Contact.tsx
+++ b/components/Contact.tsx
@@ -1,3 +1,7 @@
+"use client";
+
+import { useState } from "react";
+
const contactItems = [
{
icon: (
@@ -21,7 +25,41 @@ const contactItems = [
},
];
+type Status = "idle" | "loading" | "success" | "error";
+
export default function Contact() {
+ const [name, setName] = useState("");
+ const [email, setEmail] = useState("");
+ const [betreff, setBetreff] = useState("");
+ const [nachricht, setNachricht] = useState("");
+ const [status, setStatus] = useState("idle");
+ const [errorMsg, setErrorMsg] = useState("");
+
+ async function handleSubmit(e: React.FormEvent) {
+ e.preventDefault();
+ setStatus("loading");
+ setErrorMsg("");
+
+ try {
+ const res = await fetch("/api/contact", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ name, email, betreff, nachricht }),
+ });
+ const data = await res.json();
+
+ if (!res.ok || !data.ok) {
+ setErrorMsg(data.error ?? "Unbekannter Fehler");
+ setStatus("error");
+ } else {
+ setStatus("success");
+ }
+ } catch {
+ setErrorMsg("Netzwerkfehler – bitte versuchen Sie es erneut.");
+ setStatus("error");
+ }
+ }
+
return (
- {/* Contact form */}
-
+
+
+ )}
{/* Divider */}
diff --git a/lib/email-queue.ts b/lib/email-queue.ts
index 2a38ff7..c55bb79 100644
--- a/lib/email-queue.ts
+++ b/lib/email-queue.ts
@@ -111,18 +111,19 @@ async function dbMarkRetry(id: string, retryCount: number, error: string) {
// ─── Queue-Eintrag speichern ───────────────────────────────────────────────
-export async function queueEmail(mail: QueuedMail): Promise
{
+export async function queueEmail(mail: QueuedMail): Promise {
if (!isSupabaseConfigured()) {
console.warn(
`[EmailQueue] Supabase nicht konfiguriert – Mail nicht gespeichert: "${mail.subject}" → "${mail.mail_to}"`
);
- return;
+ return false;
}
const saved = await dbInsert(mail);
if (saved) {
console.log(`[EmailQueue] "${mail.subject}" → "${mail.mail_to}" in Queue gespeichert`);
processQueue().catch(() => {});
}
+ return saved;
}
// ─── Worker ───────────────────────────────────────────────────────────────
diff --git a/lib/mailer.ts b/lib/mailer.ts
index b136847..0d451aa 100644
--- a/lib/mailer.ts
+++ b/lib/mailer.ts
@@ -22,7 +22,7 @@ const transporter = nodemailer.createTransport({
export interface KontaktEmailData {
name: string;
anrede?: string;
- telefon: string;
+ telefon?: string;
email: string;
betreff: string;
nachricht?: string;
@@ -37,18 +37,22 @@ interface MailOptions {
html: string;
}
-async function sendWithFallback(options: MailOptions, label: string) {
+async function sendWithFallback(
+ options: MailOptions,
+ label: string
+): Promise<{ sent: boolean; queued: boolean }> {
if (!options.to) {
console.error(`[Mailer] Kein Empfänger für "${label}" – Mail übersprungen`);
- return;
+ return { sent: false, queued: false };
}
try {
await transporter.sendMail(options);
console.log(`[Mailer] ✓ Mail "${label}" an "${options.to}" gesendet`);
+ return { sent: true, queued: false };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
- console.error(`[Mailer] ✗ Mail "${label}" fehlgeschlagen (${msg}) – in Queue gespeichert`);
- await queueEmail({
+ console.error(`[Mailer] ✗ Mail "${label}" fehlgeschlagen (${msg}) – versuche Queue`);
+ const queued = await queueEmail({
mail_from: options.from,
mail_to: options.to,
reply_to: options.replyTo,
@@ -56,10 +60,13 @@ async function sendWithFallback(options: MailOptions, label: string) {
html: options.html,
body_text: options.text,
});
+ return { sent: false, queued };
}
}
-export async function sendeKontaktEmail(data: KontaktEmailData) {
+export async function sendeKontaktEmail(
+ data: KontaktEmailData
+): Promise<{ sent: boolean; queued: boolean }> {
const anrede = data.anrede
? `${data.anrede.charAt(0).toUpperCase() + data.anrede.slice(1)} `
: "";
@@ -77,7 +84,7 @@ export async function sendeKontaktEmail(data: KontaktEmailData) {
Kontaktanfrage von ${anrede}${data.name}
@@ -93,13 +100,13 @@ export async function sendeKontaktEmail(data: KontaktEmailData) {