855 lines
54 KiB
TypeScript
855 lines
54 KiB
TypeScript
import { ArrowRight, Check, CreditCard, DollarSign, MapPin, Palette, Sparkles, Ticket, Zap } from 'lucide-react';
|
|
import { AnimatePresence, motion } from 'motion/react';
|
|
import { useEffect, useState } from 'react';
|
|
import { Layout } from '../Layout';
|
|
import { ImageWithFallback } from './figma/ImageWithFallback';
|
|
import { MobileAppSection } from './MobileAppSection';
|
|
import { TrustSection } from './TrustSection';
|
|
import { Button } from './ui/button';
|
|
|
|
interface User {
|
|
email: string;
|
|
name: string;
|
|
}
|
|
|
|
interface DiscoverPageProps {
|
|
onHomeClick: () => void;
|
|
onPassesClick: () => void;
|
|
onCheckoutClick?: () => void;
|
|
onSignInClick: () => void;
|
|
onSignOutClick?: () => void;
|
|
onBlogsClick: () => void;
|
|
onHowItWorksClick: () => void;
|
|
onFAQClick: () => void;
|
|
onPrivacyPolicyClick: () => void;
|
|
onAboutUsClick: () => void;
|
|
onProfileClick?: () => void;
|
|
onCityCardsClick?: () => void;
|
|
onMagicItineraryClick?: () => void;
|
|
onPostCardsClick?: () => void;
|
|
onOffersClick?: () => void;
|
|
onEsimsClick?: () => void;
|
|
onHotelDiscountsClick?: () => void;
|
|
onContactUsClick?: () => void;
|
|
onAttractionsClick?: () => void;
|
|
onDiscoverClick?: () => void;
|
|
onProductsClick?: () => void;
|
|
currentPage?: string;
|
|
user?: User | null;
|
|
}
|
|
|
|
export function DiscoverPage({
|
|
onHomeClick,
|
|
onPassesClick,
|
|
onCheckoutClick,
|
|
onSignInClick,
|
|
onSignOutClick,
|
|
onBlogsClick,
|
|
onHowItWorksClick,
|
|
onFAQClick,
|
|
onPrivacyPolicyClick,
|
|
onAboutUsClick,
|
|
onProfileClick,
|
|
onCityCardsClick,
|
|
onMagicItineraryClick,
|
|
onPostCardsClick,
|
|
onOffersClick,
|
|
onEsimsClick,
|
|
onHotelDiscountsClick,
|
|
onContactUsClick,
|
|
onAttractionsClick,
|
|
onDiscoverClick,
|
|
onProductsClick,
|
|
currentPage,
|
|
user
|
|
}: DiscoverPageProps) {
|
|
const [selectedPass, setSelectedPass] = useState<string>('unlimited');
|
|
const [currentSlide, setCurrentSlide] = useState(0);
|
|
const [direction, setDirection] = useState(0);
|
|
const [activeStep, setActiveStep] = useState(0);
|
|
|
|
const handleStepInView = (index: number) => {
|
|
setActiveStep(index);
|
|
};
|
|
|
|
const steps = [
|
|
{
|
|
number: '01',
|
|
title: 'Choose Your City',
|
|
description: 'Browse our curated collection of world-class destinations. From the romantic streets of Paris to the bustling energy of Tokyo, find the perfect backdrop for your next adventure.',
|
|
icon: MapPin,
|
|
color: '#F95F62',
|
|
image: "https://images.unsplash.com/photo-1601981580769-ee141c0c8c0c?w=800&q=80"
|
|
},
|
|
{
|
|
number: '02',
|
|
title: 'Get Your Pass',
|
|
description: 'Select the pass that fits your schedule. Whether you prefer a flexible Explorer Pass for casual sightseeing or an Unlimited Pass for maximum value, we have you covered.',
|
|
icon: CreditCard,
|
|
color: '#FFB23F',
|
|
image: "https://images.unsplash.com/photo-1654163601023-88f6ba22b2c7?w=800&q=80"
|
|
},
|
|
{
|
|
number: '03',
|
|
title: 'Explore with Magic',
|
|
description: "Unlock the city's secrets with our AI-driven itinerary planner. Get real-time recommendations, skip-the-line access, and exclusive perks that make your trip unforgettable.",
|
|
icon: Sparkles,
|
|
color: '#10B981',
|
|
image: "https://images.unsplash.com/photo-1509576931792-214960705f8a?w=800&q=80"
|
|
}
|
|
];
|
|
|
|
const slides = [
|
|
{
|
|
type: 'overview',
|
|
description: "Explore the world's greatest cities seamlessly. Save money, skip the lines, and discover hidden gems with your personalized Magic Itinerary—all in one card.",
|
|
image: "https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?w=1200&h=1000&fit=crop",
|
|
showButtons: true,
|
|
},
|
|
{
|
|
type: 'feature',
|
|
subtitle: 'Save Big',
|
|
title: 'Save up to 50% on Attractions',
|
|
description: "Why pay full price? Get entry to top museums, tours, and landmarks for a fraction of the cost. The more you see, the more you save.",
|
|
image: "https://images.unsplash.com/photo-1516306580123-e6e52b1b7b5f?w=1200&h=1000&fit=crop",
|
|
showButtons: true,
|
|
},
|
|
{
|
|
type: 'feature',
|
|
subtitle: 'Travel Smart',
|
|
title: 'AI-Powered Magic Itinerary',
|
|
description: "Forget planning stress. Our intelligent system builds the perfect schedule based on your interests and travel pace.",
|
|
image: "https://images.unsplash.com/photo-1501785888041-af3ef285b470?w=1200&h=1000&fit=crop",
|
|
showButtons: true,
|
|
}
|
|
];
|
|
|
|
const currentSlideData = slides[currentSlide];
|
|
|
|
useEffect(() => {
|
|
const timer = setInterval(() => {
|
|
setDirection(1);
|
|
setCurrentSlide((prev) => (prev + 1) % slides.length);
|
|
}, 5000);
|
|
return () => clearInterval(timer);
|
|
}, [slides.length]);
|
|
|
|
const passes = [
|
|
{
|
|
id: 'flexi',
|
|
name: 'FLEXI CARD',
|
|
description: 'Perfect for travelers who want to explore selected attractions at their own pace.',
|
|
price: '$59.99',
|
|
originalPrice: '$89.99',
|
|
savings: '33%',
|
|
features: [
|
|
'Access to selected attractions',
|
|
'Limited number of attractions per pass',
|
|
'Flexible validity period',
|
|
'Priority entry where available',
|
|
'Mobile ticket delivery'
|
|
],
|
|
color: 'bg-foreground',
|
|
popular: false
|
|
},
|
|
{
|
|
id: 'unlimited',
|
|
name: 'UNLIMITED CARD',
|
|
description: 'The ultimate experience for adventure seekers who want unlimited access to all attractions.',
|
|
price: '$89.99',
|
|
originalPrice: '$149.99',
|
|
savings: '40%',
|
|
features: [
|
|
'Unlimited access to all attractions',
|
|
'Time-limited validity (7 days)',
|
|
'Skip-the-line access',
|
|
'Expert guide inclusion',
|
|
'Mobile app access',
|
|
'Premium customer support'
|
|
],
|
|
color: 'bg-primary',
|
|
popular: true
|
|
}
|
|
];
|
|
|
|
return (
|
|
<Layout
|
|
activeCity={sessionStorage.getItem("lastKnownCity") ||"shared"}
|
|
onSignInClick={onSignInClick}
|
|
onSignOutClick={onSignOutClick}
|
|
user={user}
|
|
>
|
|
<div className="min-h-screen bg-background">
|
|
|
|
{/* Hero Section */}
|
|
<div className="relative h-[82vh] w-full overflow-hidden bg-black">
|
|
<AnimatePresence initial={false} custom={direction} mode="wait">
|
|
<motion.div
|
|
key={currentSlide}
|
|
className="absolute inset-0 w-full h-full"
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
exit={{ opacity: 0 }}
|
|
transition={{ duration: 0.8 }}
|
|
>
|
|
{/* Background Image Layer */}
|
|
<div className="absolute inset-0 z-0">
|
|
<motion.div
|
|
className="w-full h-full"
|
|
initial={{ scale: 1.1 }}
|
|
animate={{ scale: 1 }}
|
|
transition={{ duration: 8, ease: "easeOut" }}
|
|
>
|
|
<ImageWithFallback
|
|
src={currentSlideData.image}
|
|
alt={currentSlideData.title || "Travel the World"}
|
|
className="w-full h-full object-cover opacity-90"
|
|
/>
|
|
</motion.div>
|
|
{/* Cinematic Overlay */}
|
|
<div className="absolute inset-0 bg-gradient-to-r from-black/80 via-black/40 to-transparent" />
|
|
<div className="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-black/30" />
|
|
</div>
|
|
|
|
{/* Content Layer */}
|
|
<div className="relative z-10 container mx-auto px-4 sm:px-6 lg:px-8 h-full flex flex-col justify-center pt-[80px] md:justify-start md:pt-[120px] lg:justify-center lg:pt-0">
|
|
<div className="max-w-4xl pl-4 md:pl-8 border-l-4 border-primary/80 backdrop-blur-sm bg-black/10 py-8 pr-8 rounded-r-3xl md:max-w-lg lg:max-w-3xl">
|
|
{currentSlideData.type === 'overview' ? (
|
|
<>
|
|
<motion.div
|
|
initial={{ opacity: 0, x: -20 }}
|
|
animate={{ opacity: 1, x: 0 }}
|
|
transition={{ duration: 0.6, delay: 0.2 }}
|
|
className="mb-8"
|
|
>
|
|
<div className="flex gap-3 mb-4">
|
|
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-white/20 backdrop-blur-md text-white text-xs font-medium tracking-wider uppercase border border-white/10">
|
|
<MapPin className="w-3 h-3" /> Explore
|
|
</span>
|
|
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-primary/90 backdrop-blur-md text-white text-xs font-medium tracking-wider uppercase shadow-lg">
|
|
<Sparkles className="w-3 h-3" /> New
|
|
</span>
|
|
</div>
|
|
<h1 className="font-poppins text-3xl md:text-3xl lg:text-5xl font-bold text-white leading-tight mb-4 md:mb-4">
|
|
<span className="block font-light text-white/90 text-xl md:text-lg lg:text-3xl mb-1 md:mb-2">Wanderlust Awaits</span>
|
|
Your Passport to <br />
|
|
<span className="text-primary bg-clip-text">Global Discovery</span>
|
|
</h1>
|
|
<motion.p
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
transition={{ duration: 0.6, delay: 0.4 }}
|
|
className="font-poppins font-light text-base md:text-xs lg:text-lg text-white/90 leading-relaxed max-w-xl md:max-w-sm lg:max-w-xl"
|
|
>
|
|
Unlock the world's greatest cities with one smart pass. Save money, skip the lines, and discover hidden gems with your personalized itinerary.
|
|
</motion.p>
|
|
</motion.div>
|
|
|
|
{currentSlideData.showButtons && (
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.6, delay: 0.5 }}
|
|
className="flex flex-col sm:flex-row gap-4"
|
|
>
|
|
<Button
|
|
onClick={onCheckoutClick}
|
|
className="h-12 md:h-10 lg:h-12 px-6 md:px-5 lg:px-8 rounded-full bg-primary hover:bg-primary/90 text-white font-poppins font-semibold text-base md:text-sm lg:text-base shadow-[0_0_20px_rgba(249,95,98,0.4)] hover:shadow-[0_0_30px_rgba(249,95,98,0.6)] transition-all duration-300 border-none group"
|
|
>
|
|
<span className="flex items-center gap-2">
|
|
Start Your Journey <ArrowRight className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
|
|
</span>
|
|
</Button>
|
|
<Button
|
|
onClick={onPassesClick}
|
|
variant="outline"
|
|
className="h-12 md:h-10 lg:h-12 px-6 md:px-5 lg:px-8 rounded-full bg-white/10 backdrop-blur-md border-white/30 text-white hover:bg-white hover:text-primary font-poppins font-semibold text-base md:text-sm lg:text-base transition-all duration-300"
|
|
>
|
|
View Destinations
|
|
</Button>
|
|
</motion.div>
|
|
)}
|
|
</>
|
|
) : (
|
|
<>
|
|
<motion.div
|
|
initial={{ opacity: 0, x: -20 }}
|
|
animate={{ opacity: 1, x: 0 }}
|
|
transition={{ duration: 0.6, delay: 0.2 }}
|
|
className="mb-8"
|
|
>
|
|
<div className="flex gap-3 mb-4">
|
|
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-primary text-white text-xs font-medium tracking-wider uppercase shadow-lg">
|
|
{currentSlideData.subtitle}
|
|
</span>
|
|
</div>
|
|
<h1 className="font-poppins text-3xl md:text-4xl lg:text-5xl font-bold text-white leading-tight mb-4 md:mb-6">
|
|
{currentSlideData.title === 'AI-Powered Magic Itinerary' ? 'Intelligent Magic Itinerary' : currentSlideData.title}
|
|
</h1>
|
|
<motion.p
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
transition={{ duration: 0.6, delay: 0.4 }}
|
|
className="font-poppins font-light text-base md:text-sm lg:text-lg text-white/90 leading-relaxed max-w-xl md:max-w-md lg:max-w-xl"
|
|
>
|
|
{currentSlideData.description}
|
|
</motion.p>
|
|
</motion.div>
|
|
{currentSlideData.showButtons && (
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.6, delay: 0.5 }}
|
|
className="flex flex-col sm:flex-row gap-4"
|
|
>
|
|
<Button
|
|
onClick={onCheckoutClick}
|
|
className="h-12 md:h-12 lg:h-12 px-6 md:px-6 lg:px-8 rounded-full bg-primary hover:bg-primary/90 text-white font-poppins font-semibold text-base md:text-base lg:text-base shadow-[0_0_20px_rgba(249,95,98,0.4)] transition-all duration-300 border-none"
|
|
>
|
|
Get Started
|
|
</Button>
|
|
<Button
|
|
onClick={onPassesClick}
|
|
variant="outline"
|
|
className="h-12 md:h-12 lg:h-12 px-6 md:px-6 lg:px-8 rounded-full bg-white/10 backdrop-blur-md border-white/30 text-white hover:bg-white hover:text-primary font-poppins font-semibold text-base md:text-base lg:text-base transition-all duration-300"
|
|
>
|
|
Learn More
|
|
</Button>
|
|
</motion.div>
|
|
)}
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
</AnimatePresence>
|
|
</div>
|
|
|
|
{/* How It Works Section */}
|
|
{/* How It Works Section - Travel Journal Style */}
|
|
<section className="relative py-24 bg-[#FFFBF0] overflow-hidden">
|
|
{/* Background Texture */}
|
|
<div className="absolute inset-0 z-0 opacity-40 pointer-events-none"
|
|
style={{
|
|
backgroundImage: `url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23F95F62' fill-opacity='0.05'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`
|
|
}}
|
|
/>
|
|
|
|
{/* Decorative Blobs */}
|
|
<div className="absolute top-0 right-0 w-[500px] h-[500px] bg-orange-200/20 rounded-full blur-3xl -mr-32 -mt-32 pointer-events-none"></div>
|
|
<div className="absolute bottom-0 left-0 w-[500px] h-[500px] bg-red-200/20 rounded-full blur-3xl -ml-32 -mb-32 pointer-events-none"></div>
|
|
|
|
<div className="container mx-auto px-4 relative z-10">
|
|
<motion.div
|
|
className="text-center mb-24"
|
|
initial={{ opacity: 0, y: 30 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.6 }}
|
|
>
|
|
<div className="inline-block mb-3">
|
|
<span className="font-poppins font-medium text-primary uppercase tracking-[0.2em] text-sm bg-primary/10 px-4 py-2 rounded-full">Process</span>
|
|
</div>
|
|
<h2 className="font-poppins text-4xl md:text-5xl lg:text-6xl font-bold text-gray-900 leading-tight">
|
|
Start Your <span className="relative inline-block text-primary">
|
|
Journey
|
|
<svg className="absolute w-full h-3 -bottom-1 left-0 text-yellow-400 opacity-60" viewBox="0 0 100 10" preserveAspectRatio="none">
|
|
<path d="M0 5 Q 50 10 100 5" stroke="currentColor" strokeWidth="8" fill="none" />
|
|
</svg>
|
|
</span>
|
|
</h2>
|
|
<p className="font-poppins text-gray-500 mt-6 max-w-2xl mx-auto text-lg font-light">
|
|
Three simple steps to unlock the city's best experiences. It's like having a local guide in your pocket.
|
|
</p>
|
|
</motion.div>
|
|
|
|
<div className="relative max-w-6xl mx-auto">
|
|
{/* Central Connecting Line (Desktop) */}
|
|
<div className="hidden lg:block absolute left-1/2 top-10 bottom-10 w-0.5 border-l-2 border-primary/20 border-dashed transform -translate-x-1/2 z-0"></div>
|
|
|
|
{steps.map((step, index) => {
|
|
const isEven = index % 2 === 0;
|
|
|
|
return (
|
|
<motion.div
|
|
key={step.number}
|
|
className={`flex flex-col lg:flex-row items-center gap-12 lg:gap-20 mb-24 last:mb-0 relative z-10 ${isEven ? '' : 'lg:flex-row-reverse'
|
|
}`}
|
|
initial={{ opacity: 0, y: 50 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true, margin: "-100px" }}
|
|
transition={{ duration: 0.7, delay: index * 0.1 }}
|
|
>
|
|
{/* Image Side - Polaroid Style - Always on left for odd, right for even */}
|
|
<div className={`flex-1 w-full flex justify-center ${isEven ? 'lg:order-1' : 'lg:order-2'
|
|
}`}>
|
|
<div className={`relative max-w-md mx-auto transform transition-transform duration-500 hover:scale-105 hover:z-20 ${isEven ? 'lg:rotate-[-3deg] hover:rotate-0' : 'lg:rotate-[3deg] hover:rotate-0'
|
|
}`}>
|
|
{/* Washi Tape */}
|
|
<div className="absolute -top-4 left-1/2 -translate-x-1/2 w-32 h-8 bg-yellow-100/90 shadow-sm z-20 rotate-[-1deg] opacity-90 backdrop-blur-sm"></div>
|
|
|
|
{/* Polaroid Frame */}
|
|
<div className="bg-white p-4 pb-12 shadow-[0_10px_40px_rgba(0,0,0,0.1)] rounded-sm border border-gray-100">
|
|
<div className="aspect-[4/3] w-full overflow-hidden bg-gray-100 mb-4 relative">
|
|
<div className="absolute inset-0 bg-black/5 z-10 pointer-events-none mix-blend-multiply"></div>
|
|
<ImageWithFallback
|
|
src={step.image}
|
|
alt={step.title}
|
|
className="w-full h-full object-cover filter contrast-[1.1] saturate-[0.9]"
|
|
/>
|
|
</div>
|
|
<div className="font-poppins text-gray-400 text-sm italic text-center flex items-center justify-center gap-2">
|
|
<MapPin className="w-3 h-3" />
|
|
<span>Step {step.number} • {step.title}</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Stamp Decoration */}
|
|
<div className={`absolute -bottom-6 ${isEven ? '-right-6' : '-left-6'
|
|
} w-24 h-24 bg-white/90 rounded-full border-4 border-double border-primary/30 flex items-center justify-center shadow-lg rotate-12 z-30`}>
|
|
<div className="text-center">
|
|
<div className="text-[10px] font-bold text-primary uppercase tracking-widest">APPROVED</div>
|
|
<div className="text-xs text-gray-400 font-serif italic">CityCards</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Center Marker (Desktop) */}
|
|
<div className="hidden lg:flex absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-12 h-12 bg-white border-4 border-primary rounded-full items-center justify-center shadow-lg z-20">
|
|
<div className="w-3 h-3 bg-primary rounded-full"></div>
|
|
</div>
|
|
|
|
{/* Text Side - Always on right for odd, left for even */}
|
|
<div className={`flex-1 ${isEven ? 'lg:order-2' : 'lg:order-1'
|
|
} text-center lg:text-left`}>
|
|
<div className={`inline-flex items-center justify-center w-16 h-16 rounded-2xl mb-6 shadow-sm ${index === 0 ? 'bg-red-100 text-red-600' :
|
|
index === 1 ? 'bg-orange-100 text-orange-600' :
|
|
'bg-green-100 text-green-600'
|
|
}`}>
|
|
<step.icon className="w-8 h-8" strokeWidth={1.5} />
|
|
</div>
|
|
<h3 className="font-poppins font-bold text-3xl text-gray-900 mb-4">
|
|
<span className="text-primary/40 mr-2 text-4xl font-serif italic">0{index + 1}.</span>
|
|
{step.title}
|
|
</h3>
|
|
<p className="font-poppins text-lg text-gray-600 leading-relaxed font-light">
|
|
{step.description}
|
|
</p>
|
|
</div>
|
|
</motion.div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Why Choose City Cards Section */}
|
|
<section className="relative py-24 bg-[#FFF9F5] overflow-hidden">
|
|
{/* Background Map Decoration */}
|
|
<div className="absolute inset-0 z-0 opacity-[0.05] pointer-events-none">
|
|
<ImageWithFallback
|
|
src="https://images.unsplash.com/photo-1723307061004-6e2e087deae1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHx3b3JsZCUyMG1hcCUyMHZlY3RvciUyMHNrZXRjaCUyMG1pbmltYWxpc3R8ZW58MXx8fHwxNzY5NjcwODI4fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
|
|
alt="World Map"
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
</div>
|
|
|
|
{/* Floating Travel Icons Background */}
|
|
<div className="absolute top-20 left-10 text-primary/10 rotate-12 animate-pulse hidden lg:block">
|
|
<MapPin className="w-24 h-24" />
|
|
</div>
|
|
<div className="absolute bottom-20 right-10 text-orange-400/10 -rotate-12 animate-bounce hidden lg:block" style={{ animationDuration: '3s' }}>
|
|
<Sparkles className="w-24 h-24" />
|
|
</div>
|
|
|
|
<div className="container mx-auto px-4 relative z-10">
|
|
<motion.div
|
|
className="text-center mb-16"
|
|
initial={{ opacity: 0, y: 30 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.6, ease: "easeOut" }}
|
|
>
|
|
<div className="inline-flex items-center gap-2 mb-4 px-5 py-2 rounded-full bg-white border border-primary/20 shadow-sm transform hover:scale-105 transition-transform duration-300">
|
|
<span className="w-2 h-2 rounded-full bg-primary animate-pulse"></span>
|
|
<span className="font-poppins text-sm font-semibold text-primary tracking-wide uppercase">Why Travelers Choose Us</span>
|
|
</div>
|
|
<motion.h2
|
|
className="font-poppins text-4xl md:text-5xl lg:text-6xl leading-tight mb-6"
|
|
initial={{ opacity: 0, y: 20 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.6, delay: 0.1 }}
|
|
>
|
|
<span className="font-light text-gray-900">Unlock Your </span>
|
|
<span className="font-bold text-transparent bg-clip-text bg-gradient-to-r from-primary to-orange-500 italic pr-2">Adventure</span>
|
|
</motion.h2>
|
|
<motion.p
|
|
className="font-poppins text-xl leading-relaxed font-light text-gray-600 max-w-2xl mx-auto"
|
|
initial={{ opacity: 0, y: 20 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.6, delay: 0.2 }}
|
|
>
|
|
Travel smarter, not harder. We've curated the ultimate toolkit for modern explorers to experience cities like a local.
|
|
</motion.p>
|
|
</motion.div>
|
|
|
|
<motion.div
|
|
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"
|
|
initial="hidden"
|
|
whileInView="visible"
|
|
viewport={{ once: true }}
|
|
variants={{
|
|
visible: { transition: { staggerChildren: 0.1 } }
|
|
}}
|
|
>
|
|
{[
|
|
{
|
|
type: 'feature',
|
|
icon: DollarSign,
|
|
title: "Maximum Savings",
|
|
subtitle: "Budget Friendly",
|
|
desc: "Keep your travel funds for what matters. Save up to 43% compared to buying individual tickets.",
|
|
color: "emerald",
|
|
badge: "BEST VALUE"
|
|
},
|
|
{
|
|
type: 'feature',
|
|
icon: Zap,
|
|
title: "Priority Access",
|
|
subtitle: "Skip The Line",
|
|
desc: "Feel like a VIP. Walk past the long queues at the most popular landmarks and museums.",
|
|
color: "amber",
|
|
badge: "TIME SAVER"
|
|
},
|
|
{
|
|
type: 'image',
|
|
image: "https://images.unsplash.com/photo-1768639401082-f45f9241c768?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxoaWRkZW4lMjBnZW0lMjB0cmF2ZWwlMjBzcG90JTIwYmVhdXRpZnVsfGVufDF8fHx8MTc2OTY3MDgzOHww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
|
|
title: "Hidden Gems",
|
|
desc: "Discover secret spots only locals know about.",
|
|
badge: "INSIDER TIP"
|
|
},
|
|
{
|
|
type: 'image',
|
|
image: "https://images.unsplash.com/photo-1574178508948-d01c15d33e76?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxkZWxpY2lvdXMlMjBmb29kJTIwdHJhdmVsJTIwZGluaW5nJTIwYWVzdGhldGljfGVufDF8fHx8MTc2OTY3MDgzOHww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
|
|
title: "Culinary Journey",
|
|
desc: "Taste your way through the city with exclusive dining perks.",
|
|
badge: "DELICIOUS"
|
|
},
|
|
{
|
|
type: 'feature',
|
|
icon: Palette,
|
|
title: "Cultural Deep Dive",
|
|
subtitle: "Immersive Tours",
|
|
desc: "Connect with the soul of the city through expert-led art, history, and cultural experiences.",
|
|
color: "violet",
|
|
},
|
|
{
|
|
type: 'feature',
|
|
icon: Ticket,
|
|
title: "All-Digital Pass",
|
|
subtitle: "Eco-Friendly",
|
|
desc: "Travel light. Your entire trip fits in your pocket with our seamless mobile pass system.",
|
|
color: "blue",
|
|
}
|
|
].map((item, index) => (
|
|
<motion.div
|
|
key={index}
|
|
className={`relative group rounded-[2.5rem] overflow-hidden transition-all duration-500 ${item.type === 'image'
|
|
? 'h-[320px] shadow-lg hover:shadow-2xl hover:-translate-y-2'
|
|
: 'bg-white p-8 border border-white/50 shadow-[0_10px_40px_-10px_rgba(0,0,0,0.08)] hover:shadow-[0_20px_60px_-15px_rgba(0,0,0,0.12)] hover:-translate-y-2'
|
|
}`}
|
|
variants={{
|
|
hidden: { opacity: 0, y: 30 },
|
|
visible: { opacity: 1, y: 0, transition: { duration: 0.5 } }
|
|
}}
|
|
>
|
|
{item.type === 'feature' ? (
|
|
<>
|
|
<div className={`absolute top-0 right-0 w-32 h-32 bg-${item.color}-50 rounded-bl-[100px] -mr-10 -mt-10 transition-transform group-hover:scale-110 duration-500`}></div>
|
|
|
|
<div className="relative z-10">
|
|
<div className="flex justify-between items-start mb-6">
|
|
<div className={`w-16 h-16 rounded-2xl bg-${item.color}-100 text-${item.color}-600 flex items-center justify-center transform group-hover:rotate-6 transition-transform duration-300 shadow-sm`}>
|
|
<item.icon className="w-8 h-8" strokeWidth={2} />
|
|
</div>
|
|
{item.badge && (
|
|
<span className={`px-3 py-1 rounded-full text-[10px] font-bold tracking-wider uppercase bg-${item.color}-100 text-${item.color}-700 border border-${item.color}-200`}>
|
|
{item.badge}
|
|
</span>
|
|
)}
|
|
</div>
|
|
|
|
<h3 className="font-poppins text-2xl font-bold text-gray-900 mb-2">{item.title}</h3>
|
|
<p className={`font-poppins text-sm font-medium mb-3 text-${item.color}-600/80 uppercase tracking-wide`}>
|
|
{item.subtitle}
|
|
</p>
|
|
<p className="font-poppins text-gray-500 leading-relaxed text-base font-light">
|
|
{item.desc}
|
|
</p>
|
|
</div>
|
|
</>
|
|
) : (
|
|
<>
|
|
<div className="absolute inset-0">
|
|
<ImageWithFallback
|
|
src={item.image || ""}
|
|
alt={item.title}
|
|
className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110"
|
|
/>
|
|
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent"></div>
|
|
</div>
|
|
|
|
<div className="relative z-10 h-full flex flex-col justify-end p-8 text-white">
|
|
{item.badge && (
|
|
<div className="absolute top-6 right-6">
|
|
<span className="px-3 py-1 rounded-full text-[10px] font-bold tracking-wider uppercase bg-white/20 backdrop-blur-md border border-white/30 text-white">
|
|
{item.badge}
|
|
</span>
|
|
</div>
|
|
)}
|
|
<h3 className="font-poppins text-2xl font-bold mb-2">{item.title}</h3>
|
|
<p className="font-poppins text-white/90 font-light leading-relaxed">
|
|
{item.desc}
|
|
</p>
|
|
</div>
|
|
</>
|
|
)}
|
|
</motion.div>
|
|
))}
|
|
</motion.div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Pass Options Overview - Refactored with RadioGroup and Card Design */}
|
|
<section className="py-24 bg-white">
|
|
<div className="container mx-auto px-4">
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 30 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.6 }}
|
|
className="text-center mb-16"
|
|
>
|
|
<div className="inline-block mb-4 px-4 py-1.5 rounded-full bg-primary/10 border border-primary/20">
|
|
<span className="font-poppins text-sm font-semibold text-primary tracking-wide uppercase">PRICING PLANS</span>
|
|
</div>
|
|
<h2 className="font-poppins text-3xl md:text-4xl lg:text-5xl leading-tight mb-6">
|
|
<span className="font-light text-gray-900">Choose Your </span>
|
|
<span className="font-bold text-primary">Perfect Pass</span>
|
|
</h2>
|
|
<p className="font-poppins text-xl leading-relaxed font-normal text-gray-600 max-w-2xl mx-auto">
|
|
Flexible options designed to match your travel style. Compare our two pass types and find the perfect fit.
|
|
</p>
|
|
</motion.div>
|
|
|
|
<div className="grid md:grid-cols-2 gap-8 max-w-4xl mx-auto">
|
|
{/* Flexi Card */}
|
|
<motion.div
|
|
initial={{ opacity: 0, x: -30 }}
|
|
whileInView={{ opacity: 1, x: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.6 }}
|
|
className="bg-white rounded-3xl p-8 border-2 border-gray-200 hover:border-gray-300 transition-all duration-300 hover:shadow-xl"
|
|
>
|
|
<div className="mb-6 text-center">
|
|
<h3 className="font-poppins font-bold text-2xl text-foreground mb-3">
|
|
FLEXI CARD
|
|
</h3>
|
|
<p className="font-poppins text-gray-600 leading-relaxed">
|
|
Perfect for travelers who want to explore selected attractions at their own pace with essential features.
|
|
</p>
|
|
</div>
|
|
|
|
<ul className="space-y-3 mb-6 min-h-[210px]">
|
|
{[
|
|
'Access to selected attractions',
|
|
'Limited number of attractions per pass',
|
|
'Flexible validity period',
|
|
'Priority entry where available',
|
|
'Mobile ticket delivery'
|
|
].map((feature) => (
|
|
<li key={feature} className="flex items-start gap-3">
|
|
<div className="w-5 h-5 rounded-full bg-green-500 flex items-center justify-center flex-shrink-0 mt-0.5">
|
|
<Check className="w-3 h-3 text-white" strokeWidth={3} />
|
|
</div>
|
|
<span className="font-poppins text-gray-700">{feature}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
|
|
<div className="mb-4">
|
|
<p className="font-poppins text-xs text-gray-500 text-center">
|
|
✓ Free cancellation up to 24 hours • Instant delivery
|
|
</p>
|
|
</div>
|
|
|
|
<Button
|
|
onClick={onPassesClick}
|
|
className="w-full py-6 rounded-full font-poppins font-semibold text-lg bg-gray-900 hover:bg-black text-white transition-all duration-300"
|
|
>
|
|
VIEW FLEXI OPTIONS
|
|
</Button>
|
|
</motion.div>
|
|
|
|
{/* Unlimited Card */}
|
|
<motion.div
|
|
initial={{ opacity: 0, x: 30 }}
|
|
whileInView={{ opacity: 1, x: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.6 }}
|
|
className="bg-white rounded-3xl p-8 border-2 border-primary hover:border-primary/80 transition-all duration-300 hover:shadow-xl relative"
|
|
>
|
|
{/* Popular Badge */}
|
|
<div className="absolute -top-4 left-1/2 -translate-x-1/2 z-10">
|
|
<div className="bg-[#FFD700] text-black px-6 py-1.5 rounded-full font-poppins font-semibold text-sm shadow-md uppercase tracking-wide whitespace-nowrap">
|
|
Most Popular
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mb-6 text-center">
|
|
<h3 className="font-poppins font-bold text-2xl text-foreground mb-3">
|
|
UNLIMITED CARD
|
|
</h3>
|
|
<p className="font-poppins text-gray-600 leading-relaxed">
|
|
The ultimate experience for adventure seekers who want unlimited access to all attractions with premium features.
|
|
</p>
|
|
</div>
|
|
|
|
<ul className="space-y-3 mb-6 min-h-[210px]">
|
|
{[
|
|
'Unlimited access to all attractions',
|
|
'Time-limited validity (7 days)',
|
|
'Skip-the-line access',
|
|
'Expert guide inclusion',
|
|
'Mobile app access',
|
|
'Premium customer support'
|
|
].map((feature) => (
|
|
<li key={feature} className="flex items-start gap-3">
|
|
<div className="w-5 h-5 rounded-full bg-green-500 flex items-center justify-center flex-shrink-0 mt-0.5">
|
|
<Check className="w-3 h-3 text-white" strokeWidth={3} />
|
|
</div>
|
|
<span className="font-poppins text-gray-700">{feature}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
|
|
<div className="mb-4">
|
|
<p className="font-poppins text-xs text-gray-500 text-center">
|
|
✓ Free cancellation up to 24 hours • Instant delivery
|
|
</p>
|
|
</div>
|
|
|
|
<Button
|
|
onClick={onPassesClick}
|
|
className="w-full py-6 rounded-full font-poppins font-semibold text-lg bg-primary hover:bg-primary/90 text-white transition-all duration-300"
|
|
>
|
|
VIEW UNLIMITED OPTIONS
|
|
</Button>
|
|
</motion.div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<TrustSection />
|
|
<MobileAppSection />
|
|
|
|
{/* CTA Section */}
|
|
<section className="mt-20 py-32 md:py-40 bg-gradient-to-br from-primary to-secondary relative overflow-hidden">
|
|
<div className="absolute inset-0 opacity-10">
|
|
<div className="absolute top-0 left-0 w-96 h-96 bg-white rounded-full blur-3xl" />
|
|
<div className="absolute bottom-0 right-0 w-96 h-96 bg-white rounded-full blur-3xl" />
|
|
</div>
|
|
|
|
<div className="container mx-auto px-4 relative z-10">
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.6 }}
|
|
className="text-center max-w-3xl mx-auto"
|
|
>
|
|
<h2 className="font-poppins text-3xl md:text-4xl lg:text-5xl font-semibold text-white mb-6">
|
|
Ready to Start Your Adventure?
|
|
</h2>
|
|
<p className="font-poppins text-lg md:text-xl text-white/90 mb-8 font-normal leading-relaxed">
|
|
Join millions of travelers who've discovered the smarter way to explore cities
|
|
</p>
|
|
|
|
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
|
<Button
|
|
onClick={onCheckoutClick}
|
|
className="px-10 py-6 rounded-full font-poppins font-semibold text-lg bg-white text-primary hover:bg-gray-100 transition-all duration-300 hover:scale-105 shadow-xl"
|
|
>
|
|
Select Your City
|
|
<ArrowRight className="w-5 h-5 ml-2" />
|
|
</Button>
|
|
<Button
|
|
onClick={onPassesClick}
|
|
variant="outline"
|
|
className="px-10 py-6 rounded-full font-poppins font-semibold text-lg border-2 border-white !text-white bg-transparent hover:!bg-white hover:!text-primary transition-all duration-300"
|
|
>
|
|
View All Passes
|
|
</Button>
|
|
</div>
|
|
</motion.div>
|
|
</div>
|
|
</section>
|
|
|
|
</div>
|
|
</Layout>
|
|
);
|
|
}
|
|
|
|
function StepSection({ step, index, onInView }: { step: any, index: number, onInView: (i: number) => void }) {
|
|
const isEven = index % 2 === 0;
|
|
|
|
return (
|
|
<motion.div
|
|
className={`relative flex flex-col ${isEven ? 'lg:flex-row' : 'lg:flex-row-reverse'} items-center gap-6 lg:gap-12 max-w-6xl mx-auto z-10 py-6`}
|
|
initial={{ opacity: 0, y: 50 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: false, amount: 0.25 }}
|
|
transition={{ duration: 0.6 }}
|
|
onViewportEnter={() => onInView(index)}
|
|
>
|
|
<div className={`flex-1 text-center ${isEven ? 'lg:text-left' : 'lg:text-right'}`}>
|
|
<div className={`inline-flex items-center justify-center w-12 h-12 rounded-2xl mb-4 text-lg font-bold shadow-sm`} style={{ backgroundColor: step.color + '26', color: step.color }}>
|
|
{step.number}
|
|
</div>
|
|
<h3 className="text-2xl md:text-3xl lg:text-4xl font-bold font-poppins mb-3 text-gray-900 leading-tight">{step.title}</h3>
|
|
<p className="text-base md:text-lg text-gray-500 font-poppins leading-relaxed mb-6 max-w-lg mx-auto lg:mx-0 ml-auto">{step.description}</p>
|
|
<Button
|
|
className="rounded-full px-8 py-4 font-bold text-base shadow-lg hover:shadow-xl transition-all duration-300 hover:-translate-y-1"
|
|
style={{ backgroundColor: step.color, color: 'white' }}
|
|
>
|
|
Learn More
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="flex-1 relative w-full max-w-md lg:max-w-full">
|
|
<motion.div
|
|
className="relative bg-white p-3 pb-12 shadow-[0_20px_50px_-12px_rgba(0,0,0,0.15)] rotate-2 hover:rotate-0 transition-all duration-500 ease-out"
|
|
whileHover={{ scale: 1.02, rotate: 0 }}
|
|
>
|
|
<div className="absolute -top-3 left-1/2 -translate-x-1/2 z-20">
|
|
<div className="w-6 h-6 rounded-full shadow-lg flex items-center justify-center bg-gray-100 border border-gray-200">
|
|
<div className="w-3 h-3 rounded-full" style={{ backgroundColor: step.color }}></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="relative aspect-[3/2] overflow-hidden bg-gray-100">
|
|
<ImageWithFallback
|
|
src={step.image}
|
|
alt={step.title}
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
</div>
|
|
</motion.div>
|
|
</div>
|
|
</motion.div>
|
|
);
|
|
}
|