MBO-Tech-IT-Webseite/components/Contact.tsx

236 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useState } from "react";
const contactItems = [
{
icon: (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
),
label: "Telefon",
value: "+49 171 9345193",
href: "tel:+4917193451093",
},
{
icon: (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
),
label: "E-Mail",
value: "kontakt@mbo-tech-it.de",
href: "mailto:kontakt@mbo-tech-it.de",
},
];
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<Status>("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 (
<section id="contact" className="py-24 px-4 sm:px-6 lg:px-8 relative">
<div className="absolute inset-0 bg-[#e8eef4] dark:bg-[#111925]" />
<div className="absolute inset-0 bg-grid opacity-40" />
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_center,rgba(249,115,22,0.07)_0%,transparent_70%)]" />
<div className="max-w-4xl mx-auto relative">
{/* Header */}
<div className="text-center mb-12">
<span className="text-orange-400 font-mono text-xs font-bold tracking-[0.25em] uppercase">
Kontakt
</span>
<h2 className="text-4xl sm:text-5xl font-black text-slate-900 dark:text-white mt-3 mb-4">
Projekt anfragen
</h2>
<p className="text-slate-600 dark:text-slate-400 text-lg max-w-xl mx-auto">
Sie haben ein IT-Projekt oder eine Frage? Schreiben Sie uns &mdash;
wir melden uns schnellstmöglich bei Ihnen.
</p>
</div>
<div className="bg-white dark:bg-gray-900 border border-slate-200 dark:border-gray-800 rounded-3xl p-8 sm:p-10">
{status === "success" ? (
<div className="flex flex-col items-center justify-center py-10 text-center">
<div className="w-16 h-16 rounded-full bg-orange-500/10 border border-orange-500/30 flex items-center justify-center mb-6">
<svg className="w-8 h-8 text-orange-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
</div>
<h3 className="text-2xl font-bold text-slate-900 dark:text-white mb-2">Anfrage gesendet!</h3>
<p className="text-slate-600 dark:text-slate-400 mb-8">
Wir haben Ihre Nachricht erhalten und melden uns schnellstmöglich bei Ihnen.
</p>
<button
onClick={() => {
setStatus("idle");
setName("");
setEmail("");
setBetreff("");
setNachricht("");
}}
className="btn-secondary px-6 py-2"
>
Neue Anfrage
</button>
</div>
) : (
<form className="space-y-6" onSubmit={handleSubmit}>
<div className="grid sm:grid-cols-2 gap-6">
<div>
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Name</label>
<input
type="text"
required
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Max Mustermann"
className="w-full px-4 py-3 rounded-xl bg-slate-50 dark:bg-[#111925] border border-slate-300 dark:border-gray-700 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-600 focus:outline-none focus:border-orange-500/60 focus:ring-1 focus:ring-orange-500/20 transition-colors"
/>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">E-Mail</label>
<input
type="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="max@beispiel.de"
className="w-full px-4 py-3 rounded-xl bg-slate-50 dark:bg-[#111925] border border-slate-300 dark:border-gray-700 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-600 focus:outline-none focus:border-orange-500/60 focus:ring-1 focus:ring-orange-500/20 transition-colors"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-slate-300 mb-2">Betreff</label>
<select
required
value={betreff}
onChange={(e) => setBetreff(e.target.value)}
className="w-full px-4 py-3 rounded-xl bg-slate-50 dark:bg-[#111925] border border-slate-300 dark:border-gray-700 text-slate-900 dark:text-white focus:outline-none focus:border-orange-500/60 focus:ring-1 focus:ring-orange-500/20 transition-colors appearance-none"
>
<option value="">Thema auswählen...</option>
<option value="hardware">Hard- &amp; Software</option>
<option value="netzwerk">Netzwerk &amp; WLAN</option>
<option value="backup">Datensicherung &amp; Backup</option>
<option value="docker">Docker Installation</option>
<option value="fernwartung">Fernwartung &amp; Support</option>
<option value="hetzner">Hetzner Cloud Infrastruktur</option>
<option value="beratung">IT-Beratung</option>
<option value="sicherheit">IT-Sicherheit &amp; Datenschutz</option>
<option value="kubernetes">Kubernetes Setup</option>
<option value="proxmox">Proxmox Virtualisierung</option>
<option value="server">Server &amp; Hosting</option>
<option value="webseiten">Webseiten &amp; Webanwendungen</option>
<option value="other">Sonstiges</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-slate-300 mb-2">Nachricht</label>
<textarea
rows={5}
value={nachricht}
onChange={(e) => setNachricht(e.target.value)}
placeholder="Beschreiben Sie Ihr Projekt oder Ihre Anfrage..."
className="w-full px-4 py-3 rounded-xl bg-slate-50 dark:bg-[#111925] border border-slate-300 dark:border-gray-700 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-600 focus:outline-none focus:border-orange-500/60 focus:ring-1 focus:ring-orange-500/20 transition-colors resize-none"
/>
</div>
{status === "error" && (
<div className="flex items-start gap-3 px-4 py-3 rounded-xl bg-red-500/10 border border-red-500/20 text-red-400 text-sm">
<svg className="w-5 h-5 mt-0.5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>
Nachricht konnte nicht gesendet werden. Bitte versuchen Sie es erneut oder
kontaktieren Sie uns direkt.
{errorMsg && <span className="block mt-1 text-red-400/70 text-xs">{errorMsg}</span>}
</span>
</div>
)}
<button
type="submit"
disabled={status === "loading"}
className="btn-primary w-full py-4 text-lg disabled:opacity-60 disabled:cursor-not-allowed flex items-center justify-center gap-2"
>
{status === "loading" ? (
<>
<svg className="w-5 h-5 animate-spin" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8z" />
</svg>
Wird gesendet...
</>
) : (
"Nachricht senden"
)}
</button>
</form>
)}
{/* Divider */}
<div className="flex items-center gap-4 my-8">
<div className="flex-1 h-px bg-slate-200 dark:bg-gray-800" />
<span className="text-slate-400 dark:text-slate-600 text-sm">oder direkt</span>
<div className="flex-1 h-px bg-slate-200 dark:bg-gray-800" />
</div>
{/* Contact info */}
<div className="flex flex-col sm:flex-row items-center justify-center gap-6">
{contactItems.map((item) => (
<a
key={item.label}
href={item.href}
data-source-element="kontakt-section"
className="flex items-center gap-3 text-slate-700 dark:text-slate-300 hover:text-orange-400 transition-colors duration-200 group"
>
<span className="w-10 h-10 rounded-lg bg-orange-500/10 border border-orange-500/20 flex items-center justify-center text-orange-400 group-hover:bg-orange-500/20 transition-colors duration-200">
{item.icon}
</span>
<div>
<div className="text-xs text-slate-500">{item.label}</div>
<div className="font-medium">{item.value}</div>
</div>
</a>
))}
</div>
</div>
</div>
</section>
);
}