main #12

Merged
Hemant.Vishwakarma merged 9 commits from main into testing 2026-04-22 14:26:45 +00:00
7 changed files with 1926 additions and 6 deletions
Showing only changes of commit 4c199f721a - Show all commits

View File

@@ -185,7 +185,7 @@ function App() {
</div>
{/* Card Title in Orange */}
<p className="absolute font-poppins font-medium leading-[1.3] left-[50%] text-[#ffb23f] text-[24px] text-center top-[65px] tracking-[-0.96px] translate-x-[-50%] w-[202px]" style={{ fontVariationSettings: "'wdth' 100" }}>
<p className="absolute font-appoppins font-medium leading-[1.3] left-[50%] text-[#ffb23f] text-[24px] text-center top-[65px] tracking-[-0.96px] translate-x-[-50%] w-[202px]" style={{ fontVariationSettings: "'wdth' 100" }}>
{stickyCardType === 'unlimited' ? (
<>Melbourne Unlimited Card</>
) : (

View File

@@ -37,6 +37,8 @@ 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';
// User type definition
interface User {
@@ -194,6 +196,12 @@ export function AppRouter({
<ProfilePage {...commonNavHandlers} />
</motion.div>
} />
<Route path="/view-card-design" element={
<motion.div key="profile" {...pageTransition}>
<ViewCardDetailsPage {...commonNavHandlers} />
</motion.div>
} />
{/* Itinerary Routes */}
<Route path="/create-itinerary" element={
@@ -201,12 +209,22 @@ export function AppRouter({
<CreateMagicItineraryPage {...commonNavHandlers} />
</motion.div>
} />
<Route path="/create-itinerary-design" element={
<motion.div key="create-itinerary" {...pageTransition}>
<CreateMagicItineraryPageDesign {...commonNavHandlers} />
</motion.div>
} />
<Route path="/itinerary-view" element={
<motion.div key="itinerary-view" {...pageTransition}>
<ItineraryViewPage {...commonNavHandlers} />
</motion.div>
} />
<Route path="/itinerary-view-design" element={
<motion.div key="itinerary-view" {...pageTransition}>
<ItineraryViewPage {...commonNavHandlers} />
</motion.div>
} />
<Route path="/magic-itinerary" element={
<motion.div key="magic-itinerary" {...pageTransition}>

View File

@@ -4,6 +4,7 @@ import { citiesApi } from "./services/cities.service";
import { authApi } from "./services/auth.service";
import { profileApi } from "./services/profile.service";
import { cardsApi } from "./services/cards.service";
import { itineraryApi } from "./services/itinerary.service";
export const store = configureStore({
reducer: {
@@ -11,7 +12,8 @@ export const store = configureStore({
[citiesApi.reducerPath]: citiesApi.reducer,
[authApi.reducerPath]: authApi.reducer,
[profileApi.reducerPath]: profileApi.reducer,
[cardsApi.reducerPath]:cardsApi.reducer
[cardsApi.reducerPath]:cardsApi.reducer,
[itineraryApi.reducerPath]:itineraryApi.reducer
},
@@ -21,7 +23,8 @@ export const store = configureStore({
citiesApi.middleware,
authApi.middleware,
profileApi.middleware,
cardsApi.middleware
cardsApi.middleware,
itineraryApi.middleware
),
});
export type RootState = ReturnType<typeof store.getState>;

View File

@@ -0,0 +1,28 @@
import { createApi} from "@reduxjs/toolkit/query/react";
import { baseQuery } from "../baseQuery";
export const itineraryApi = createApi({
reducerPath: "itApi",
baseQuery,
endpoints: (builder) => ({
createMagicItinerary: builder.mutation({
query: (itineraryDetails) => ({ // keep the name of the variables being passed here same as when calling the mutation hook
url: `/website/itinerary`,
method: "POST",
body: itineraryDetails
}),
}),
})
});
export const {
useCreateMagicItineraryMutation,
} = itineraryApi;

View File

@@ -425,9 +425,9 @@ export default function Navbar({
}, []);
useEffect(() => {
if (activeCity.toLowerCase() === 'melbourne') {
if (activeCity?.toLowerCase() === 'melbourne') {
setLastKnownCity('melbourne');
} else if (activeCity.toLowerCase() === 'landing' || activeCity.toLowerCase() === 'landingpage') {
} else if (activeCity?.toLowerCase() === 'landing' || activeCity?.toLowerCase() === 'landingpage') {
setLastKnownCity('landing');
}
}, [activeCity]);
@@ -692,7 +692,7 @@ export default function Navbar({
label: 'My Profile',
icon: <User className="w-4 h-4" />,
action: () => {
navigate(citySelected ? `/${slugify(cityName)}/profile` : '/profile');
navigate(citySelected ? `/profile` : '/profile');
setActiveUserDropdown(false);
}
},

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,746 @@
import React, { useState } from 'react';
import { motion } from 'motion/react';
import { ArrowLeft, Calendar, Clock, MapPin, Users, Star, Heart, Share2, Download, CheckCircle, Navigation, Cloud, Sun } from 'lucide-react';
import { Button } from '../components/ui/button';
import { Card, CardContent } from '../components/ui/card';
import { Badge } from '../components/ui/badge';
import Navbar from '../components/Navbar';
import { Footer } from '../components/Footer';
import { ImageWithFallback } from '../components/figma/ImageWithFallback';
interface ItineraryViewPageDesignProps {
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;
onCreateItineraryClick: () => void;
onContactUsClick?: () => void;
onEsimsClick?: () => void;
onHotelDiscountsClick?: () => void;
currentPage: string;
user?: { email: string; name: string; } | null;
}
// Enhanced activity type with more details
interface Activity {
time: string;
activity: string;
location: string;
address: string;
image: string;
categories: string[];
description: string[];
isFavorite?: boolean;
}
export function ItineraryViewPageDesign({
onBackClick,
onHomeClick,
onMelbourneClick,
onPassesClick,
onCheckoutClick,
onSignInClick,
onSignOutClick,
onAttractionsClick,
onBlogsClick,
onHowItWorksClick,
onFAQClick,
onPrivacyPolicyClick,
onAboutUsClick,
onProfileClick,
onCityCardsClick,
onMagicItineraryClick,
onPostCardsClick,
onOffersClick,
onCreateItineraryClick,
onContactUsClick,
onEsimsClick,
onHotelDiscountsClick,
currentPage,
user
}: ItineraryViewPageDesignProps) {
const [viewMode, setViewMode] = useState<'daily' | 'summary'>('daily');
const [favorites, setFavorites] = useState<Set<string>>(new Set());
const toggleFavorite = (activityKey: string) => {
setFavorites(prev => {
const newSet = new Set(prev);
if (newSet.has(activityKey)) {
newSet.delete(activityKey);
} else {
newSet.add(activityKey);
}
return newSet;
});
};
// Enhanced itinerary data with images, addresses, and detailed info
const generatedItinerary = {
destination: {
name: 'Melbourne',
country: 'Australia',
weather: '18°C, Sunny',
image: 'https://images.unsplash.com/photo-1514395462725-fb4566210144?w=400&h=300&fit=crop'
},
totalDays: 3,
estimatedCost: '$450 AUD',
includedActivities: 18,
dailyPlans: [
{
day: 1,
title: "City Center & Culture",
activities: [
{
time: '8:00 am',
activity: 'The Langham Melbourne',
location: 'The Langham Melbourne',
address: '1 Southgate Avenue, Southbank VIC 3006',
image: 'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=800&h=600&fit=crop',
categories: ['Accommodation', 'Luxury'],
description: [
'Check-in at luxury riverside hotel',
'Enjoy complimentary breakfast',
'Relax at the spa facilities',
'Explore the surrounding Southbank area'
]
},
{
time: '10:00 am',
activity: 'Federation Square',
location: 'Federation Square',
address: 'Corner Swanston & Flinders Streets, Melbourne VIC 3000',
image: 'https://images.unsplash.com/photo-1514395462725-fb4566210144?w=800&h=600&fit=crop',
categories: ['Culture', 'Landmark'],
description: [
'Explore Melbourne\'s cultural precinct',
'Visit the ACMI museum',
'Enjoy street performances',
'Take photos at iconic locations'
]
},
{
time: '12:00 pm',
activity: 'Degrave Street Café',
location: 'Degrave Street Espresso Bar',
address: '23-25 Degraves Street, Melbourne VIC 3000',
image: 'https://images.unsplash.com/photo-1554118811-1e0d58224f24?w=800&h=600&fit=crop',
categories: ['Food', 'Drinks', 'Culture'],
description: [
'Coffee at Pellegrini\'s Espresso Bar (iconic old-school cafe)',
'Try the famous jam doughnuts',
'Shop for fresh produce in the Deli Hall',
'Pick up unique souvenirs in the General Merchandise section'
]
},
{
time: '2:00 pm',
activity: 'Royal Botanic Gardens',
location: 'Royal Botanic Gardens Victoria',
address: 'Birdwood Avenue, South Yarra VIC 3141',
image: 'https://images.unsplash.com/photo-1585320806297-9794b3e4eeae?w=800&h=600&fit=crop',
categories: ['Nature', 'Culture'],
description: [
'Stroll through stunning landscaped gardens',
'Visit the Australian Forest Walk',
'Relax by the Ornamental Lake',
'Join a free guided walking tour'
]
},
{
time: '4:00 pm',
activity: 'National Gallery of Victoria',
location: 'NGV International',
address: '180 St Kilda Road, Melbourne VIC 3006',
image: 'https://images.unsplash.com/photo-1564399577149-749794d74eee?w=800&h=600&fit=crop',
categories: ['Culture', 'Art'],
description: [
'Explore Australia\'s oldest art museum',
'View international and Australian art collections',
'Visit the stunning water wall entrance',
'Browse the NGV design store'
]
},
{
time: '7:00 pm',
activity: 'Dinner at Chin Chin',
location: 'Chin Chin Restaurant',
address: '125 Flinders Lane, Melbourne VIC 3000',
image: 'https://images.unsplash.com/photo-1552566626-52f8b828add9?w=800&h=600&fit=crop',
categories: ['Food', 'Drinks'],
description: [
'Experience modern Thai cuisine',
'Try signature dishes like the Betel Leaf',
'Enjoy the vibrant atmosphere',
'Book ahead or walk-in for bar seating'
]
}
]
},
{
day: 2,
title: "Markets & Neighborhoods",
activities: [
{
time: '8:00 am',
activity: 'Queen Victoria Market',
location: 'Queen Victoria Market',
address: 'Queen Street, Melbourne VIC 3000',
image: 'https://images.unsplash.com/photo-1555939594-58d7cb561ad1?w=800&h=600&fit=crop',
categories: ['Food', 'Shopping', 'Culture'],
description: [
'Explore Melbourne\'s historic market (since 1878)',
'Sample fresh local produce',
'Shop for artisan goods and souvenirs',
'Grab breakfast at the Deli Hall'
]
},
{
time: '10:30 am',
activity: 'Fitzroy Street Art Tour',
location: 'Fitzroy Arts Precinct',
address: 'Gertrude Street, Fitzroy VIC 3065',
image: 'https://images.unsplash.com/photo-1499781350541-7783f6c6a0c8?w=800&h=600&fit=crop',
categories: ['Culture', 'Art'],
description: [
'Walk through famous street art laneways',
'Discover works by renowned artists',
'Visit independent galleries',
'Explore vintage and record stores'
]
},
{
time: '12:30 pm',
activity: 'Brunswick Street Lunch',
location: 'Brunswick Street Precinct',
address: 'Brunswick Street, Fitzroy VIC 3065',
image: 'https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?w=800&h=600&fit=crop',
categories: ['Food', 'Drinks'],
description: [
'Choose from diverse dining options',
'Try local cafes and restaurants',
'Explore bookshops and boutiques',
'Enjoy the vibrant neighborhood atmosphere'
]
},
{
time: '2:30 pm',
activity: 'Carlton Gardens',
location: 'Carlton Gardens',
address: 'Carlton Gardens, Carlton VIC 3053',
image: 'https://images.unsplash.com/photo-1519331379826-f10be5486c6f?w=800&h=600&fit=crop',
categories: ['Nature', 'Culture', 'Landmark'],
description: [
'Visit the UNESCO World Heritage site',
'See the Royal Exhibition Building',
'Stroll through Victorian-era gardens',
'Relax by the ornamental fountains'
]
},
{
time: '4:00 pm',
activity: 'Melbourne Museum',
location: 'Melbourne Museum',
address: '11 Nicholson Street, Carlton VIC 3053',
image: 'https://images.unsplash.com/photo-1566127992631-137a642a90f4?w=800&h=600&fit=crop',
categories: ['Culture', 'Museum'],
description: [
'Explore natural and cultural history',
'Visit the Bunjilaka Aboriginal Centre',
'See the Forest Gallery living ecosystem',
'Discover Melbourne\'s story exhibition'
]
},
{
time: '7:00 pm',
activity: 'Rooftop Bar Experience',
location: 'Naked for Satan',
address: '285 Brunswick Street, Fitzroy VIC 3065',
image: 'https://images.unsplash.com/photo-1514933651103-005eec06c04b?w=800&h=600&fit=crop',
categories: ['Drinks', 'Food'],
description: [
'Enjoy sunset views from the rooftop',
'Try Spanish-style pintxos',
'Sample craft cocktails and local beers',
'Experience Melbourne\'s bar culture'
]
}
]
},
{
day: 3,
title: "Coastal Adventure",
activities: [
{
time: '8:00 am',
activity: 'St. Kilda Beach',
location: 'St. Kilda Beach',
address: 'Jacka Boulevard, St Kilda VIC 3182',
image: 'https://images.unsplash.com/photo-1505142468610-359e7d316be0?w=800&h=600&fit=crop',
categories: ['Nature', 'Beach'],
description: [
'Morning walk along the iconic beach',
'Visit the historic St Kilda Pier',
'See the little penguins at sunset',
'Explore the Sunday Esplanade Market (weekends)'
]
},
{
time: '10:00 am',
activity: 'Acland Street Cafes',
location: 'Acland Street',
address: 'Acland Street, St Kilda VIC 3182',
image: 'https://images.unsplash.com/photo-1495474472287-4d71bcdd2085?w=800&h=600&fit=crop',
categories: ['Food', 'Drinks'],
description: [
'Brunch at famous cake shops',
'Try traditional European pastries',
'Visit Lentil as Anything (pay-as-you-feel)',
'Browse vintage shops and bookstores'
]
},
{
time: '12:00 pm',
activity: 'Luna Park Melbourne',
location: 'Luna Park Melbourne',
address: '18 Lower Esplanade, St Kilda VIC 3182',
image: 'https://images.unsplash.com/photo-1513026705753-bc3fffca8bf4?w=800&h=600&fit=crop',
categories: ['Entertainment', 'Landmark'],
description: [
'Visit Melbourne\'s iconic amusement park',
'Ride the historic Scenic Railway (1912)',
'Take photos at Mr Moon entrance',
'Enjoy carnival games and rides'
]
},
{
time: '2:00 pm',
activity: 'Brighton Beach Boxes',
location: 'Brighton Beach',
address: 'Esplanade, Brighton VIC 3186',
image: 'https://images.unsplash.com/photo-1520208422220-d12a3c588e6c?w=800&h=600&fit=crop',
categories: ['Culture', 'Landmark'],
description: [
'Photograph the famous colorful bathing boxes',
'Walk along the pristine beach',
'Learn about the heritage structures',
'Relax in the beachside atmosphere'
]
},
{
time: '4:00 pm',
activity: 'Southbank Promenade',
location: 'Southbank',
address: 'Southbank Promenade, Southbank VIC 3006',
image: 'https://images.unsplash.com/photo-1559827260-dc66d52bef19?w=800&h=600&fit=crop',
categories: ['Culture', 'Shopping'],
description: [
'Stroll along the Yarra River',
'Visit arts and craft markets',
'Explore restaurants and cafes',
'Enjoy river views and street performers'
]
},
{
time: '7:00 pm',
activity: 'Farewell Dinner at Vue de Monde',
location: 'Vue de Monde',
address: 'Level 55, Rialto, 525 Collins Street, Melbourne VIC 3000',
image: 'https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=800&h=600&fit=crop',
categories: ['Food', 'Drinks', 'Luxury'],
description: [
'Experience fine dining at 55th floor',
'Enjoy panoramic Melbourne views',
'Taste modern Australian cuisine',
'Celebrate the end of your journey'
]
}
]
}
]
};
return (
<div className="min-h-screen bg-background">
{/* Navbar */}
<Navbar
activeCity=""
onCityChange={() => {}}
onSignInClick={onSignInClick}
onPassesClick={onPassesClick}
onCheckoutClick={onCheckoutClick}
onHomeClick={onHomeClick}
onMelbourneClick={onMelbourneClick}
onAttractionsClick={onAttractionsClick}
onBlogsClick={onBlogsClick}
onHowItWorksClick={onHowItWorksClick}
onFAQClick={onFAQClick}
onPrivacyPolicyClick={onPrivacyPolicyClick}
onAboutUsClick={onAboutUsClick}
onProfileClick={onProfileClick}
onCityCardsClick={onCityCardsClick}
onMagicItineraryClick={onMagicItineraryClick}
onPostCardsClick={onPostCardsClick}
onOffersClick={onOffersClick}
currentPage="itinerary-view"
isUserSignedIn={!!user}
user={user}
/>
{/* Header Section */}
<section className="pt-32 pb-8 bg-gradient-to-br from-primary/5 to-secondary/5">
<div className="container mx-auto px-4 pt-32">
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className="text-center"
>
<Button
variant="ghost"
onClick={onBackClick}
className="mb-6 hover:bg-primary/5 font-poppins font-medium"
>
<ArrowLeft className="w-4 h-4 mr-2" />
Back to Magic Itinerary
</Button>
<div className="flex items-center justify-center gap-2 text-primary mb-4">
<Star className="w-6 h-6 fill-current" />
<h1 className="font-merchant text-4xl md:text-5xl lg:text-6xl leading-tight">
<span className="font-light">Your</span>{' '}
<span className="font-bold italic bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">Magic Itinerary</span>
</h1>
<Star className="w-6 h-6 fill-current" />
</div>
<p className="font-poppins text-xl leading-relaxed font-normal text-gray-600 max-w-2xl mx-auto">
Here's your personalized {generatedItinerary.totalDays}-day adventure in {generatedItinerary.destination.name}!
</p>
</motion.div>
</div>
</section>
{/* Main Content */}
<section className="py-8">
<div className="container mx-auto px-4">
<div className="max-w-6xl mx-auto space-y-8">
{/* View Toggle */}
<div className="flex justify-center">
<div className="bg-muted p-1 rounded-lg">
<Button
variant={viewMode === 'daily' ? 'default' : 'ghost'}
size="sm"
onClick={() => setViewMode('daily')}
className="rounded-md font-poppins font-medium"
>
Daily View
</Button>
<Button
variant={viewMode === 'summary' ? 'default' : 'ghost'}
size="sm"
onClick={() => setViewMode('summary')}
className="rounded-md font-poppins font-medium"
>
Summary
</Button>
</div>
</div>
{/* Itinerary Overview */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.2 }}
>
<Card className="p-6">
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="text-center">
<div className="font-merchant text-3xl text-primary mb-2">{generatedItinerary.totalDays}</div>
<div className="font-poppins text-sm text-muted-foreground font-normal">Days</div>
</div>
<div className="text-center">
<div className="font-merchant text-3xl text-primary mb-2">{generatedItinerary.includedActivities}</div>
<div className="font-poppins text-sm text-muted-foreground font-normal">Activities</div>
</div>
<div className="text-center">
<div className="font-merchant text-3xl text-primary mb-2">{generatedItinerary.estimatedCost}</div>
<div className="font-poppins text-sm text-muted-foreground font-normal">Estimated Cost</div>
</div>
</div>
</Card>
</motion.div>
{/* Daily Plans - Enhanced View */}
{viewMode === 'daily' && (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.3 }}
className="space-y-12"
>
{generatedItinerary.dailyPlans.map((day, dayIndex) => (
<div key={dayIndex} className="space-y-6">
{/* Location Header with Weather - Only show for first day or when city actually changes */}
{(() => {
// Get current day's destination (fallback to main destination if not specified)
const currentDestination = (day as any).destination || generatedItinerary.destination;
// Check if this is the first day
if (dayIndex === 0) return true;
// Check if destination changed from previous day
if (dayIndex > 0) {
const previousDay = generatedItinerary.dailyPlans[dayIndex - 1];
const previousDestination = (previousDay as any).destination || generatedItinerary.destination;
// Only show if city name is different
return currentDestination.name !== previousDestination.name;
}
return false;
})() && (
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.6, delay: 0.4 + dayIndex * 0.1 }}
className="bg-gray-50 rounded-2xl p-6 shadow-sm border border-gray-200"
>
<div className="flex items-center justify-between">
<div>
<h2 className="font-poppins text-3xl md:text-4xl leading-tight mb-2">
{((day as any).destination || generatedItinerary.destination).name}, {((day as any).destination || generatedItinerary.destination).country}
</h2>
<p className="font-poppins text-base text-primary font-medium">{((day as any).destination || generatedItinerary.destination).weather}</p>
</div>
<div className="flex items-center gap-2">
<Sun className="w-10 h-10 text-amber-500" />
</div>
</div>
</motion.div>
)}
{/* Day Header */}
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.6, delay: 0.5 + dayIndex * 0.1 }}
className="flex items-center gap-4 pl-2"
>
<div className="bg-gradient-to-br from-primary to-secondary text-white w-16 h-16 rounded-full flex items-center justify-center shadow-lg">
<span className="font-merchant text-2xl font-semibold">{day.day}</span>
</div>
<div>
<h3 className="font-merchant text-2xl md:text-3xl leading-snug font-semibold">Day {day.day}</h3>
<p className="font-poppins text-base text-muted-foreground font-normal">{day.title}</p>
</div>
</motion.div>
{/* GMT Label */}
<div className="pl-2">
<p className="font-poppins text-sm text-gray-500 font-normal">GMT</p>
</div>
{/* Activity Cards - Desktop Grid Layout */}
<div className="space-y-8">
{day.activities.map((activity, actIndex) => {
const activityKey = `day${day.day}-act${actIndex}`;
const isFavorite = favorites.has(activityKey);
return (
<motion.div
key={actIndex}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.6 + dayIndex * 0.1 + actIndex * 0.05 }}
className="flex gap-6"
>
{/* Time Column */}
<div className="flex-shrink-0 w-24 pt-2">
<div className="font-poppins text-base font-medium text-gray-700">{activity.time}</div>
</div>
{/* Activity Card */}
<div className="flex-1">
<Card className="overflow-hidden hover:shadow-xl transition-shadow duration-300 border-2 border-gray-100">
<CardContent className="p-0">
{/* Hero Image with Overlay Buttons */}
<div className="relative h-64 md:h-72 bg-gray-200">
<ImageWithFallback
src={activity.image}
alt={activity.activity}
className="w-full h-full object-cover"
/>
{/* Favorite Heart Button - Top Right */}
<div className="absolute top-4 right-4">
<Button
size="icon"
variant="secondary"
className="bg-white/95 hover:bg-white shadow-lg backdrop-blur-sm rounded-full w-12 h-12"
onClick={() => toggleFavorite(activityKey)}
>
<Heart className={`w-5 h-5 ${isFavorite ? 'fill-primary text-primary' : 'text-gray-700'}`} />
</Button>
</div>
{/* Get Directions Button - Bottom Left */}
<div className="absolute bottom-4 left-4">
<Button
className="bg-primary hover:bg-primary/90 text-white font-poppins font-semibold shadow-lg px-6 py-3 rounded-xl"
>
<Navigation className="w-4 h-4 mr-2" />
Get Directions
</Button>
</div>
</div>
{/* Content Section */}
<div className="p-6 space-y-4">
{/* Location Name & Address */}
<div className="space-y-2">
<h4 className="font-merchant text-xl md:text-2xl leading-snug font-semibold text-gray-900">
{activity.activity}
</h4>
<div className="flex items-start gap-2 text-gray-600">
<MapPin className="w-4 h-4 mt-1 flex-shrink-0 text-primary" />
<span className="font-poppins text-sm font-normal leading-relaxed">{activity.address}</span>
</div>
</div>
{/* Category Badges */}
<div className="flex flex-wrap gap-2">
{activity.categories.map((category, catIndex) => (
<Badge
key={catIndex}
variant="secondary"
className="font-poppins font-normal text-sm bg-primary/10 text-primary hover:bg-primary/20 px-3 py-1"
>
{category}
</Badge>
))}
</div>
{/* Activity Details - Bullet Points */}
<div className="space-y-2 pt-2">
{activity.description.map((detail, detailIndex) => (
<div key={detailIndex} className="flex items-start gap-3">
<span className="text-primary font-semibold mt-1.5 flex-shrink-0"></span>
<span className="font-poppins text-sm font-normal text-gray-600 leading-relaxed">{detail}</span>
</div>
))}
</div>
</div>
</CardContent>
</Card>
</div>
</motion.div>
);
})}
</div>
</div>
))}
</motion.div>
)}
{/* Summary View */}
{viewMode === 'summary' && (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.3 }}
className="space-y-4"
>
<h3 className="font-merchant text-2xl md:text-3xl text-center mb-8 leading-tight font-semibold">Trip Summary</h3>
<Card className="p-6">
<div className="space-y-6">
{generatedItinerary.dailyPlans.map((day, index) => (
<div key={index} className="border-l-4 border-primary pl-6">
<div className="flex items-center gap-2 mb-3">
<Calendar className="w-5 h-5 text-primary" />
<h4 className="font-merchant text-lg md:text-xl leading-snug font-semibold">Day {day.day}: {day.title}</h4>
</div>
<div className="space-y-2">
{day.activities.map((activity, actIndex) => (
<div key={actIndex} className="flex items-start gap-3 text-sm">
<CheckCircle className="w-4 h-4 text-green-500 flex-shrink-0 mt-0.5" />
<div className="flex-1">
<span className="font-poppins text-gray-700 font-medium">{activity.activity}</span>
<div className="flex items-center gap-2 mt-1">
<span className="font-poppins text-gray-500 text-xs font-normal">{activity.time}</span>
<span className="text-gray-400"></span>
<span className="font-poppins text-gray-500 text-xs font-normal">{activity.location}</span>
</div>
</div>
</div>
))}
</div>
</div>
))}
</div>
</Card>
</motion.div>
)}
{/* Action Buttons */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.5 }}
className="flex flex-col sm:flex-row gap-4 justify-center pt-8"
>
<Button
variant="outline"
onClick={onCreateItineraryClick}
className="font-poppins font-medium px-8 py-3 text-lg"
>
<Heart className="w-5 h-5 mr-2" />
Create Another
</Button>
<Button
className="bg-primary hover:bg-primary/90 font-poppins font-semibold px-8 py-3 text-lg"
>
<Download className="w-5 h-5 mr-2" />
Save Itinerary
</Button>
<Button
variant="outline"
className="font-poppins font-medium px-8 py-3 text-lg"
>
<Share2 className="w-5 h-5 mr-2" />
Share Trip
</Button>
</motion.div>
</div>
</div>
</section>
{/* Footer */}
<Footer
onHomeClick={onHomeClick}
onMelbourneClick={onMelbourneClick}
onPassesClick={onPassesClick}
onSignInClick={onSignInClick}
onAttractionsClick={onAttractionsClick}
onBlogsClick={onBlogsClick}
onHowItWorksClick={onHowItWorksClick}
onFAQClick={onFAQClick}
onPrivacyPolicyClick={onPrivacyPolicyClick}
onContactUsClick={onContactUsClick}
currentPage={currentPage}
/>
</div>
);
}