Wire contact form to self-hosted email relay API
Replace broken mailto: form with proper fetch-based submission to email-relay.jeffemmett.com/contact. Adds loading spinner, success confirmation, and error feedback states. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ca63536783
commit
850b4e6a2f
|
|
@ -1,11 +1,54 @@
|
|||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useInView } from "@/hooks/use-in-view";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Mail, Phone, MapPin, Zap } from "lucide-react";
|
||||
import { Mail, Phone, MapPin, Zap, Check, AlertCircle, Loader2 } from "lucide-react";
|
||||
|
||||
const CONTACT_API = "https://email-relay.jeffemmett.com/contact";
|
||||
|
||||
export function ContactSection() {
|
||||
const { ref, isInView } = useInView(0.1);
|
||||
const [status, setStatus] = useState<"idle" | "sending" | "sent" | "error">("idle");
|
||||
const [errorMsg, setErrorMsg] = useState("");
|
||||
|
||||
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||
e.preventDefault();
|
||||
setStatus("sending");
|
||||
setErrorMsg("");
|
||||
|
||||
const form = e.currentTarget;
|
||||
const data = new FormData(form);
|
||||
|
||||
try {
|
||||
const res = await fetch(CONTACT_API, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
name: data.get("name"),
|
||||
email: data.get("email"),
|
||||
subject: "PortaPower Event Inquiry",
|
||||
message: data.get("message") || "",
|
||||
fields: {
|
||||
"Festival / Event": data.get("festival") || "Not specified",
|
||||
"Expected Attendance": data.get("attendees") || "Not specified",
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
setStatus("sent");
|
||||
form.reset();
|
||||
} else {
|
||||
const body = await res.json().catch(() => ({}));
|
||||
setErrorMsg(body.error || "Something went wrong. Please try again.");
|
||||
setStatus("error");
|
||||
}
|
||||
} catch {
|
||||
setErrorMsg("Network error. Please check your connection and try again.");
|
||||
setStatus("error");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<section id="contact" className="py-24 px-4 bg-brown-dark/30" ref={ref}>
|
||||
|
|
@ -34,10 +77,27 @@ export function ContactSection() {
|
|||
className={`${isInView ? "animate-fade-in-up" : "opacity-0"}`}
|
||||
style={{ animationDelay: "0.2s" }}
|
||||
>
|
||||
{status === "sent" ? (
|
||||
<div className="flex flex-col items-center justify-center gap-4 py-16 text-center">
|
||||
<div className="flex h-16 w-16 items-center justify-center rounded-full bg-neon/10 border border-neon/30">
|
||||
<Check className="h-8 w-8 text-neon" />
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold text-cream">Message Sent!</h3>
|
||||
<p className="text-cream-dim max-w-sm">
|
||||
Thanks for reaching out. We'll get back to you shortly.
|
||||
</p>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={() => setStatus("idle")}
|
||||
className="mt-4"
|
||||
>
|
||||
Send Another
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<form
|
||||
action="mailto:hello@portapower.buzz"
|
||||
method="POST"
|
||||
encType="text/plain"
|
||||
onSubmit={handleSubmit}
|
||||
className="space-y-5"
|
||||
>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
|
|
@ -128,11 +188,23 @@ export function ContactSection() {
|
|||
/>
|
||||
</div>
|
||||
|
||||
<Button type="submit" size="lg" className="w-full">
|
||||
<Zap className="h-5 w-5" />
|
||||
Send Inquiry
|
||||
{status === "error" && (
|
||||
<div className="flex items-center gap-2 rounded-lg border border-red-500/30 bg-red-500/10 px-4 py-3 text-sm text-red-400">
|
||||
<AlertCircle className="h-4 w-4 flex-shrink-0" />
|
||||
{errorMsg}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Button type="submit" size="lg" className="w-full" disabled={status === "sending"}>
|
||||
{status === "sending" ? (
|
||||
<Loader2 className="h-5 w-5 animate-spin" />
|
||||
) : (
|
||||
<Zap className="h-5 w-5" />
|
||||
)}
|
||||
{status === "sending" ? "Sending..." : "Send Inquiry"}
|
||||
</Button>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Contact info */}
|
||||
|
|
|
|||
Loading…
Reference in New Issue