Seed: photography template (19 files)
This commit is contained in:
@@ -0,0 +1,177 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||||
|
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
|
||||||
|
import { MapPin, Mail, Phone, Send } from "lucide-react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import { useSaasMutation } from "@/hooks/use-tygarun";
|
||||||
|
import Header from "@/components/Header";
|
||||||
|
import Footer from "@/components/Footer";
|
||||||
|
|
||||||
|
export default function ContactPage() {
|
||||||
|
const [sending, setSending] = useState(false);
|
||||||
|
const [sessionType, setSessionType] = useState("");
|
||||||
|
const [budget, setBudget] = useState("");
|
||||||
|
// Session booking is LIVE via tyga.run scheduling
|
||||||
|
const { mutate: bookSession } = useSaasMutation("scheduling", "/bookings");
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const fd = new FormData(e.currentTarget);
|
||||||
|
setSending(true);
|
||||||
|
try {
|
||||||
|
await bookSession({
|
||||||
|
name: fd.get("name"),
|
||||||
|
email: fd.get("email"),
|
||||||
|
sessionType,
|
||||||
|
date: fd.get("date"),
|
||||||
|
location: fd.get("location"),
|
||||||
|
budget,
|
||||||
|
message: fd.get("message"),
|
||||||
|
});
|
||||||
|
toast.success("Your session request is in, I will confirm within 24 hours.");
|
||||||
|
e.currentTarget.reset();
|
||||||
|
setSessionType("");
|
||||||
|
setBudget("");
|
||||||
|
} catch (err) {
|
||||||
|
toast.error("Something went wrong. Please try again or email me directly.");
|
||||||
|
} finally {
|
||||||
|
setSending(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-zinc-950 text-white antialiased">
|
||||||
|
<Header />
|
||||||
|
|
||||||
|
<section className="pt-32 pb-24 px-6">
|
||||||
|
<div className="mx-auto max-w-7xl">
|
||||||
|
<h1 className="text-4xl md:text-6xl font-serif font-light tracking-tight mb-4 animate-fade-up">Get in Touch</h1>
|
||||||
|
<p className="text-zinc-500 max-w-xl mb-16">Have a project in mind? I would love to hear your story. Fill out the form and I will get back to you within 24 hours.</p>
|
||||||
|
|
||||||
|
<div className="grid lg:grid-cols-5 gap-16">
|
||||||
|
{/* ── FORM ── */}
|
||||||
|
<form onSubmit={handleSubmit} className="lg:col-span-3 space-y-6">
|
||||||
|
<div className="grid sm:grid-cols-2 gap-6">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="name" className="text-zinc-400 text-sm">Name</Label>
|
||||||
|
<Input id="name" name="name" required placeholder="Your full name" className="bg-zinc-900 border-zinc-800 text-white placeholder:text-zinc-600 focus:border-zinc-500" />
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="email" className="text-zinc-400 text-sm">Email</Label>
|
||||||
|
<Input id="email" name="email" type="email" required placeholder="you@example.com" className="bg-zinc-900 border-zinc-800 text-white placeholder:text-zinc-600 focus:border-zinc-500" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid sm:grid-cols-2 gap-6">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="text-zinc-400 text-sm">Event Type</Label>
|
||||||
|
<Select value={sessionType} onValueChange={setSessionType}>
|
||||||
|
<SelectTrigger className="bg-zinc-900 border-zinc-800 text-white">
|
||||||
|
<SelectValue placeholder="Select type" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="wedding">Wedding</SelectItem>
|
||||||
|
<SelectItem value="portrait">Portrait</SelectItem>
|
||||||
|
<SelectItem value="commercial">Commercial</SelectItem>
|
||||||
|
<SelectItem value="event">Event</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="date" className="text-zinc-400 text-sm">Preferred Date</Label>
|
||||||
|
<Input id="date" name="date" type="date" className="bg-zinc-900 border-zinc-800 text-white focus:border-zinc-500" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid sm:grid-cols-2 gap-6">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="location" className="text-zinc-400 text-sm">Location</Label>
|
||||||
|
<Input id="location" name="location" placeholder="City or venue" className="bg-zinc-900 border-zinc-800 text-white placeholder:text-zinc-600 focus:border-zinc-500" />
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="text-zinc-400 text-sm">Budget Range</Label>
|
||||||
|
<Select value={budget} onValueChange={setBudget}>
|
||||||
|
<SelectTrigger className="bg-zinc-900 border-zinc-800 text-white">
|
||||||
|
<SelectValue placeholder="Select range" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="under1k">Under $1,000</SelectItem>
|
||||||
|
<SelectItem value="1k-3k">$1,000 - $3,000</SelectItem>
|
||||||
|
<SelectItem value="3k-5k">$3,000 - $5,000</SelectItem>
|
||||||
|
<SelectItem value="5k-10k">$5,000 - $10,000</SelectItem>
|
||||||
|
<SelectItem value="10kplus">$10,000+</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="message" className="text-zinc-400 text-sm">Message</Label>
|
||||||
|
<Textarea id="message" name="message" required rows={5} placeholder="Tell me about your vision..." className="bg-zinc-900 border-zinc-800 text-white placeholder:text-zinc-600 focus:border-zinc-500 resize-none" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button type="submit" disabled={sending} size="lg" className="rounded-none bg-white text-zinc-900 hover:bg-zinc-200 px-10 tracking-wider w-full sm:w-auto">
|
||||||
|
{sending ? "Sending..." : "Book My Session"} <Send className="ml-2 h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{/* ── STUDIO INFO ── */}
|
||||||
|
<div className="lg:col-span-2 space-y-8">
|
||||||
|
<Card className="backdrop-blur-sm bg-card/80 border-zinc-800">
|
||||||
|
<CardContent className="pt-6 space-y-5">
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<MapPin className="h-5 w-5 text-zinc-500 mt-0.5 shrink-0" />
|
||||||
|
<div>
|
||||||
|
<p className="text-white text-sm font-medium">Studio</p>
|
||||||
|
<p className="text-zinc-400 text-sm">412 Mission Street, Studio 7, San Francisco, CA 94105</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<Mail className="h-5 w-5 text-zinc-500 mt-0.5 shrink-0" />
|
||||||
|
<div>
|
||||||
|
<p className="text-white text-sm font-medium">Email</p>
|
||||||
|
<p className="text-zinc-400 text-sm">hello@elenatorres.com</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<Phone className="h-5 w-5 text-zinc-500 mt-0.5 shrink-0" />
|
||||||
|
<div>
|
||||||
|
<p className="text-white text-sm font-medium">Phone</p>
|
||||||
|
<p className="text-zinc-400 text-sm">+1 (415) 555-0142</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* ── FAQ ── */}
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg font-light tracking-tight mb-4 animate-fade-up">Frequently Asked</h3>
|
||||||
|
<Accordion type="single" collapsible className="space-y-2">
|
||||||
|
<AccordionItem value="faq-1" className="border-zinc-800">
|
||||||
|
<AccordionTrigger className="text-sm text-zinc-300 hover:text-white">How does pricing work?</AccordionTrigger>
|
||||||
|
<AccordionContent className="text-zinc-500 text-sm">Pricing depends on the type of session, duration, and deliverables. After our initial consultation, I provide a detailed custom quote. No surprises.</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
<AccordionItem value="faq-2" className="border-zinc-800">
|
||||||
|
<AccordionTrigger className="text-sm text-zinc-300 hover:text-white">What is the typical turnaround time?</AccordionTrigger>
|
||||||
|
<AccordionContent className="text-zinc-500 text-sm">Portrait and commercial galleries are delivered within two weeks. Wedding collections take three to four weeks for the full edited gallery.</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
<AccordionItem value="faq-3" className="border-zinc-800">
|
||||||
|
<AccordionTrigger className="text-sm text-zinc-300 hover:text-white">Do you travel for shoots?</AccordionTrigger>
|
||||||
|
<AccordionContent className="text-zinc-500 text-sm">Absolutely. I am based in San Francisco but regularly travel for destination weddings and on-location shoots. Travel fees apply for sessions beyond 50 miles.</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user