import { useState, useEffect } from 'react'; import { motion } from 'motion/react'; import { Search, MapPin, Clock, Star, DollarSign, Filter, X, ArrowLeft } from 'lucide-react'; import { Button } from './ui/button'; import { Input } from './ui/input'; import { Card, CardContent } from './ui/card'; import { Badge } from './ui/badge'; import { Checkbox } from './ui/checkbox'; import { Slider } from './ui/slider'; import Navbar from './Navbar'; import { EnhancedTestimonials } from './EnhancedTestimonials'; import { Footer } from './Footer'; import { ImageWithFallback } from './figma/ImageWithFallback'; interface Attraction { id: string; name: string; description: string; image: string; location: string; duration: string; rating: number; price: number; category: string; passType: 'unlimited' | 'selective' | 'both'; isPopular?: boolean; } interface CityData { id: string; name: string; country: string; hero_image: string; currency: string; description: string; attractions: Attraction[]; } const cityAttractions: Record = { paris: { id: 'paris', name: 'Paris', country: 'France', hero_image: 'https://images.unsplash.com/photo-1652254693457-5f6d7db674c6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxwYXJpcyUyMHRvdXJpc20lMjBhdHRyYWN0aW9uc3xlbnwxfHx8fDE3NTc2NjQwMjB8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', currency: 'EUR', description: 'City of Light with world-famous landmarks, art museums, and romantic atmosphere', attractions: [ { id: 'eiffel-tower', name: 'Eiffel Tower', description: 'Iconic iron tower offering breathtaking views of Paris from its observation decks', image: 'https://images.unsplash.com/photo-1431274172761-fca41d930114?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxwYXJpcyUyMGVpZmZlbCUyMHRvd2VyfGVufDF8fHx8MTc1NzYxNjQ2OXww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', location: 'Champ de Mars', duration: '2-3 hours', rating: 4.5, price: 29, category: 'culture', passType: 'unlimited', isPopular: true }, { id: 'louvre-museum', name: 'Louvre Museum', description: 'World\'s largest art museum housing the Mona Lisa and countless masterpieces', image: 'https://images.unsplash.com/photo-1566139536744-6270a2e5a3a3?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxsb3V2cmUlMjBtdXNldW18ZW58MXx8fHwxNzU3NjY0MDY3fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', location: 'Palais Royal', duration: '3-4 hours', rating: 4.7, price: 17, category: 'culture', passType: 'unlimited', isPopular: true }, { id: 'notre-dame', name: 'Notre-Dame Cathedral', description: 'Gothic masterpiece and historic cathedral in the heart of Paris', image: 'https://images.unsplash.com/photo-1539650116574-75c0c6d0d0e3?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxub3RyZSUyMGRhbWUlMjBwYXJpc3xlbnwxfHx8fDE3NTc2NjQwNzF8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', location: 'Île de la Cité', duration: '1-2 hours', rating: 4.6, price: 0, category: 'culture', passType: 'unlimited' }, { id: 'arc-de-triomphe', name: 'Arc de Triomphe', description: 'Monumental arch honoring those who fought for France, with panoramic city views', image: 'https://images.unsplash.com/photo-1598975106642-dc3a8c79c854?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxhcmMlMjBkZSUyMHRyaW9tcGhlfGVufDF8fHx8MTc1NzY2NDA3NXww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', location: 'Champs-Élysées', duration: '1-2 hours', rating: 4.4, price: 13, category: 'culture', passType: 'both' }, { id: 'seine-cruise', name: 'Seine River Cruise', description: 'Scenic boat tour along the Seine passing famous Parisian landmarks', image: 'https://images.unsplash.com/photo-1502602898536-47ad22581b52?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxzZWluZSUyMHJpdmVyJTIwY3J1aXNlfGVufDF8fHx8MTc1NzY2NDA3OXww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', location: 'Various Docks', duration: '1 hour', rating: 4.3, price: 15, category: 'adventure', passType: 'both' }, { id: 'montmartre', name: 'Montmartre & Sacré-Cœur', description: 'Bohemian hilltop district with the stunning Sacré-Cœur Basilica', image: 'https://images.unsplash.com/photo-1471939743851-c4df8b6ee c95?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxtb250bWFydHJlJTIwc2FjcmUlMjBjb2V1cnxlbnwxfHx8fDE3NTc2NjQwODN8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', location: 'Montmartre', duration: '2-4 hours', rating: 4.5, price: 0, category: 'culture', passType: 'unlimited' } ] }, tokyo: { id: 'tokyo', name: 'Tokyo', country: 'Japan', hero_image: 'https://images.unsplash.com/photo-1713263367828-9eafd7fc3797?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHx0b2t5byUyMGF0dHJhY3Rpb25zJTIwY2l0eXNjYXBlfGVufDF8fHx8MTc1NzY2NDAyNHww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', currency: 'JPY', description: 'Vibrant metropolis blending ancient traditions with cutting-edge technology', attractions: [ { id: 'tokyo-tower', name: 'Tokyo Tower', description: 'Iconic red tower offering spectacular city views and broadcasting facilities', image: 'https://images.unsplash.com/photo-1598976838083-ad00095bb123?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHx0b2t5byUyMHRvd2VyfGVufDF8fHx8MTc1NzY2NDEwOHww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', location: 'Minato', duration: '2-3 hours', rating: 4.4, price: 25, category: 'adventure', passType: 'unlimited', isPopular: true }, { id: 'sensoji-temple', name: 'Sensoji Temple', description: 'Ancient Buddhist temple and Tokyo\'s oldest temple with traditional atmosphere', image: 'https://images.unsplash.com/photo-1503899036084-c55cdd92da26?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxzZW5zb2ppJTIwdGVtcGxlfGVufDF8fHx8MTc1NzY2NDExMnww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', location: 'Asakusa', duration: '1-2 hours', rating: 4.6, price: 0, category: 'culture', passType: 'unlimited' }, { id: 'shibuya-crossing', name: 'Shibuya Crossing', description: 'World\'s busiest pedestrian crossing and symbol of modern Tokyo', image: 'https://images.unsplash.com/photo-1542051841857-5f90071e7989?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxzaGlidXlhJTIwY3Jvc3Npbmd8ZW58MXx8fHwxNzU3NjY0MTE2fDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', location: 'Shibuya', duration: '1 hour', rating: 4.3, price: 0, category: 'adventure', passType: 'unlimited', isPopular: true }, { id: 'tokyo-skytree', name: 'Tokyo Skytree', description: 'World\'s second tallest structure with observation decks and stunning views', image: 'https://images.unsplash.com/photo-1576538509036-c47f3604da84?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHx0b2t5byUyMHNreXRyZWV8ZW58MXx8fHwxNzU3NjY0MTIwfDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', location: 'Sumida', duration: '2-3 hours', rating: 4.5, price: 32, category: 'adventure', passType: 'selective', isPopular: true } ] }, london: { id: 'london', name: 'London', country: 'United Kingdom', hero_image: 'https://images.unsplash.com/photo-1645544865499-8b768cf70562?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxsb25kb24lMjBsYW5kbWFya3MlMjB0b3VyaXNtfGVufDF8fHx8MTc1NzY2NDAyOHww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', currency: 'GBP', description: 'Historic capital with royal palaces, world-class museums, and modern culture', attractions: [ { id: 'big-ben', name: 'Big Ben & Parliament', description: 'Iconic clock tower and seat of British government with guided tours', image: 'https://images.unsplash.com/photo-1486299267070-83823f5448dd?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxsb25kb24lMjBiaWclMjBiZW58ZW58MXx8fHwxNzU3NjQ3OTYxfDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', location: 'Westminster', duration: '2 hours', rating: 4.7, price: 28, category: 'culture', passType: 'unlimited', isPopular: true }, { id: 'british-museum', name: 'British Museum', description: 'World-renowned museum with artifacts from across human history', image: 'https://images.unsplash.com/photo-1603838354146-f5ffc0b45cd9?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxicml0aXNoJTIwbXVzZXVtfGVufDF8fHx8MTc1NzY2NDE0NHww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', location: 'Bloomsbury', duration: '3-4 hours', rating: 4.6, price: 0, category: 'culture', passType: 'unlimited' }, { id: 'tower-bridge', name: 'Tower Bridge', description: 'Victorian bascule bridge with glass floor and panoramic walkways', image: 'https://images.unsplash.com/photo-1513635269975-59663e0ac1ad?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHx0b3dlciUyMGJyaWRnZSUyMGxvbmRvbnxlbnwxfHx8fDE3NTc2NjQxNDh8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', location: 'Tower Hamlets', duration: '1-2 hours', rating: 4.4, price: 12, category: 'culture', passType: 'both', isPopular: true }, { id: 'buckingham-palace', name: 'Buckingham Palace', description: 'Official residence of the British monarch with state rooms tours', image: 'https://images.unsplash.com/photo-1529655683826-ac6bbde65424?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxidWNraW5naGFtJTIwcGFsYWNlfGVufDF8fHx8MTc1NzY2NDE1Mnww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral', location: 'Westminster', duration: '2-3 hours', rating: 4.3, price: 30, category: 'culture', passType: 'selective' } ] } }; interface CityAttractionsPageProps { cityId: string; onBackClick: () => void; onHomeClick: () => void; onMelbourneClick: () => void; onPassesClick: () => void; onCitiesClick: () => void; onSignInClick: () => void; onAttractionsClick: () => void; onBlogsClick: () => void; onHowItWorksClick: () => void; onFAQClick: () => void; onPrivacyPolicyClick: () => void; onAboutUsClick: () => void; onAttractionClick?: (attractionId: string) => void; currentPage: string; } export function CityAttractionsPage({ cityId, onBackClick, onHomeClick, onMelbourneClick, onPassesClick, onCitiesClick, onSignInClick, onAttractionsClick, onBlogsClick, onHowItWorksClick, onFAQClick, onPrivacyPolicyClick, onAboutUsClick, onAttractionClick, currentPage }: CityAttractionsPageProps) { const [searchQuery, setSearchQuery] = useState(''); const [selectedCategories, setSelectedCategories] = useState([]); const [selectedPassTypes, setSelectedPassTypes] = useState([]); const [priceRange, setPriceRange] = useState([0, 50]); const [showMobileFilters, setShowMobileFilters] = useState(false); const [pageNumber, setPageNumber] = useState(1); const [itemsPerPage] = useState(12); // Get city data const cityData = cityAttractions[cityId]; if (!cityData) { return (

City Not Found

Sorry, this city is not available yet.

); } const categories = [ { value: 'adventure', label: 'Adventure', count: cityData.attractions.filter(a => a.category === 'adventure').length }, { value: 'culture', label: 'Culture', count: cityData.attractions.filter(a => a.category === 'culture').length }, { value: 'family', label: 'Family Friendly', count: cityData.attractions.filter(a => a.category === 'family').length } ].filter(cat => cat.count > 0); const passTypes = [ { value: 'unlimited', label: 'Unlimited', count: cityData.attractions.filter(a => a.passType === 'unlimited').length }, { value: 'selective', label: 'Selective', count: cityData.attractions.filter(a => a.passType === 'selective').length }, { value: 'both', label: 'Both', count: cityData.attractions.filter(a => a.passType === 'both').length } ].filter(type => type.count > 0); const filteredAttractions = cityData.attractions.filter(attraction => { const matchesSearch = attraction.name.toLowerCase().includes(searchQuery.toLowerCase()) || attraction.description.toLowerCase().includes(searchQuery.toLowerCase()); const matchesCategory = selectedCategories.length === 0 || selectedCategories.includes(attraction.category); const matchesPassType = selectedPassTypes.length === 0 || selectedPassTypes.includes(attraction.passType); const matchesPrice = attraction.price >= priceRange[0] && attraction.price <= priceRange[1]; return matchesSearch && matchesCategory && matchesPassType && matchesPrice; }); // Pagination logic const totalPages = Math.ceil(filteredAttractions.length / itemsPerPage); const startIndex = (pageNumber - 1) * itemsPerPage; const endIndex = startIndex + itemsPerPage; const currentAttractions = filteredAttractions.slice(startIndex, endIndex); const totalItems = filteredAttractions.length; const showingFrom = totalItems > 0 ? startIndex + 1 : 0; const showingTo = Math.min(endIndex, totalItems); // Reset to first page when filters change useEffect(() => { setPageNumber(1); }, [searchQuery, selectedCategories, selectedPassTypes, priceRange]); const toggleCategory = (category: string) => { setSelectedCategories(prev => prev.includes(category) ? prev.filter(c => c !== category) : [...prev, category] ); }; const togglePassType = (passType: string) => { setSelectedPassTypes(prev => prev.includes(passType) ? prev.filter(p => p !== passType) : [...prev, passType] ); }; const clearAllFilters = () => { setSelectedCategories([]); setSelectedPassTypes([]); setPriceRange([0, 50]); setSearchQuery(''); }; const FilterSidebar = ({ isMobile = false }) => (

