"use client" import { useState, useRef } from "react" import { motion } from "motion/react" import { SendIcon, BugIcon, DatabaseIcon, FlagIcon, LightbulbIcon, MessageSquareIcon, AlertTriangleIcon, CheckCircleIcon, Loader2Icon, } from "lucide-react" type Category = "bug" | "game_data" | "user_report" | "feature" | "feedback" | "database" interface CategoryOption { id: Category label: string icon: React.ElementType color: string } const CATEGORIES: CategoryOption[] = [ { id: "bug", label: "Bug Report", icon: BugIcon, color: "text-red-400 border-red-500/20 bg-red-500/5 hover:bg-red-500/10" }, { id: "game_data", label: "Game Data Issue", icon: AlertTriangleIcon, color: "text-yellow-400 border-yellow-500/20 bg-yellow-500/5 hover:bg-yellow-500/10" }, { id: "user_report", label: "User Report", icon: FlagIcon, color: "text-blue-400 border-blue-500/20 bg-blue-500/5 hover:bg-blue-500/10" }, { id: "feature", label: "Feature Request", icon: LightbulbIcon, color: "text-green-400 border-green-500/20 bg-green-500/5 hover:bg-green-500/10" }, { id: "feedback", label: "General Feedback", icon: MessageSquareIcon, color: "text-text/60 border-border bg-text/3 hover:bg-text/6" }, { id: "database", label: "Database Error", icon: DatabaseIcon, color: "text-red-400 border-red-500/20 bg-red-500/5 hover:bg-red-500/10" }, ] export default function ContactPage() { const [category, setCategory] = useState("") const [name, setName] = useState("") const [email, setEmail] = useState("") const [subject, setSubject] = useState("") const [message, setMessage] = useState("") const [gameUrl, setGameUrl] = useState("") const [honeypot, setHoneypot] = useState("") const timestampRef = useRef("") const [submitting, setSubmitting] = useState(false) const [submitted, setSubmitted] = useState(false) const [error, setError] = useState(null) const [fieldErrors, setFieldErrors] = useState>({}) // Set timestamp when user starts interacting const startTimestamp = () => { if (!timestampRef.current) { timestampRef.current = Date.now().toString() } } const validate = (): boolean => { const errors: Record = {} if (!category) errors.category = "Please select a category" if (!subject.trim()) errors.subject = "Subject is required" else if (subject.length > 200) errors.subject = "Subject must be 200 characters or less" if (!message.trim()) errors.message = "Message is required" else if (message.length > 2000) errors.message = "Message must be 2000 characters or less" if (email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) errors.email = "Invalid email format" if (category === "game_data" && gameUrl && !gameUrl.includes("/game/")) errors.gameUrl = "Please provide a valid DeckyVault game link" setFieldErrors(errors) return Object.keys(errors).length === 0 } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() startTimestamp() if (!validate()) return setSubmitting(true) setError(null) try { const res = await fetch("/api/contact", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ category, name: name || undefined, email: email || undefined, subject: subject.trim(), message: message.trim(), gameUrl: category === "game_data" ? gameUrl || undefined : undefined, honeypot, _timestamp: timestampRef.current || undefined, }), }) const data = await res.json() if (!res.ok) { if (res.status === 429) { setError("You've sent too many messages. Please try again later.") } else { setError(data.error || "Something went wrong. Please try again.") } return } setSubmitted(true) } catch { setError("Network error. Please check your connection and try again.") } finally { setSubmitting(false) } } if (submitted) { return (

Message Sent

Thank you for reaching out. We'll review your message as soon as possible.

) } return (
{/* Header */}

Contact & Report

Report issues, suggest features, or send us feedback.

{/* Honeypot */} setHoneypot(e.target.value)} tabIndex={-1} autoComplete="off" style={{ position: "absolute", opacity: 0, pointerEvents: "none" }} aria-hidden="true" /> {/* Category */}
Category *
{CATEGORIES.map((cat) => ( ))}
{fieldErrors.category && (

{fieldErrors.category}

)}
{/* Name & Email (optional) */}
{ setName(e.target.value); startTimestamp() }} placeholder="Your name" className="w-full bg-text/5 border border-border rounded-md px-3 py-2 text-sm outline-none focus:border-primary/80 focus:ring-2 focus:ring-primary/50 focus:ring-offset-2 focus:ring-offset-background transition-colors" />
{ setEmail(e.target.value); startTimestamp() }} placeholder="you@example.com" className="w-full bg-text/5 border border-border rounded-md px-3 py-2 text-sm outline-none focus:border-primary/80 focus:ring-2 focus:ring-primary/50 focus:ring-offset-2 focus:ring-offset-background transition-colors" /> {fieldErrors.email && (

{fieldErrors.email}

)}
{/* Subject */}
{ setSubject(e.target.value) startTimestamp() if (fieldErrors.subject) setFieldErrors((prev) => { const next = { ...prev }; delete next.subject; return next }) }} placeholder="Brief description of your issue" maxLength={200} className="w-full bg-text/5 border border-border rounded-md px-3 py-2 text-sm outline-none focus:border-primary/80 focus:ring-2 focus:ring-primary/50 focus:ring-offset-2 focus:ring-offset-background transition-colors" /> {fieldErrors.subject && (

{fieldErrors.subject}

)}
{/* Game URL (conditional) */} {category === "game_data" && ( setGameUrl(e.target.value)} placeholder="https://deckyvault.xyz/game/..." className="w-full bg-text/5 border border-border rounded-md px-3 py-2 text-sm outline-none focus:border-primary/80 focus:ring-2 focus:ring-primary/50 focus:ring-offset-2 focus:ring-offset-background transition-colors" /> {fieldErrors.gameUrl && (

{fieldErrors.gameUrl}

)}
)} {/* Message */}