172 lines
5.2 KiB
TypeScript
172 lines
5.2 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { Button } from "./Button";
|
|
|
|
interface FormState {
|
|
name: string;
|
|
email: string;
|
|
phone: string;
|
|
message: string;
|
|
}
|
|
|
|
interface FormErrors {
|
|
name?: string;
|
|
email?: string;
|
|
message?: string;
|
|
}
|
|
|
|
export function ContactForm() {
|
|
const [form, setForm] = useState<FormState>({
|
|
name: "",
|
|
email: "",
|
|
phone: "",
|
|
message: "",
|
|
});
|
|
const [errors, setErrors] = useState<FormErrors>({});
|
|
const [submitted, setSubmitted] = useState(false);
|
|
|
|
function validate(): FormErrors {
|
|
const newErrors: FormErrors = {};
|
|
if (!form.name.trim()) newErrors.name = "Bitte geben Sie Ihren Namen ein.";
|
|
if (!form.email.trim()) {
|
|
newErrors.email = "Bitte geben Sie Ihre E-Mail-Adresse ein.";
|
|
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.email)) {
|
|
newErrors.email = "Bitte geben Sie eine gültige E-Mail-Adresse ein.";
|
|
}
|
|
if (!form.message.trim())
|
|
newErrors.message = "Bitte geben Sie eine Nachricht ein.";
|
|
return newErrors;
|
|
}
|
|
|
|
function handleSubmit(e: React.FormEvent) {
|
|
e.preventDefault();
|
|
const newErrors = validate();
|
|
setErrors(newErrors);
|
|
if (Object.keys(newErrors).length === 0) {
|
|
setSubmitted(true);
|
|
}
|
|
}
|
|
|
|
function handleChange(
|
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
|
) {
|
|
const { name, value } = e.target;
|
|
setForm((prev) => ({ ...prev, [name]: value }));
|
|
if (errors[name as keyof FormErrors]) {
|
|
setErrors((prev) => ({ ...prev, [name]: undefined }));
|
|
}
|
|
}
|
|
|
|
if (submitted) {
|
|
return (
|
|
<div
|
|
className="border border-success p-8 text-center"
|
|
style={{ borderRadius: "var(--radius-md)" }}
|
|
role="status"
|
|
aria-live="polite"
|
|
>
|
|
<p className="text-lg font-bold mb-2">Vielen Dank für Ihre Nachricht!</p>
|
|
<p className="text-muted">
|
|
Wir werden uns so schnell wie möglich bei Ihnen melden.
|
|
</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<form onSubmit={handleSubmit} noValidate className="space-y-6">
|
|
<div>
|
|
<label htmlFor="contact-name" className="block text-sm font-medium mb-1.5">
|
|
Name <span aria-hidden="true">*</span>
|
|
</label>
|
|
<input
|
|
id="contact-name"
|
|
name="name"
|
|
type="text"
|
|
autoComplete="name"
|
|
aria-required="true"
|
|
aria-invalid={!!errors.name}
|
|
aria-describedby={errors.name ? "name-error" : undefined}
|
|
value={form.name}
|
|
onChange={handleChange}
|
|
className="w-full border border-border px-4 py-3 text-sm bg-background text-foreground transition-colors focus:border-primary focus:outline-none"
|
|
style={{ borderRadius: "var(--radius-sm)" }}
|
|
/>
|
|
{errors.name && (
|
|
<p id="name-error" className="mt-1.5 text-sm text-error" role="alert">
|
|
{errors.name}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="contact-email" className="block text-sm font-medium mb-1.5">
|
|
E-Mail <span aria-hidden="true">*</span>
|
|
</label>
|
|
<input
|
|
id="contact-email"
|
|
name="email"
|
|
type="email"
|
|
autoComplete="email"
|
|
aria-required="true"
|
|
aria-invalid={!!errors.email}
|
|
aria-describedby={errors.email ? "email-error" : undefined}
|
|
value={form.email}
|
|
onChange={handleChange}
|
|
className="w-full border border-border px-4 py-3 text-sm bg-background text-foreground transition-colors focus:border-primary focus:outline-none"
|
|
style={{ borderRadius: "var(--radius-sm)" }}
|
|
/>
|
|
{errors.email && (
|
|
<p id="email-error" className="mt-1.5 text-sm text-error" role="alert">
|
|
{errors.email}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="contact-phone" className="block text-sm font-medium mb-1.5">
|
|
Telefon
|
|
</label>
|
|
<input
|
|
id="contact-phone"
|
|
name="phone"
|
|
type="tel"
|
|
autoComplete="tel"
|
|
value={form.phone}
|
|
onChange={handleChange}
|
|
className="w-full border border-border px-4 py-3 text-sm bg-background text-foreground transition-colors focus:border-primary focus:outline-none"
|
|
style={{ borderRadius: "var(--radius-sm)" }}
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="contact-message" className="block text-sm font-medium mb-1.5">
|
|
Nachricht <span aria-hidden="true">*</span>
|
|
</label>
|
|
<textarea
|
|
id="contact-message"
|
|
name="message"
|
|
rows={5}
|
|
aria-required="true"
|
|
aria-invalid={!!errors.message}
|
|
aria-describedby={errors.message ? "message-error" : undefined}
|
|
value={form.message}
|
|
onChange={handleChange}
|
|
className="w-full border border-border px-4 py-3 text-sm bg-background text-foreground transition-colors focus:border-primary focus:outline-none resize-y"
|
|
style={{ borderRadius: "var(--radius-sm)" }}
|
|
/>
|
|
{errors.message && (
|
|
<p id="message-error" className="mt-1.5 text-sm text-error" role="alert">
|
|
{errors.message}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<Button type="submit" variant="primary">
|
|
Nachricht senden
|
|
</Button>
|
|
</form>
|
|
);
|
|
}
|