Filters

{isMobile && ( )}
{/* Categories */} {categories.length > 0 && (

Category

{categories.map(category => (
toggleCategory(category.value)} />
))}
)} {/* Pass Types */} {passTypes.length > 0 && (

Pass Type

{passTypes.map(passType => (
togglePassType(passType.value)} />
))}
)} {/* Price Range */}

Price Range ({cityData.currency})

{priceRange[0]} {cityData.currency} {priceRange[1]} {cityData.currency}
{/* Clear filters */}
); return (
{}} onSignInClick={onSignInClick} onPassesClick={onPassesClick} onCitiesClick={onCitiesClick} onHomeClick={onHomeClick} onAttractionsClick={onAttractionsClick} onBlogsClick={onBlogsClick} onHowItWorksClick={onHowItWorksClick} onFAQClick={onFAQClick} onPrivacyPolicyClick={onPrivacyPolicyClick} onAboutUsClick={onAboutUsClick} currentPage="cities" isUserSignedIn={!!user} user={user} /> {/* Hero Section */}
Back to Cities Explore{' '} {cityData.name} {cityData.description}
{/* Desktop Sidebar */}
{/* Main Content */}
{/* Header */}

{cityData.name} Attractions

Discover the best attractions and experiences in {cityData.name}

{/* Search Bar */}
setSearchQuery(e.target.value)} className="pl-10 bg-white border-gray-200" />
{/* Mobile Filter Button */}
{/* Results Count */}

