Seed: travel template (16 files)
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
import { useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
|
||||
import { MapPin, Phone, Mail, Clock, 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 { mutate: createBooking, loading: sending } = useSaasMutation("scheduling", "/bookings");
|
||||
const [destination, setDestination] = useState("");
|
||||
const [groupSize, setGroupSize] = useState("");
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
const data = new FormData(e.currentTarget);
|
||||
try {
|
||||
await createBooking({
|
||||
name: data.get("name"),
|
||||
email: data.get("email"),
|
||||
phone: data.get("phone"),
|
||||
destination,
|
||||
dates: data.get("dates"),
|
||||
groupSize,
|
||||
message: data.get("message"),
|
||||
});
|
||||
toast.success("Message sent! Our travel experts will get back to you within 24 hours.");
|
||||
e.currentTarget.reset();
|
||||
setDestination("");
|
||||
setGroupSize("");
|
||||
} catch (err) {
|
||||
toast.error("Could not send your inquiry. Please try again.");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background text-foreground antialiased">
|
||||
<Header />
|
||||
|
||||
{/* ── HERO ── */}
|
||||
<section className="pt-32 pb-16 bg-gradient-to-b from-slate-950 via-blue-950/30 to-slate-900">
|
||||
<div className="mx-auto max-w-7xl px-6 text-center">
|
||||
<Badge variant="secondary" className="mb-4 px-3 py-1 text-xs tracking-widest uppercase bg-blue-900/30 text-cyan-300 border-blue-700/30">Get in Touch</Badge>
|
||||
<h1 className="text-4xl md:text-5xl font-bold text-white animate-fade-up">Plan Your Trip</h1>
|
||||
<p className="mt-3 text-slate-400 max-w-xl mx-auto">Tell us about your dream destination and we will craft the perfect itinerary.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-16 bg-slate-900">
|
||||
<div className="mx-auto max-w-7xl px-6">
|
||||
<div className="grid lg:grid-cols-3 gap-12">
|
||||
{/* ── FORM ── */}
|
||||
<div className="lg:col-span-2">
|
||||
<Card className="border-slate-800 bg-slate-950/50">
|
||||
<CardContent className="p-6 md:p-8">
|
||||
<h2 className="text-xl font-bold text-white mb-6">Trip Inquiry</h2>
|
||||
<form onSubmit={handleSubmit} className="space-y-5">
|
||||
<div className="grid sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-300 mb-1.5 block">Full Name</label>
|
||||
<Input name="name" required placeholder="John Smith" className="bg-slate-900 border-slate-700 text-white rounded-lg" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-300 mb-1.5 block">Email</label>
|
||||
<Input name="email" required type="email" placeholder="john@example.com" className="bg-slate-900 border-slate-700 text-white rounded-lg" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-300 mb-1.5 block">Phone</label>
|
||||
<Input name="phone" type="tel" placeholder="+1 (555) 000-0000" className="bg-slate-900 border-slate-700 text-white rounded-lg" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-300 mb-1.5 block">Destination Interest</label>
|
||||
<Select value={destination} onValueChange={setDestination}>
|
||||
<SelectTrigger className="bg-slate-900 border-slate-700 text-white rounded-lg">
|
||||
<SelectValue placeholder="Select destination" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="asia">Asia</SelectItem>
|
||||
<SelectItem value="europe">Europe</SelectItem>
|
||||
<SelectItem value="americas">Americas</SelectItem>
|
||||
<SelectItem value="africa">Africa</SelectItem>
|
||||
<SelectItem value="oceania">Oceania</SelectItem>
|
||||
<SelectItem value="undecided">Not sure yet</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-300 mb-1.5 block">Preferred Travel Dates</label>
|
||||
<Input name="dates" type="text" placeholder="e.g. June 2026" className="bg-slate-900 border-slate-700 text-white rounded-lg" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-300 mb-1.5 block">Group Size</label>
|
||||
<Select value={groupSize} onValueChange={setGroupSize}>
|
||||
<SelectTrigger className="bg-slate-900 border-slate-700 text-white rounded-lg">
|
||||
<SelectValue placeholder="Number of travelers" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="1">Solo Traveler</SelectItem>
|
||||
<SelectItem value="2">Couple (2)</SelectItem>
|
||||
<SelectItem value="3-4">Small Group (3-4)</SelectItem>
|
||||
<SelectItem value="5-8">Medium Group (5-8)</SelectItem>
|
||||
<SelectItem value="9+">Large Group (9+)</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-300 mb-1.5 block">Message</label>
|
||||
<Textarea name="message" placeholder="Tell us about your dream trip, interests, budget, and any special requirements..." rows={5} className="bg-slate-900 border-slate-700 text-white rounded-lg resize-none" />
|
||||
</div>
|
||||
<Button type="submit" disabled={sending} className="w-full sm:w-auto bg-blue-600 hover:bg-blue-500 text-white rounded-full px-8 font-semibold active:scale-[0.98] shadow-lg shadow-blue-600/20">
|
||||
{sending ? "Sending..." : "Send Inquiry"} <Send className="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* ── SIDEBAR ── */}
|
||||
<div className="space-y-6">
|
||||
{/* Office info */}
|
||||
<Card className="border-slate-800 bg-slate-950/50">
|
||||
<CardContent className="p-6">
|
||||
<h3 className="text-lg font-bold text-white mb-4">Our Office</h3>
|
||||
<div className="space-y-4 text-sm">
|
||||
<div className="flex items-start gap-3">
|
||||
<MapPin className="h-4 w-4 mt-0.5 text-cyan-400 shrink-0" />
|
||||
<span className="text-slate-300">350 Fifth Avenue, Suite 4200, New York, NY 10118</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<Phone className="h-4 w-4 text-cyan-400 shrink-0" />
|
||||
<span className="text-slate-300">+1 (212) 555-0199</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<Mail className="h-4 w-4 text-cyan-400 shrink-0" />
|
||||
<span className="text-slate-300">hello@wanderlusttravels.com</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<Clock className="h-4 w-4 text-cyan-400 shrink-0" />
|
||||
<span className="text-slate-300">Mon–Fri 9 AM – 7 PM EST</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* FAQ */}
|
||||
<Card className="border-slate-800 bg-slate-950/50">
|
||||
<CardContent className="p-6">
|
||||
<h3 className="text-lg font-bold text-white mb-4">Frequently Asked</h3>
|
||||
<Accordion type="single" collapsible className="space-y-1">
|
||||
<AccordionItem value="faq-1" className="border-slate-800">
|
||||
<AccordionTrigger className="text-sm text-slate-200 hover:text-cyan-400 hover:no-underline py-3">Do I need a visa for international travel?</AccordionTrigger>
|
||||
<AccordionContent className="text-sm text-slate-400">Visa requirements vary by destination and nationality. Our team will provide detailed visa guidance and can assist with applications for all included destinations.</AccordionContent>
|
||||
</AccordionItem>
|
||||
<AccordionItem value="faq-2" className="border-slate-800">
|
||||
<AccordionTrigger className="text-sm text-slate-200 hover:text-cyan-400 hover:no-underline py-3">Is travel insurance included?</AccordionTrigger>
|
||||
<AccordionContent className="text-sm text-slate-400">Basic travel insurance is included with all packages. We also offer comprehensive premium insurance covering medical emergencies, trip cancellation, and lost luggage.</AccordionContent>
|
||||
</AccordionItem>
|
||||
<AccordionItem value="faq-3" className="border-slate-800">
|
||||
<AccordionTrigger className="text-sm text-slate-200 hover:text-cyan-400 hover:no-underline py-3">What is your cancellation policy?</AccordionTrigger>
|
||||
<AccordionContent className="text-sm text-slate-400">Free cancellation up to 48 hours before departure for a full refund. Cancellations within 48 hours may be subject to a partial fee depending on the package.</AccordionContent>
|
||||
</AccordionItem>
|
||||
<AccordionItem value="faq-4" className="border-slate-800">
|
||||
<AccordionTrigger className="text-sm text-slate-200 hover:text-cyan-400 hover:no-underline py-3">Do you offer group discounts?</AccordionTrigger>
|
||||
<AccordionContent className="text-sm text-slate-400">Yes! Groups of 6 or more receive a 10% discount on most packages. Corporate and school groups can contact us for custom group pricing and tailored itineraries.</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user