fix(forms): repair public form validation and reset
This commit is contained in:
parent
3456b04ed4
commit
7d5689cfa4
4 changed files with 24 additions and 17 deletions
|
|
@ -13,7 +13,7 @@ export async function POST(request: Request) {
|
||||||
const subject = text(form.get("subject"));
|
const subject = text(form.get("subject"));
|
||||||
const message = text(form.get("message"));
|
const message = text(form.get("message"));
|
||||||
|
|
||||||
if (!name || !email.includes("@") || !subject || message.length < 10 || form.get("privacy") !== "on") {
|
if (!name || !email.includes("@") || !subject || message.length < 10 || form.get("privacyAccepted") !== "on") {
|
||||||
return NextResponse.json({ message: "Bitte füllen Sie alle Pflichtfelder aus." }, { status: 400 });
|
return NextResponse.json({ message: "Bitte füllen Sie alle Pflichtfelder aus." }, { status: 400 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@ export async function POST(request: Request) {
|
||||||
const model = form.get("model");
|
const model = form.get("model");
|
||||||
const deviceType = form.get("deviceType");
|
const deviceType = form.get("deviceType");
|
||||||
const description = form.get("description");
|
const description = form.get("description");
|
||||||
const privacy = form.get("privacy");
|
const privacyAccepted = form.get("privacyAccepted");
|
||||||
|
|
||||||
if (!required(name) || !required(email) || !required(manufacturer) || !required(model) || !required(deviceType) || !required(description) || privacy !== "on") {
|
if (!required(name) || !required(email) || !required(manufacturer) || !required(model) || !required(deviceType) || !required(description) || privacyAccepted !== "on") {
|
||||||
return NextResponse.json({ message: "Bitte füllen Sie alle Pflichtfelder aus." }, { status: 400 });
|
return NextResponse.json({ message: "Bitte füllen Sie alle Pflichtfelder aus." }, { status: 400 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, type FormEvent } from "react";
|
import { useRef, useState, type FormEvent } from "react";
|
||||||
|
|
||||||
export default function ContactForm() {
|
export default function ContactForm() {
|
||||||
|
const formRef = useRef<HTMLFormElement>(null);
|
||||||
const [message, setMessage] = useState("");
|
const [message, setMessage] = useState("");
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const [pending, setPending] = useState(false);
|
const [pending, setPending] = useState(false);
|
||||||
|
|
@ -16,8 +17,9 @@ export default function ContactForm() {
|
||||||
const email = String(form.get("email") ?? "").trim();
|
const email = String(form.get("email") ?? "").trim();
|
||||||
const subject = String(form.get("subject") ?? "").trim();
|
const subject = String(form.get("subject") ?? "").trim();
|
||||||
const text = String(form.get("message") ?? "").trim();
|
const text = String(form.get("message") ?? "").trim();
|
||||||
|
const privacyAccepted = form.get("privacyAccepted") === "on";
|
||||||
|
|
||||||
if (!name || !email.includes("@") || !subject || text.length < 10 || form.get("privacy") !== "on") {
|
if (!name || !email.includes("@") || !subject || text.length < 10 || !privacyAccepted) {
|
||||||
setError("Bitte füllen Sie alle Pflichtfelder aus und bestätigen Sie die Datenschutz-Hinweise.");
|
setError("Bitte füllen Sie alle Pflichtfelder aus und bestätigen Sie die Datenschutz-Hinweise.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -27,17 +29,17 @@ export default function ContactForm() {
|
||||||
const response = await fetch("/api/contact", { method: "POST", body: form });
|
const response = await fetch("/api/contact", { method: "POST", body: form });
|
||||||
const result = await response.json() as { message?: string };
|
const result = await response.json() as { message?: string };
|
||||||
if (!response.ok) throw new Error(result.message ?? "Nachricht konnte nicht gesendet werden.");
|
if (!response.ok) throw new Error(result.message ?? "Nachricht konnte nicht gesendet werden.");
|
||||||
event.currentTarget.reset();
|
formRef.current?.reset();
|
||||||
setMessage(result.message ?? "Ihre Nachricht wurde vorbereitet.");
|
setMessage(result.message ?? "Ihre Nachricht wurde vorbereitet.");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(err instanceof Error ? err.message : "Nachricht konnte nicht gesendet werden.");
|
setError(err instanceof Error ? err.message : "Nachricht konnte nicht gesendet werden. Bitte versuchen Sie es später erneut.");
|
||||||
} finally {
|
} finally {
|
||||||
setPending(false);
|
setPending(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="form" onSubmit={submit} noValidate>
|
<form ref={formRef} className="form" onSubmit={submit} noValidate>
|
||||||
<div className="field">
|
<div className="field">
|
||||||
<label htmlFor="name">Name</label>
|
<label htmlFor="name">Name</label>
|
||||||
<input id="name" name="name" />
|
<input id="name" name="name" />
|
||||||
|
|
@ -59,7 +61,7 @@ export default function ContactForm() {
|
||||||
<textarea id="message" name="message" />
|
<textarea id="message" name="message" />
|
||||||
</div>
|
</div>
|
||||||
<label className="checkbox">
|
<label className="checkbox">
|
||||||
<input type="checkbox" name="privacy" />
|
<input type="checkbox" name="privacyAccepted" />
|
||||||
<span>Ich stimme zu, dass meine Angaben zur Bearbeitung der Kontaktanfrage verarbeitet werden.</span>
|
<span>Ich stimme zu, dass meine Angaben zur Bearbeitung der Kontaktanfrage verarbeitet werden.</span>
|
||||||
</label>
|
</label>
|
||||||
{error && <p className="error">{error}</p>}
|
{error && <p className="error">{error}</p>}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,21 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, type FormEvent } from "react";
|
import { useRef, useState, type FormEvent } from "react";
|
||||||
|
|
||||||
type ErrorField = "name" | "email" | "manufacturer" | "model" | "deviceType" | "description" | "privacy";
|
type ErrorField = "name" | "email" | "manufacturer" | "model" | "deviceType" | "description" | "privacyAccepted";
|
||||||
type Errors = Partial<Record<ErrorField, string>>;
|
type Errors = Partial<Record<ErrorField, string>>;
|
||||||
|
|
||||||
export default function RepairForm() {
|
export default function RepairForm() {
|
||||||
|
const formRef = useRef<HTMLFormElement>(null);
|
||||||
const [errors, setErrors] = useState<Errors>({});
|
const [errors, setErrors] = useState<Errors>({});
|
||||||
const [status, setStatus] = useState("");
|
const [status, setStatus] = useState("");
|
||||||
|
const [submitError, setSubmitError] = useState("");
|
||||||
const [pending, setPending] = useState(false);
|
const [pending, setPending] = useState(false);
|
||||||
|
|
||||||
async function submit(event: FormEvent<HTMLFormElement>) {
|
async function submit(event: FormEvent<HTMLFormElement>) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
setStatus("");
|
setStatus("");
|
||||||
|
setSubmitError("");
|
||||||
const form = new FormData(event.currentTarget);
|
const form = new FormData(event.currentTarget);
|
||||||
const nextErrors: Errors = {};
|
const nextErrors: Errors = {};
|
||||||
|
|
||||||
|
|
@ -22,7 +25,7 @@ export default function RepairForm() {
|
||||||
if (!String(form.get("model") ?? "").trim()) nextErrors.model = "Bitte nennen Sie das Modell.";
|
if (!String(form.get("model") ?? "").trim()) nextErrors.model = "Bitte nennen Sie das Modell.";
|
||||||
if (!String(form.get("deviceType") ?? "").trim()) nextErrors.deviceType = "Bitte wählen Sie die Geräteart aus.";
|
if (!String(form.get("deviceType") ?? "").trim()) nextErrors.deviceType = "Bitte wählen Sie die Geräteart aus.";
|
||||||
if (String(form.get("description") ?? "").trim().length < 20) nextErrors.description = "Bitte beschreiben Sie den Fehler mit mindestens 20 Zeichen.";
|
if (String(form.get("description") ?? "").trim().length < 20) nextErrors.description = "Bitte beschreiben Sie den Fehler mit mindestens 20 Zeichen.";
|
||||||
if (form.get("privacy") !== "on") nextErrors.privacy = "Bitte stimmen Sie der Verarbeitung Ihrer Angaben zu.";
|
if (form.get("privacyAccepted") !== "on") nextErrors.privacyAccepted = "Bitte stimmen Sie der Verarbeitung Ihrer Angaben zu.";
|
||||||
|
|
||||||
setErrors(nextErrors);
|
setErrors(nextErrors);
|
||||||
if (Object.keys(nextErrors).length > 0) return;
|
if (Object.keys(nextErrors).length > 0) return;
|
||||||
|
|
@ -35,17 +38,18 @@ export default function RepairForm() {
|
||||||
});
|
});
|
||||||
const result = await response.json() as { message?: string };
|
const result = await response.json() as { message?: string };
|
||||||
if (!response.ok) throw new Error(result.message ?? "Anfrage konnte nicht gesendet werden.");
|
if (!response.ok) throw new Error(result.message ?? "Anfrage konnte nicht gesendet werden.");
|
||||||
event.currentTarget.reset();
|
formRef.current?.reset();
|
||||||
|
setErrors({});
|
||||||
setStatus(result.message ?? "Ihre Reparaturanfrage wurde vorbereitet.");
|
setStatus(result.message ?? "Ihre Reparaturanfrage wurde vorbereitet.");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setStatus(error instanceof Error ? error.message : "Anfrage konnte nicht gesendet werden.");
|
setSubmitError(error instanceof Error ? error.message : "Anfrage konnte nicht gesendet werden. Bitte versuchen Sie es später erneut.");
|
||||||
} finally {
|
} finally {
|
||||||
setPending(false);
|
setPending(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="form" onSubmit={submit} noValidate>
|
<form ref={formRef} className="form" onSubmit={submit} noValidate>
|
||||||
<div className="grid two">
|
<div className="grid two">
|
||||||
<Field label="Name" name="name" error={errors.name} />
|
<Field label="Name" name="name" error={errors.name} />
|
||||||
<Field label="E-Mail" name="email" type="email" error={errors.email} />
|
<Field label="E-Mail" name="email" type="email" error={errors.email} />
|
||||||
|
|
@ -90,10 +94,11 @@ export default function RepairForm() {
|
||||||
</div>
|
</div>
|
||||||
<p className="notice">Fotos vom Gerät, Typenschild oder Innenleben können später nach Rückmeldung ergänzt werden. Bitte senden Sie aktuell noch keine Dateien unaufgefordert.</p>
|
<p className="notice">Fotos vom Gerät, Typenschild oder Innenleben können später nach Rückmeldung ergänzt werden. Bitte senden Sie aktuell noch keine Dateien unaufgefordert.</p>
|
||||||
<label className="checkbox">
|
<label className="checkbox">
|
||||||
<input type="checkbox" name="privacy" />
|
<input type="checkbox" name="privacyAccepted" />
|
||||||
<span>Ich stimme zu, dass meine Angaben zur Bearbeitung der Reparaturanfrage verarbeitet werden.</span>
|
<span>Ich stimme zu, dass meine Angaben zur Bearbeitung der Reparaturanfrage verarbeitet werden.</span>
|
||||||
</label>
|
</label>
|
||||||
{errors.privacy && <span className="error">{errors.privacy}</span>}
|
{errors.privacyAccepted && <span className="error">{errors.privacyAccepted}</span>}
|
||||||
|
{submitError && <p className="error">{submitError}</p>}
|
||||||
{status && <p className="success">{status}</p>}
|
{status && <p className="success">{status}</p>}
|
||||||
<button className="button" type="submit" disabled={pending}>{pending ? "Wird gesendet..." : "Reparatur anfragen"}</button>
|
<button className="button" type="submit" disabled={pending}>{pending ? "Wird gesendet..." : "Reparatur anfragen"}</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue