diff --git a/src/Redux/Store.tsx b/src/Redux/Store.tsx index ecb7f5d..725a87a 100644 --- a/src/Redux/Store.tsx +++ b/src/Redux/Store.tsx @@ -3,13 +3,15 @@ import { attractionsApi } from "./services/attractions.service"; import { citiesApi } from "./services/cities.service"; import { authApi } from "./services/auth.service"; import { profileApi } from "./services/profile.service"; +import { cardsApi } from "./services/cards.service"; export const store = configureStore({ reducer: { [attractionsApi.reducerPath]: attractionsApi.reducer, [citiesApi.reducerPath]: citiesApi.reducer, [authApi.reducerPath]: authApi.reducer, - [profileApi.reducerPath]: profileApi.reducer + [profileApi.reducerPath]: profileApi.reducer, + [cardsApi.reducerPath]:cardsApi.reducer }, @@ -18,7 +20,8 @@ export const store = configureStore({ attractionsApi.middleware, citiesApi.middleware, authApi.middleware, - profileApi.middleware + profileApi.middleware, + cardsApi.middleware ), }); export type RootState = ReturnType; diff --git a/src/Redux/services/cards.service.ts b/src/Redux/services/cards.service.ts new file mode 100644 index 0000000..689e9cf --- /dev/null +++ b/src/Redux/services/cards.service.ts @@ -0,0 +1,37 @@ + +import { createApi } from "@reduxjs/toolkit/query/react"; +import { baseQuery } from "../baseQuery"; + +export const cardsApi = createApi({ + reducerPath: "cardsApi", + baseQuery, + + tagTypes: ["cardsInCart"], + + endpoints: (builder) => ({ + + getCardsinCart: builder.query({ + query: (cityId) => { + const params = new URLSearchParams() + params.append('cityXid', cityId); + return `/website/passes/cart/passes?${params.toString()}` + }, + providesTags: ["cardsInCart"] + }), + + getUpcomingCities: builder.query({ + query: (listType) => `/cities/list/all?listType=${listType}`, + + }), + + getCheckoutPageData:builder.query({ + query: (cityId) => `/website/pass/${cityId}`, + + }), + }) +}); + +export const { + useGetCardsinCartQuery, + useGetCheckoutPageDataQuery +} = cardsApi; \ No newline at end of file diff --git a/src/pages/CartPage.tsx b/src/pages/CartPage.tsx index 497f6ec..3f06370 100644 --- a/src/pages/CartPage.tsx +++ b/src/pages/CartPage.tsx @@ -1,137 +1,140 @@ import React, { useState } from 'react'; import { motion, AnimatePresence } from 'motion/react'; import { - Users, Baby, ShoppingBag, Trash2, Check, CreditCard, Mail, - ChevronRight, ChevronDown, Minus, Plus, Calendar, ArrowLeft, MapPin, - Zap, Shield, Clock, Percent, Sparkles + Users, Baby, ShoppingBag, Trash2, Check, CreditCard, Mail, + ChevronRight, ChevronDown, Minus, Plus, Calendar, ArrowLeft, MapPin, + Zap, Shield, Clock, Percent, Sparkles } from 'lucide-react'; -import Navbar from './Navbar'; -import { Footer } from './Footer'; -import { ImageWithFallback } from './figma/ImageWithFallback'; -import { CheckoutStepper } from './CheckoutStepper'; -import imgRectangle26 from "figma:asset/2496f45326066d3adf0d5494c1dc1595575894ff.png"; +import Navbar from '../components/Navbar'; +import { Footer } from '../components/Footer'; +import { ImageWithFallback } from '../components/figma/ImageWithFallback'; +import { useNavigate } from 'react-router-dom'; +import { useGetCardsinCartQuery } from '../Redux/services/cards.service'; +import LoadingSpinner from '../components/LoadingSpinner'; +// import { CheckoutStepper } from './CheckoutStepper'; +// import imgRectangle26 from "figma:asset/2496f45326066d3adf0d5494c1dc1595575894ff.png"; /* ─── Types ─── */ export interface CartItem { - id: string; - city: string; - cardType: 'Flexi' | 'Unlimited'; - days: number; - adults: number; - children: number; - quantity: number; - pricePerUnit: number; - image: string; + id: string; + city: string; + cardType: 'Flexi' | 'Unlimited'; + days: number; + adults: number; + children: number; + quantity: number; + pricePerUnit: number; + image: string; } interface Attraction { - id: string; - name: string; - image: string; - category: string; - included: boolean; + id: string; + name: string; + image: string; + category: string; + included: boolean; } interface CartPageProps { - onBackClick: () => void; - onHomeClick: () => void; - onPassesClick: () => void; - onCheckoutClick?: () => void; - onSecureCheckoutClick?: (item: CartItem) => void; - onSignInClick: () => void; - onSignOutClick?: () => void; - onAttractionsClick?: () => void; - onBlogsClick?: () => void; - onHowItWorksClick?: () => void; - onFAQClick?: () => void; - onPrivacyPolicyClick?: () => void; - onAboutUsClick?: () => void; - onProfileClick?: () => void; - onCityCardsClick?: () => void; - onMagicItineraryClick?: () => void; - onPostCardsClick?: () => void; - onOffersClick?: () => void; - onSuperSavingsClick?: () => void; - onEsimsClick?: () => void; - onHotelDiscountsClick?: () => void; - onContactUsClick?: () => void; - onCartClick?: () => void; - currentPage?: string; - user?: { email: string; name: string } | null; + onBackClick: () => void; + onHomeClick: () => void; + onPassesClick: () => void; + onCheckoutClick?: () => void; + onSecureCheckoutClick?: (item: CartItem) => void; + onSignInClick: () => void; + onSignOutClick?: () => void; + onAttractionsClick?: () => void; + onBlogsClick?: () => void; + onHowItWorksClick?: () => void; + onFAQClick?: () => void; + onPrivacyPolicyClick?: () => void; + onAboutUsClick?: () => void; + onProfileClick?: () => void; + onCityCardsClick?: () => void; + onMagicItineraryClick?: () => void; + onPostCardsClick?: () => void; + onOffersClick?: () => void; + onSuperSavingsClick?: () => void; + onEsimsClick?: () => void; + onHotelDiscountsClick?: () => void; + onContactUsClick?: () => void; + onCartClick?: () => void; + currentPage?: string; + user?: { email: string; name: string } | null; } /* ─── Data ─── */ const initialCartItems: CartItem[] = [ - { - id: '1', city: 'Melbourne', cardType: 'Flexi', days: 3, adults: 3, children: 3, quantity: 2, pricePerUnit: 49.50, - image: 'https://images.unsplash.com/photo-1655963754904-2cf2b562a681?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBmbGluZGVycyUyMHN0YXRpb24lMjBzdW5zZXR8ZW58MXx8fHwxNzc2MzE5NDgzfDA&ixlib=rb-4.1.0&q=80&w=1080', - }, - { - id: '2', city: 'Sydney', cardType: 'Flexi', days: 3, adults: 3, children: 3, quantity: 2, pricePerUnit: 49.50, - image: 'https://images.unsplash.com/photo-1695018228065-2e0026c654af?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxTeWRuZXklMjBvcGVyYSUyMGhvdXNlJTIwaGFyYm91ciUyMGJyaWRnZXxlbnwxfHx8fDE3NzYzMTk0ODN8MA&ixlib=rb-4.1.0&q=80&w=1080', - }, - { - id: '3', city: 'Melbourne', cardType: 'Unlimited', days: 6, adults: 2, children: 1, quantity: 1, pricePerUnit: 79.00, - image: 'https://images.unsplash.com/photo-1705120624704-0970afc29fea?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBzdHJlZXQlMjBhcnQlMjBsYW5ld2F5c3xlbnwxfHx8fDE3NzYzMTk0ODR8MA&ixlib=rb-4.1.0&q=80&w=1080', - }, + { + id: '1', city: 'Melbourne', cardType: 'Flexi', days: 3, adults: 3, children: 3, quantity: 2, pricePerUnit: 49.50, + image: 'https://images.unsplash.com/photo-1655963754904-2cf2b562a681?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBmbGluZGVycyUyMHN0YXRpb24lMjBzdW5zZXR8ZW58MXx8fHwxNzc2MzE5NDgzfDA&ixlib=rb-4.1.0&q=80&w=1080', + }, + { + id: '2', city: 'Sydney', cardType: 'Flexi', days: 3, adults: 3, children: 3, quantity: 2, pricePerUnit: 49.50, + image: 'https://images.unsplash.com/photo-1695018228065-2e0026c654af?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxTeWRuZXklMjBvcGVyYSUyMGhvdXNlJTIwaGFyYm91ciUyMGJyaWRnZXxlbnwxfHx8fDE3NzYzMTk0ODN8MA&ixlib=rb-4.1.0&q=80&w=1080', + }, + { + id: '3', city: 'Melbourne', cardType: 'Unlimited', days: 6, adults: 2, children: 1, quantity: 1, pricePerUnit: 79.00, + image: 'https://images.unsplash.com/photo-1705120624704-0970afc29fea?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBzdHJlZXQlMjBhcnQlMjBsYW5ld2F5c3xlbnwxfHx8fDE3NzYzMTk0ODR8MA&ixlib=rb-4.1.0&q=80&w=1080', + }, ]; const dayOptions = [3, 6, 12, 18, 24]; const attractionsData: Record> = { - Melbourne: { - Flexi: [ - { id: 'mel-1', name: 'SEA LIFE Aquarium', image: 'https://images.unsplash.com/photo-1536845111858-bb269af65cb6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBhcXVhcml1bSUyMHVuZGVyd2F0ZXJ8ZW58MXx8fHwxNzc2MzE5OTcwfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Wildlife', included: true }, - { id: 'mel-2', name: 'Melbourne Zoo', image: 'https://images.unsplash.com/photo-1730074888490-31239540bacf?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjB6b28lMjB3aWxkbGlmZXxlbnwxfHx8fDE3NzYzMTk5NzB8MA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Wildlife', included: true }, - { id: 'mel-3', name: 'Royal Botanic Gardens', image: 'https://images.unsplash.com/photo-1585894507208-eeead8cb9a56?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBib3RhbmljYWwlMjBnYXJkZW4lMjBncmVlbnxlbnwxfHx8fDE3NzYzMTk5NzF8MA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Nature', included: true }, - { id: 'mel-4', name: 'NGV Art Gallery', image: 'https://images.unsplash.com/photo-1752429242469-55ba7ec210d2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxhcnQlMjBnYWxsZXJ5JTIwbXVzZXVtJTIwaW50ZXJpb3J8ZW58MXx8fHwxNzc2MzE5OTczfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Culture', included: true }, - ], - Unlimited: [ - { id: 'mel-1', name: 'SEA LIFE Aquarium', image: 'https://images.unsplash.com/photo-1536845111858-bb269af65cb6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBhcXVhcml1bSUyMHVuZGVyd2F0ZXJ8ZW58MXx8fHwxNzc2MzE5OTcwfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Wildlife', included: true }, - { id: 'mel-2', name: 'Melbourne Zoo', image: 'https://images.unsplash.com/photo-1730074888490-31239540bacf?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjB6b28lMjB3aWxkbGlmZXxlbnwxfHx8fDE3NzYzMTk5NzB8MA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Wildlife', included: true }, - { id: 'mel-3', name: 'Royal Botanic Gardens', image: 'https://images.unsplash.com/photo-1585894507208-eeead8cb9a56?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBib3RhbmljYWwlMjBnYXJkZW4lMjBncmVlbnxlbnwxfHx8fDE3NzYzMTk5NzF8MA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Nature', included: true }, - { id: 'mel-4', name: 'NGV Art Gallery', image: 'https://images.unsplash.com/photo-1752429242469-55ba7ec210d2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxhcnQlMjBnYWxsZXJ5JTIwbXVzZXVtJTIwaW50ZXJpb3J8ZW58MXx8fHwxNzc2MzE5OTczfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Culture', included: true }, - { id: 'mel-5', name: 'Melbourne Star Wheel', image: 'https://images.unsplash.com/photo-1769880659692-fa77e04c5ffa?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxvYnNlcnZhdGlvbiUyMHdoZWVsJTIwYW11c2VtZW50JTIwbmlnaHR8ZW58MXx8fHwxNzc2MzE5OTc2fDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Experience', included: true }, - { id: 'mel-6', name: 'Penguin Parade', image: 'https://images.unsplash.com/photo-1670391050251-d1cfbc3891c4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxwZW5ndWlucyUyMHdpbGRsaWZlJTIwbmF0dXJlfGVufDF8fHx8MTc3NjMxOTk3Nnww&ixlib=rb-4.1.0&q=80&w=1080', category: 'Wildlife', included: true }, - { id: 'mel-7', name: 'Yarra River Cruise', image: 'https://images.unsplash.com/photo-1562003914-018a4a6c2171?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxyaXZlciUyMGNydWlzZSUyMGJvYXQlMjBjaXR5fGVufDF8fHx8MTc3NjMxOTk3M3ww&ixlib=rb-4.1.0&q=80&w=1080', category: 'Experience', included: true }, - ], - }, - Sydney: { - Flexi: [ - { id: 'syd-1', name: 'Harbour Bridge Climb', image: 'https://images.unsplash.com/photo-1767974062666-2685a670e353?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxTeWRuZXklMjBoYXJib3VyJTIwYnJpZGdlJTIwY2xpbWJ8ZW58MXx8fHwxNzc2MzE5OTcxfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Adventure', included: true }, - { id: 'syd-2', name: 'Taronga Zoo', image: 'https://images.unsplash.com/photo-1704852168456-b70e08441917?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxTeWRuZXklMjB0YXJvbmdhJTIwem9vJTIwYW5pbWFsc3xlbnwxfHx8fDE3NzYzMTk5NzJ8MA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Wildlife', included: true }, - { id: 'syd-3', name: 'Art Gallery NSW', image: 'https://images.unsplash.com/photo-1752429242469-55ba7ec210d2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxhcnQlMjBnYWxsZXJ5JTIwbXVzZXVtJTIwaW50ZXJpb3J8ZW58MXx8fHwxNzc2MzE5OTczfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Culture', included: true }, - ], - Unlimited: [ - { id: 'syd-1', name: 'Harbour Bridge Climb', image: 'https://images.unsplash.com/photo-1767974062666-2685a670e353?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxTeWRuZXklMjBoYXJib3VyJTIwYnJpZGdlJTIwY2xpbWJ8ZW58MXx8fHwxNzc2MzE5OTcxfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Adventure', included: true }, - { id: 'syd-2', name: 'Taronga Zoo', image: 'https://images.unsplash.com/photo-1704852168456-b70e08441917?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxTeWRuZXklMjB0YXJvbmdhJTIwem9vJTIwYW5pbWFsc3xlbnwxfHx8fDE3NzYzMTk5NzJ8MA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Wildlife', included: true }, - { id: 'syd-3', name: 'Art Gallery NSW', image: 'https://images.unsplash.com/photo-1752429242469-55ba7ec210d2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxhcnQlMjBnYWxsZXJ5JTIwbXVzZXVtJTIwaW50ZXJpb3J8ZW58MXx8fHwxNzc2MzE5OTczfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Culture', included: true }, - { id: 'syd-4', name: 'Sydney Harbour Cruise', image: 'https://images.unsplash.com/photo-1562003914-018a4a6c2171?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxyaXZlciUyMGNydWlzZSUyMGJvYXQlMjBjaXR5fGVufDF8fHx8MTc3NjMxOTk3M3ww&ixlib=rb-4.1.0&q=80&w=1080', category: 'Experience', included: true }, - { id: 'syd-5', name: 'SEA LIFE Aquarium', image: 'https://images.unsplash.com/photo-1536845111858-bb269af65cb6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBhcXVhcml1bSUyMHVuZGVyd2F0ZXJ8ZW58MXx8fHwxNzc2MzE5OTcwfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Wildlife', included: true }, - ], - }, + Melbourne: { + Flexi: [ + { id: 'mel-1', name: 'SEA LIFE Aquarium', image: 'https://images.unsplash.com/photo-1536845111858-bb269af65cb6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBhcXVhcml1bSUyMHVuZGVyd2F0ZXJ8ZW58MXx8fHwxNzc2MzE5OTcwfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Wildlife', included: true }, + { id: 'mel-2', name: 'Melbourne Zoo', image: 'https://images.unsplash.com/photo-1730074888490-31239540bacf?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjB6b28lMjB3aWxkbGlmZXxlbnwxfHx8fDE3NzYzMTk5NzB8MA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Wildlife', included: true }, + { id: 'mel-3', name: 'Royal Botanic Gardens', image: 'https://images.unsplash.com/photo-1585894507208-eeead8cb9a56?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBib3RhbmljYWwlMjBnYXJkZW4lMjBncmVlbnxlbnwxfHx8fDE3NzYzMTk5NzF8MA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Nature', included: true }, + { id: 'mel-4', name: 'NGV Art Gallery', image: 'https://images.unsplash.com/photo-1752429242469-55ba7ec210d2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxhcnQlMjBnYWxsZXJ5JTIwbXVzZXVtJTIwaW50ZXJpb3J8ZW58MXx8fHwxNzc2MzE5OTczfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Culture', included: true }, + ], + Unlimited: [ + { id: 'mel-1', name: 'SEA LIFE Aquarium', image: 'https://images.unsplash.com/photo-1536845111858-bb269af65cb6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBhcXVhcml1bSUyMHVuZGVyd2F0ZXJ8ZW58MXx8fHwxNzc2MzE5OTcwfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Wildlife', included: true }, + { id: 'mel-2', name: 'Melbourne Zoo', image: 'https://images.unsplash.com/photo-1730074888490-31239540bacf?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjB6b28lMjB3aWxkbGlmZXxlbnwxfHx8fDE3NzYzMTk5NzB8MA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Wildlife', included: true }, + { id: 'mel-3', name: 'Royal Botanic Gardens', image: 'https://images.unsplash.com/photo-1585894507208-eeead8cb9a56?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBib3RhbmljYWwlMjBnYXJkZW4lMjBncmVlbnxlbnwxfHx8fDE3NzYzMTk5NzF8MA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Nature', included: true }, + { id: 'mel-4', name: 'NGV Art Gallery', image: 'https://images.unsplash.com/photo-1752429242469-55ba7ec210d2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxhcnQlMjBnYWxsZXJ5JTIwbXVzZXVtJTIwaW50ZXJpb3J8ZW58MXx8fHwxNzc2MzE5OTczfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Culture', included: true }, + { id: 'mel-5', name: 'Melbourne Star Wheel', image: 'https://images.unsplash.com/photo-1769880659692-fa77e04c5ffa?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxvYnNlcnZhdGlvbiUyMHdoZWVsJTIwYW11c2VtZW50JTIwbmlnaHR8ZW58MXx8fHwxNzc2MzE5OTc2fDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Experience', included: true }, + { id: 'mel-6', name: 'Penguin Parade', image: 'https://images.unsplash.com/photo-1670391050251-d1cfbc3891c4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxwZW5ndWlucyUyMHdpbGRsaWZlJTIwbmF0dXJlfGVufDF8fHx8MTc3NjMxOTk3Nnww&ixlib=rb-4.1.0&q=80&w=1080', category: 'Wildlife', included: true }, + { id: 'mel-7', name: 'Yarra River Cruise', image: 'https://images.unsplash.com/photo-1562003914-018a4a6c2171?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxyaXZlciUyMGNydWlzZSUyMGJvYXQlMjBjaXR5fGVufDF8fHx8MTc3NjMxOTk3M3ww&ixlib=rb-4.1.0&q=80&w=1080', category: 'Experience', included: true }, + ], + }, + Sydney: { + Flexi: [ + { id: 'syd-1', name: 'Harbour Bridge Climb', image: 'https://images.unsplash.com/photo-1767974062666-2685a670e353?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxTeWRuZXklMjBoYXJib3VyJTIwYnJpZGdlJTIwY2xpbWJ8ZW58MXx8fHwxNzc2MzE5OTcxfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Adventure', included: true }, + { id: 'syd-2', name: 'Taronga Zoo', image: 'https://images.unsplash.com/photo-1704852168456-b70e08441917?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxTeWRuZXklMjB0YXJvbmdhJTIwem9vJTIwYW5pbWFsc3xlbnwxfHx8fDE3NzYzMTk5NzJ8MA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Wildlife', included: true }, + { id: 'syd-3', name: 'Art Gallery NSW', image: 'https://images.unsplash.com/photo-1752429242469-55ba7ec210d2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxhcnQlMjBnYWxsZXJ5JTIwbXVzZXVtJTIwaW50ZXJpb3J8ZW58MXx8fHwxNzc2MzE5OTczfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Culture', included: true }, + ], + Unlimited: [ + { id: 'syd-1', name: 'Harbour Bridge Climb', image: 'https://images.unsplash.com/photo-1767974062666-2685a670e353?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxTeWRuZXklMjBoYXJib3VyJTIwYnJpZGdlJTIwY2xpbWJ8ZW58MXx8fHwxNzc2MzE5OTcxfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Adventure', included: true }, + { id: 'syd-2', name: 'Taronga Zoo', image: 'https://images.unsplash.com/photo-1704852168456-b70e08441917?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxTeWRuZXklMjB0YXJvbmdhJTIwem9vJTIwYW5pbWFsc3xlbnwxfHx8fDE3NzYzMTk5NzJ8MA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Wildlife', included: true }, + { id: 'syd-3', name: 'Art Gallery NSW', image: 'https://images.unsplash.com/photo-1752429242469-55ba7ec210d2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxhcnQlMjBnYWxsZXJ5JTIwbXVzZXVtJTIwaW50ZXJpb3J8ZW58MXx8fHwxNzc2MzE5OTczfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Culture', included: true }, + { id: 'syd-4', name: 'Sydney Harbour Cruise', image: 'https://images.unsplash.com/photo-1562003914-018a4a6c2171?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxyaXZlciUyMGNydWlzZSUyMGJvYXQlMjBjaXR5fGVufDF8fHx8MTc3NjMxOTk3M3ww&ixlib=rb-4.1.0&q=80&w=1080', category: 'Experience', included: true }, + { id: 'syd-5', name: 'SEA LIFE Aquarium', image: 'https://images.unsplash.com/photo-1536845111858-bb269af65cb6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxNZWxib3VybmUlMjBhcXVhcml1bSUyMHVuZGVyd2F0ZXJ8ZW58MXx8fHwxNzc2MzE5OTcwfDA&ixlib=rb-4.1.0&q=80&w=1080', category: 'Wildlife', included: true }, + ], + }, }; const offersData: Record = { - Flexi: [ - { title: 'Astor Hotels Ultra Deluxe', description: '15% Discount on all treatments for first-time clients', image: 'https://images.unsplash.com/photo-1715191904112-4a5d9c3089fa?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxsdXh1cnklMjBob3RlbCUyMHJlc29ydCUyMGV4dGVyaW9yfGVufDF8fHx8MTc3NjMyMTM2MXww&ixlib=rb-4.1.0&q=80&w=1080' }, - { title: 'Green Valley Spa Lux', description: '20% Off on membership plans for new members', image: 'https://images.unsplash.com/photo-1759216853079-831ef8c8b327?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxzcGElMjB3ZWxsbmVzcyUyMHRyZWF0bWVudCUyMGludGVyaW9yfGVufDF8fHx8MTc3NjMyMTM2M3ww&ixlib=rb-4.1.0&q=80&w=1080' }, - { title: 'Harbour Dining Co.', description: '10% Off your first dining experience at waterfront', image: 'https://images.unsplash.com/photo-1676471932681-45fa972d848a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxyZXN0YXVyYW50JTIwZmluZSUyMGRpbmluZ3xlbnwxfHx8fDE3NzYzMTkxNDl8MA&ixlib=rb-4.1.0&q=80&w=1080' }, - { title: 'National Gallery Exhibition', description: 'Free audio guide with every gallery visit', image: 'https://images.unsplash.com/photo-1569342380852-035f42d9ca41?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxtdXNldW0lMjBnYWxsZXJ5JTIwZXhoaWJpdGlvbnxlbnwxfHx8fDE3NzYyNDYwMjh8MA&ixlib=rb-4.1.0&q=80&w=1080' }, - { title: 'Sunset Harbour Cruise', description: 'Complimentary drink on every sunset cruise booking', image: 'https://images.unsplash.com/photo-1765783800962-83d99ff7b158?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxjcnVpc2UlMjBib2F0JTIwaGFyYm9yJTIwdG91cnxlbnwxfHx8fDE3NzYzMjE2MDd8MA&ixlib=rb-4.1.0&q=80&w=1080' }, - ], - Unlimited: [ - { title: 'SkyView Ferris Wheel', description: 'Complimentary second ride for all pass holders', image: 'https://images.unsplash.com/photo-1626209025747-b41ee6ec191f?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxmZXJyaXMlMjB3aGVlbCUyMGFtdXNlbWVudCUyMHBhcmt8ZW58MXx8fHwxNzc2MzE3NDI2fDA&ixlib=rb-4.1.0&q=80&w=1080' }, - { title: 'City Mall Boutique', description: '15% Off at select boutique stores with your pass', image: 'https://images.unsplash.com/photo-1567966689299-819568579d36?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxzaG9wcGluZyUyMG1hbGwlMjBib3V0aXF1ZSUyMHJldGFpbHxlbnwxfHx8fDE3NzYzMjEzNjN8MA&ixlib=rb-4.1.0&q=80&w=1080' }, - { title: 'Adventure Outfitters', description: 'Free gear rental on outdoor adventure bookings', image: 'https://images.unsplash.com/photo-1761131221577-0716baffc6ef?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxhZHZlbnR1cmUlMjBzcG9ydHMlMjBvdXRkb29yJTIwYWN0aXZpdHl8ZW58MXx8fHwxNzc2MzIxMzYzfDA&ixlib=rb-4.1.0&q=80&w=1080' }, - { title: 'Skyline Rooftop Lounge', description: 'Buy one get one free on signature cocktails', image: 'https://images.unsplash.com/photo-1642114955097-8f3d0e141641?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxyb29mdG9wJTIwYmFyJTIwY2l0eSUyMHNreWxpbmUlMjBuaWdodHxlbnwxfHx8fDE3NzYyNDU2NTl8MA&ixlib=rb-4.1.0&q=80&w=1080' }, - { title: 'Yarra Valley Wines', description: 'Exclusive wine tasting tour with pass holders discount', image: 'https://images.unsplash.com/photo-1764649841527-c8852b63cc53?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHx3aW5lJTIwdGFzdGluZyUyMHZpbmV5YXJkJTIwY2VsbGFyfGVufDF8fHx8MTc3NjMyMTYwOHww&ixlib=rb-4.1.0&q=80&w=1080' }, - ], + Flexi: [ + { title: 'Astor Hotels Ultra Deluxe', description: '15% Discount on all treatments for first-time clients', image: 'https://images.unsplash.com/photo-1715191904112-4a5d9c3089fa?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxsdXh1cnklMjBob3RlbCUyMHJlc29ydCUyMGV4dGVyaW9yfGVufDF8fHx8MTc3NjMyMTM2MXww&ixlib=rb-4.1.0&q=80&w=1080' }, + { title: 'Green Valley Spa Lux', description: '20% Off on membership plans for new members', image: 'https://images.unsplash.com/photo-1759216853079-831ef8c8b327?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxzcGElMjB3ZWxsbmVzcyUyMHRyZWF0bWVudCUyMGludGVyaW9yfGVufDF8fHx8MTc3NjMyMTM2M3ww&ixlib=rb-4.1.0&q=80&w=1080' }, + { title: 'Harbour Dining Co.', description: '10% Off your first dining experience at waterfront', image: 'https://images.unsplash.com/photo-1676471932681-45fa972d848a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxyZXN0YXVyYW50JTIwZmluZSUyMGRpbmluZ3xlbnwxfHx8fDE3NzYzMTkxNDl8MA&ixlib=rb-4.1.0&q=80&w=1080' }, + { title: 'National Gallery Exhibition', description: 'Free audio guide with every gallery visit', image: 'https://images.unsplash.com/photo-1569342380852-035f42d9ca41?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxtdXNldW0lMjBnYWxsZXJ5JTIwZXhoaWJpdGlvbnxlbnwxfHx8fDE3NzYyNDYwMjh8MA&ixlib=rb-4.1.0&q=80&w=1080' }, + { title: 'Sunset Harbour Cruise', description: 'Complimentary drink on every sunset cruise booking', image: 'https://images.unsplash.com/photo-1765783800962-83d99ff7b158?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxjcnVpc2UlMjBib2F0JTIwaGFyYm9yJTIwdG91cnxlbnwxfHx8fDE3NzYzMjE2MDd8MA&ixlib=rb-4.1.0&q=80&w=1080' }, + ], + Unlimited: [ + { title: 'SkyView Ferris Wheel', description: 'Complimentary second ride for all pass holders', image: 'https://images.unsplash.com/photo-1626209025747-b41ee6ec191f?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxmZXJyaXMlMjB3aGVlbCUyMGFtdXNlbWVudCUyMHBhcmt8ZW58MXx8fHwxNzc2MzE3NDI2fDA&ixlib=rb-4.1.0&q=80&w=1080' }, + { title: 'City Mall Boutique', description: '15% Off at select boutique stores with your pass', image: 'https://images.unsplash.com/photo-1567966689299-819568579d36?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxzaG9wcGluZyUyMG1hbGwlMjBib3V0aXF1ZSUyMHJldGFpbHxlbnwxfHx8fDE3NzYzMjEzNjN8MA&ixlib=rb-4.1.0&q=80&w=1080' }, + { title: 'Adventure Outfitters', description: 'Free gear rental on outdoor adventure bookings', image: 'https://images.unsplash.com/photo-1761131221577-0716baffc6ef?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxhZHZlbnR1cmUlMjBzcG9ydHMlMjBvdXRkb29yJTIwYWN0aXZpdHl8ZW58MXx8fHwxNzc2MzIxMzYzfDA&ixlib=rb-4.1.0&q=80&w=1080' }, + { title: 'Skyline Rooftop Lounge', description: 'Buy one get one free on signature cocktails', image: 'https://images.unsplash.com/photo-1642114955097-8f3d0e141641?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxyb29mdG9wJTIwYmFyJTIwY2l0eSUyMHNreWxpbmUlMjBuaWdodHxlbnwxfHx8fDE3NzYyNDU2NTl8MA&ixlib=rb-4.1.0&q=80&w=1080' }, + { title: 'Yarra Valley Wines', description: 'Exclusive wine tasting tour with pass holders discount', image: 'https://images.unsplash.com/photo-1764649841527-c8852b63cc53?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHx3aW5lJTIwdGFzdGluZyUyMHZpbmV5YXJkJTIwY2VsbGFyfGVufDF8fHx8MTc3NjMyMTYwOHww&ixlib=rb-4.1.0&q=80&w=1080' }, + ], }; const priceTable: Record> = { - Flexi: { 3: 49.5, 6: 69, 12: 99, 18: 129, 24: 159 }, - Unlimited: { 3: 79, 6: 109, 12: 149, 18: 189, 24: 229 }, + Flexi: { 3: 49.5, 6: 69, 12: 99, 18: 129, 24: 159 }, + Unlimited: { 3: 79, 6: 109, 12: 149, 18: 189, 24: 229 }, }; /* ═══════════════════════════════════════════ @@ -139,101 +142,99 @@ const priceTable: Record> = { ═══════════════════════════════════════════ */ function FlexiCardPreview({ city, adultPrice, childPrice, isSelected }: { city: string; adultPrice: number; childPrice: number; isSelected: boolean }) { - return ( -
- {/* Card bg */} -
- {/* City image */} -
- -
- {/* City name - left aligned */} -
-

{city}

-
- {/* Pricing */} -
-
- From - ${adultPrice} - /Adult + return ( +
+ {/* Card bg */} +
+ {/* City image */} +
+ {/* */} +
+ {/* City name - left aligned */} +
+

{city}

+
+ {/* Pricing */} +
+
+ From + ${adultPrice} + /Adult +
+
+ and + ${childPrice} + /Child +
+
+ {/* Description */} +
+

+ Dive into an extensive selection of thrilling destinations! +

+
+ {/* Side tab - Flexi (pink) */} +
+ Card + Flexi +
+ {/* Selected checkmark */} + {isSelected && ( +
+ +
+ )}
-
- and - ${childPrice} - /Child -
-
- {/* Description */} -
-

- Dive into an extensive selection of thrilling destinations! -

-
- {/* Side tab - Flexi (pink) */} -
- Card - Flexi -
- {/* Selected checkmark */} - {isSelected && ( -
- -
- )} -
- ); + ); } function UnlimitedCardPreview({ city, adultPrice, childPrice, isSelected }: { city: string; adultPrice: number; childPrice: number; isSelected: boolean }) { - return ( -
- {/* Card bg */} -
- {/* City image */} -
- -
- {/* City name - left aligned */} -
-

{city}

-
- {/* Pricing */} -
-
- From - ${adultPrice} - /Adult + return ( +
+ {/* Card bg */} +
+ {/* City image */} +
+ {/* */} +
+ {/* City name - left aligned */} +
+

{city}

+
+ {/* Pricing */} +
+
+ From + ${adultPrice} + /Adult +
+
+ and + ${childPrice} + /Child +
+
+ {/* Description */} +
+

+ Dive into an extensive selection of thrilling destinations! +

+
+ {/* Side tab - Unlimited (coral) */} +
+ Card + Unlimited +
+ {/* Selected checkmark */} + {isSelected && ( +
+ +
+ )}
-
- and - ${childPrice} - /Child -
-
- {/* Description */} -
-

- Dive into an extensive selection of thrilling destinations! -

-
- {/* Side tab - Unlimited (coral) */} -
- Card - Unlimited -
- {/* Selected checkmark */} - {isSelected && ( -
- -
- )} -
- ); + ); } /* ═══════════════════════════════════════════ @@ -241,150 +242,148 @@ function UnlimitedCardPreview({ city, adultPrice, childPrice, isSelected }: { ci ═══════════════════════════════════════════ */ function CheckoutConfigCard({ - item, - onChange, - onProceed, + item, + onChange, + onProceed, }: { - item: CartItem; - onChange: (updates: Partial) => void; - onProceed: () => void; + item: CartItem; + onChange: (updates: Partial) => void; + onProceed: () => void; }) { - const [daysOpen, setDaysOpen] = useState(false); - const originalPrice = (item.pricePerUnit * item.quantity * 1.35); - const totalPrice = item.pricePerUnit * item.quantity; + const [daysOpen, setDaysOpen] = useState(false); + const originalPrice = (item.pricePerUnit * item.quantity * 1.35); + const totalPrice = item.pricePerUnit * item.quantity; - return ( -
- {/* City header */} -
-

{item.city}

-
- - {item.cardType} Card - -
-
+ const navigate = useNavigate() - {/* Configuration rows */} -
- {/* No. of Adults */} -
- No. of Adults -
- - {item.adults} - -
-
+ return ( +
+ {/* City header */} +
+

{item.city}

+
+ + {item.cardType} Card + +
+
- {/* No. of Children */} -
- No. of Children -
- - {item.children} - -
-
+ {/* Configuration rows */} +
+ {/* No. of Adults */} +
+ No. of Adults +
+ + {item.adults} + +
+
- {/* No. of Days (dropdown) */} -
- - {item.cardType === 'Flexi' ? 'No. of Attractions' : 'No. of Days'} - -
- - - {daysOpen && ( - + No. of Children +
+ + {item.children} + +
+
+ + {/* No. of Days (dropdown) */} +
+ + {item.cardType === 'Flexi' ? 'No. of Attractions' : 'No. of Days'} + +
+ + + {daysOpen && ( + + {dayOptions.map((d) => ( + + ))} + + )} + +
+
+ + {/* You Pay */} +
+ You Pay +
+ + ${originalPrice.toFixed(0)} + + + ${totalPrice.toFixed(0)} + +
+
+
+ + {/* Proceed button */} +
+ navigate("/payment")} + className="w-full py-4 rounded-full bg-[#f95f62] text-white font-poppins text-base font-medium hover:bg-[#e8545a] transition-colors shadow-lg shadow-[#f95f62]/20" > - {dayOptions.map((d) => ( - - ))} - - )} - -
+ Proceed to Pay + +
- - {/* You Pay */} -
- You Pay -
- - ${originalPrice.toFixed(0)} - - - ${totalPrice.toFixed(0)} - -
-
-
- - {/* Proceed button */} -
- - Proceed to Pay - -
-
- ); + ); } /* ═══════════════════════════════════════════ @@ -392,486 +391,499 @@ function CheckoutConfigCard({ ═══════════════════════════════════════════ */ export function CartPage({ - onBackClick, - onHomeClick, - onPassesClick, - onCheckoutClick, - onSecureCheckoutClick, - onSignInClick, - onSignOutClick, - onAttractionsClick, - onBlogsClick, - onHowItWorksClick, - onFAQClick, - onPrivacyPolicyClick, - onAboutUsClick, - onProfileClick, - onCityCardsClick, - onMagicItineraryClick, - onPostCardsClick, - onOffersClick, - onSuperSavingsClick, - onEsimsClick, - onHotelDiscountsClick, - onContactUsClick, - onCartClick, - currentPage, - user, + onBackClick, + onHomeClick, + onPassesClick, + onCheckoutClick, + onSecureCheckoutClick, + onSignInClick, + onSignOutClick, + onAttractionsClick, + onBlogsClick, + onHowItWorksClick, + onFAQClick, + onPrivacyPolicyClick, + onAboutUsClick, + onProfileClick, + onCityCardsClick, + onMagicItineraryClick, + onPostCardsClick, + onOffersClick, + onSuperSavingsClick, + onEsimsClick, + onHotelDiscountsClick, + onContactUsClick, + onCartClick, + currentPage, + user, }: CartPageProps) { - const [activeTab, setActiveTab] = useState<'cards' | 'postcards'>('cards'); - const [cartItems, setCartItems] = useState(initialCartItems); - const [selectedCardId, setSelectedCardId] = useState(null); - const [view, setView] = useState<'cart' | 'checkout'>('cart'); - const [checkoutItem, setCheckoutItem] = useState(null); + const [activeTab, setActiveTab] = useState<'cards' | 'postcards'>('cards'); + const [cartItems, setCartItems] = useState(initialCartItems); + const [selectedCardId, setSelectedCardId] = useState(null); + const [view, setView] = useState<'cart' | 'checkout'>('cart'); + const [checkoutItem, setCheckoutItem] = useState(null); - const handleRemoveItem = (id: string) => { - setCartItems(prev => prev.filter(item => item.id !== id)); - if (selectedCardId === id) setSelectedCardId(null); - }; + const navigate = useNavigate() - const handleSelectCard = (id: string) => { - setSelectedCardId(prev => (prev === id ? null : id)); - }; + const cityId = localStorage.getItem("cityId") - const handleGoToCheckout = () => { - const item = cartItems.find(i => i.id === selectedCardId); - if (item) { - setCheckoutItem({ ...item }); - setView('checkout'); - window.scrollTo({ top: 0, behavior: 'smooth' }); + const { data, isLoading } = useGetCardsinCartQuery(cityId) + + const CartItems = data?.cartItems ?? [] + + if (isLoading) { + return ( + + ) } - }; - const handleBackToCart = () => { - setView('cart'); - setCheckoutItem(null); - }; + const handleRemoveItem = (id: string) => { + setCartItems(prev => prev.filter(item => item.id !== id)); + if (selectedCardId === id) setSelectedCardId(null); + }; - const handleCheckoutItemChange = (updates: Partial) => { - if (!checkoutItem) return; - const updated = { ...checkoutItem, ...updates }; - const prices = priceTable[updated.cardType]; - if (prices && prices[updated.days] !== undefined) { - updated.pricePerUnit = prices[updated.days]; - } - setCheckoutItem(updated); - }; + const handleSelectCard = (id: string) => { + setSelectedCardId(prev => (prev === id ? null : id)); + }; - const isEmpty = cartItems.length === 0; - const selectedItem = cartItems.find(i => i.id === selectedCardId); - const attractions = checkoutItem ? (attractionsData[checkoutItem.city]?.[checkoutItem.cardType] || []) : []; - const offers = checkoutItem ? (offersData[checkoutItem.cardType] || []) : []; + const handleGoToCheckout = () => { + // const item = cartItems.find(i => i.id === selectedCardId); + // if (item) { + // setCheckoutItem({ ...item }); + // setView('checkout'); + // window.scrollTo({ top: 0, behavior: 'smooth' }); + // } + navigate("/payment") + }; - return ( -
- {}} onSignInClick={onSignInClick} onSignOutClick={onSignOutClick} - onPassesClick={onPassesClick} onCheckoutClick={onCheckoutClick} onHomeClick={onHomeClick} - onAttractionsClick={onAttractionsClick} onBlogsClick={onBlogsClick} onHowItWorksClick={onHowItWorksClick} - onFAQClick={onFAQClick} onPrivacyPolicyClick={onPrivacyPolicyClick} onAboutUsClick={onAboutUsClick} - onProfileClick={onProfileClick} onCityCardsClick={onCityCardsClick} onMagicItineraryClick={onMagicItineraryClick} - onPostCardsClick={onPostCardsClick} onOffersClick={onOffersClick} onSuperSavingsClick={onSuperSavingsClick} - onEsimsClick={onEsimsClick} onHotelDiscountsClick={onHotelDiscountsClick} onCartClick={onCartClick} - currentPage={currentPage as any} user={user} - /> + const handleBackToCart = () => { + setView('cart'); + setCheckoutItem(null); + }; - - {view === 'cart' ? ( - /* ─── CART VIEW ─── */ - - {/* Header */} -
-

- Your{' '} - Cart -

-

- {isEmpty ? 'Your cart is empty' : `${cartItems.length} ${cartItems.length === 1 ? 'item' : 'items'} in your cart`} -

-
+ const handleCheckoutItemChange = (updates: Partial) => { + if (!checkoutItem) return; + const updated = { ...checkoutItem, ...updates }; + const prices = priceTable[updated.cardType]; + if (prices && prices[updated.days] !== undefined) { + updated.pricePerUnit = prices[updated.days]; + } + setCheckoutItem(updated); + }; - {/* Tab switcher */} - {/* Cards listed directly below */} + const isEmpty = cartItems.length === 0; + const selectedItem = CartItems.find((i: any) => i.id === selectedCardId); + const attractions = checkoutItem ? (attractionsData[checkoutItem.city]?.[checkoutItem.cardType] || []) : []; + const offers = checkoutItem ? (offersData[checkoutItem.cardType] || []) : []; + + return ( +
+ { }} onSignInClick={onSignInClick} onSignOutClick={onSignOutClick} + onPassesClick={onPassesClick} onCheckoutClick={onCheckoutClick} onHomeClick={onHomeClick} + onAttractionsClick={onAttractionsClick} onBlogsClick={onBlogsClick} onHowItWorksClick={onHowItWorksClick} + onFAQClick={onFAQClick} onPrivacyPolicyClick={onPrivacyPolicyClick} onAboutUsClick={onAboutUsClick} + onProfileClick={onProfileClick} onCityCardsClick={onCityCardsClick} onMagicItineraryClick={onMagicItineraryClick} + onPostCardsClick={onPostCardsClick} onOffersClick={onOffersClick} onSuperSavingsClick={onSuperSavingsClick} + onEsimsClick={onEsimsClick} onHotelDiscountsClick={onHotelDiscountsClick} onCartClick={onCartClick} + currentPage={currentPage as any} user={user} + /> - {/* Content */} - {activeTab === 'cards' ? ( - - {isEmpty ? ( - } title="No cards in your cart" description="Browse our city passes to unlock amazing experiences and savings on your next adventure" actionLabel="Explore Passes" onAction={onPassesClick} /> - ) : ( -
- {/* Table header (desktop) */} -
-
City Cards
-
Travellers
-
Qty
-
Price
-
-
+ {view === 'cart' ? ( + /* ─── CART VIEW ─── */ + + {/* Header */} +
+

+ Your{' '} + Cart +

+

+ {isEmpty ? 'Your cart is empty' : `${CartItems.length} ${CartItems.length === 1 ? 'item' : 'items'} in your cart`} +

+
- - {cartItems.map((item) => { - const isSelected = selectedCardId === item.id; - const totalPrice = item.pricePerUnit * item.quantity; + {/* Tab switcher */} + {/* Cards listed directly below */} - return ( - handleSelectCard(item.id)} - className={`relative bg-white rounded-2xl overflow-hidden cursor-pointer transition-all duration-300 ${ - isSelected ? 'ring-2 ring-[#F95F62] shadow-lg shadow-[#F95F62]/8' : 'ring-1 ring-gray-100 hover:ring-gray-200 hover:shadow-md' - }`} - > - {/* Selected badge */} - - {isSelected && ( - - - - )} - + {/* Content */} + + {activeTab === 'cards' ? ( + + {isEmpty ? ( + } title="No cards in your cart" description="Browse our city passes to unlock amazing experiences and savings on your next adventure" actionLabel="Explore Passes" onAction={onPassesClick} /> + ) : ( +
+ {/* Table header (desktop) */} +
+
City Cards
+
Travellers
+ {/*
Qty
*/} +
Price
+
+
- {/* Mobile layout */} -
-
- -
-
-
-
-
{item.city}
-
- {item.cardType} - {item.days}d -
-
- -
-
- {item.adults}A · {item.children}C · Qty {item.quantity} -
- ${totalPrice.toFixed(2)} - {item.quantity > 1 && ${item.pricePerUnit.toFixed(2)}/ea} -
-
-
-
+ + {CartItems.map((item: any) => { + const isSelected = selectedCardId === item.id; + const totalPrice = item.pricePerUnit * item.quantity; - {/* Desktop layout */} -
-
-
- -
-
-
{item.city}
-
- {item.cardType} Card - {item.days} days -
-
-
-
-
- {item.adults} - {item.children} -
-
-
- {item.quantity} -
-
- ${totalPrice.toFixed(2)} - {item.quantity > 1 && ${item.pricePerUnit.toFixed(2)} per unit} -
-
- -
-
- - ); - })} -
+ return ( + handleSelectCard(item.id)} + className={`relative bg-white rounded-2xl overflow-hidden cursor-pointer transition-all duration-300 ${isSelected ? 'ring-2 ring-[#F95F62] shadow-lg shadow-[#F95F62]/8' : 'ring-1 ring-gray-100 hover:ring-gray-200 hover:shadow-md' + }`} + > + {/* Selected badge */} + + {isSelected && ( + + + + )} + - {/* Bottom checkout bar */} - -
- {selectedItem ? ( + {/* Mobile layout */} +
+
+ +
+
+
+
+
{item.city?.cityName}
+
+ {item.displayCardMode} + {item.cardMode === 'flexi' ? `${item.noOfAttractions} ${item.noOfAttractions === 1 ? 'attraction' : 'attractions'}` : `${item.noOfDays} ${item.noOfDays === 1 ? 'day' : 'days'}`} +
+
+ {/* */} +
+
+ {item.totalAdult}A · {item.totalChild}C +
+ ${item.totalAmount} + {/* {item.quantity > 1 && ${item.pricePerUnit.toFixed(2)}/ea} */} +
+
+
+
+ + {/* Desktop layout */} +
+
+
+ +
+
+
{item.city?.cityName}
+
+ {item.displayCardMode} + {item.cardMode === 'flexi' ? `${item.noOfAttractions} ${item.noOfAttractions === 1 ? 'attraction' : 'attractions'}` : `${item.noOfDays} ${item.noOfDays === 1 ? 'day' : 'days'}`} +
+
+
+
+
+ {item.totalAdult} + {item.totalChild} +
+
+ {/*
+ {item.quantity} +
*/} +
+ ${item.totalAmount} + {/* {item.quantity > 1 && ${item.pricePerUnit.toFixed(2)} per unit} */} +
+ {/*
+ +
*/} +
+ + ); + })} + + + {/* Bottom checkout bar */} + +
+ {selectedItem ? ( + <> +

+ Selected: {selectedItem.city.cityName} {selectedItem.displayCardMode} · {selectedItem.cardMode === 'flexi' ? `${selectedItem.noOfAttractions} ${selectedItem.noOfAttractions === 1 ? 'attraction' : 'attractions'}` : `${selectedItem.noOfDays} ${selectedItem.noOfDays === 1 ? 'day' : 'days'}`} +

+

+ ${selectedItem.totalAmount} +

+ + ) : ( +

Tap a card above to select it for checkout

+ )} +
+ + Secure Checkout + +
+
+ )} +
+ ) : ( + + } title="No post cards yet" description="Send beautiful digital post cards to friends and family from your favourite destinations around the world" actionLabel="Browse Post Cards" onAction={onPostCardsClick} /> + + )} + +
+ ) : ( + /* ─── CHECKOUT VIEW ─── */ + + {checkoutItem && ( <> -

- Selected: {selectedItem.city} {selectedItem.cardType} · {selectedItem.days}d · Qty {selectedItem.quantity} -

-

- ${(selectedItem.pricePerUnit * selectedItem.quantity).toFixed(2)} -

+ {/* Back */} + + + {/* Stepper */} + {/* */} + + {/* Checkout heading */} +
+

+ Checkout{' '} + {checkoutItem.city} +

+ +
+ +
+ {/* Left column */} +
+ + {/* ── Card Type Selection (Figma cards) ── */} +
+

+ Choose Your Card +

+

+ Select the card type that best suits your travel style +

+
+ {/* Flexi */} + + + {/* Unlimited */} + +
+ + {/* ── Config Card (mobile only) — right after card selection ── */} +
+ checkoutItem && onSecureCheckoutClick?.(checkoutItem)} + /> +
+ + {/* Features Comparison */} +
+
+ {/* Header */} +

Features

+

Flexi

+

Unlimited

+ {[ + { feature: 'Access to attractions', flexi: true, unlimited: true }, + { feature: 'Entry to attractions', flexi: true, unlimited: true }, + { feature: 'Access to experiences', flexi: true, unlimited: true }, + { feature: 'Entry to sites', flexi: false, unlimited: true }, + { feature: 'Access to venues', flexi: true, unlimited: true }, + { feature: 'Entry to events', flexi: true, unlimited: true }, + { feature: 'Access to experiences', flexi: false, unlimited: true }, + { feature: 'Access to Itinerary creation', flexi: false, unlimited: true }, + { feature: 'Access to postcard creation', flexi: false, unlimited: true }, + ].map((row, i) => ( + +

+ {row.feature} +

+
+ {row.flexi ? ( +
+ +
+ ) : ( + + )} +
+
+ {row.unlimited ? ( +
+ +
+ ) : ( + + )} +
+
+ ))} +
+
+
+ + {/* ── Offers ── */} +
+

+ {checkoutItem.cardType} Card Offers +

+

+ Exclusive deals and discounts included with your {checkoutItem.cardType} pass +

+
+ {offers.map((offer, idx) => ( +
+
+
+ +
+
+

+ {offer.title} +

+
+
+

+ {offer.description} +

+
+
+
+
+ ))} +
+
+ + {/* ── Available Attractions ── */} +
+
+

Available Attractions

+ {attractions.length} included +
+

+ Explore all the experiences you can enjoy with your pass +

+
+ {attractions.map((a) => ( +
+
+ +
+
+ {a.category} +
+
+
{a.name}
+
+ +
+
+ ))} +
+
+
+ + {/* Right column: Config card (desktop only, sticky) */} +
+
+ checkoutItem && onSecureCheckoutClick?.(checkoutItem)} + /> +
+
+
- ) : ( -

Tap a card above to select it for checkout

- )} -
- - Secure Checkout - - -
- )} -
- ) : ( - - } title="No post cards yet" description="Send beautiful digital post cards to friends and family from your favourite destinations around the world" actionLabel="Browse Post Cards" onAction={onPostCardsClick} /> - - )} + )} + + )} - - ) : ( - /* ─── CHECKOUT VIEW ─── */ - - {checkoutItem && ( - <> - {/* Back */} - - {/* Stepper */} - - - {/* Checkout heading */} -
-

- Checkout{' '} - {checkoutItem.city} -

- -
- -
- {/* Left column */} -
- - {/* ── Card Type Selection (Figma cards) ── */} -
-

- Choose Your Card -

-

- Select the card type that best suits your travel style -

-
- {/* Flexi */} - - - {/* Unlimited */} - -
- - {/* ── Config Card (mobile only) — right after card selection ── */} -
- checkoutItem && onSecureCheckoutClick?.(checkoutItem)} - /> -
- - {/* Features Comparison */} -
-
- {/* Header */} -

Features

-

Flexi

-

Unlimited

- {[ - { feature: 'Access to attractions', flexi: true, unlimited: true }, - { feature: 'Entry to attractions', flexi: true, unlimited: true }, - { feature: 'Access to experiences', flexi: true, unlimited: true }, - { feature: 'Entry to sites', flexi: false, unlimited: true }, - { feature: 'Access to venues', flexi: true, unlimited: true }, - { feature: 'Entry to events', flexi: true, unlimited: true }, - { feature: 'Access to experiences', flexi: false, unlimited: true }, - { feature: 'Access to Itinerary creation', flexi: false, unlimited: true }, - { feature: 'Access to postcard creation', flexi: false, unlimited: true }, - ].map((row, i) => ( - -

- {row.feature} -

-
- {row.flexi ? ( -
- -
- ) : ( - - )} -
-
- {row.unlimited ? ( -
- -
- ) : ( - - )} -
-
- ))} -
-
-
- - {/* ── Offers ── */} -
-

- {checkoutItem.cardType} Card Offers -

-

- Exclusive deals and discounts included with your {checkoutItem.cardType} pass -

-
- {offers.map((offer, idx) => ( -
-
-
- -
-
-

- {offer.title} -

-
-
-

- {offer.description} -

-
-
-
-
- ))} -
-
- - {/* ── Available Attractions ── */} -
-
-

Available Attractions

- {attractions.length} included -
-

- Explore all the experiences you can enjoy with your pass -

-
- {attractions.map((a) => ( -
-
- -
-
- {a.category} -
-
-
{a.name}
-
- -
-
- ))} -
-
-
- - {/* Right column: Config card (desktop only, sticky) */} -
-
- checkoutItem && onSecureCheckoutClick?.(checkoutItem)} - /> -
-
-
- - )} - - )} - - -
-
- ); +
+
+ ); } /* ─── Empty state ─── */ function EmptyState({ icon, title, description, actionLabel, onAction }: { - icon: React.ReactNode; title: string; description: string; actionLabel: string; onAction?: () => void; + icon: React.ReactNode; title: string; description: string; actionLabel: string; onAction?: () => void; }) { - return ( - - {icon} -

{title}

-

{description}

- {actionLabel} -
- ); + return ( + + {icon} +

{title}

+

{description}

+ {actionLabel} +
+ ); } \ No newline at end of file