Showing {showingFrom}-{showingTo} of {totalItems} attraction(s)

{/* Attractions Grid */} {currentAttractions.map((attraction, index) => ( onAttractionClick?.(attraction.id)} >
{attraction.isPopular && ( Popular )}

{attraction.location}

{attraction.name}

{attraction.description}

{attraction.duration}
{attraction.rating}
{attraction.price > 0 ? ( <> {attraction.price} {cityData.currency} ) : ( Free )}
{attraction.passType === 'unlimited' ? 'Unlimited' : attraction.passType === 'selective' ? 'Selective' : 'Both'}
))}
{totalItems === 0 && (

No attractions found matching your criteria

)} {/* Pagination */} {totalPages > 1 && (
Page {pageNumber} of {totalPages}
{/* Page numbers */}
{Array.from({ length: Math.min(5, totalPages) }, (_, i) => { let pageNum; if (totalPages <= 5) { pageNum = i + 1; } else if (pageNumber <= 3) { pageNum = i + 1; } else if (pageNumber >= totalPages - 2) { pageNum = totalPages - 4 + i; } else { pageNum = pageNumber - 2 + i; } return ( ); })}
)}
{/* Mobile Filter Modal */} {showMobileFilters && (
setShowMobileFilters(false)} />
)} {/* Enhanced Testimonials Section */}
); }