From 351c767104cf869340920401d5b3a8560fabb0a2 Mon Sep 17 00:00:00 2001 From: aryabenade Date: Wed, 22 Apr 2026 23:20:26 +0530 Subject: [PATCH 01/11] replace the citySelected condition from local to session storage --- src/components/CitySelectionDialog.tsx | 1 + src/components/Navbar.tsx | 61 ++++---------------------- 2 files changed, 10 insertions(+), 52 deletions(-) diff --git a/src/components/CitySelectionDialog.tsx b/src/components/CitySelectionDialog.tsx index 188d4a0..a972fc5 100644 --- a/src/components/CitySelectionDialog.tsx +++ b/src/components/CitySelectionDialog.tsx @@ -45,6 +45,7 @@ export function CitySelectionDialog({ navigate(`/${slugify(city.cityName)}`); localStorage.setItem("cityId", String(city.id)) localStorage.setItem("cityName", String(city.cityName)) + sessionStorage.setItem("citySelected", String(city.cityName)) onClose(); }; diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 3a7d78c..905ecfe 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -2,12 +2,10 @@ import { useState, useEffect, useRef, forwardRef } from 'react'; import { Menu, X, ShoppingBag, ChevronDown, Globe, User, Settings, LogOut } from 'lucide-react'; import { motion, AnimatePresence } from 'motion/react'; import { Link, useLocation, useNavigate } from 'react-router-dom'; -import Frame1597884853 from '../imports/Frame1597884853'; import { Button } from './ui/button'; import { ImageWithFallback } from './figma/ImageWithFallback'; import { CTAButton } from './CTAButton'; import logoImage from '../assets/cit-logo.png'; -import melbourneLogo from '../assets/melbourne-logo.png'; import { CitySelectionDialog, slugify } from './CitySelectionDialog'; import { useAuth } from '../context/AuthContext'; import { LoginModal } from './LoginModal'; @@ -62,15 +60,12 @@ interface NavigationItem { export default function Navbar({ activeCity, onCityChange, - onSignInClick, - onSignOutClick, isUserSignedIn = false, // user }: NavbarProps) { const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const [isScrolled, setIsScrolled] = useState(false); const [activeLanguageDropdown, setActiveLanguageDropdown] = useState(false); - const [activeCartDropdown, setActiveCartDropdown] = useState(false); const [activeUserDropdown, setActiveUserDropdown] = useState(false); const [activeCityDropdown, setActiveCityDropdown] = useState(false); const [isCityDialogOpen, setIsCityDialogOpen] = useState(false); @@ -79,7 +74,6 @@ export default function Navbar({ const [dialogSource, setDialogSource] = useState<'navbar' | 'cta'>('navbar'); const languageRef = useRef(null); - const cartRef = useRef(null); const userRef = useRef(null); const cityRef = useRef(null); @@ -96,7 +90,7 @@ export default function Navbar({ const cityName = localStorage.getItem("cityName") // const citySelected = location.pathname.includes(slugify(cityName) || "") - const citySelected = cityName + const citySelected = sessionStorage.getItem("citySelected") const baseUrl = import.meta.env.VITE_BASE_URL; @@ -137,15 +131,6 @@ export default function Navbar({ path: '/whats-included', isShared: false }, - // Position 4 - Shared item - // { - // label: 'Your Card', - // path: '/passes', - // isShared: true, - // landingLabel: 'Your Card', - // melbourneLabel: 'Your Card' - // }, - // Position 5 { label: 'FAQ', path: '/faq', @@ -159,7 +144,7 @@ export default function Navbar({ melbourneLabel: 'Your Postcard' } ], - melbourne: [ + citySelected: [ // Position 1 { label: 'Attractions', @@ -240,20 +225,20 @@ export default function Navbar({ }, [location.pathname]); // ✅ Determine which navbar to show - const getAutoNavigationSource = (): 'landing' | 'melbourne' => { + const getAutoNavigationSource = () => { const path = location.pathname; // Explicit routes - if (path.startsWith('/melbourne')) return 'melbourne'; + // if (path.startsWith('/melbourne')) return 'melbourne'; if (path === '/' || path.startsWith('/explore')) return 'landing'; // Shared routes - if (['/passes', '/how-it-works'].includes(path)) { - return lastKnownCity; // ← remembers where user came from - } + // if (['/passes', '/how-it-works'].includes(path)) { + // return lastKnownCity; // ← remembers where user came from + // } // Fallback - return lastKnownCity; + return citySelected; }; @@ -261,7 +246,7 @@ export default function Navbar({ const getNavigationItems = (): NavigationItem[] => { const currentSource = getAutoNavigationSource(); const items = currentSource === 'landing' ? - navigationConfig.landing : navigationConfig.melbourne; + navigationConfig.landing : navigationConfig.citySelected; return items.map((item, index) => ({ ...item, @@ -370,34 +355,6 @@ export default function Navbar({ { id: '2', name: 'Melbourne Premium Pass', price: '$129', quantity: 1 }, ]; - // Calculate cart total - const cartTotal = cartItems.reduce((total, item) => { - const price = parseFloat(item.price.replace('$', '')); - return total + (price * item.quantity); - }, 0); - - // Cart dropdown items with proper navigation for checkout - const cartDropdownItems: DropdownItem[] = [ - ...cartItems.map(item => ({ - id: item.id, - label: `${item.name} - ${item.price}`, - badge: `${item.quantity}x` - })), - { - id: 'total', - label: `Total: $${cartTotal.toFixed(2)}`, - icon: - }, - { - id: 'checkout', - label: 'Proceed to Checkout', - action: () => { - navigate('/checkout'); - setActiveCartDropdown(false); - } - } - ]; - const closeMobileMenu = () => { setIsMobileMenuOpen(false); }; From 617b49424951136c80a37d841bc4946ae6fe2c02 Mon Sep 17 00:00:00 2001 From: aryabenade Date: Wed, 22 Apr 2026 23:49:59 +0530 Subject: [PATCH 02/11] rename and replace the design files with actual page names --- src/AppRouter.tsx | 43 +- src/pages/CartPageDesign.tsx | 878 ---------- src/pages/CheckoutPage.tsx | 1259 +++++++------- src/pages/CheckoutPage2.tsx | 886 ---------- ...Design.tsx => CreateMagicIternaryPage.tsx} | 48 +- src/pages/CreateMagicItineraryPage.tsx | 1450 ----------------- src/pages/ItineraryViewPage.tsx | 569 ++----- src/pages/ItineraryViewPageDesign.tsx | 501 ------ src/pages/ProfilePage.tsx | 6 +- ...PageDesign.tsx => ViewCardDetailsPage.tsx} | 16 +- 10 files changed, 734 insertions(+), 4922 deletions(-) delete mode 100644 src/pages/CartPageDesign.tsx delete mode 100644 src/pages/CheckoutPage2.tsx rename src/pages/{CreateMagicIternaryPageDesign.tsx => CreateMagicIternaryPage.tsx} (96%) delete mode 100644 src/pages/CreateMagicItineraryPage.tsx delete mode 100644 src/pages/ItineraryViewPageDesign.tsx rename src/pages/{ViewCardDetailsPageDesign.tsx => ViewCardDetailsPage.tsx} (97%) diff --git a/src/AppRouter.tsx b/src/AppRouter.tsx index a8e8300..f875fdb 100644 --- a/src/AppRouter.tsx +++ b/src/AppRouter.tsx @@ -6,17 +6,13 @@ import { MelbournePage } from './pages/MelbournePage'; import { PassesPage } from './pages/PassesPage'; import { AttractionsPage } from './pages/AttractionsPage'; import { AttractionDetailsPage } from './pages/AttractionDetailsPage'; -import { CheckoutPage } from './pages/CheckoutPage'; import { SecureCheckoutPage } from './pages/SecureCheckoutPage'; import { BlogsPage } from './pages/BlogsPage'; import { BlogDetailsPage } from './pages/BlogDetailsPage'; -import { HowItWorksPage } from './components/HowItWorksPage'; import { FAQPage } from './components/FAQPage'; import { PrivacyPolicyPage } from './pages/PrivacyPolicyPage'; import { AboutUsPage } from './pages/AboutUsPage'; import { ProfilePage } from './pages/ProfilePage'; -import { CreateMagicItineraryPage } from './pages/CreateMagicItineraryPage'; -import { ItineraryViewPage } from './pages/ItineraryViewPage'; import { OffersPage } from './pages/OffersPage'; import { CityCardsPage } from './pages/CityCardsPage'; import { MagicItineraryPage } from './pages/MagicItineraryPage'; @@ -24,7 +20,6 @@ import { PostCardsPage } from './pages/PostCardsPage'; import { DownloadAppPage } from './pages/DownloadAppPage'; import { HotelDiscountsPage } from './pages/HotelDiscountsPage'; import { ContactUsPage } from './pages/ContactUsPage'; - import { pageTransition } from './utils/animations'; import { LandingPage } from './pages/landingPage'; import ComingSoonPage from './pages/ComingSoonPage'; @@ -34,15 +29,14 @@ import { LandingMagicItineraryPage } from './pages/LandingMagicItineraryPage'; import { DiscoverPage } from './pages/DiscoverPage'; import { CartPage } from './pages/CartPage'; import { PaymentDetailsPage } from './pages/PaymentDetailsPage'; -import { CartPageDesign } from './pages/CartPageDesign'; -import { CheckoutPage2 } from './pages/CheckoutPage2'; import { SuperSavingsDetailsPage } from './pages/SuperSavingsDetailsPage'; -import { ViewCardDetailsPage } from './pages/ViewCardDetailsPageDesign'; -import { CreateMagicItineraryPageDesign } from './pages/CreateMagicIternaryPageDesign'; -import { ItineraryViewPageDesign } from './pages/ItineraryViewPageDesign'; +import { ViewCardDetailsPage } from './pages/ViewCardDetailsPage'; import ItinerarySummaryPage from './pages/ItinerarySummaryPage'; import { PaymentSuccessPage } from './pages/PaymentSuccessPage'; import { PaymentCancelPage } from './pages/PaymentCancelPage'; +import { ItineraryViewPage } from './pages/ItineraryViewPage'; +import { CheckoutPage } from './pages/CheckoutPage'; +import { CreateMagicItineraryPage } from './pages/CreateMagicIternaryPage'; // User type definition interface User { @@ -134,13 +128,6 @@ export function AppRouter({ } /> - {/* Checkout Routes */} - {/* - - - } /> */} - @@ -200,7 +187,7 @@ export function AppRouter({ } /> - @@ -213,22 +200,12 @@ export function AppRouter({ } /> - - - - } /> - } /> - - - - } /> @@ -310,14 +287,10 @@ export function AppRouter({ } /> - - - } /> - - + } /> + diff --git a/src/pages/CartPageDesign.tsx b/src/pages/CartPageDesign.tsx deleted file mode 100644 index e51725c..0000000 --- a/src/pages/CartPageDesign.tsx +++ /dev/null @@ -1,878 +0,0 @@ -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 -} from 'lucide-react'; -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' - -/* ─── Types ─── */ -export interface CartItem { - 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; -} - -interface CartPageDesignProps { - 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', - }, -]; - -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 }, - ], - }, -}; - -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' }, - ], -}; - -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 }, -}; - -/* ═══════════════════════════════════════════ - FIGMA CARD TYPE COMPONENTS - ═══════════════════════════════════════════ */ - -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 -
-
- 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 -
-
- and - ${childPrice} - /Child -
-
- {/* Description */} -
-

- Dive into an extensive selection of thrilling destinations! -

-
- {/* Side tab - Unlimited (coral) */} -
- Card - Unlimited -
- {/* Selected checkmark */} - {isSelected && ( -
- -
- )} -
- ); -} - -/* ═══════════════════════════════════════════ - CHECKOUT CONFIGURATION CARD (Mobile-first) - ═══════════════════════════════════════════ */ - -function CheckoutConfigCard({ - item, - onChange, - onProceed, -}: { - 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; - - return ( -
- {/* City header */} -
-

{item.city}

-
- - {item.cardType} Card - -
-
- - {/* Configuration rows */} -
- {/* No. of Adults */} -
- No. of Adults -
- - {item.adults} - -
-
- - {/* No. of Children */} -
- 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 */} -
- - Proceed to Pay - -
-
- ); -} - -/* ═══════════════════════════════════════════ - MAIN CART PAGE - ═══════════════════════════════════════════ */ - -export function CartPageDesign({ - 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, -}: CartPageDesignProps) { - 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 handleSelectCard = (id: string) => { - setSelectedCardId(prev => (prev === id ? null : id)); - }; - - const handleGoToCheckout = () => { - const item = cartItems.find(i => i.id === selectedCardId); - if (item) { - setCheckoutItem({ ...item }); - setView('checkout'); - window.scrollTo({ top: 0, behavior: 'smooth' }); - } - }; - - const handleBackToCart = () => { - setView('cart'); - setCheckoutItem(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 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] || []) : []; - - 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} - /> - - - {view === 'cart' ? ( - /* ─── CART VIEW ─── */ - - {/* Header */} -
-

- Your{' '} - Cart -

-

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

-
- - {/* Tab switcher */} - {/* Cards listed directly below */} - - {/* 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
-
-
- - - {cartItems.map((item) => { - const isSelected = selectedCardId === item.id; - const totalPrice = item.pricePerUnit * item.quantity; - - 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 && ( - - - - )} - - - {/* 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} -
-
-
-
- - {/* 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} -
-
- -
-
-
- ); - })} -
- - {/* Bottom checkout bar */} - -
- {selectedItem ? ( - <> -

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

-

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

- - ) : ( -

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; -}) { - return ( - - {icon} -

{title}

-

{description}

- {actionLabel} -
- ); -} \ No newline at end of file diff --git a/src/pages/CheckoutPage.tsx b/src/pages/CheckoutPage.tsx index 235aa7e..8ee3100 100644 --- a/src/pages/CheckoutPage.tsx +++ b/src/pages/CheckoutPage.tsx @@ -1,733 +1,574 @@ -import { useState, useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import { motion, AnimatePresence } from 'motion/react'; -import { ArrowLeft, CreditCard, Users, Calendar, MapPin, Shield, Truck, Clock, ChevronRight, Check, ChevronDown, X, Mail, Smartphone } from 'lucide-react'; -import { Button } from '../components/ui/button'; -import { Input } from '../components/ui/input'; -import { Label } from '../components/ui/label'; -import { Card, CardContent, CardHeader, CardTitle } from '../components/ui/card'; -import { Separator } from '../components/ui/separator'; -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '../components/ui/dialog'; -import { RadioGroup, RadioGroupItem } from '../components/ui/radio-group'; -import { Checkbox } from '../components/ui/checkbox'; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../components/ui/select'; -import { Badge } from '../components/ui/badge'; -import { Textarea } from '../components/ui/textarea'; +import { + ArrowLeft, Check, Minus, Plus, ChevronDown +} from 'lucide-react'; +import Navbar from '../components/Navbar'; +import { Footer } from '../components/Footer'; import { ImageWithFallback } from '../components/figma/ImageWithFallback'; -import { Layout } from '../Layout'; +import { useNavigate } from 'react-router-dom'; +import { useAddCardToCartMutation, useGetCheckoutPageDataQuery } from '../Redux/services/cards.service'; +import LoadingSpinner from '../components/LoadingSpinner'; +import { toast } from 'sonner'; -interface CheckoutPageProps { - onBackClick?: () => void; - onHomeClick?: () => void; - onMelbourneClick?: () => void; - onPassesClick?: () => void; - onCheckoutClick?: () => 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; - onSecureCheckoutClick?: () => void; - onContactUsClick?: () => void; - onEsimsClick?: () => void; - onHotelDiscountsClick?: () => void; - currentPage?: string; - user?: { email: string; name: string } | null; +/* ─── Types ─── */ +export interface CartItem { + 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; +} -// Mock cart data -const mockCartItems = [ - { - id: '1', - name: 'Paris Unlimited Pass', - type: '7-Day Pass', - price: 79, - originalPrice: 149, - discount: 47, - attractions: 45, - validity: '7 days', - image: 'https://images.unsplash.com/photo-1502602898536-47ad22581b52?w=400', - features: ['Skip-the-line access', 'Mobile voucher', 'Free cancellation'] - } -]; +/* ─── Data (Same as Original) ─── */ +const dayOptions = [3, 6, 12, 18, 24]; -export function CheckoutPage({ - onBackClick, - onHomeClick, - onMelbourneClick, - onPassesClick, - onCheckoutClick, - onSignInClick, - onSignOutClick, - onAttractionsClick, - onBlogsClick, - onHowItWorksClick, - onFAQClick, - onPrivacyPolicyClick, - onAboutUsClick, - onProfileClick, - onCityCardsClick, - onMagicItineraryClick, - onPostCardsClick, - onOffersClick, - onSecureCheckoutClick, - onContactUsClick, - onEsimsClick, - onHotelDiscountsClick, - currentPage, - user, -}: CheckoutPageProps) { - const [purchaseType, setPurchaseType] = useState<'self' | 'gift'>('self'); - const [selectedPayment, setSelectedPayment] = useState('credit-card'); - const [showEmailVerification, setShowEmailVerification] = useState(false); - const [verificationCode, setVerificationCode] = useState(''); - const [isEmailVerified, setIsEmailVerified] = useState(false); - const [formData, setFormData] = useState({ - email: '', - firstName: '', - lastName: '', - phone: '', - country: '', - address: '', - city: '', - postalCode: '', - cardNumber: '', - expiry: '', - cvv: '', - cardName: '', - agreeTerms: false, - subscribeNewsletter: false - }); - const [giftData, setGiftData] = useState({ - recipientName: '', - recipientPhone: '', - recipientEmail: '', - personalizedMessage: '' - }); +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 }, +}; - const subtotal = mockCartItems.reduce((sum, item) => sum + item.price, 0); - const tax = Math.round(subtotal * 0.1); - const total = subtotal + tax; - const totalSavings = mockCartItems.reduce((sum, item) => sum + (item.originalPrice - item.price), 0); +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 }, + ], + }, +}; - const handleInputChange = (field: string, value: string | boolean) => { - setFormData(prev => ({ ...prev, [field]: value })); - - // Trigger email verification when email is complete - if (field === 'email' && typeof value === 'string' && value.includes('@') && value.includes('.') && !isEmailVerified) { - setTimeout(() => { - setShowEmailVerification(true); - }, 1000); - } - }; +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' }, + ], +}; - const handleGiftInputChange = (field: string, value: string) => { - setGiftData(prev => ({ ...prev, [field]: value })); - }; +/* ─── FIGMA CARD PREVIEWS (Exact Copy) ─── */ +function FlexiCardPreview({ city, adultPrice, childPrice, isSelected, image }: { city: string; adultPrice: number; childPrice: number; isSelected: boolean, image: string; }) { + 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 && ( +
+ +
+ )} +
+ ); +} - const handleEmailVerification = () => { - if (verificationCode === '123456') { - setIsEmailVerified(true); - setShowEmailVerification(false); - } - }; +function UnlimitedCardPreview({ city, adultPrice, childPrice, isSelected, image }: { city: string; adultPrice: number; childPrice: number; isSelected: boolean, image: string; }) { + 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 && ( +
+ +
+ )} +
+ ); +} - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - if (!isEmailVerified) { - setShowEmailVerification(true); - return; - } - const checkoutData = { - purchaseType, - formData, - ...(purchaseType === 'gift' && { giftData }), - selectedPayment, - cartItems: mockCartItems +/* ─── CheckoutConfigCard (Exact Copy) ─── */ +function CheckoutConfigCard({ + item, + onProceed, +}: { + item: any; + onProceed: () => void; +}) { + const [dropdownOpen, setDropdownOpen] = useState(false); + const [noOfAdults, setNoOfAdults] = useState(1) + const [noOfChildren, setNoOfChildren] = useState(0) + const [noOfAttractions, setNoOfAttractions] = useState(item?.minNumber); + const [noOfDays, setNoOfDays] = useState(item?.minNumber) + + const cityId = localStorage.getItem("cityId") + const cityName = localStorage.getItem("cityName") + const cardTypeId = item?.cardType?.id + const cardId = item?.id + const cardMode = item?.cardType?.name === "selective_pass" ? "flexi" : "unlimited" + const adultPrice = item?.adultPrice * noOfAdults + const childPrice = item?.childPrice * noOfChildren + const basePrice = adultPrice + childPrice + const taxAmount = basePrice * 0.1 + const strikedPrice = basePrice + 20 + + const [addCardToCart] = useAddCardToCartMutation() + + useEffect(() => { + setNoOfAttractions(item?.minNumber) + setNoOfDays(item?.minNumber) + }, [item]) + + const numberArray = Array.from( + { length: item?.maxNumber - item?.minNumber + 1 }, + (_, i) => item?.minNumber + i + ); + const navigate = useNavigate(); + + const cardBookingDetails = { + cityXid: cityId, + cardTypeXid: cardTypeId, + cardXid: cardId, + cardMode, // stays as-is + totalAdult: noOfAdults, + baseAmount: basePrice, // static value + taxAmount, + totalChild: noOfChildren, + noOfAttractions, + noOfDays }; - console.log('Processing checkout...', checkoutData); - }; - const paymentMethods = [ - { - id: 'credit-card', - name: 'Credit Card', - icon: , - description: 'Visa, Mastercard, American Express' - }, - { - id: 'paypal', - name: 'PayPal', - icon:
P
, - description: 'Pay with your PayPal account' - }, - { - id: 'google-pay', - name: 'Google Pay', - icon:
G
, - description: 'Pay with Google Pay' + const handleProceedToPayment = async () => { + try { + console.log("Adding card to cart", cardBookingDetails); + const response = await addCardToCart(cardBookingDetails); + console.log(response) + const bookingId = response?.data?.id + navigate(`/payment/${bookingId}`) + } catch (error) { + console.error("Error adding card to cart:", error); + toast.error("Failed to move forward. Please try again."); + } } - ]; - return ( -
- - - {/* Header Section */} -
-
- {/* Back Button */} - - - Back to Cart - - - {/* Page Title */} - -

- Secure{' '} - Checkout -

-

- Complete your purchase and start exploring Paris -

-
-
-
- - {/* Main Checkout Content */} -
-
-
- {/* Left Column - Form Inputs (3/5 width) */} -
- {/* Purchase Type Selection */} - - - - Purchase Type - - - setPurchaseType(value as 'self' | 'gift')} - className="grid grid-cols-1 md:grid-cols-2 gap-4" - > -
- - -
-
- - -
-
-
-
-
- - {/* Gift Recipient Information - Only shown when gift is selected */} - {purchaseType === 'gift' && ( - - - - - - Gift Recipient Details - - - -
- - handleGiftInputChange('recipientName', e.target.value)} - placeholder="Jane Smith" - required={purchaseType === 'gift'} - className="mt-1 font-poppins" - /> -
-
- - handleGiftInputChange('recipientEmail', e.target.value)} - placeholder="recipient@email.com" - required={purchaseType === 'gift'} - className="mt-1 font-poppins" - /> -
-
- - handleGiftInputChange('recipientPhone', e.target.value)} - placeholder="+1 (555) 123-4567" - required={purchaseType === 'gift'} - className="mt-1 font-poppins" - /> -
-
- -