changes of 29 jan

This commit is contained in:
priyanshuvish
2026-01-29 14:57:04 +05:30
parent c0c9c86a58
commit ca809e226d
17 changed files with 2556 additions and 497 deletions

View File

@@ -33,6 +33,7 @@ import ComingSoonPage from './pages/ComingSoonPage';
import { SuperSavingsPage } from './components/SuperSavingsPage';
import { WhatsIncluded } from './components/WhatsIncluded';
import { LandingMagicItineraryPage } from './components/LandingMagicItineraryPage';
import { DiscoverPage } from './components/DiscoverPage';
// User type definition
interface User {
@@ -160,6 +161,12 @@ export function AppRouter({
</motion.div>
} />
<Route path="/discover" element={
<motion.div key="discover" {...pageTransition}>
<DiscoverPage {...commonNavHandlers} />
</motion.div>
} />
<Route path="/faq" element={
<motion.div key="faq" {...pageTransition}>
<FAQPage {...commonNavHandlers} />

Binary file not shown.

View File

@@ -211,7 +211,7 @@ const filterCategories = [
];
const passTypeCategories = [
{ value: 'selective', label: 'Selective Pass', count: 6 },
{ value: 'selective', label: 'Flexi Pass', count: 6 },
{ value: 'unlimited', label: 'Unlimited Pass', count: 6 }
];
@@ -441,7 +441,7 @@ export function AttractionsPage({
</Badge>
) : (
<Badge className="bg-gradient-to-r from-blue-500 to-cyan-500 text-white px-3 py-1 font-poppins font-semibold shadow-lg border-0">
Selective Pass
Flexi Pass
</Badge>
)}
</div>

View File

@@ -138,7 +138,7 @@ export function CityCardsPage({
</motion.div>
<div className="grid md:grid-cols-2 gap-8 max-w-5xl mx-auto">
{/* Selective Pass */}
{/* Flexi Pass */}
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
@@ -148,7 +148,7 @@ export function CityCardsPage({
<Card className="relative transition-all duration-300 cursor-pointer flex flex-col w-full border-gray-200 shadow-md hover:shadow-lg hover:border-primary/30">
<CardHeader className="text-center pb-6 pt-8 flex-shrink-0">
<CardTitle className="font-poppins text-2xl font-bold mb-2 text-gray-900">
SELECTIVE PASS
Flexi Pass
</CardTitle>
<CardDescription className="text-gray-600 mb-6 leading-relaxed font-poppins h-[48px] flex items-center justify-center">
Perfect for travelers who want to explore selected attractions at their own pace with essential features.

View File

@@ -999,7 +999,7 @@ export function CustomPostcards() {
<div className="text-center">
<Button
onClick={handleCreatePostcard}
className="bg-warm-coral hover:bg-warm-coral/90 text-white px-8 py-3 rounded-full shadow-lg hover:shadow-xl transition-all duration-300 transform hover:scale-105 mx-auto"
className="bg-[#f95f62] hover:bg-warm-coral/90 text-white px-8 py-3 rounded-full shadow-lg hover:shadow-xl transition-all duration-300 transform hover:scale-105 mx-auto"
>
Customize Your Postcard
<ArrowRight className="w-5 h-5 ml-2" />

View File

@@ -0,0 +1,854 @@
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="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">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>
);
}

View File

@@ -70,7 +70,7 @@ const faqData: FAQItem[] = [
{
id: '2',
question: 'What\'s the difference between Selective and Unlimited passes?',
answer: 'Our Selective pass allows you to choose specific attractions you want to visit, perfect for targeted exploration. The Unlimited pass gives you access to all participating attractions in the city during your pass validity period, ideal for comprehensive city discovery.',
answer: 'Our Flexi Pass allows you to choose specific attractions you want to visit, perfect for targeted exploration. The Unlimited pass gives you access to all participating attractions in the city during your pass validity period, ideal for comprehensive city discovery.',
category: 'Passes'
},
{

View File

@@ -0,0 +1,234 @@
import { useState, useEffect } from 'react';
import { motion } from 'motion/react';
import { ArrowRight } from 'lucide-react';
import { ImageWithFallback } from './figma/ImageWithFallback';
interface HeroBannerCarouselProps {
onCheckoutClick?: () => void;
onPassesClick?: () => void;
onEsimsClick?: () => void;
onHotelDiscountsClick?: () => void;
}
export function HeroBannerCarousel({
onCheckoutClick,
onPassesClick,
onEsimsClick,
onHotelDiscountsClick
}: HeroBannerCarouselProps) {
const [currentSlide, setCurrentSlide] = useState(0);
const [isPaused, setIsPaused] = useState(false);
const slides = [
{
id: 1,
title: "Discover",
highlight: "Melbourne",
subtitle: "Ultimate Guide to Iconic City",
description: "From Flinders Street to St Kilda Beach: explore the best of Melbourne's landmarks, culture, food and more!",
image: "https://images.unsplash.com/photo-1757470238279-0e9f331d02c9?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBza3lsaW5lJTIwc3Vuc2V0fGVufDF8fHx8MTc2MDUwOTIyMHww&ixlib=rb-4.1.0&q=80&w=1080",
cta: "Get Started",
onClick: onCheckoutClick
},
{
id: 2,
title: "Unlock",
highlight: "City Passes",
subtitle: "Save More, Experience More",
description: "Get unlimited access to top attractions with our flexible city passes. Choose from 1, 2, 3, or 5-day options!",
image: "https://images.unsplash.com/photo-1743441914096-e8f9aaded6f8?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxjaXR5JTIwYXR0cmFjdGlvbiUyMHBhc3N8ZW58MXx8fHwxNzYwNTA5MjIxfDA&ixlib=rb-4.1.0&q=80&w=1080",
cta: "Explore Passes",
onClick: onPassesClick
},
{
id: 3,
title: "Stay",
highlight: "Connected",
subtitle: "Travel eSIMs for Every Journey",
description: "Never lose touch while traveling. Get instant data connectivity in over 190 countries with our eSIM solutions!",
image: "https://images.unsplash.com/photo-1755286218783-5b8334109336?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxtb2JpbGUlMjBwaG9uZSUyMHJvYW1pbmd8ZW58MXx8fHwxNzYwNTA5MjIxfDA&ixlib=rb-4.1.0&q=80&w=1080",
cta: "Get eSIM",
onClick: onEsimsClick
},
{
id: 4,
title: "Exclusive",
highlight: "Hotel Deals",
subtitle: "Luxury Stays at Best Prices",
description: "Book premium hotels at unbeatable rates. Enjoy exclusive discounts on handpicked accommodations worldwide!",
image: "https://images.unsplash.com/photo-1634041441461-a1789d008830?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxsdXh1cnklMjBob3RlbCUyMGV4dGVyaW9yfGVufDF8fHx8MTc2MDQ5NzY1MXww&ixlib=rb-4.1.0&q=80&w=1080",
cta: "View Hotels",
onClick: onHotelDiscountsClick
}
];
// Auto-scroll effect
useEffect(() => {
if (isPaused) return;
const interval = setInterval(() => {
setCurrentSlide((prev) => (prev + 1) % slides.length);
}, 5000); // Change slide every 5 seconds
return () => clearInterval(interval);
}, [isPaused, slides.length]);
const goToSlide = (index: number) => {
setCurrentSlide(index);
};
return (
<div
className="relative w-full min-h-screen overflow-hidden"
onMouseEnter={() => setIsPaused(true)}
onMouseLeave={() => setIsPaused(false)}
>
{/* Slides */}
{slides.map((slide, index) => {
return (
<motion.div
key={slide.id}
className="absolute inset-0 w-full h-full flex"
initial={{ opacity: 0 }}
animate={{
opacity: currentSlide === index ? 1 : 0,
zIndex: currentSlide === index ? 1 : 0
}}
transition={{ duration: 1, ease: "easeInOut" }}
>
{/* Left Side - Content Panel (60% width) */}
<motion.div
initial={{ opacity: 0, x: -30 }}
animate={{
opacity: currentSlide === index ? 1 : 0,
x: currentSlide === index ? 0 : -30
}}
transition={{ duration: 0.8, delay: 0.2 }}
className="relative w-full md:w-[60%] h-full flex items-center"
style={{ backgroundColor: '#FFF5F5' }}
>
<div className="px-6 sm:px-8 md:px-10 lg:px-16 xl:px-20 py-8 w-full">
<h1 className="font-poppins leading-tight mb-4 lg:mb-6">
<div className="text-3xl sm:text-4xl md:text-5xl lg:text-6xl xl:text-7xl mb-0">
<span className="font-light" style={{ color: '#1F2937' }}>{slide.title} </span>
<span className="font-bold text-white px-3 py-1.5 md:px-4 md:py-2 inline-block" style={{ backgroundColor: '#F95F62' }}>
{slide.highlight}
</span>
</div>
<div className="text-3xl sm:text-4xl md:text-5xl lg:text-6xl xl:text-7xl font-bold mt-3 md:mt-4" style={{ color: '#1F2937', lineHeight: '1.2' }}>
{slide.subtitle}
</div>
</h1>
<p className="font-poppins text-base md:text-lg lg:text-xl leading-relaxed font-normal mb-6 lg:mb-8 max-w-2xl" style={{ color: '#4B5563' }}>
{slide.description}
</p>
<button
onClick={slide.onClick}
className="group px-6 py-3 md:px-8 md:py-4 rounded-full flex items-center gap-3 transition-all duration-300 hover:scale-105 shadow-lg hover:shadow-xl font-poppins font-semibold text-base text-white"
style={{ backgroundColor: '#F95F62' }}
>
{slide.cta}
<ArrowRight className="w-5 h-5 group-hover:translate-x-1 transition-transform duration-300" />
</button>
</div>
</motion.div>
{/* Right Side - Full Height Image (40% width) */}
<motion.div
initial={{ opacity: 0, x: 30 }}
animate={{
opacity: currentSlide === index ? 1 : 0,
x: currentSlide === index ? 0 : 30
}}
transition={{ duration: 0.8, ease: "easeOut" }}
className="relative w-full md:w-[40%] h-full overflow-hidden"
>
<ImageWithFallback
src={slide.image}
alt={`${slide.highlight} - ${slide.subtitle}`}
className="w-full h-full object-cover"
/>
{/* Subtle overlay for depth */}
<div className="absolute inset-0 bg-gradient-to-l from-transparent to-black/10" />
</motion.div>
</motion.div>
);
})}
{/* Slide Indicators - Bottom Center (All Screens) */}
<div className="absolute bottom-8 left-1/2 transform -translate-x-1/2 z-20 flex gap-3">
{slides.map((_, index) => (
<button
key={index}
onClick={() => goToSlide(index)}
className="group"
aria-label={`Go to slide ${index + 1}`}
>
<div
className={`h-2 rounded-full transition-all duration-300 ${
currentSlide === index
? 'w-12'
: 'w-2 group-hover:opacity-75'
}`}
style={{
backgroundColor: currentSlide === index ? '#F95F62' : '#9CA3AF',
opacity: currentSlide === index ? 1 : 0.5
}}
/>
</button>
))}
</div>
{/* Numbered Slide Navigation - Bottom Left (Desktop) */}
<div className="hidden md:block absolute bottom-8 left-8 lg:left-16 z-20">
<div className="flex gap-6 lg:gap-8">
{slides.map((slide, index) => (
<button
key={index}
onClick={() => goToSlide(index)}
className="group text-left transition-all duration-300"
aria-label={`Go to slide ${index + 1}: ${slide.highlight}`}
>
<div className="flex flex-col gap-2">
{/* Number with active indicator line */}
<div className="relative">
{currentSlide === index && (
<div
className="absolute -top-2 left-0 right-0 h-0.5 rounded-full transition-all duration-300"
style={{ backgroundColor: '#F95F62' }}
/>
)}
<span
className={`font-poppins font-semibold transition-all duration-300 ${
currentSlide === index
? 'text-lg'
: 'text-base'
}`}
style={{
color: currentSlide === index ? '#F95F62' : '#FFFFFF',
opacity: currentSlide === index ? 1 : 0.6
}}
>
{String(index + 1).padStart(2, '0')}
</span>
</div>
{/* Label */}
<div className={`transition-all duration-300 ${
currentSlide === index ? 'opacity-100' : 'opacity-0 group-hover:opacity-70'
}`}>
<p className="font-poppins text-xs text-white/90 whitespace-nowrap max-w-[120px]">
{slide.highlight}
</p>
</div>
</div>
</button>
))}
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,325 @@
import { motion } from 'motion/react';
import { ArrowRight, Wifi, Hotel } from 'lucide-react';
interface HotelEsimOffersProps {
onEsimsClick?: () => void;
onHotelDiscountsClick?: () => void;
}
export function HotelEsimOffers({ onEsimsClick, onHotelDiscountsClick }: HotelEsimOffersProps) {
return (
<div>
<div className="space-y-0">
{/* e-SIM Offers Section */}
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="relative overflow-hidden bg-white py-20 md:py-28"
>
{/* Subtle Background Elements */}
<div className="absolute inset-0 overflow-hidden">
<motion.div
className="absolute top-0 right-0 w-96 h-96 bg-primary/5 rounded-full blur-3xl"
animate={{
scale: [1, 1.2, 1],
opacity: [0.3, 0.5, 0.3],
}}
transition={{
duration: 8,
repeat: Infinity,
ease: "easeInOut"
}}
/>
<motion.div
className="absolute bottom-0 left-0 w-72 h-72 bg-orange-200/20 rounded-full blur-2xl"
animate={{
scale: [1, 1.3, 1],
opacity: [0.2, 0.4, 0.2],
}}
transition={{
duration: 6,
repeat: Infinity,
ease: "easeInOut"
}}
/>
</div>
<div className="container mx-auto px-4">
<div className="max-w-6xl mx-auto relative z-10">
{/* Header */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: 0.2 }}
className="text-center mb-16"
>
<motion.div
className="inline-flex items-center gap-2 bg-primary/10 px-4 py-2 rounded-full mb-6"
whileHover={{ scale: 1.05 }}
transition={{ duration: 0.2 }}
>
<Wifi className="w-4 h-4 text-primary" />
<span className="font-poppins text-sm font-medium text-primary">
Stay Connected in Melbourne
</span>
</motion.div>
<h2 className="font-poppins text-3xl md:text-5xl lg:text-6xl leading-tight text-foreground mb-6">
<span className="font-light">Travel </span>
<span className="font-bold text-primary italic">Connected</span>
</h2>
<p className="font-poppins text-xl leading-relaxed font-normal text-gray-700 max-w-2xl mx-auto">
Get instant e-SIM connectivity across Australia. Stay online from the moment you land in Melbourne.
</p>
</motion.div>
{/* Main Card */}
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: 0.3 }}
onClick={onEsimsClick}
className="bg-gradient-to-br from-primary to-orange-500 rounded-3xl p-8 md:p-12 shadow-2xl cursor-pointer group relative overflow-hidden"
whileHover={{ scale: 1.02 }}
>
<motion.div
className="absolute top-0 right-0 w-40 h-40 bg-white/20 rounded-full blur-2xl"
animate={{
scale: [1, 1.5, 1],
}}
transition={{
duration: 4,
repeat: Infinity,
ease: "easeInOut"
}}
/>
<div className="relative z-10 grid md:grid-cols-2 gap-8 items-center">
{/* Left Content */}
<div>
<div className="inline-flex items-center gap-2 bg-white/20 px-3 py-1 rounded-full mb-4">
<span className="font-poppins text-xs font-semibold text-white">🇦🇺 AUSTRALIA-WIDE COVERAGE</span>
</div>
<h3 className="font-poppins text-3xl md:text-4xl font-semibold text-white mb-4 leading-tight">
Exclusive e-SIM Offers for Melbourne Visitors
</h3>
<p className="font-poppins text-base text-white/90 mb-6">
No more hunting for local SIM cards at the airport. Activate your e-SIM instantly and explore Melbourne with seamless connectivity.
</p>
<motion.div
className="inline-flex items-center gap-3 bg-white text-primary py-4 px-8 rounded-full font-poppins font-semibold"
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.98 }}
>
<span>Explore Plans</span>
<motion.div
animate={{ x: [0, 5, 0] }}
transition={{ duration: 1.5, repeat: Infinity }}
>
<ArrowRight className="w-5 h-5" />
</motion.div>
</motion.div>
</div>
{/* Right Features */}
<div className="grid grid-cols-2 gap-4">
{[
{ icon: '🌐', label: 'Australia Coverage', value: '100%', unit: 'nationwide' },
{ icon: '⚡', label: 'Instant Setup', value: '< 1', unit: 'minute' },
{ icon: '💰', label: 'Save Up To', value: '85%', unit: 'vs roaming' },
{ icon: '🔒', label: 'Secure', value: '100%', unit: 'encrypted' }
].map((item, index) => (
<motion.div
key={index}
initial={{ opacity: 0, scale: 0.9 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.4, delay: 0.4 + index * 0.1 }}
className="bg-white/15 backdrop-blur-md rounded-2xl p-4 text-center"
>
<div className="text-3xl mb-2">{item.icon}</div>
<div className="font-poppins text-2xl font-bold text-white mb-1">{item.value}</div>
<div className="font-poppins text-xs text-white/80">{item.unit}</div>
</motion.div>
))}
</div>
</div>
</motion.div>
</div>
</div>
</motion.div>
{/* Hotel Discounts Section */}
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="relative overflow-hidden bg-gradient-to-br from-orange-50 via-pink-50 to-red-50 py-20 md:py-28"
>
{/* Animated Background Elements */}
<div className="absolute inset-0 overflow-hidden">
<motion.div
className="absolute top-0 right-0 w-96 h-96 bg-primary/10 rounded-full blur-3xl"
animate={{
scale: [1, 1.2, 1],
opacity: [0.3, 0.5, 0.3],
}}
transition={{
duration: 8,
repeat: Infinity,
ease: "easeInOut"
}}
/>
<motion.div
className="absolute bottom-0 left-0 w-72 h-72 bg-orange-200/30 rounded-full blur-2xl"
animate={{
scale: [1, 1.3, 1],
opacity: [0.2, 0.4, 0.2],
}}
transition={{
duration: 6,
repeat: Infinity,
ease: "easeInOut"
}}
/>
</div>
<div className="container mx-auto px-4">
<div className="max-w-6xl mx-auto relative z-10">
{/* Header */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: 0.2 }}
className="text-center mb-16"
>
<motion.div
className="inline-flex items-center gap-2 bg-primary/10 px-4 py-2 rounded-full mb-6"
whileHover={{ scale: 1.05 }}
transition={{ duration: 0.2 }}
>
<Hotel className="w-4 h-4 text-primary" />
<span className="font-poppins text-sm font-medium text-primary">
Premium Melbourne Hotels
</span>
</motion.div>
<h2 className="font-poppins text-3xl md:text-5xl lg:text-6xl leading-tight text-foreground mb-6">
<span className="font-light">Sleep in </span>
<span className="font-bold text-primary italic">Luxury</span>
</h2>
<p className="font-poppins text-xl leading-relaxed font-normal text-gray-700 max-w-2xl mx-auto">
Unlock exclusive rates at Melbourne's finest hotels. Your CityCard membership opens doors to premium CBD and waterfront stays.
</p>
</motion.div>
{/* Main Card */}
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: 0.3 }}
onClick={onHotelDiscountsClick}
className="bg-white rounded-3xl p-8 md:p-12 shadow-2xl cursor-pointer group relative overflow-hidden border border-gray-100"
whileHover={{ scale: 1.02, y: -5 }}
>
<div className="grid md:grid-cols-2 gap-8 items-center mb-8">
{/* Left Content */}
<div>
<div className="inline-flex items-center gap-2 bg-gradient-to-r from-primary to-orange-500 px-4 py-2 rounded-full mb-4">
<span className="font-poppins text-xs font-semibold text-white">🔥 MARRIOTT BONVOY PARTNER</span>
</div>
<h3 className="font-poppins text-3xl md:text-4xl font-semibold text-foreground mb-4 leading-tight">
Melbourne Premium Stays at <span className="text-primary italic">Unbeatable Prices</span>
</h3>
<p className="font-poppins text-base text-gray-700 mb-6">
Access exclusive member rates at Melbourne's top hotels including Crown Towers, W Melbourne, and premium CBD properties. Enjoy complimentary upgrades and special amenities.
</p>
</div>
{/* Right - Savings Badge */}
<div className="flex justify-center">
<motion.div
className="relative"
whileHover={{ rotate: [0, -5, 5, 0] }}
transition={{ duration: 0.3 }}
>
<div className="bg-gradient-to-br from-primary to-orange-500 rounded-3xl p-8 text-center shadow-xl">
<div className="font-poppins text-6xl font-bold text-white mb-2">25%</div>
<div className="font-poppins text-lg text-white/90 mb-1">Average Savings</div>
<div className="font-poppins text-sm text-white/70">on Melbourne hotels</div>
</div>
<motion.div
className="absolute -top-2 -right-2 bg-yellow-400 rounded-full px-3 py-1"
animate={{
scale: [1, 1.1, 1],
}}
transition={{
duration: 2,
repeat: Infinity,
}}
>
<span className="font-poppins text-xs font-bold text-gray-900">NEW</span>
</motion.div>
</motion.div>
</div>
</div>
{/* Features Grid */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8">
{[
{ icon: '🏆', title: 'Premium Locations', desc: 'CBD, Southbank & St Kilda' },
{ icon: '💎', title: 'Member Perks', desc: 'Free upgrades included' },
{ icon: '⚡', title: 'Instant Booking', desc: 'Confirm in seconds' }
].map((feature, index) => (
<motion.div
key={index}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.4 + index * 0.1 }}
className="flex items-start gap-3 p-4 rounded-2xl bg-gradient-to-br from-orange-50 to-pink-50"
>
<div className="text-3xl">{feature.icon}</div>
<div>
<h4 className="font-poppins font-semibold text-foreground mb-1">{feature.title}</h4>
<p className="font-poppins text-sm text-gray-600">{feature.desc}</p>
</div>
</motion.div>
))}
</div>
{/* CTA */}
<div className="text-center">
<motion.div
className="inline-flex items-center gap-3 bg-primary text-white py-4 px-8 rounded-full font-poppins font-semibold shadow-lg"
whileHover={{ scale: 1.05, boxShadow: "0 20px 60px rgba(249, 95, 98, 0.4)" }}
whileTap={{ scale: 0.98 }}
>
<span>View Hotel Deals</span>
<motion.div
animate={{ x: [0, 5, 0] }}
transition={{ duration: 1.5, repeat: Infinity }}
>
<ArrowRight className="w-5 h-5" />
</motion.div>
</motion.div>
<p className="font-poppins text-sm text-gray-500 mt-4">
Limited time offer No booking fees Best price guarantee
</p>
</div>
</motion.div>
</div>
</div>
</motion.div>
</div>
</div>
);
}

View File

@@ -96,14 +96,14 @@ export function LandingNewsletterSection() {
</div>
<div className="font-semibold">exclusive offers.</div>
</h2>
<motion.p
<motion.p
className="font-poppins text-xl leading-relaxed font-normal text-gray-600 max-w-2xl mx-auto"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.2 }}
>
We recommend you to subscribe, drop your email below to get daily update about us
Subscribe now and receive <span className="font-semibold text-primary">10% off</span> your first purchase! We'll send your exclusive discount code directly to your inbox.
</motion.p>
</motion.div>

