Add contact email confirmation and abuse protection

This commit is contained in:
t.indorf
2026-05-16 11:38:30 +02:00
parent 9542def530
commit 0b80c62beb
12 changed files with 376 additions and 17 deletions
+41 -3
View File
@@ -11,6 +11,7 @@ import {
contactRequestSchema,
contactRequestTypeLabels,
type ContactRequestInput,
type ContactSubmissionPayload,
} from "@/lib/contact-schema";
import { Button } from "@/components/ui/button";
import {
@@ -44,16 +45,27 @@ export function ContactForm() {
},
});
function onSubmit(values: ContactRequestInput) {
function onSubmit(
values: ContactRequestInput,
event?: React.BaseSyntheticEvent,
) {
const formEl = event?.target as HTMLFormElement | undefined;
const website =
(formEl?.elements.namedItem("website") as HTMLInputElement | null)
?.value ?? "";
startTransition(async () => {
const result = await submitContactRequest(values);
const payload: ContactSubmissionPayload = { ...values, website };
const result = await submitContactRequest(payload);
if (!result.success) {
toast.error(result.error);
return;
}
toast.success("Danke! Wir melden uns in Kürze bei euch.");
toast.success(
"Danke! Wir haben dir eine Bestätigung an deine E-Mail-Adresse geschickt.",
);
form.reset({
name: "",
kitaName: "",
@@ -61,6 +73,10 @@ export function ContactForm() {
requestType: "DEMO",
message: "",
});
const honeypot = formEl?.elements.namedItem(
"website",
) as HTMLInputElement | null;
if (honeypot) honeypot.value = "";
});
}
@@ -171,6 +187,28 @@ export function ContactForm() {
)}
/>
<div
aria-hidden="true"
style={{
position: "absolute",
left: "-10000px",
top: "auto",
width: "1px",
height: "1px",
overflow: "hidden",
}}
>
<label htmlFor="contact-website">Website (bitte leer lassen)</label>
<input
id="contact-website"
type="text"
name="website"
tabIndex={-1}
autoComplete="off"
defaultValue=""
/>
</div>
<Button type="submit" size="lg" disabled={isPending} className="h-12">
{isPending ? (
<Loader2 className="h-4 w-4 animate-spin" />