"use client"; import { useState } from "react"; import { motion } from "framer-motion"; import { SiGitea } from "react-icons/si"; import { ArrowRight, Mail, MapPin, Clock, Send, CheckCircle2, Loader2, AlertCircle, } from "lucide-react"; import GlassCard from "@/components/ui/GlassCard"; import GlowButton from "@/components/ui/GlowButton"; import { fadeUp, stagger, viewportConfig } from "@/lib/animations"; import type { Dictionary } from "@/lib/dictionaries"; interface ContactFormProps { dict: Dictionary; } export default function ContactForm({ dict }: ContactFormProps) { const t = dict.contactPage; const [status, setStatus] = useState<"idle" | "sending" | "sent" | "error">( "idle", ); const [errorMsg, setErrorMsg] = useState(""); async function handleSubmit(e: React.FormEvent) { e.preventDefault(); setStatus("sending"); setErrorMsg(""); const form = e.currentTarget; const data = { name: (form.elements.namedItem("name") as HTMLInputElement).value, email: (form.elements.namedItem("email") as HTMLInputElement).value, subject: (form.elements.namedItem("subject") as HTMLInputElement).value, message: (form.elements.namedItem("message") as HTMLTextAreaElement) .value, // Honeypot — hidden from real users, bots fill it in company: (form.elements.namedItem("company") as HTMLInputElement).value, }; try { const res = await fetch("/api/contact", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), }); if (!res.ok) { const err = await res.json(); throw new Error(err.error || "Failed to send"); } setStatus("sent"); form.reset(); } catch (err) { setStatus("error"); setErrorMsg( err instanceof Error ? err.message : "Something went wrong", ); } } const contactInfo = [ { icon: Mail, label: t.emailLabel, value: "contact@ksan.dev", href: "mailto:contact@ksan.dev", }, { icon: SiGitea, label: "Source Code", value: "git.ksan.dev/ksan", href: "https://git.ksan.dev/ksan", }, { icon: Clock, label: t.responseTime, value: t.responseValue, }, { icon: MapPin, label: t.location, value: t.locationValue, }, ]; return ( {/* Form */} {status === "sent" ? (

{t.successTitle}

{t.successMessage}

) : (
{/* Honeypot field — invisible to humans, catches spam bots */}
{status === "error" && (
{errorMsg}
)}

{t.avgResponse}

) : ( ) } > {status === "sending" ? t.sending : t.send}
)}
{/* Sidebar */} {contactInfo.map((item) => { const inner = (
{item.label}
{item.value}
{item.href && ( )}
); return item.href ? ( {inner} ) : (
{inner}
); })}
); } function Field({ label, id, type = "text", placeholder, required, multiline, }: { label: string; id: string; type?: string; placeholder?: string; required?: boolean; multiline?: boolean; }) { const className = "w-full rounded-xl border border-border/60 bg-surface/60 px-4 py-3 text-sm text-text-primary placeholder:text-text-secondary/40 transition-all focus:border-purple-400/60 focus:bg-surface/80 focus:outline-none focus:ring-2 focus:ring-purple-500/20"; return (
{multiline ? (