diff --git a/src/AppRouter.tsx b/src/AppRouter.tsx index e076e54..e345acc 100644 --- a/src/AppRouter.tsx +++ b/src/AppRouter.tsx @@ -39,6 +39,8 @@ 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 ItinerarySummaryPage from './pages/ItinerarySummaryPage'; // User type definition interface User { @@ -222,7 +224,12 @@ export function AppRouter({ } /> - + + + } /> + + } /> diff --git a/src/Redux/services/itinerary.service.ts b/src/Redux/services/itinerary.service.ts index f19723e..7934c46 100644 --- a/src/Redux/services/itinerary.service.ts +++ b/src/Redux/services/itinerary.service.ts @@ -1,5 +1,5 @@ -import { createApi} from "@reduxjs/toolkit/query/react"; +import { createApi } from "@reduxjs/toolkit/query/react"; import { baseQuery } from "../baseQuery"; export const itineraryApi = createApi({ @@ -8,7 +8,7 @@ export const itineraryApi = createApi({ endpoints: (builder) => ({ - + createMagicItinerary: builder.mutation({ query: (itineraryDetails) => ({ // keep the name of the variables being passed here same as when calling the mutation hook @@ -16,13 +16,18 @@ export const itineraryApi = createApi({ method: "POST", body: itineraryDetails }), - + }), - + getItineraryDetailsById: builder.query({ + query: (itineraryId: number) => `/website/itinerary/${itineraryId}`, + }), + + }) }); export const { useCreateMagicItineraryMutation, + useGetItineraryDetailsByIdQuery, } = itineraryApi; \ No newline at end of file diff --git a/src/pages/CreateMagicIternaryPageDesign.tsx b/src/pages/CreateMagicIternaryPageDesign.tsx index 7ae60d8..214a1f6 100644 --- a/src/pages/CreateMagicIternaryPageDesign.tsx +++ b/src/pages/CreateMagicIternaryPageDesign.tsx @@ -48,6 +48,7 @@ import MuseumSoundsGoodIcon from '../imports/NounRelax65970551-9923-633'; import MuseumLoveItIcon from '../imports/NounRelax65970551-9923-637'; import { useCreateMagicItineraryMutation } from '../Redux/services/itinerary.service'; import { toast } from 'sonner'; +import { useNavigate } from 'react-router-dom'; interface User { @@ -190,6 +191,8 @@ export function CreateMagicItineraryPageDesign({ const [selectedActivity, setSelectedActivity] = useState(null); const [createMagicItinerary] = useCreateMagicItineraryMutation(); + const navigate= useNavigate() + const toggleFavorite = (activityKey: string) => { setFavorites(prev => { const newSet = new Set(prev); @@ -259,6 +262,7 @@ export function CreateMagicItineraryPageDesign({ setGeneratedItinerary(response); setShowResults(true); toast.success("Itinerary created successfully!"); + navigate(`/itinerary-summary/${response?.data?.id}`) } catch (error) { console.error("Error creating itinerary:", error); toast.error("Failed to create itinerary. Please try again."); diff --git a/src/pages/ItinerarySummaryPage.tsx b/src/pages/ItinerarySummaryPage.tsx new file mode 100644 index 0000000..db4609c --- /dev/null +++ b/src/pages/ItinerarySummaryPage.tsx @@ -0,0 +1,331 @@ +import React, { useState } from 'react'; +import { motion, AnimatePresence } from 'motion/react'; +import { + MapPin, + Calendar, + ChevronDown, + Share2, + Download, + ChevronRight, +} from 'lucide-react'; +import { Button } from '../components/ui/button'; +import { Card, CardContent } from '../components/ui/card'; +import { ImageWithFallback } from '../components/figma/ImageWithFallback'; +import { useCreateMagicItineraryMutation, useGetItineraryDetailsByIdQuery } from '../Redux/services/itinerary.service'; +import { toast } from 'sonner'; +import { useNavigate, useParams } from 'react-router-dom'; + +const ItinerarySummaryPage = () => { + const [viewMode, setViewMode] = useState<'daily' | 'summary'>('daily'); + const [selectedDayTab, setSelectedDayTab] = useState(1); + const [selectedActivity, setSelectedActivity] = useState(null); + + const navigate = useNavigate(); + + const { itineraryId } = useParams() + const { data: itineraryDetails, isLoading: itineraryDetailsLoading } = useGetItineraryDetailsByIdQuery(itineraryId); + + const generatedItinerary = itineraryDetails ?? null; + const days = generatedItinerary?.days ?? []; + const summaries = generatedItinerary?.summary ?? []; + + const selectedDayPlan = days?.find((d: any) => d.dayNumber === selectedDayTab); + + + return ( + + {/* Title */} +
+

