111 lines
5.5 KiB
TypeScript
111 lines
5.5 KiB
TypeScript
"use client";
|
|
|
|
import { useState, type FormEvent } from "react";
|
|
|
|
type ErrorField = "name" | "email" | "manufacturer" | "model" | "deviceType" | "description" | "privacy";
|
|
type Errors = Partial<Record<ErrorField, string>>;
|
|
|
|
export default function RepairForm() {
|
|
const [errors, setErrors] = useState<Errors>({});
|
|
const [status, setStatus] = useState("");
|
|
const [pending, setPending] = useState(false);
|
|
|
|
async function submit(event: FormEvent<HTMLFormElement>) {
|
|
event.preventDefault();
|
|
setStatus("");
|
|
const form = new FormData(event.currentTarget);
|
|
const nextErrors: Errors = {};
|
|
|
|
if (!String(form.get("name") ?? "").trim()) nextErrors.name = "Bitte geben Sie Ihren Namen ein.";
|
|
if (!String(form.get("email") ?? "").includes("@")) nextErrors.email = "Bitte geben Sie eine gültige E-Mail-Adresse ein.";
|
|
if (!String(form.get("manufacturer") ?? "").trim()) nextErrors.manufacturer = "Bitte nennen Sie den Hersteller.";
|
|
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("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.";
|
|
|
|
setErrors(nextErrors);
|
|
if (Object.keys(nextErrors).length > 0) return;
|
|
|
|
setPending(true);
|
|
try {
|
|
const response = await fetch("/api/repair", {
|
|
method: "POST",
|
|
body: form,
|
|
});
|
|
const result = await response.json() as { message?: string };
|
|
if (!response.ok) throw new Error(result.message ?? "Anfrage konnte nicht gesendet werden.");
|
|
event.currentTarget.reset();
|
|
setStatus(result.message ?? "Ihre Reparaturanfrage wurde vorbereitet.");
|
|
} catch (error) {
|
|
setStatus(error instanceof Error ? error.message : "Anfrage konnte nicht gesendet werden.");
|
|
} finally {
|
|
setPending(false);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<form className="form" onSubmit={submit} noValidate>
|
|
<div className="grid two">
|
|
<Field label="Name" name="name" error={errors.name} />
|
|
<Field label="E-Mail" name="email" type="email" error={errors.email} />
|
|
<Field label="Telefon" name="phone" />
|
|
<Field label="Hersteller" name="manufacturer" error={errors.manufacturer} />
|
|
<Field label="Modell" name="model" error={errors.model} />
|
|
<Field label="Seriennummer optional" name="serialNumber" />
|
|
</div>
|
|
<div className="field">
|
|
<label htmlFor="deviceType">Geräteart</label>
|
|
<select id="deviceType" name="deviceType" defaultValue="">
|
|
<option value="">Bitte auswählen</option>
|
|
<option value="cb-radio">CB-Funkgerät</option>
|
|
<option value="amateur-radio">Amateurfunkgerät</option>
|
|
<option value="business-radio">Betriebsfunkgerät</option>
|
|
<option value="receiver">Empfänger / Scanner</option>
|
|
<option value="measurement">Messtechnik</option>
|
|
<option value="other">Sonstige Kommunikationstechnik</option>
|
|
</select>
|
|
{errors.deviceType && <span className="error">{errors.deviceType}</span>}
|
|
</div>
|
|
<div className="field">
|
|
<label htmlFor="accessories">Zubehör vorhanden</label>
|
|
<textarea id="accessories" name="accessories" placeholder="z. B. Netzteil, Mikrofon, Kabel, Adapter, Antenne oder Bediengerät" />
|
|
</div>
|
|
<div className="field">
|
|
<label htmlFor="opened">Wurde das Gerät bereits geöffnet?</label>
|
|
<select id="opened" name="opened" defaultValue="unknown">
|
|
<option value="unknown">Bitte auswählen</option>
|
|
<option value="no">Nein</option>
|
|
<option value="yes">Ja</option>
|
|
</select>
|
|
</div>
|
|
<div className="field">
|
|
<label htmlFor="previousWork">Gibt es Vorarbeiten?</label>
|
|
<textarea id="previousWork" name="previousWork" placeholder="z. B. Bauteile getauscht, Abgleich versucht, Reinigung, Messung, Fremdwerkstatt" />
|
|
</div>
|
|
<div className="field">
|
|
<label htmlFor="description">Fehlerbeschreibung</label>
|
|
<textarea id="description" name="description" placeholder="Bitte Fehlerbild möglichst konkret beschreiben: tritt der Fehler beim Empfang, Senden, bei Modulation, Frequenz, Anzeige oder Stromversorgung auf?" />
|
|
{errors.description && <span className="error">{errors.description}</span>}
|
|
</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>
|
|
<label className="checkbox">
|
|
<input type="checkbox" name="privacy" />
|
|
<span>Ich stimme zu, dass meine Angaben zur Bearbeitung der Reparaturanfrage verarbeitet werden.</span>
|
|
</label>
|
|
{errors.privacy && <span className="error">{errors.privacy}</span>}
|
|
{status && <p className="success">{status}</p>}
|
|
<button className="button" type="submit" disabled={pending}>{pending ? "Wird gesendet..." : "Reparatur anfragen"}</button>
|
|
</form>
|
|
);
|
|
}
|
|
|
|
function Field({ label, name, type = "text", error }: { label: string; name: string; type?: string; error?: string }) {
|
|
return (
|
|
<div className="field">
|
|
<label htmlFor={name}>{label}</label>
|
|
<input id={name} name={name} type={type} />
|
|
{error && <span className="error">{error}</span>}
|
|
</div>
|
|
);
|
|
}
|