feat: add CMS inquiries and group bookings

This commit is contained in:
2026-09-17 15:48:40 +02:00
parent 97dd32a2b4
commit a2b3e99174
28 changed files with 1200 additions and 45 deletions
+33 -22
View File
@@ -5,37 +5,48 @@ import { track } from "@/lib/analytics/client";
import { TextField, TextAreaField } from "@/components/FormField";
type ContactFormProps = {
toEmail: string;
toEmail?: string;
subjectPrefix?: string;
type?: "contact" | "appointment";
submitLabel?: string;
};
/**
* Opens the visitor's email client with a pre-filled message. There is no
* backend configured yet — swap this for a Server Action once a mail
* provider is connected.
*/
export function ContactForm({
toEmail,
subjectPrefix = "Nachricht über anouma.org",
subjectPrefix = "Allgemeine Anfrage",
type = "contact",
submitLabel = "Nachricht senden",
}: ContactFormProps) {
const [sent, setSent] = useState(false);
const [state, setState] = useState<{ sent: boolean; error?: string }>({ sent: false });
const [submitting, setSubmitting] = useState(false);
function handleSubmit(e: FormEvent<HTMLFormElement>) {
async function handleSubmit(e: FormEvent<HTMLFormElement>) {
e.preventDefault();
const data = new FormData(e.currentTarget);
const name = String(data.get("name") ?? "");
const email = String(data.get("email") ?? "");
const message = String(data.get("message") ?? "");
const subject = encodeURIComponent(`${subjectPrefix} von ${name}`);
const body = encodeURIComponent(`${message}\n\n– ${name} (${email})`);
window.location.href = `mailto:${toEmail}?subject=${subject}&body=${body}`;
// Event only — never the form's name/email/message content, see
// lib/analytics/events.ts and the data-minimization requirement.
track("contact_clicked");
setSent(true);
setSubmitting(true);
setState({ sent: false });
try {
const response = await fetch("/api/contact/inquiry", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name, email, message, subject: `${subjectPrefix} von ${name}`, type }),
});
const result = await response.json().catch(() => ({}));
if (!response.ok) {
setState({ sent: false, error: result.error || "Die Nachricht konnte nicht gesendet werden." });
setSubmitting(false);
return;
}
track("contact_clicked");
setState({ sent: true });
e.currentTarget.reset();
} catch {
setState({ sent: false, error: "Verbindung fehlgeschlagen. Bitte versuche es erneut." });
} finally {
setSubmitting(false);
}
}
return (
@@ -47,14 +58,14 @@ export function ContactForm({
type="submit"
className="inline-flex items-center justify-center rounded-full bg-anouma-mauve-dark px-7 py-3.5 text-sm font-medium tracking-wide text-white transition-colors duration-300 hover:bg-anouma-plum"
>
{submitLabel}
{submitting ? "Wird gesendet …" : submitLabel}
</button>
{sent && (
{state.sent && (
<p className="text-sm text-anouma-olive" role="status">
Dein E-Mail-Programm sollte sich jetzt geöffnet haben. Falls nicht, schreib gerne direkt an{" "}
{toEmail}.
Danke, deine Nachricht ist angekommen. Anna antwortet dir per E-Mail; du kannst direkt auf ihre Antwort reagieren.
</p>
)}
{state.error && <p className="text-sm text-red-700" role="alert">{state.error}</p>}
</form>
);
}