"use client"; import { useEffect, useMemo, useState } from "react"; import { site } from "@/lib/site"; type Status = { state: "idle" | "submitting" | "success" | "error"; message?: string }; export default function ContactPage() { const [startedAt, setStartedAt] = useState(""); const [status, setStatus] = useState({ state: "idle" }); useEffect(() => { setStartedAt(String(Date.now())); }, []); const disabledEarly = useMemo(() => { if (!startedAt) return true; const min = Number(process.env.NEXT_PUBLIC_CONTACT_MIN_SUBMIT_SECONDS ?? 3) || 3; return Date.now() - Number(startedAt) < min * 1000; }, [startedAt]); async function onSubmit(e: React.FormEvent) { e.preventDefault(); setStatus({ state: "submitting" }); const form = e.currentTarget; const formData = new FormData(form); const payload = Object.fromEntries(formData.entries()); try { const res = await fetch("/api/contact", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); const json = (await res.json()) as { ok: boolean; error?: string }; if (!res.ok || !json.ok) throw new Error(json.error || "Failed"); setStatus({ state: "success", message: "Thanks! We’ll get back to you shortly." }); form.reset(); setStartedAt(String(Date.now())); // reset time trap } catch { setStatus({ state: "error", message: "Could not send. Please try again." }); } } return (

Contact

Tell us what you want fixed or managed. We’ll confirm scope and start fast.

{/* Honeypot (hidden from users & screen readers) */}
{/* Time trap */}