File diff suppressed because it is too large Load Diff

View File

@@ -93,7 +93,7 @@ export default function Navbar({
// Position 1 - Shared item
{
label: 'Discover',
path: '/how-it-works',
path: '/discover',
isShared: true,
landingLabel: 'Discover',
melbourneLabel: 'How It Works'
@@ -535,7 +535,7 @@ export default function Navbar({
? 'Melbourne CityCards Logo'
: 'CityCards Logo'
}
className="h-10 w-auto"
className="h-14 w-auto"
/>
</Link>
</motion.div>

View File

@@ -10,6 +10,7 @@ import { Footer } from './Footer';
import { ReviewsSection } from './ReviewsSection';
import { Layout } from '../Layout';
import { LoginModal } from './LoginModal';
import { ImageWithFallback } from './figma/ImageWithFallback';
interface PassesPageProps {
onCheckoutClick?: () => void;
@@ -45,7 +46,7 @@ interface PassType {
const passTypes: PassType[] = [
{
id: 'selective',
name: 'Selective Pass',
name: 'Flexi Pass',
title: 'Flexi Card',
description: 'Perfect for travelers who want to explore selected attractions at their own pace with essential features.',
price: '$59.99',
@@ -218,12 +219,13 @@ export function PassesPage({
>
{passTypes.map((pass) => (
<div key={pass.id} className="relative h-full">
<Card className={`relative h-full flex flex-col transition-all duration-300 cursor-pointer ${pass.popular
? 'ring-2 ring-primary shadow-xl'
: selectedPass === pass.id
? 'ring-2 ring-primary/50 shadow-lg'
: 'border-gray-200 shadow-md hover:shadow-lg hover:border-primary/30'
}`}>
<Card className={`relative h-full flex flex-col transition-all duration-300 cursor-pointer ${
pass.popular
? 'ring-2 ring-primary shadow-xl'
: selectedPass === pass.id
? 'ring-2 ring-primary/50 shadow-lg'
: 'border-gray-200 shadow-md hover:shadow-lg hover:border-primary/30'
}`}>
{/* Popular Badge */}
{pass.popular && (
@@ -249,6 +251,40 @@ export function PassesPage({
</CardDescription>
</CardHeader>
{/* Attraction Images Grid */}
<div className="px-6 pb-4 flex-shrink-0">
<div className="grid grid-cols-4 gap-3">
<div className="aspect-square rounded-xl overflow-hidden shadow-md hover:shadow-lg transition-all duration-300 ring-1 ring-gray-200 hover:ring-primary/50 group">
<ImageWithFallback
src="https://images.unsplash.com/photo-1639655001512-e4b58d4874b8?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBGZWRlcmF0aW9uJTIwU3F1YXJlfGVufDF8fHx8MTc2MjQyMzkwMHww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
alt="Federation Square"
className="w-full h-full object-cover group-hover:scale-105 group-hover:brightness-110 transition-all duration-500"
/>
</div>
<div className="aspect-square rounded-xl overflow-hidden shadow-md hover:shadow-lg transition-all duration-300 ring-1 ring-gray-200 hover:ring-primary/50 group">
<ImageWithFallback
src="https://images.unsplash.com/photo-1721272962395-a848331ce92d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBSb3lhbCUyMEJvdGFuaWMlMjBHYXJkZW5zfGVufDF8fHx8MTc2MjQyMzk2NHww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
alt="Royal Botanic Gardens"
className="w-full h-full object-cover group-hover:scale-105 group-hover:brightness-110 transition-all duration-500"
/>
</div>
<div className="aspect-square rounded-xl overflow-hidden shadow-md hover:shadow-lg transition-all duration-300 ring-1 ring-gray-200 hover:ring-primary/50 group">
<ImageWithFallback
src="https://images.unsplash.com/photo-1720044109127-0aee490512be?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBFdXJla2ElMjBTa3lkZWNrfGVufDF8fHx8MTc2MjQyMzk2NXww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
alt="Eureka Skydeck"
className="w-full h-full object-cover group-hover:scale-105 group-hover:brightness-110 transition-all duration-500"
/>
</div>
<div className="aspect-square rounded-xl overflow-hidden shadow-md hover:shadow-lg transition-all duration-300 ring-1 ring-gray-200 hover:ring-primary/50 group">
<ImageWithFallback
src="https://images.unsplash.com/photo-1705464079585-0975f0aa5013?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBOYXRpb25hbCUyMEdhbGxlcnl8ZW58MXx8fHwxNzYyNDIzOTY0fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
alt="National Gallery"
className="w-full h-full object-cover group-hover:scale-105 group-hover:brightness-110 transition-all duration-500"
/>
</div>
</div>
</div>
{/* Pricing Section - Fixed Height */}
<div className="px-6 pb-6 flex-shrink-0">
<div className="flex items-baseline justify-center gap-2 mb-2">
@@ -279,16 +315,17 @@ export function PassesPage({
</div>
</div>
{/* ✅ UPDATED: CTA Button with login logic */}
{/* CTA Button - Pushed to bottom */}
<div className="flex-shrink-0 space-y-3">
<Button
className={`w-full h-12 rounded-lg font-semibold transition-all duration-300 font-poppins ${pass.popular
? 'bg-primary hover:bg-primary/90 text-white shadow-md hover:shadow-lg'
: 'bg-gray-900 hover:bg-gray-800 text-white hover:shadow-md'
}`}
onClick={handlePurchaseClick} // ✅ Use the new handler
className={`w-full h-12 rounded-lg font-semibold transition-all duration-300 font-poppins ${
pass.popular
? 'bg-primary hover:bg-primary/90 text-white shadow-md hover:shadow-lg'
: 'bg-gray-900 hover:bg-gray-800 text-white hover:shadow-md'
}`}
onClick={user ? onCheckoutClick : onSignInClick}
>
PURCHASE NOW
{user ? 'PURCHASE NOW' : 'LOGIN TO BUY PASS'}
</Button>
<p className="text-xs text-gray-500 text-center font-poppins font-normal leading-tight">
@@ -302,6 +339,136 @@ export function PassesPage({
</RadioGroup>
</div>
{/* Good to Know Section */}
<div className="mb-24">
<div className="text-center mb-16">
<h2 className="font-merchant text-4xl md:text-5xl text-gray-900 mb-6">
<span className="font-light">Good to</span>{' '}
<span className="font-bold italic bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">Know</span>
</h2>
<p className="font-poppins text-lg text-gray-600 font-light max-w-2xl mx-auto leading-relaxed">
Simple tips to help you get the most out of your CityCard experience
</p>
</div>
<div className="max-w-7xl mx-auto">
<div className="grid lg:grid-cols-12 gap-8 items-start">
{/* Left Column: The Rules */}
<div className="lg:col-span-7 space-y-6">
{/* Rule 1: Calendar Days */}
<div className="bg-white rounded-[2rem] p-8 border border-gray-100 shadow-[0_8px_30px_rgb(0,0,0,0.04)] hover:shadow-[0_8px_30px_rgb(0,0,0,0.08)] transition-all duration-500 relative overflow-hidden">
<div className="absolute top-0 right-0 w-64 h-64 bg-blue-50/50 rounded-full blur-3xl -mr-32 -mt-32 pointer-events-none"></div>
<div className="flex flex-col sm:flex-row items-start gap-6 relative z-10">
<div className="w-14 h-14 bg-blue-100/50 rounded-2xl flex items-center justify-center shrink-0 text-blue-600">
<Clock className="w-7 h-7" strokeWidth={1.5} />
</div>
<div className="flex-1 w-full">
<h3 className="font-merchant text-2xl text-gray-900 mb-3">Calendar Days Policy</h3>
<p className="font-poppins text-gray-600 leading-relaxed mb-6">
Unlimited passes work on a <span className="font-medium text-gray-900">consecutive calendar day basis</span>, not 24-hour periods. Your pass expires at 11:59 PM on your final day.
</p>
{/* Visual Timeline Example */}
<div className="bg-blue-50/30 rounded-xl p-5 border border-blue-100/50 flex flex-col sm:flex-row gap-4 sm:items-center justify-between w-full">
<div className="flex-1">
<div className="text-xs font-bold text-blue-800 uppercase tracking-wider mb-1">Start</div>
<div className="font-poppins font-medium text-gray-900 text-sm sm:text-base">Monday 4:30 PM</div>
<div className="text-xs text-gray-500 mt-1">First scan</div>
</div>
<div className="hidden sm:flex flex-col items-center px-4 shrink-0">
<div className="text-[10px] font-medium text-blue-400 mb-1">3 Days</div>
<div className="w-24 h-0.5 bg-blue-200 relative">
<div className="absolute inset-0 bg-blue-400 w-1/2 animate-pulse"></div>
</div>
</div>
<div className="flex-1 text-left sm:text-right">
<div className="text-xs font-bold text-blue-800 uppercase tracking-wider mb-1">End</div>
<div className="font-poppins font-medium text-gray-900 text-sm sm:text-base">Wednesday 11:59 PM</div>
<div className="text-xs text-gray-500 mt-1">Expiration</div>
</div>
</div>
</div>
</div>
</div>
{/* Rule 2: Fair Use */}
<div className="bg-white rounded-[2rem] p-8 border border-gray-100 shadow-[0_8px_30px_rgb(0,0,0,0.04)] hover:shadow-[0_8px_30px_rgb(0,0,0,0.08)] transition-all duration-500 relative overflow-hidden">
<div className="absolute top-0 right-0 w-64 h-64 bg-orange-50/50 rounded-full blur-3xl -mr-32 -mt-32 pointer-events-none"></div>
<div className="flex flex-col sm:flex-row items-start gap-6 relative z-10">
<div className="w-14 h-14 bg-orange-100/50 rounded-2xl flex items-center justify-center shrink-0 text-orange-600">
<Shield className="w-7 h-7" strokeWidth={1.5} />
</div>
<div className="flex-1">
<h3 className="font-merchant text-2xl text-gray-900 mb-3">60-Minute Adventure Gap</h3>
<p className="font-poppins text-gray-600 leading-relaxed">
To keep the journey smooth for everyone, there's a simple <span className="font-medium text-gray-900">60-minute wait</span> between scanning your pass at attractions.
</p>
<div className="mt-4 flex flex-wrap items-center gap-3 text-sm text-orange-800 bg-orange-50/50 py-2 px-4 rounded-full w-fit">
<span className="w-2 h-2 bg-orange-400 rounded-full animate-pulse shrink-0"></span>
Perfect for grabbing a coffee or traveling to your next stop!
</div>
</div>
</div>
</div>
</div>
{/* Right Column: The "Card Types" Summary */}
<div className="lg:col-span-5 h-full min-h-[400px]">
<div className="bg-gradient-to-br from-[#F95F62] to-[#ff8f92] rounded-[2rem] p-8 border border-white/20 shadow-[0_8px_30px_rgb(249,95,98,0.3)] h-full relative overflow-hidden flex flex-col justify-center text-white">
{/* Abstract Shapes */}
<div className="absolute top-0 right-0 w-64 h-64 bg-white/10 rounded-full blur-3xl -mr-10 -mt-10 pointer-events-none"></div>
<div className="absolute bottom-0 left-0 w-64 h-64 bg-black/5 rounded-full blur-3xl -ml-10 -mb-10 pointer-events-none"></div>
<div className="relative z-10">
<h3 className="font-merchant text-3xl mb-2 text-white">Your Pass, Your Way</h3>
<p className="text-white/90 font-poppins mb-8 font-light leading-relaxed">Choose the flexibility that matches your travel style.</p>
<div className="space-y-4">
{/* Flex Option - White Card */}
<div className="bg-white rounded-2xl p-5 shadow-lg border border-white/50 hover:scale-[1.02] transition-transform duration-300 cursor-default group relative overflow-hidden">
<div className="absolute left-0 top-0 bottom-0 w-1.5 bg-[#F95FAF]"></div>
<div className="flex justify-between items-center mb-2 pl-3">
<span className="font-poppins font-semibold text-lg text-gray-900 group-hover:text-[#F95FAF] transition-colors">Flexi Card</span>
<span className="text-[10px] uppercase tracking-wider bg-[#F95FAF]/10 px-2 py-1 rounded-md text-[#F95FAF] font-bold">Casual</span>
</div>
<p className="text-sm text-gray-600 font-light mb-4 pl-3">Best for visiting specific attractions at your own pace.</p>
<div className="flex gap-2 pl-3">
{[3, 5, 7].map(n => (
<div key={n} className="text-xs border border-[#F95FAF]/30 text-[#F95FAF] rounded-lg px-3 py-1.5 font-medium bg-[#F95FAF]/5">{n}</div>
))}
<span className="text-xs flex items-center text-gray-400 ml-1">Attractions</span>
</div>
</div>
{/* Unlimited Option - White Card with Highlight */}
<div className="bg-white rounded-2xl p-5 shadow-lg border border-white/50 hover:scale-[1.02] transition-transform duration-300 cursor-default group relative overflow-hidden">
<div className="absolute top-0 right-0 bg-[#F95F62] text-white text-[10px] font-bold px-3 py-1 rounded-bl-xl shadow-sm z-10">POPULAR</div>
<div className="absolute left-0 top-0 bottom-0 w-1.5 bg-[#F95F62]"></div>
<div className="flex justify-between items-center mb-2 pl-3">
<span className="font-poppins font-semibold text-lg text-gray-900 group-hover:text-[#F95F62] transition-colors">Unlimited Card</span>
<span className="text-[10px] uppercase tracking-wider bg-[#F95F62]/10 px-2 py-1 rounded-md text-[#F95F62] border border-[#F95F62]/20 font-bold">Power User</span>
</div>
<p className="text-sm text-gray-600 font-light mb-4 pl-3">Unlimited access for full days of exploration.</p>
<div className="flex gap-2 flex-wrap pl-3">
{[2, 3, 5, 7].map(n => (
<div key={n} className="text-xs bg-white text-[#F95F62] border border-[#F95F62]/20 rounded-lg px-3 py-1.5 font-medium shadow-sm">{n}</div>
))}
<span className="text-xs flex items-center text-gray-500 ml-1">Days</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Detailed Features Comparison Table */}
<Card className="overflow-hidden mb-20 bg-white shadow-lg">
<CardHeader className="text-center">
@@ -319,8 +486,8 @@ export function PassesPage({
<thead>
<tr className="border-b border-gray-200 bg-gray-50">
<th className="text-left p-6 font-semibold text-gray-900 min-w-[200px]">Features</th>
<th className="text-center p-6 font-semibold text-gray-900 min-w-[200px]">Selective Pass</th>
<th className="text-center p-6 font-semibold text-gray-900 min-w-[200px] bg-primary/5">Premium Unlimited</th>
<th className="text-center p-6 font-semibold text-gray-900 min-w-[200px]">Flexi Pass</th>
<th className="text-center p-6 font-semibold text-gray-900 min-w-[200px] bg-primary/5">Unlimited Pass</th>
</tr>
</thead>

View File

@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'motion/react';
import { Sparkles, MapPin, Calendar, Wand2, Clock } from 'lucide-react';
// import { ImageWithFallback } from './figma/ImageWithFallback';
import cityTourVideo from '../assets/itinenary-animation-vid.mp4';
import cityTourVideo from '../assets/citycards-vid.mp4';
interface PersonalizedTourHeroProps {
onCreateItineraryClick?: () => void;

View File

@@ -89,7 +89,7 @@ const mockPasses = [
id: '2',
name: 'Melbourne Selective Card',
city: 'Melbourne',
type: 'Selective Pass',
type: 'Flexi Pass',
status: 'active',
price: 89.00,
originalPrice: 149.00,
@@ -383,7 +383,7 @@ export function ProfilePage({
{(() => {
// Determine which pass type to show
const hasUnlimitedPass = activePasses.some(pass => pass.type === 'Unlimited Pass');
const hasSelectivePass = activePasses.some(pass => pass.type === 'Selective Pass');
const hasSelectivePass = activePasses.some(pass => pass.type === 'Flexi Pass');
if (hasUnlimitedPass) {
return (

View File

@@ -535,130 +535,196 @@ export function SuperSavingsPage({
</section>
{/* How It Works Section */}
<section className="py-20 bg-muted/30">
<div className="container mx-auto px-4">
<section className="py-24 relative overflow-hidden bg-[#FFF5F5]/50">
{/* Background decorative elements */}
<div className="absolute top-0 right-0 w-[600px] h-[600px] bg-primary/5 rounded-full blur-[100px] pointer-events-none -mr-40 -mt-40"></div>
<div className="absolute bottom-0 left-0 w-[400px] h-[400px] bg-primary/5 rounded-full blur-[80px] pointer-events-none -ml-20 -mb-20"></div>
<div className="container mx-auto px-4 relative z-10">
<motion.div
className="text-center mb-16"
className="text-center mb-20"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
>
<h2 className="font-poppins text-3xl md:text-4xl lg:text-5xl leading-tight mb-4">
<span className="font-light">How</span>{' '}
<span className="font-bold italic bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">
It Works
</span>
<div className="flex items-center justify-center gap-3 mb-4">
<div className="h-px w-8 bg-primary"></div>
<span className="text-primary font-semibold tracking-widest uppercase text-xs font-poppins">Simple Process</span>
<div className="h-px w-8 bg-primary"></div>
</div>
<h2 className="font-merchant text-4xl md:text-5xl lg:text-6xl text-gray-900 mb-6">
Start Saving in <span className="text-primary italic">Minutes</span>
</h2>
<p className="font-poppins leading-relaxed text-gray-600 max-w-2xl mx-auto">
Access massive discounts in three simple steps
<p className="font-poppins text-lg text-gray-500 font-light max-w-xl mx-auto leading-relaxed">
Your journey to smarter travel and bigger savings begins with three simple steps.
</p>
</motion.div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{[
{
step: '01',
title: 'Get Your Pass',
description: 'Purchase a CityCards pass and unlock instant access',
icon: '🎫'
},
{
step: '02',
title: 'Browse Deals',
description: 'Explore hundreds of exclusive super savings across categories',
icon: '💎'
},
{
step: '03',
title: 'Save Big',
description: 'Enjoy discounts up to 65% on premium experiences',
icon: '🎉'
}
].map((item, index) => (
<motion.div
key={item.step}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: index * 0.2 }}
>
<Card className="bg-white p-8 rounded-xl hover:shadow-lg transition-shadow duration-300">
<div className="text-6xl mb-4">{item.icon}</div>
<div className="font-poppins text-5xl font-bold text-primary/20 mb-4">
{item.step}
<div className="relative max-w-6xl mx-auto">
{/* Connecting line for desktop */}
<div className="hidden md:block absolute top-12 left-[16%] right-[16%] h-0.5 border-t-2 border-dashed border-primary/20 z-0"></div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-12 md:gap-8">
{[
{
step: '01',
title: 'Unlock Access',
description: 'Get your CityCards pass to instantly activate membership perks.',
icon: MapPinned
},
{
step: '02',
title: 'Discover Deals',
description: 'Browse exclusive offers on hotels, flights, and experiences.',
icon: Search
},
{
step: '03',
title: 'Enjoy Savings',
description: 'Redeem discounts instantly and watch your travel budget grow.',
icon: Percent
}
].map((item, index) => (
<motion.div
key={item.step}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: index * 0.2 }}
className="relative z-10 group"
>
<div className="flex flex-col items-center text-center">
{/* Icon Container */}
<div className="relative mb-8">
<div className="w-24 h-24 rounded-[2rem] bg-white flex items-center justify-center shadow-[0_8px_30px_rgb(0,0,0,0.06)] group-hover:scale-110 group-hover:-rotate-3 transition-transform duration-300 border border-primary/10 relative overflow-hidden">
<div className="absolute inset-0 bg-primary/5 group-hover:bg-primary/10 transition-colors duration-300"></div>
<item.icon className="w-10 h-10 text-primary relative z-10" />
</div>
<div className="absolute -top-3 -right-3 w-8 h-8 rounded-full bg-primary text-white flex items-center justify-center font-bold font-poppins text-sm border-4 border-white shadow-md">
{index + 1}
</div>
</div>
<h3 className="font-merchant text-2xl text-gray-900 mb-3 group-hover:text-primary transition-colors">
{item.title}
</h3>
<p className="font-poppins text-gray-500 font-light leading-relaxed max-w-xs">
{item.description}
</p>
</div>
<h3 className="font-poppins font-semibold text-gray-900 mb-3">
{item.title}
</h3>
<p className="font-poppins leading-relaxed text-gray-600">
{item.description}
</p>
</Card>
</motion.div>
))}
</motion.div>
))}
</div>
</div>
</div>
</section>
{/* Categories Section */}
<section className="py-20">
<div className="container mx-auto px-4">
<motion.div
className="text-center mb-16"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
>
<h2 className="font-poppins text-3xl md:text-4xl lg:text-5xl leading-tight mb-4">
<span className="font-bold italic bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">
Top Categories
</span>{' '}
<span className="font-light">to Save</span>
</h2>
<p className="font-poppins leading-relaxed text-gray-600 max-w-2xl mx-auto">
From luxury hotels to exciting tours, find massive savings on everything you love
</p>
</motion.div>
<section className="py-24 bg-gray-50/50 relative overflow-hidden">
{/* Abstract Travel Patterns */}
<div className="absolute top-0 right-0 w-[800px] h-[800px] bg-gradient-to-bl from-primary/5 via-secondary/5 to-transparent rounded-full blur-3xl pointer-events-none -mr-40 -mt-40"></div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div className="container mx-auto px-4 relative z-10">
{/* Section Header */}
<div className="flex flex-col md:flex-row items-end justify-between mb-12 gap-6">
<motion.div
className="max-w-2xl"
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.6 }}
>
<div className="flex items-center gap-2 mb-4">
<div className="h-px w-8 bg-primary"></div>
<span className="text-primary font-semibold tracking-widest uppercase text-xs font-poppins">Explore Collections</span>
</div>
<h2 className="font-merchant text-4xl md:text-5xl lg:text-6xl text-gray-900 mb-4 leading-tight">
Curated for the <span className="text-primary italic">Modern Traveler</span>
</h2>
<p className="font-poppins text-lg text-gray-500 font-light max-w-lg leading-relaxed">
Discover exclusive savings across our most sought-after travel categories.
</p>
</motion.div>
<motion.div
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.6 }}
className="hidden md:block"
>
<Button
onClick={onSignInClick}
variant="ghost"
className="group gap-2 text-gray-600 hover:text-primary font-poppins text-lg"
>
View All Categories
<span className="w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center group-hover:bg-primary group-hover:text-white transition-all duration-300">
<ChevronRight className="w-4 h-4" />
</span>
</Button>
</motion.div>
</div>
{/* Bento Grid Layout */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{categoriesData.map((category, index) => (
<motion.div
key={category.title}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: index * 0.1 }}
transition={{ duration: 0.4, delay: index * 0.1 }}
className={`${index === 0 ? 'md:col-span-2' : ''} group`}
>
<Card className="bg-white p-8 rounded-xl hover:shadow-lg transition-all duration-300 group cursor-pointer">
<div className={`w-16 h-16 rounded-full bg-gradient-to-br ${category.color} flex items-center justify-center mb-6 group-hover:scale-110 transition-transform duration-300`}>
<category.icon className="w-8 h-8 text-white" />
<div
onClick={onSignInClick}
className={`
relative h-full bg-white rounded-[2rem] p-8 border border-gray-100
shadow-[0_4px_20px_-4px_rgba(0,0,0,0.05)] hover:shadow-[0_20px_40px_-10px_rgba(0,0,0,0.1)]
transition-all duration-500 cursor-pointer overflow-hidden flex flex-col justify-between
group-hover:border-primary/20
`}
>
{/* Background Gradient Hover */}
<div className={`absolute inset-0 bg-gradient-to-br ${category.color} opacity-0 group-hover:opacity-[0.03] transition-opacity duration-500`}></div>
{/* Large Watermark Icon for visual depth */}
<category.icon className="absolute -bottom-8 -right-8 w-48 h-48 text-gray-50 group-hover:text-primary/5 transition-colors duration-500 -rotate-12" />
<div className="relative z-10">
<div className="flex justify-between items-start mb-6">
<div className={`
w-14 h-14 rounded-2xl flex items-center justify-center shadow-sm transition-all duration-300
${index === 0 ? 'bg-primary text-white shadow-primary/20' : 'bg-gray-50 text-gray-600 group-hover:bg-primary group-hover:text-white'}
`}>
<category.icon className="w-7 h-7" />
</div>
<Badge className="bg-emerald-50 text-emerald-600 border-emerald-100 font-poppins font-medium px-3 py-1.5">
{category.savings}
</Badge>
</div>
<h3 className={`font-merchant text-gray-900 mb-2 group-hover:text-primary transition-colors ${index === 0 ? 'text-4xl' : 'text-2xl'}`}>
{category.title}
</h3>
<p className="font-poppins text-gray-500 font-light leading-relaxed max-w-md">
{category.description}
</p>
</div>
<h3 className="font-poppins font-semibold text-gray-900 mb-3">
{category.title}
</h3>
<p className="font-poppins leading-relaxed text-gray-600 mb-4">
{category.description}
</p>
<div className="flex items-center justify-between">
<span className="font-poppins text-sm font-medium text-primary">
{category.savings}
</span>
<Button
onClick={onSignInClick}
variant="ghost"
size="sm"
className="text-primary hover:text-primary/80 font-poppins font-medium"
>
Explore
</Button>
<div className="relative z-10 mt-8 flex items-center gap-2 text-primary font-poppins font-medium text-sm opacity-0 group-hover:opacity-100 transform translate-y-2 group-hover:translate-y-0 transition-all duration-300">
<span>Explore Deals</span>
<ArrowLeft className="w-4 h-4 rotate-180" />
</div>
</Card>
</div>
</motion.div>
))}
</div>
<div className="text-center mt-12">
{/* Mobile View All Button */}
<div className="mt-8 md:hidden text-center">
<Button
onClick={onSignInClick}
className="bg-primary hover:bg-primary/90 text-white px-8 py-6 font-poppins font-semibold"
className="w-full bg-primary hover:bg-primary/90 text-white font-poppins font-semibold py-6 rounded-xl shadow-lg shadow-primary/20"
>
Browse All Categories
</Button>

View File

@@ -108,78 +108,59 @@ export function LandingPage({ onSignInClick,
/> */}
{/* Hero Section */}
<div
className="relative z-10 min-h-screen flex items-end justify-start pt-24 pb-16 bg-cover bg-center bg-no-repeat"
style={{ backgroundImage: `url(${heroBannerImage})` }}
className="relative z-10 min-h-[90vh] flex items-end justify-start pt-24 pb-16 bg-cover bg-[center_35%] bg-no-repeat"
style={{ backgroundImage: `url(${heroBannerImage})` }}
>
<div className="container mx-auto px-4">
<motion.div
className="max-w-4xl lg:max-w-3xl xl:max-w-4xl"
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{
duration: 0.8,
delay: 0.5,
ease: [0.25, 0.1, 0.25, 1],
}}
>
{/* Overlay */}
<div className="absolute inset-0 bg-black/40 z-0"></div>
{/* Main Headline */}
<div className="mb-6 text-left">
<h1 className="font-poppins leading-tight text-white text-5xl md:text-6xl lg:text-7xl drop-shadow-lg">
<span className="block font-light">CityCards.</span>
<span className="block font-normal">See More, Spend Less.</span>
</h1>
</div>
<div className="container mx-auto px-4 relative z-10">
<motion.div
className="max-w-4xl lg:max-w-3xl xl:max-w-4xl"
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{
duration: 0.8,
delay: 0.5,
ease: [0.25, 0.1, 0.25, 1],
}}
>
{/* Main Headline */}
<div className="mb-6 text-left">
<h1 className="font-poppins leading-tight text-white text-5xl md:text-6xl lg:text-7xl drop-shadow-lg">
<span className="block font-light">CityCards.</span>
<span className="block font-normal">See More, Spend Less.</span>
</h1>
</div>
{/* Subheading */}
<div className="mb-8 text-left">
<p className="font-poppins text-xl leading-relaxed font-normal text-white/90 drop-shadow-md">
Instant QR access to 40+ attractions,
<br className="hidden sm:block" />
exclusive perks, and <span className="font-bold text-white border-b-2 border-primary/50 pb-0.5">save up to 50-60%</span>
</p>
</div>
{/* Subheading */}
<div className="mb-8 text-left">
<p className="font-poppins text-xl leading-relaxed font-normal text-white/90 drop-shadow-md">
Instant QR access to 40+ attractions,
<br className="hidden sm:block" />
exclusive perks, and savings up to 30%
</p>
</div>
{/* CTA Button */}
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{
duration: 0.8,
delay: 0.7,
ease: [0.25, 0.1, 0.25, 1],
}}
>
<Link to="/melbourne">
<Button
withShine={true}
size="xl"
className="bg-primary hover:bg-primary/90 py-4 rounded-full text-lg font-poppins font-semibold px-8 text-white shadow-lg hover:shadow-xl transition-all duration-300"
>
Explore Cities
</Button>
</Link>
</motion.div>
</motion.div>
</div>
{/* Scroll Indicator */}
<motion.div
className="absolute bottom-8 left-1/2 transform -translate-x-1/2"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 1.2, duration: 0.8 }}
{/* CTA Button */}
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{
duration: 0.8,
delay: 0.7,
ease: [0.25, 0.1, 0.25, 1],
}}
>
<Button
onClick={() => setIsCityDialogOpen(true)}
withShine={true}
size="xl"
className="bg-primary hover:bg-primary/90 py-4 rounded-full font-poppins font-semibold px-8 text-white shadow-lg hover:shadow-xl transition-all duration-300"
>
<button
onClick={scrollToCities}
className="text-white hover:text-primary transition-colors duration-300"
>
<ChevronDown className="w-8 h-8 animate-bounce" />
</button>
</motion.div>
</div>
Explore Cities
</Button>
</motion.div>
</motion.div>
</div>
</div>
{/* Features Section */}
<LandingWhyChooseCityCards />
@@ -194,7 +175,6 @@ export function LandingPage({ onSignInClick,
<LandingBookAttractionSection />
{/* CustomPostcards Section */}
{/* <LandingCustomPostcards /> */}
<CustomPostcards/>
{/* UpcomingCities Section */}