"use client"; import React, { useId, useState } from "react"; import { ArrowRight, Check } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { siteConfig } from "@/lib/site"; import { contactServices, validateContact, type ContactFieldErrors, type ContactServiceId, } from "@/lib/contact"; import { cn } from "@/lib/utils"; const inputClass = "h-11 rounded-xl border-border bg-card px-4 text-foreground"; export function ContactForm() { const formId = useId(); const [name, setName] = useState(""); const [email, setEmail] = useState(""); const [message, setMessage] = useState(""); const [service, setService] = useState(""); const [honeypot, setHoneypot] = useState(""); const [errors, setErrors] = useState({}); const [status, setStatus] = useState<"idle" | "sending" | "success" | "error">( "idle", ); const [serverError, setServerError] = useState(""); const toggleService = (id: ContactServiceId) => { setService((current) => (current === id ? "" : id)); }; const onSubmit = async (event: React.FormEvent) => { event.preventDefault(); setServerError(""); const payload = { name, email, message, service, website: honeypot }; const nextErrors = validateContact(payload); if (nextErrors) { setErrors(nextErrors); setStatus("idle"); return; } setErrors({}); setStatus("sending"); try { const response = await fetch("/api/contact", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); const data = (await response.json()) as { ok?: boolean; error?: string; errors?: ContactFieldErrors; }; if (!response.ok || !data.ok) { if (data.errors) setErrors(data.errors); setServerError( data.error || "Couldn't send the message. Please email me directly.", ); setStatus("error"); return; } setStatus("success"); setName(""); setEmail(""); setMessage(""); setService(""); } catch { setServerError("Couldn't send the message. Please email me directly."); setStatus("error"); } }; if (status === "success") { return (

Message sent.

Thanks — I'll read this and get back to you. If it's urgent, email me at{" "} {siteConfig.email} .

); } return (
What can I help you with?

Optional — pick one and it travels with the message.

{contactServices.map((item) => { const selected = service === item.id; return ( ); })}
setName(event.target.value)} aria-invalid={Boolean(errors.name) || undefined} aria-describedby={errors.name ? `${formId}-name-error` : undefined} className={cn("mt-2", inputClass)} /> {errors.name && (

{errors.name}

)}
setEmail(event.target.value)} aria-invalid={Boolean(errors.email) || undefined} aria-describedby={ errors.email ? `${formId}-email-error` : undefined } className={cn("mt-2", inputClass)} /> {errors.email && (

{errors.email}

)}