Files
CityCards-Website/src/components/MelbourneCardComparison.tsx

294 lines
11 KiB
TypeScript

import { useEffect, useState } from 'react';
import { Check, X, Star, Users, MapPin, Calendar, Clock, Zap, Eye } from 'lucide-react';
import { Button } from './ui/button';
import { motion } from 'motion/react';
// const cardOptions = [
// {
// id: 'selective',
// name: 'Flexi Card',
// subtitle: 'Pick 5-10 things to do from a choice of 102 attractions tours and activities',
// priceRange: '$89-159',
// duration: '3-7 days',
// popular: false,
// color: 'from-blue-500 to-cyan-500',
// features: {
// passCategory: 'Selective Card',
// accessToAttractions: true,
// entryToAttractions: true,
// accessToExperiences: true,
// entryToSites: true,
// accessToVenues: false,
// entryToEvents: 'Pass Category',
// accessToLocations: 'Pass Category',
// entryToActivities: true,
// accessToExhibits: true,
// entryToActivitiesSecond: true
// }
// },
// {
// id: 'unlimited',
// name: 'Melbourne Unlimited Card',
// subtitle: 'Pick 5-30 things to do from a choice of 102 attractions tours and activities',
// priceRange: '$159-299',
// duration: '3-7 days',
// popular: true,
// color: 'from-purple-500 to-pink-500',
// features: {
// passCategory: 'Pass Category',
// accessToAttractions: true,
// entryToAttractions: true,
// accessToExperiences: true,
// entryToSites: true,
// accessToVenues: true,
// entryToEvents: 'Pass Category',
// accessToLocations: 'Pass Category',
// entryToActivities: true,
// accessToExhibits: true,
// entryToActivitiesSecond: true
// }
// }
// ];
const features = [
{ key: 'passCategory', label: 'Pass Category', icon: Star },
{ key: 'accessToAttractions', label: 'Access to Attractions', icon: MapPin },
{ key: 'entryToAttractions', label: 'Entry to Attractions', icon: Zap },
{ key: 'accessToExperiences', label: 'Access to Experiences', icon: Users },
{ key: 'entryToSites', label: 'Entry to Sites', icon: MapPin },
{ key: 'accessToVenues', label: 'Access to Venues', icon: MapPin },
{ key: 'entryToEvents', label: 'Entry to Events', icon: Calendar },
{ key: 'accessToLocations', label: 'Access to Locations', icon: MapPin },
{ key: 'entryToActivities', label: 'Entry to Activities', icon: Users },
{ key: 'accessToExhibits', label: 'Access to Exhibits', icon: Eye },
{ key: 'entryToActivitiesSecond', label: 'Entry to Activities', icon: Users }
];
const FeatureIcon = ({ feature }: { feature: typeof features[0] }) => {
const Icon = feature.icon;
return <Icon className="w-4 h-4 text-gray-500" />;
};
interface MelbourneCardComparisonProps {
onCheckoutClick?: () => void;
cards: any[]
}
export function MelbourneCardComparison({ onCheckoutClick, cards }: MelbourneCardComparisonProps) {
const [selectedCard, setSelectedCard] = useState<string>('unlimited');
const cardOptions = [
{
id: cards[0]?.id,
name: cards[0]?.title,
subtitle: cards[0]?.description,
priceRange: `$${cards[0]?.adultPrice}`,
duration: '3-7 days',
popular: false,
color: 'from-blue-500 to-cyan-500',
features: {
passCategory: 'Selective Card',
accessToAttractions: true,
entryToAttractions: true,
accessToExperiences: true,
entryToSites: true,
accessToVenues: false,
entryToEvents: 'Pass Category',
accessToLocations: 'Pass Category',
entryToActivities: true,
accessToExhibits: true,
entryToActivitiesSecond: true
}
},
{
id: cards[1]?.id,
name: cards[1]?.title,
subtitle: cards[1]?.description,
priceRange: `$${cards[1]?.adultPrice}`,
duration: '3-7 days',
popular: true,
color: 'from-purple-500 to-pink-500',
features: {
passCategory: 'Pass Category',
accessToAttractions: true,
entryToAttractions: true,
accessToExperiences: true,
entryToSites: true,
accessToVenues: true,
entryToEvents: 'Pass Category',
accessToLocations: 'Pass Category',
entryToActivities: true,
accessToExhibits: true,
entryToActivitiesSecond: true
}
}
];
const renderFeatureValue = (value: boolean | string, cardId: string) => {
if (typeof value === 'boolean') {
return value ? (
<div className="flex justify-center">
<div className="w-6 h-6 bg-green-500 rounded-full flex items-center justify-center">
<Check className="w-4 h-4 text-white" />
</div>
</div>
) : (
<div className="flex justify-center">
<div className="w-6 h-6 bg-gray-200 rounded-full flex items-center justify-center">
<X className="w-3 h-3 text-gray-400" />
</div>
</div>
);
}
return (
<div className="text-center text-sm text-gray-600 px-2">
{value}
</div>
);
};
return (
<section className="py-20 bg-gradient-to-br from-gray-50 via-white to-gray-50 relative overflow-hidden">
{/* Background Pattern */}
<div className="absolute inset-0 opacity-5">
<div className="absolute top-0 left-0 w-full h-full bg-gradient-to-br from-primary/10 to-secondary/10"></div>
</div>
<div className="container mx-auto px-4 relative z-10">
{/* Header */}
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
viewport={{ once: true }}
className="text-center mb-16"
>
<div className="inline-flex items-center gap-2 bg-gradient-to-r from-primary/10 to-secondary/10 px-4 py-2 rounded-full mb-6">
<div className="w-2 h-2 bg-gradient-to-r from-primary to-secondary rounded-full"></div>
<span className="text-sm font-medium bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">
Choose Your Adventure
</span>
</div>
<h2 className="font-merchant text-4xl md:text-5xl lg:text-6xl text-gray-900 mb-6">
<span className="font-bold bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent italic pr-2">
Buy
</span>{' '}
<span className="font-normal">Now</span>
</h2>
<p className="text-xl text-gray-600 max-w-4xl mx-auto leading-relaxed">
Melbourne is a must-visit cultural epicenter, and this spectacular trip unlocks
your access around the city in one easy. Save over the cost of visiting Melbourne's
landmarks, have lunch at Phi Phi Leh, snorkel at Bamboo Island, and visit Monkey Beach.
</p>
</motion.div>
{/* Comparison Table */}
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.3 }}
viewport={{ once: true }}
className="bg-white rounded-3xl shadow-xl border border-gray-100 overflow-hidden"
>
{/* Table Header */}
<div className="bg-gradient-to-r from-gray-50 to-gray-100 px-8 py-6">
<div className="grid grid-cols-3 gap-8 items-center">
<div className="font-poppins text-xl font-semibold text-gray-900">
Features
</div>
{cardOptions.map((card,index) => (
<div key={card.id ?? index} className="text-center">
<div className="mb-2">
<div className="font-poppins font-semibold text-2xl" style={{ color: '#F95F62' }}>{card.name}</div>
</div>
<div className="font-poppins text-sm text-gray-600 max-w-xs mx-auto leading-relaxed">
{card.subtitle}
</div>
</div>
))}
</div>
</div>
{/* Table Body */}
<div className="divide-y divide-gray-100">
{features.map((feature, index) => (
<motion.div
key={feature.key}
initial={{ opacity: 0, x: -20 }}
whileInView={{ opacity: 1, x: 0 }}
transition={{ duration: 0.4, delay: index * 0.05 }}
viewport={{ once: true }}
className="grid grid-cols-3 gap-8 items-center px-8 py-6 hover:bg-gray-50/50 transition-colors duration-200"
>
<div className="flex items-center gap-3">
<FeatureIcon feature={feature} />
<span className="font-medium text-gray-900">{feature.label}</span>
</div>
{cardOptions.map((card, index) => (
<div key={card.id ?? index} className="text-center">
{renderFeatureValue(card.features[feature.key as keyof typeof card.features], card.id)}
</div>
))}
</motion.div>
))}
</div>
{/* Call to Action Footer */}
<div className="bg-gradient-to-r from-primary/5 to-secondary/5 px-8 py-8">
<div className="grid grid-cols-3 gap-8 items-center">
<div className="text-center">
<div className="font-medium text-gray-600 text-sm mb-2">Ready to explore?</div>
<div className="text-xs text-gray-500">Compare features above</div>
</div>
{cardOptions.map((card,index) => (
<motion.div key={card.id ?? index} className="text-center">
<div className="mb-4">
<div className="text-3xl font-bold text-gray-900">{card.priceRange}</div>
<div className="text-sm text-gray-600">{card.duration}</div>
</div>
<Button
withShine={true}
className="w-full h-14 rounded-2xl text-white font-semibold text-lg hover:scale-105 transition-all duration-300 shadow-lg hover:shadow-xl cursor-pointer"
style={{ backgroundColor: '#F95F62' }}
onClick={onCheckoutClick}
>
Buy {card.name}
</Button>
</motion.div>
))}
</div>
</div>
</motion.div>
{/* Additional Info */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.4 }}
viewport={{ once: true }}
className="text-center mt-12"
>
<div className="flex flex-wrap justify-center gap-8 text-sm text-gray-600">
<div className="flex items-center gap-2">
<Clock className="w-4 h-4 text-primary" />
<span>Instant digital delivery</span>
</div>
<div className="flex items-center gap-2">
<Users className="w-4 h-4 text-primary" />
<span>24/7 customer support</span>
</div>
<div className="flex items-center gap-2">
<Star className="w-4 h-4 text-primary" />
<span>90-day money back guarantee</span>
</div>
</div>
</motion.div>
</div>
</section>
);
}