281 lines
11 KiB
TypeScript
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'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's Make Shift Happen
|
|
</h3>
|
|
<p className="text-cream-dim leading-relaxed">
|
|
Whether you're producing a 500-person campout or a 50,000-person
|
|
mega-festival, we'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>
|
|
);
|
|
}
|