portapower-website/components/contact-section.tsx

281 lines
11 KiB
TypeScript

"use client";
import { useState } from "react";
import { useInView } from "@/hooks/use-in-view";
import { Button } from "@/components/ui/button";
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}>
<div className="mx-auto max-w-6xl">
<div className="text-center mb-16">
<h2
className={`text-3xl sm:text-4xl md:text-5xl font-bold mb-4 ${
isInView ? "animate-fade-in-up" : "opacity-0"
}`}
>
Ready to <span className="text-neon">Power Up</span>?
</h2>
<p
className={`text-cream-dim text-lg max-w-2xl mx-auto ${
isInView ? "animate-fade-in-up" : "opacity-0"
}`}
style={{ animationDelay: "0.1s" }}
>
Get in touch to learn how we can power your next event sustainably.
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12">
{/* Contact form */}
<div
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&apos;ll get back to you shortly.
</p>
<Button
type="button"
variant="outline"
onClick={() => setStatus("idle")}
className="mt-4"
>
Send Another
</Button>
</div>
) : (
<form
onSubmit={handleSubmit}
className="space-y-5"
>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label
htmlFor="name"
className="block text-sm font-medium text-cream mb-1.5"
>
Name
</label>
<input
type="text"
id="name"
name="name"
required
className="w-full rounded-lg border border-brown-light/40 bg-bg-card px-4 py-3 text-cream placeholder-cream-dim/50 focus:border-neon focus:outline-none focus:ring-1 focus:ring-neon transition-colors"
placeholder="Your name"
/>
</div>
<div>
<label
htmlFor="email"
className="block text-sm font-medium text-cream mb-1.5"
>
Email
</label>
<input
type="email"
id="email"
name="email"
required
className="w-full rounded-lg border border-brown-light/40 bg-bg-card px-4 py-3 text-cream placeholder-cream-dim/50 focus:border-neon focus:outline-none focus:ring-1 focus:ring-neon transition-colors"
placeholder="you@festival.com"
/>
</div>
</div>
<div>
<label
htmlFor="festival"
className="block text-sm font-medium text-cream mb-1.5"
>
Festival / Event Name
</label>
<input
type="text"
id="festival"
name="festival"
className="w-full rounded-lg border border-brown-light/40 bg-bg-card px-4 py-3 text-cream placeholder-cream-dim/50 focus:border-neon focus:outline-none focus:ring-1 focus:ring-neon transition-colors"
placeholder="Your festival name"
/>
</div>
<div>
<label
htmlFor="attendees"
className="block text-sm font-medium text-cream mb-1.5"
>
Expected Attendance
</label>
<select
id="attendees"
name="attendees"
className="w-full rounded-lg border border-brown-light/40 bg-bg-card px-4 py-3 text-cream focus:border-neon focus:outline-none focus:ring-1 focus:ring-neon transition-colors"
>
<option value="">Select attendance range</option>
<option value="under-1000">Under 1,000</option>
<option value="1000-5000">1,000 - 5,000</option>
<option value="5000-10000">5,000 - 10,000</option>
<option value="10000-25000">10,000 - 25,000</option>
<option value="25000+">25,000+</option>
</select>
</div>
<div>
<label
htmlFor="message"
className="block text-sm font-medium text-cream mb-1.5"
>
Tell Us About Your Event
</label>
<textarea
id="message"
name="message"
rows={4}
className="w-full rounded-lg border border-brown-light/40 bg-bg-card px-4 py-3 text-cream placeholder-cream-dim/50 focus:border-neon focus:outline-none focus:ring-1 focus:ring-neon transition-colors resize-none"
placeholder="Dates, location, power needs, number of stages..."
/>
</div>
{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 */}
<div
className={`flex flex-col justify-center gap-8 ${
isInView ? "animate-fade-in-up" : "opacity-0"
}`}
style={{ animationDelay: "0.3s" }}
>
<div>
<h3 className="text-2xl font-bold text-cream mb-4">
Let&apos;s Make Shift Happen
</h3>
<p className="text-cream-dim leading-relaxed">
Whether you&apos;re producing a 500-person campout or a 50,000-person
mega-festival, we&apos;ll engineer a custom waste-to-energy solution
tailored to your event. Our team handles everything from site
planning to post-event teardown.
</p>
</div>
<div className="space-y-4">
<div className="flex items-center gap-4">
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-neon/10 border border-neon/30">
<Mail className="h-5 w-5 text-neon" />
</div>
<div>
<p className="text-sm text-cream-dim">Email</p>
<p className="font-medium text-cream">
hello@portapower.buzz
</p>
</div>
</div>
<div className="flex items-center gap-4">
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-neon/10 border border-neon/30">
<Phone className="h-5 w-5 text-neon" />
</div>
<div>
<p className="text-sm text-cream-dim">Phone</p>
<p className="font-medium text-cream">1-800-POO-POWER</p>
</div>
</div>
<div className="flex items-center gap-4">
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-neon/10 border border-neon/30">
<MapPin className="h-5 w-5 text-neon" />
</div>
<div>
<p className="text-sm text-cream-dim">Headquarters</p>
<p className="font-medium text-cream">
Austin, TX (We deploy nationwide)
</p>
</div>
</div>
</div>
<div className="rounded-xl border border-accent/20 bg-accent/5 p-5">
<p className="text-sm text-accent font-medium mb-1">
Fun fact 💩
</p>
<p className="text-sm text-cream-dim">
One festival-goer produces enough waste over a 3-day weekend
to generate roughly 2 kWh of electricity enough to fully
charge a smartphone 100 times. Multiply that by 10,000 attendees.
</p>
</div>
</div>
</div>
</div>
</section>
);
}