+ Your +

+

+ {generatedItinerary?.title} +

+
+ + {/* Trip Details Card */} +
+ {/* Background Image */} +
+ +
+
+

Your Trip

+

{generatedItinerary?.city}

+
+
+ {/* Stats Row */} +
+
+ {generatedItinerary?.totalDays} + Days +
+
+ {generatedItinerary?.totalStops} + Stops +
+
+ {generatedItinerary?.days[0]?.date} + Start Date +
+
+
+ + {/* Share & Download Buttons */} +
+ + +
+ + {/* View Toggle */} +
+
+ + +
+
+ + {/* Daily View */} + {viewMode === 'daily' && ( +
+ {/* Day Tabs */} +
+ {days?.map((day: any) => ( + + ))} + {days?.length > 4 && ( + + )} +
+ + {/* Activities for selected day */} + {selectedDayPlan && ( + + + {selectedDayPlan?.items?.map((activity: any, actIndex: number) => { + const activityKey = `day${selectedDayPlan.day}-act${actIndex}`; + + return ( + + {/* Time Label */} +

+ {activity.timeSlot} +

+ + {/* Activity Card */} + + + {/* Image */} +
+ + + {/* TODO: Get Directions Badge redirect it to lat,long */} +
+ +
+
+ + {/* Content */} +
+

+ {activity.title} +

+

+ {activity.locationName} +

+ + {/* Category Tags */} +
+ {activity.categories?.map((cat: string, ci: number) => ( + + {cat} + + ))} +
+ + {/* Bullet Points */} +
+ +
+ + {activity.description} +
+ +
+
+
+
+
+ ); + })} +
+
+ )} +
+ )} + + {/* Summary View */} + {viewMode === 'summary' && ( +
+ {days?.map((day: any, dayIndex: number) => { + const dayDate = days[0]?.date + ? new Date( + new Date(days[0].date).setDate( + new Date(days[0].date).getDate() + dayIndex + ) + ).toLocaleDateString('en-AU', { + day: '2-digit', + month: '2-digit', + year: 'numeric', + }) + : ''; + + // ✅ Find the matching summary for this day + const daySummary = summaries.find((s: any) => s.dayNumber === day.dayNumber); + + return ( +
+ {/* Day Header */} +
+

+ Day {day.dayNumber}: +

+
+ + {dayDate} +
+
+ + {/* Activity List */} +
+ {daySummary?.items?.map((item: any, actIndex: number) => { + const activityKey = `summary-day${day.dayNumber}-act${actIndex}`; + const isExpanded = selectedActivity === activityKey; + + return ( +
+
+ setSelectedActivity(isExpanded ? null : activityKey) + } + > +

+ {item.timeSlot}: {item.title} +

+ +
+ + + {isExpanded && ( + +
+
+ + + {item.description} + +
+ +
+
+ )} +
+
+ ); + })} +
+
+ ); + })} +
+ )} + + {/* Bottom Action */} +
+ +
+ + ); +} + +export default ItinerarySummaryPage \ No newline at end of file