neireva-contact/components/ContactForm.tsx

186 lines
5.6 KiB
TypeScript

"use client";
import { useState } from "react";
import { CONSENT_TEXT, ACKNOWLEDGMENT_TEXT } from "@/lib/consent";
type Status = "idle" | "submitting" | "success" | "error";
const FIELD =
"w-full rounded-control border border-line bg-card px-3.5 py-2.5 text-[15px] text-ink placeholder:text-ink-faint transition-colors focus:border-terracotta";
const LABEL = "block text-[13px] font-medium text-ink-soft mb-1.5";
export default function ContactForm() {
const [fullName, setFullName] = useState("");
const [companyName, setCompanyName] = useState("");
const [role, setRole] = useState("");
const [email, setEmail] = useState("");
const [consentGiven, setConsentGiven] = useState(false);
const [consentAcknowledged, setConsentAcknowledged] = useState(false);
const [website, setWebsite] = useState(""); // honeypot
const [status, setStatus] = useState<Status>("idle");
const [error, setError] = useState("");
const canSubmit =
fullName.trim() &&
companyName.trim() &&
role.trim() &&
email.trim() &&
consentGiven &&
consentAcknowledged &&
status !== "submitting";
async function handleSubmit() {
setStatus("submitting");
setError("");
try {
const res = await fetch("/api/lead", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
fullName,
companyName,
role,
email,
consentGiven,
consentAcknowledged,
website,
}),
});
const data = await res.json();
if (!res.ok) {
setError(data.error ?? "Something went wrong. Please try again.");
setStatus("error");
return;
}
setStatus("success");
} catch {
setError("Network error. Please try again.");
setStatus("error");
}
}
if (status === "success") {
return (
<div className="rounded-card border border-ok/30 bg-ok-bg px-6 py-8 text-center">
<p className="text-[17px] font-semibold text-ok">Thank you.</p>
<p className="mt-1.5 text-[15px] text-ink-soft">
We&apos;ve got your details and will be in touch shortly.
</p>
</div>
);
}
return (
<div className="space-y-5">
<div className="grid gap-5 sm:grid-cols-2">
<div>
<label className={LABEL} htmlFor="fullName">
Full name
</label>
<input
id="fullName"
className={FIELD}
value={fullName}
onChange={(e) => setFullName(e.target.value)}
autoComplete="name"
/>
</div>
<div>
<label className={LABEL} htmlFor="companyName">
Company
</label>
<input
id="companyName"
className={FIELD}
value={companyName}
onChange={(e) => setCompanyName(e.target.value)}
autoComplete="organization"
/>
</div>
</div>
<div className="grid gap-5 sm:grid-cols-2">
<div>
<label className={LABEL} htmlFor="role">
Role
</label>
<input
id="role"
className={FIELD}
value={role}
onChange={(e) => setRole(e.target.value)}
autoComplete="organization-title"
/>
</div>
<div>
<label className={LABEL} htmlFor="email">
Email
</label>
<input
id="email"
type="email"
className={FIELD}
value={email}
onChange={(e) => setEmail(e.target.value)}
autoComplete="email"
/>
</div>
</div>
{/* Honeypot — visually hidden, off the tab order */}
<div aria-hidden className="absolute left-[-9999px] h-0 w-0 overflow-hidden">
<label htmlFor="website">Website</label>
<input
id="website"
tabIndex={-1}
autoComplete="off"
value={website}
onChange={(e) => setWebsite(e.target.value)}
/>
</div>
<div className="space-y-3 pt-1">
<label className="flex cursor-pointer items-start gap-3">
<input
type="checkbox"
className="mt-0.5 h-4 w-4 shrink-0 accent-terracotta"
checked={consentGiven}
onChange={(e) => setConsentGiven(e.target.checked)}
/>
<span className="text-[13px] leading-relaxed text-ink-soft">
{CONSENT_TEXT}
</span>
</label>
<label className="flex cursor-pointer items-start gap-3">
<input
type="checkbox"
className="mt-0.5 h-4 w-4 shrink-0 accent-terracotta"
checked={consentAcknowledged}
onChange={(e) => setConsentAcknowledged(e.target.checked)}
/>
<span className="text-[13px] leading-relaxed text-ink-soft">
{ACKNOWLEDGMENT_TEXT}
</span>
</label>
</div>
{status === "error" && (
<div
role="alert"
className="rounded-control border border-danger/30 bg-danger-bg px-3.5 py-2.5 text-[13px] text-danger"
>
{error}
</div>
)}
<button
type="button"
onClick={handleSubmit}
disabled={!canSubmit}
className="w-full rounded-control bg-gradient-to-br from-terracotta to-terracotta-end px-4 py-3 text-[15px] font-medium text-white transition-opacity hover:opacity-95 disabled:cursor-not-allowed disabled:opacity-40"
>
{status === "submitting" ? "Sending…" : "Send my details"}
</button>
</div>
);
}