From e778f6a46006a7b35605482d2c7c79b5796037e3 Mon Sep 17 00:00:00 2001 From: GEM CYBERSECURITY-MONITORING ASSIST Date: Tue, 7 Jul 2026 08:49:33 +0100 Subject: [PATCH 1/5] fix(contact): submit messages to the real API --- src/app/contact/ContactForm.tsx | 200 ++++++++++++++++---------------- 1 file changed, 97 insertions(+), 103 deletions(-) diff --git a/src/app/contact/ContactForm.tsx b/src/app/contact/ContactForm.tsx index 916ad0c3..16ed4e88 100644 --- a/src/app/contact/ContactForm.tsx +++ b/src/app/contact/ContactForm.tsx @@ -4,6 +4,7 @@ import { useState } from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; +import Link from "next/link"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { CheckCircle2, AlertCircle, Loader2, Send } from "lucide-react"; @@ -11,25 +12,27 @@ import { CheckCircle2, AlertCircle, Loader2, Send } from "lucide-react"; const contactSchema = z.object({ fullName: z .string() + .trim() .min(2, "Full name must be at least 2 characters") .max(100, "Full name must be under 100 characters"), - email: z.string().email("Please enter a valid email address"), + email: z.string().trim().email("Please enter a valid email address"), organization: z .string() + .trim() .min(2, "Organization name must be at least 2 characters") .max(200, "Organization name must be under 200 characters"), - subject: z.enum( - ["general", "security-incident", "partnership", "other"], - { required_error: "Please select a subject" } - ), + subject: z.enum(["general", "security-incident", "partnership", "other"], { + required_error: "Please select a subject", + }), message: z .string() + .trim() .min(20, "Message must be at least 20 characters") .max(5000, "Message must be under 5000 characters"), + website: z.string().optional(), }); type ContactFormData = z.infer; - type FormStatus = "idle" | "loading" | "success" | "error"; const subjectOptions = [ @@ -37,11 +40,14 @@ const subjectOptions = [ { value: "security-incident", label: "Security Incident" }, { value: "partnership", label: "Partnership" }, { value: "other", label: "Other" }, -]; +] as const; + +const inputClass = + "w-full rounded-lg border border-border/60 bg-input px-4 py-2.5 text-sm transition-colors placeholder:text-muted-foreground focus:border-primary/50 focus:outline-none focus:ring-2 focus:ring-ring"; export default function ContactForm() { const [status, setStatus] = useState("idle"); - const [errorMessage, setErrorMessage] = useState(""); + const [errorMessage, setErrorMessage] = useState(""); const { register, @@ -50,6 +56,7 @@ export default function ContactForm() { formState: { errors }, } = useForm({ resolver: zodResolver(contactSchema), + defaultValues: { website: "" }, }); const onSubmit = async (data: ContactFormData) => { @@ -57,20 +64,37 @@ export default function ContactForm() { setErrorMessage(""); try { - // Simulate POST to /api/contact - await new Promise((resolve, reject) => { - setTimeout(() => { - // Stub: always resolve for now - resolve(); - }, 1500); + const subjectLabel = + subjectOptions.find((option) => option.value === data.subject)?.label ?? + "Website inquiry"; + + const response = await fetch("/api/contact", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + name: data.fullName, + email: data.email, + subject: `${subjectLabel} — ${data.organization}`, + message: `Organization: ${data.organization}\n\n${data.message}`, + website: data.website, + }), }); + const result = (await response.json().catch(() => null)) as + | { ok?: boolean; error?: string } + | null; + + if (!response.ok || !result?.ok) { + throw new Error(result?.error || "Message submission failed"); + } + setStatus("success"); reset(); - } catch { + } catch (error) { + console.error("[contact-form] submission failed", error); setStatus("error"); setErrorMessage( - "An error occurred while submitting your message. Please try again or contact us directly." + "We could not submit your message. Please try again or use the published support contact.", ); } }; @@ -78,19 +102,15 @@ export default function ContactForm() { if (status === "success") { return ( - -
- + +
+
-

Message Received

-

- Your message has been received. Our team will respond within 1 business day. - For urgent security incidents, please use the emergency escalation contact provided. +

Message Submitted

+

+ Your message was accepted by our contact system. Response times vary by inquiry type and service coverage.

-
@@ -102,40 +122,29 @@ export default function ContactForm() {
- {/* Full Name */}
-
- {/* Email */}
-
- {/* Organization */}
-
- {/* Subject */}
-
- {/* Message */} + +
-