Kontaktformular: Anfragen über die Kontakt-API, damit WEBklar per Mail davon erfährt

Bisher schrieb das Formular als Gast direkt in Appwrite, und niemand las die
Einträge. Jetzt geht es an POST /api/contact (webklar-webclaw-contact-api):
die API speichert in Appwrite und meldet jede Anfrage sofort an
support@webklar.com, Antworten gehen an die Absenderadresse.

- src/lib/contact.ts ersetzt src/lib/appwrite.ts, kein Appwrite-SDK mehr im Bundle
- Honeypot-Feld "website" (unsichtbar, nicht per Tab erreichbar)
- maxLength passend zu den Grenzen der API (120/200/200/4000)
- eigener Hinweis bei 429 (zu viele Anfragen)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-17 17:53:02 +00:00
1 parent 795c79d393
commit cbc149f9f8
6 files changed
+181 -63

No files matched your search

+28 -6
View File
@@ -1,5 +1,6 @@
import { useRef, useState } from "react";
import { usePageMeta } from "@/hooks/use-page-meta";
import { CONTACT_LIMITS, ContactSendError, sendContactMessage } from "@/lib/contact";
import "./unterseiten.css";
type Rueckmeldung = { art: "erfolg" | "fehler"; titel: string; text: string };
@@ -18,6 +19,7 @@ const Contact = () => {
email: "",
company: "",
message: "",
website: "",
});
const handleChange = (
@@ -35,20 +37,21 @@ const Contact = () => {
setIsSubmitting(true);
setRueckmeldung(null);
try {
// Das Appwrite-SDK wird erst beim Absenden geladen (Spezifikation 9.7)
const { createContactDocument } = await import("@/lib/appwrite");
await createContactDocument(formData);
await sendContactMessage(formData);
setRueckmeldung({
art: "erfolg",
titel: "Nachricht gesendet.",
text: "Wir melden uns spätestens am nächsten Werktag bei Ihnen.",
});
setFormData({ name: "", email: "", company: "", message: "" });
} catch {
setFormData({ name: "", email: "", company: "", message: "", website: "" });
} catch (fehler) {
setRueckmeldung({
art: "fehler",
titel: "Die Nachricht konnte nicht gesendet werden.",
text: "Bitte versuchen Sie es noch einmal oder schreiben Sie uns direkt per E-Mail.",
text:
fehler instanceof ContactSendError && fehler.tooMany
? "Es kamen gerade zu viele Anfragen. Bitte versuchen Sie es in ein paar Minuten noch einmal oder schreiben Sie uns direkt per E-Mail."
: "Bitte versuchen Sie es noch einmal oder schreiben Sie uns direkt per E-Mail.",
});
} finally {
setIsSubmitting(false);
@@ -83,6 +86,7 @@ const Contact = () => {
type="text"
required
autoComplete="name"
maxLength={CONTACT_LIMITS.name}
value={formData.name}
onChange={handleChange}
placeholder="Ihr Name"
@@ -96,6 +100,7 @@ const Contact = () => {
type="email"
required
autoComplete="email"
maxLength={CONTACT_LIMITS.email}
value={formData.email}
onChange={handleChange}
placeholder="ihre@email.de"
@@ -112,6 +117,7 @@ const Contact = () => {
name="company"
type="text"
autoComplete="organization"
maxLength={CONTACT_LIMITS.company}
value={formData.company}
onChange={handleChange}
placeholder="Name Ihres Betriebs"
@@ -124,12 +130,28 @@ const Contact = () => {
id="message"
name="message"
required
maxLength={CONTACT_LIMITS.message}
value={formData.message}
onChange={handleChange}
placeholder="z. B. neue Website, Online-Shop, Web-App oder Automatisierung …"
/>
</div>
{/* Honeypot gegen Bots: für Menschen unsichtbar und nicht erreichbar, die Kontakt-API verwirft
Anfragen, in denen es ausgefüllt ist */}
<div className="wk-visually-hidden" aria-hidden="true">
<label htmlFor="website">Website (bitte leer lassen)</label>
<input
id="website"
name="website"
type="text"
tabIndex={-1}
autoComplete="off"
value={formData.website}
onChange={handleChange}
/>
</div>
<div className="wk-form__senden">
<button type="submit" className="wk-btn wk-btn--primary" aria-disabled={isSubmitting}>
{isSubmitting ? "Wird gesendet …" : "Nachricht senden"}