From 3fc2887ad95df84dcc6b242a18ec88f7920d75c1 Mon Sep 17 00:00:00 2001 From: SelenatorXo Date: Fri, 18 Oct 2024 15:44:28 +0200 Subject: [PATCH 1/5] Update ItineraryForm.js --- .../src/components/dashboard/ItineraryForm.js | 99 ++++++++++++++++--- 1 file changed, 84 insertions(+), 15 deletions(-) diff --git a/ai-trip-creator/src/components/dashboard/ItineraryForm.js b/ai-trip-creator/src/components/dashboard/ItineraryForm.js index b466054..6c403b2 100644 --- a/ai-trip-creator/src/components/dashboard/ItineraryForm.js +++ b/ai-trip-creator/src/components/dashboard/ItineraryForm.js @@ -39,6 +39,7 @@ import { getDocs, setDoc, doc, + addDoc, } from "firebase/firestore"; import RefreshIcon from "@mui/icons-material/Refresh"; import OpenAI from "openai"; @@ -152,11 +153,12 @@ function ItineraryForm() { const [allSelectedFlights, setAllSelectedFlights] = useState([]); // New state to track all flights - + const [user, setUser] = useState(null); //fetch userid useEffect(() => { const auth = getAuth(); onAuthStateChanged(auth, (user) => { + setUser(user); if (user) { setUserId(user.uid); } @@ -676,6 +678,42 @@ function ItineraryForm() { setActiveStep((prevActiveStep) => prevActiveStep - 1); }; + async function createItinerary(itineraryName, destination, budget, numDays, listDays) { + const user_id = user.uid; + + try { + const itinerariesRef = collection(db, "ItineraryCollection"); + const newItineraryRef = await addDoc(itinerariesRef, { + user_id: user_id, + itineraryName: itineraryName, + destination: destination, + budget: budget, + numDays: numDays, + createdAt: new Date().toISOString().split("T")[0], + }); + + const daysRef = collection(newItineraryRef, 'days'); + await Promise.all(listDays.map(async (day) => { + const dayData = { + dayNumber: day.dayNumber, + flights: day.flights || [], + accommodation: day.accommodation || [], + activities: day.activities.map(activity => ({ + name: activity.name, + time: activity.time, + description: activity.description || `Activity: ${activity.name} scheduled at ${activity.time}.` + })) || [] + }; + const dayDocRef = doc(daysRef, `day${day.dayNumber}`); + await setDoc(dayDocRef, dayData); + })); + + } catch (error) { + console.error('Error creating itinerary:', error); + } + } + + const generateItinerary = async () => { try { setLoading(true); @@ -714,30 +752,60 @@ function ItineraryForm() { } }; + // const handleFinish = async () => { + // try { + // setLoading(true); + + // // Generate day-by-day data for the itinerary + // const days = Locations.map((location, index) => { + // const dayLength = Lengths[index] || 1; + // const activities = selectedActivities.filter( + // (activity) => + // activity.day >= index + 1 && activity.day < index + 1 + dayLength, + // ); + + // return { + // dayNumber: index + 1, + // location, + // length: dayLength, + // accommodation: selectedAccommodations[index] + // ? [selectedAccommodations[index]] + // : [], + // activities, + // }; + // }); + + // // await createItinerary(itineraryName, Locations[0], budgetRange, days.length, days); + // setLoading(false); + // alert("Itinerary saved successfully!"); + // console.log("Itinerary saved successfully!"); + // } catch (error) { + // console.error("Error saving itinerary:", error); + // setErrorMessage("Failed to save itinerary. Please try again."); + // setLoading(false); + // } + // }; + const handleFinish = async () => { try { setLoading(true); - + // Generate day-by-day data for the itinerary const days = Locations.map((location, index) => { const dayLength = Lengths[index] || 1; - const activities = selectedActivities.filter( - (activity) => - activity.day >= index + 1 && activity.day < index + 1 + dayLength, - ); - + + // Structure each day's data return { dayNumber: index + 1, - location, - length: dayLength, - accommodation: selectedAccommodations[index] - ? [selectedAccommodations[index]] - : [], - activities, + flights: allSelectedFlights.filter(flight => flight.itineraries[0].segments[0].arrival.iataCode === location) || [], + accommodation: selectedAccommodations[index] ? [selectedAccommodations[index]] : [], + activities: selectedActivities.filter(activity => activity.day >= index + 1 && activity.day < index + 1 + dayLength) || [] }; }); - - // await createItinerary(itineraryName, Locations[0], budgetRange, days.length, days); + + // Call the createItinerary function from dashboard.js to save the itinerary + await createItinerary(itineraryName, Locations[0], budgetRange, days.length, days); + setLoading(false); alert("Itinerary saved successfully!"); console.log("Itinerary saved successfully!"); @@ -747,6 +815,7 @@ function ItineraryForm() { setLoading(false); } }; + //filtering for accommodations // Toggle the visibility of accommodations for a specific location From adb1cf236b703abf13360606637acf5f4ec7d195 Mon Sep 17 00:00:00 2001 From: SelenatorXo Date: Fri, 18 Oct 2024 15:48:21 +0200 Subject: [PATCH 2/5] Update SavedItineraries.js --- .../components/dashboard/SavedItineraries.js | 298 +++++++++++++----- 1 file changed, 223 insertions(+), 75 deletions(-) diff --git a/ai-trip-creator/src/components/dashboard/SavedItineraries.js b/ai-trip-creator/src/components/dashboard/SavedItineraries.js index f7751d4..0efdeab 100644 --- a/ai-trip-creator/src/components/dashboard/SavedItineraries.js +++ b/ai-trip-creator/src/components/dashboard/SavedItineraries.js @@ -1,97 +1,245 @@ +// import React, { useState, useEffect } from "react"; +// import { +// Box, +// Typography, +// Card, +// CardContent, +// TextField, +// Button, +// Avatar, +// CircularProgress, +// FormControl, +// ToggleButton, +// ToggleButtonGroup, +// List, +// ListItem, +// Container, +// Paper, +// Grid, +// Drawer, +// useTheme, +// useMediaQuery, +// Dialog, +// DialogTitle, +// DialogContent, +// DialogActions, +// IconButton, +// CardMedia, +// Slider, +// } from "@mui/material"; +// import DeleteIcon from '@mui/icons-material/Delete'; +// import Carousel from 'react-material-ui-carousel'; +// import Sidebar from "./sidebar"; +// import { getAuth, onAuthStateChanged } from "firebase/auth"; +// import { +// doc, +// getDoc, +// setDoc, +// collection, +// getDocs, +// query, +// where, +// deleteDoc, +// } from "firebase/firestore"; +// import { db } from "../../firebase/firebase-config"; +// import "./dashboard.css"; +// import ReactMarkdown from "react-markdown"; +// import remarkGfm from "remark-gfm"; + +// const SavedItineraries = () => { +// const theme = useTheme(); +// const isDarkMode = theme.palette.mode === "dark"; +// const auth = getAuth(); +// const isSmUp = useMediaQuery(theme.breakpoints.up("sm")); + +// return ( +// +// {/* Sidebar */} +// +// +// + +// {/* Main Content */} +// +// +// {/* Apply the same style as other headings */} +//

Saved Itineraries

+ +// +// +// +// +// You don't have any saved itineraries yet. +// +// +// +// +//
+//
+//
+// ); +// }; + +// export default SavedItineraries; + import React, { useState, useEffect } from "react"; import { Box, Typography, Card, CardContent, - TextField, - Button, - Avatar, - CircularProgress, - FormControl, - ToggleButton, - ToggleButtonGroup, - List, - ListItem, Container, Paper, Grid, Drawer, useTheme, useMediaQuery, - Dialog, - DialogTitle, - DialogContent, - DialogActions, - IconButton, - CardMedia, - Slider, + CircularProgress, } from "@mui/material"; -import DeleteIcon from '@mui/icons-material/Delete'; -import Carousel from 'react-material-ui-carousel'; import Sidebar from "./sidebar"; import { getAuth, onAuthStateChanged } from "firebase/auth"; -import { - doc, - getDoc, - setDoc, - collection, - getDocs, - query, - where, - deleteDoc, -} from "firebase/firestore"; +import { collection, getDocs, query, where } from "firebase/firestore"; import { db } from "../../firebase/firebase-config"; -import "./dashboard.css"; -import ReactMarkdown from "react-markdown"; -import remarkGfm from "remark-gfm"; const SavedItineraries = () => { - const theme = useTheme(); - const isDarkMode = theme.palette.mode === "dark"; + const theme = useTheme(); + const isDarkMode = theme.palette.mode === "dark"; + const isSmUp = useMediaQuery(theme.breakpoints.up("sm")); + const [userId, setUserId] = useState(null); + const [itineraries, setItineraries] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(""); + + useEffect(() => { + // Get the currently authenticated user const auth = getAuth(); - const isSmUp = useMediaQuery(theme.breakpoints.up("sm")); + onAuthStateChanged(auth, async (user) => { + if (user) { + setUserId(user.uid); + await fetchSavedItineraries(user.uid); + } else { + setLoading(false); + setError("No user authenticated"); + } + }); + }, []); - return ( - - {/* Sidebar */} - - - - - {/* Main Content */} - - - {/* Apply the same style as other headings */} -

Saved Itineraries

- - - - - - You don't have any saved itineraries yet. - - - - -
-
-
- ); + // Fetch itineraries from Firestore for the authenticated user + const fetchSavedItineraries = async (uid) => { + try { + const itinerariesRef = collection(db, "ItineraryCollection"); + const q = query(itinerariesRef, where("user_id", "==", uid)); + const querySnapshot = await getDocs(q); + const fetchedItineraries = querySnapshot.docs.map((doc) => ({ + id: doc.id, + ...doc.data(), + })); + + setItineraries(fetchedItineraries); + } catch (error) { + console.error("Error fetching itineraries: ", error); + setError("Failed to load itineraries"); + } finally { + setLoading(false); + } }; -export default SavedItineraries; \ No newline at end of file + // Render saved itineraries + return ( + + {/* Sidebar */} + + + + + {/* Main Content */} + + +

Saved Itineraries

+ + {loading ? ( + + + + ) : error ? ( + {error} + ) : itineraries.length === 0 ? ( + You don't have any saved itineraries yet. + ) : ( + + {itineraries.map((itinerary) => ( + + + + + + {itinerary.itineraryName} + + + Destination: {itinerary.destination} + + + Budget: {itinerary.budget} ZAR + + + Number of Days: {itinerary.numDays} + + + Activities: + {itinerary.days.map((day, index) => ( +
+ Day {day.dayNumber}:{" "} + {day.activities.length > 0 + ? day.activities.map( + (activity, actIndex) => ( +
  • + {activity.name} at {activity.time} +
  • + ) + ) + : "No activities"} +
    + ))} +
    +
    +
    +
    +
    + ))} +
    + )} +
    +
    +
    + ); +}; + +export default SavedItineraries; From 0439e3dc2e073242b5f1c53bc5427abd9fbfd823 Mon Sep 17 00:00:00 2001 From: SelenatorXo Date: Fri, 18 Oct 2024 15:52:18 +0200 Subject: [PATCH 3/5] Update SavedItineraries.js --- .../components/dashboard/SavedItineraries.js | 329 +++++++++++++----- 1 file changed, 241 insertions(+), 88 deletions(-) diff --git a/ai-trip-creator/src/components/dashboard/SavedItineraries.js b/ai-trip-creator/src/components/dashboard/SavedItineraries.js index 0efdeab..39dc56f 100644 --- a/ai-trip-creator/src/components/dashboard/SavedItineraries.js +++ b/ai-trip-creator/src/components/dashboard/SavedItineraries.js @@ -1,99 +1,247 @@ +// // import React, { useState, useEffect } from "react"; +// // import { +// // Box, +// // Typography, +// // Card, +// // CardContent, +// // TextField, +// // Button, +// // Avatar, +// // CircularProgress, +// // FormControl, +// // ToggleButton, +// // ToggleButtonGroup, +// // List, +// // ListItem, +// // Container, +// // Paper, +// // Grid, +// // Drawer, +// // useTheme, +// // useMediaQuery, +// // Dialog, +// // DialogTitle, +// // DialogContent, +// // DialogActions, +// // IconButton, +// // CardMedia, +// // Slider, +// // } from "@mui/material"; +// // import DeleteIcon from '@mui/icons-material/Delete'; +// // import Carousel from 'react-material-ui-carousel'; +// // import Sidebar from "./sidebar"; +// // import { getAuth, onAuthStateChanged } from "firebase/auth"; +// // import { +// // doc, +// // getDoc, +// // setDoc, +// // collection, +// // getDocs, +// // query, +// // where, +// // deleteDoc, +// // } from "firebase/firestore"; +// // import { db } from "../../firebase/firebase-config"; +// // import "./dashboard.css"; +// // import ReactMarkdown from "react-markdown"; +// // import remarkGfm from "remark-gfm"; + +// // const SavedItineraries = () => { +// // const theme = useTheme(); +// // const isDarkMode = theme.palette.mode === "dark"; +// // const auth = getAuth(); +// // const isSmUp = useMediaQuery(theme.breakpoints.up("sm")); + +// // return ( +// // +// // {/* Sidebar */} +// // +// // +// // + +// // {/* Main Content */} +// // +// // +// // {/* Apply the same style as other headings */} +// //

    Saved Itineraries

    + +// // +// // +// // +// // +// // You don't have any saved itineraries yet. +// // +// // +// // +// // +// //
    +// //
    +// //
    +// // ); +// // }; + +// // export default SavedItineraries; + // import React, { useState, useEffect } from "react"; // import { // Box, // Typography, // Card, // CardContent, -// TextField, -// Button, -// Avatar, -// CircularProgress, -// FormControl, -// ToggleButton, -// ToggleButtonGroup, -// List, -// ListItem, // Container, // Paper, // Grid, // Drawer, // useTheme, // useMediaQuery, -// Dialog, -// DialogTitle, -// DialogContent, -// DialogActions, -// IconButton, -// CardMedia, -// Slider, +// CircularProgress, // } from "@mui/material"; -// import DeleteIcon from '@mui/icons-material/Delete'; -// import Carousel from 'react-material-ui-carousel'; // import Sidebar from "./sidebar"; // import { getAuth, onAuthStateChanged } from "firebase/auth"; -// import { -// doc, -// getDoc, -// setDoc, -// collection, -// getDocs, -// query, -// where, -// deleteDoc, -// } from "firebase/firestore"; +// import { collection, getDocs, query, where } from "firebase/firestore"; // import { db } from "../../firebase/firebase-config"; -// import "./dashboard.css"; -// import ReactMarkdown from "react-markdown"; -// import remarkGfm from "remark-gfm"; // const SavedItineraries = () => { -// const theme = useTheme(); -// const isDarkMode = theme.palette.mode === "dark"; +// const theme = useTheme(); +// const isDarkMode = theme.palette.mode === "dark"; +// const isSmUp = useMediaQuery(theme.breakpoints.up("sm")); +// const [userId, setUserId] = useState(null); +// const [itineraries, setItineraries] = useState([]); +// const [loading, setLoading] = useState(true); +// const [error, setError] = useState(""); + +// useEffect(() => { +// // Get the currently authenticated user // const auth = getAuth(); -// const isSmUp = useMediaQuery(theme.breakpoints.up("sm")); - -// return ( -// -// {/* Sidebar */} -// -// -// - -// {/* Main Content */} -// -// -// {/* Apply the same style as other headings */} -//

    Saved Itineraries

    - -// -// -// -// -// You don't have any saved itineraries yet. -// -// -// -// -//
    -//
    -//
    -// ); +// onAuthStateChanged(auth, async (user) => { +// if (user) { +// setUserId(user.uid); +// await fetchSavedItineraries(user.uid); +// } else { +// setLoading(false); +// setError("No user authenticated"); +// } +// }); +// }, []); + +// // Fetch itineraries from Firestore for the authenticated user +// const fetchSavedItineraries = async (uid) => { +// try { +// const itinerariesRef = collection(db, "ItineraryCollection"); +// const q = query(itinerariesRef, where("user_id", "==", uid)); +// const querySnapshot = await getDocs(q); +// const fetchedItineraries = querySnapshot.docs.map((doc) => ({ +// id: doc.id, +// ...doc.data(), +// })); + +// setItineraries(fetchedItineraries); +// } catch (error) { +// console.error("Error fetching itineraries: ", error); +// setError("Failed to load itineraries"); +// } finally { +// setLoading(false); +// } // }; +// // Render saved itineraries +// return ( +// +// {/* Sidebar */} +// +// +// + +// {/* Main Content */} +// +// +//

    Saved Itineraries

    + +// {loading ? ( +// +// +// +// ) : error ? ( +// {error} +// ) : itineraries.length === 0 ? ( +// You don't have any saved itineraries yet. +// ) : ( +// +// {itineraries.map((itinerary) => ( +// +// +// +// +// +// {itinerary.itineraryName} +// +// +// Destination: {itinerary.destination} +// +// +// Budget: {itinerary.budget} ZAR +// +// +// Number of Days: {itinerary.numDays} +// +// +// Activities: +// {itinerary.days.map((day, index) => ( +//
    +// Day {day.dayNumber}:{" "} +// {day.activities.length > 0 +// ? day.activities.map( +// (activity, actIndex) => ( +//
  • +// {activity.name} at {activity.time} +//
  • +// ) +// ) +// : "No activities"} +//
    +// ))} +//
    +//
    +//
    +//
    +//
    +// ))} +//
    +// )} +//
    +//
    +//
    +// ); +// }; + // export default SavedItineraries; import React, { useState, useEffect } from "react"; @@ -120,12 +268,11 @@ const SavedItineraries = () => { const isDarkMode = theme.palette.mode === "dark"; const isSmUp = useMediaQuery(theme.breakpoints.up("sm")); const [userId, setUserId] = useState(null); - const [itineraries, setItineraries] = useState([]); + const [itineraries, setItineraries] = useState([]); // Initialize as an empty array const [loading, setLoading] = useState(true); const [error, setError] = useState(""); useEffect(() => { - // Get the currently authenticated user const auth = getAuth(); onAuthStateChanged(auth, async (user) => { if (user) { @@ -149,7 +296,7 @@ const SavedItineraries = () => { ...doc.data(), })); - setItineraries(fetchedItineraries); + setItineraries(fetchedItineraries); // Set fetched itineraries } catch (error) { console.error("Error fetching itineraries: ", error); setError("Failed to load itineraries"); @@ -158,7 +305,6 @@ const SavedItineraries = () => { } }; - // Render saved itineraries return ( {/* Sidebar */} @@ -180,7 +326,7 @@ const SavedItineraries = () => { flexGrow={1} p={3} sx={{ ml: isSmUp ? "240px" : "0", overflowX: "hidden" }} - className="content" // Applying the content class from the CSS + className="content" >

    Saved Itineraries

    @@ -214,20 +360,27 @@ const SavedItineraries = () => { Activities: - {itinerary.days.map((day, index) => ( -
    - Day {day.dayNumber}:{" "} - {day.activities.length > 0 - ? day.activities.map( + {/* Handle undefined or empty days array */} + {itinerary.days && itinerary.days.length > 0 ? ( + itinerary.days.map((day, index) => ( +
    + Day {day.dayNumber}:{" "} + {day.activities && day.activities.length > 0 ? ( + day.activities.map( (activity, actIndex) => (
  • {activity.name} at {activity.time}
  • ) ) - : "No activities"} -
    - ))} + ) : ( +
  • No activities
  • + )} +
    + )) + ) : ( +
    No days available
    + )}
    From 183bd39d414c7e17018a6af6894ad0841db07be0 Mon Sep 17 00:00:00 2001 From: SelenatorXo Date: Fri, 18 Oct 2024 15:53:38 +0200 Subject: [PATCH 4/5] Update SavedItineraries.js --- .../components/dashboard/SavedItineraries.js | 430 +++++++++++++----- 1 file changed, 324 insertions(+), 106 deletions(-) diff --git a/ai-trip-creator/src/components/dashboard/SavedItineraries.js b/ai-trip-creator/src/components/dashboard/SavedItineraries.js index 39dc56f..423bfe1 100644 --- a/ai-trip-creator/src/components/dashboard/SavedItineraries.js +++ b/ai-trip-creator/src/components/dashboard/SavedItineraries.js @@ -1,99 +1,247 @@ +// // // import React, { useState, useEffect } from "react"; +// // // import { +// // // Box, +// // // Typography, +// // // Card, +// // // CardContent, +// // // TextField, +// // // Button, +// // // Avatar, +// // // CircularProgress, +// // // FormControl, +// // // ToggleButton, +// // // ToggleButtonGroup, +// // // List, +// // // ListItem, +// // // Container, +// // // Paper, +// // // Grid, +// // // Drawer, +// // // useTheme, +// // // useMediaQuery, +// // // Dialog, +// // // DialogTitle, +// // // DialogContent, +// // // DialogActions, +// // // IconButton, +// // // CardMedia, +// // // Slider, +// // // } from "@mui/material"; +// // // import DeleteIcon from '@mui/icons-material/Delete'; +// // // import Carousel from 'react-material-ui-carousel'; +// // // import Sidebar from "./sidebar"; +// // // import { getAuth, onAuthStateChanged } from "firebase/auth"; +// // // import { +// // // doc, +// // // getDoc, +// // // setDoc, +// // // collection, +// // // getDocs, +// // // query, +// // // where, +// // // deleteDoc, +// // // } from "firebase/firestore"; +// // // import { db } from "../../firebase/firebase-config"; +// // // import "./dashboard.css"; +// // // import ReactMarkdown from "react-markdown"; +// // // import remarkGfm from "remark-gfm"; + +// // // const SavedItineraries = () => { +// // // const theme = useTheme(); +// // // const isDarkMode = theme.palette.mode === "dark"; +// // // const auth = getAuth(); +// // // const isSmUp = useMediaQuery(theme.breakpoints.up("sm")); + +// // // return ( +// // // +// // // {/* Sidebar */} +// // // +// // // +// // // + +// // // {/* Main Content */} +// // // +// // // +// // // {/* Apply the same style as other headings */} +// // //

    Saved Itineraries

    + +// // // +// // // +// // // +// // // +// // // You don't have any saved itineraries yet. +// // // +// // // +// // // +// // // +// // //
    +// // //
    +// // //
    +// // // ); +// // // }; + +// // // export default SavedItineraries; + // // import React, { useState, useEffect } from "react"; // // import { // // Box, // // Typography, // // Card, // // CardContent, -// // TextField, -// // Button, -// // Avatar, -// // CircularProgress, -// // FormControl, -// // ToggleButton, -// // ToggleButtonGroup, -// // List, -// // ListItem, // // Container, // // Paper, // // Grid, // // Drawer, // // useTheme, // // useMediaQuery, -// // Dialog, -// // DialogTitle, -// // DialogContent, -// // DialogActions, -// // IconButton, -// // CardMedia, -// // Slider, +// // CircularProgress, // // } from "@mui/material"; -// // import DeleteIcon from '@mui/icons-material/Delete'; -// // import Carousel from 'react-material-ui-carousel'; // // import Sidebar from "./sidebar"; // // import { getAuth, onAuthStateChanged } from "firebase/auth"; -// // import { -// // doc, -// // getDoc, -// // setDoc, -// // collection, -// // getDocs, -// // query, -// // where, -// // deleteDoc, -// // } from "firebase/firestore"; +// // import { collection, getDocs, query, where } from "firebase/firestore"; // // import { db } from "../../firebase/firebase-config"; -// // import "./dashboard.css"; -// // import ReactMarkdown from "react-markdown"; -// // import remarkGfm from "remark-gfm"; // // const SavedItineraries = () => { -// // const theme = useTheme(); -// // const isDarkMode = theme.palette.mode === "dark"; +// // const theme = useTheme(); +// // const isDarkMode = theme.palette.mode === "dark"; +// // const isSmUp = useMediaQuery(theme.breakpoints.up("sm")); +// // const [userId, setUserId] = useState(null); +// // const [itineraries, setItineraries] = useState([]); +// // const [loading, setLoading] = useState(true); +// // const [error, setError] = useState(""); + +// // useEffect(() => { +// // // Get the currently authenticated user // // const auth = getAuth(); -// // const isSmUp = useMediaQuery(theme.breakpoints.up("sm")); - -// // return ( -// // -// // {/* Sidebar */} -// // -// // -// // - -// // {/* Main Content */} -// // -// // -// // {/* Apply the same style as other headings */} -// //

    Saved Itineraries

    - -// // -// // -// // -// // -// // You don't have any saved itineraries yet. -// // -// // -// // -// // -// //
    -// //
    -// //
    -// // ); +// // onAuthStateChanged(auth, async (user) => { +// // if (user) { +// // setUserId(user.uid); +// // await fetchSavedItineraries(user.uid); +// // } else { +// // setLoading(false); +// // setError("No user authenticated"); +// // } +// // }); +// // }, []); + +// // // Fetch itineraries from Firestore for the authenticated user +// // const fetchSavedItineraries = async (uid) => { +// // try { +// // const itinerariesRef = collection(db, "ItineraryCollection"); +// // const q = query(itinerariesRef, where("user_id", "==", uid)); +// // const querySnapshot = await getDocs(q); +// // const fetchedItineraries = querySnapshot.docs.map((doc) => ({ +// // id: doc.id, +// // ...doc.data(), +// // })); + +// // setItineraries(fetchedItineraries); +// // } catch (error) { +// // console.error("Error fetching itineraries: ", error); +// // setError("Failed to load itineraries"); +// // } finally { +// // setLoading(false); +// // } // // }; +// // // Render saved itineraries +// // return ( +// // +// // {/* Sidebar */} +// // +// // +// // + +// // {/* Main Content */} +// // +// // +// //

    Saved Itineraries

    + +// // {loading ? ( +// // +// // +// // +// // ) : error ? ( +// // {error} +// // ) : itineraries.length === 0 ? ( +// // You don't have any saved itineraries yet. +// // ) : ( +// // +// // {itineraries.map((itinerary) => ( +// // +// // +// // +// // +// // +// // {itinerary.itineraryName} +// // +// // +// // Destination: {itinerary.destination} +// // +// // +// // Budget: {itinerary.budget} ZAR +// // +// // +// // Number of Days: {itinerary.numDays} +// // +// // +// // Activities: +// // {itinerary.days.map((day, index) => ( +// //
    +// // Day {day.dayNumber}:{" "} +// // {day.activities.length > 0 +// // ? day.activities.map( +// // (activity, actIndex) => ( +// //
  • +// // {activity.name} at {activity.time} +// //
  • +// // ) +// // ) +// // : "No activities"} +// //
    +// // ))} +// //
    +// //
    +// //
    +// //
    +// //
    +// // ))} +// //
    +// // )} +// //
    +// //
    +// //
    +// // ); +// // }; + // // export default SavedItineraries; // import React, { useState, useEffect } from "react"; @@ -120,12 +268,11 @@ // const isDarkMode = theme.palette.mode === "dark"; // const isSmUp = useMediaQuery(theme.breakpoints.up("sm")); // const [userId, setUserId] = useState(null); -// const [itineraries, setItineraries] = useState([]); +// const [itineraries, setItineraries] = useState([]); // Initialize as an empty array // const [loading, setLoading] = useState(true); // const [error, setError] = useState(""); // useEffect(() => { -// // Get the currently authenticated user // const auth = getAuth(); // onAuthStateChanged(auth, async (user) => { // if (user) { @@ -149,7 +296,7 @@ // ...doc.data(), // })); -// setItineraries(fetchedItineraries); +// setItineraries(fetchedItineraries); // Set fetched itineraries // } catch (error) { // console.error("Error fetching itineraries: ", error); // setError("Failed to load itineraries"); @@ -158,7 +305,6 @@ // } // }; -// // Render saved itineraries // return ( // // {/* Sidebar */} @@ -180,7 +326,7 @@ // flexGrow={1} // p={3} // sx={{ ml: isSmUp ? "240px" : "0", overflowX: "hidden" }} -// className="content" // Applying the content class from the CSS +// className="content" // > // //

    Saved Itineraries

    @@ -214,20 +360,27 @@ // // // Activities: -// {itinerary.days.map((day, index) => ( -//
    -// Day {day.dayNumber}:{" "} -// {day.activities.length > 0 -// ? day.activities.map( +// {/* Handle undefined or empty days array */} +// {itinerary.days && itinerary.days.length > 0 ? ( +// itinerary.days.map((day, index) => ( +//
    +// Day {day.dayNumber}:{" "} +// {day.activities && day.activities.length > 0 ? ( +// day.activities.map( // (activity, actIndex) => ( //
  • // {activity.name} at {activity.time} //
  • // ) // ) -// : "No activities"} -//
    -// ))} +// ) : ( +//
  • No activities
  • +// )} +//
    +// )) +// ) : ( +//
    No days available
    +// )} //
    // // @@ -260,7 +413,7 @@ import { } from "@mui/material"; import Sidebar from "./sidebar"; import { getAuth, onAuthStateChanged } from "firebase/auth"; -import { collection, getDocs, query, where } from "firebase/firestore"; +import { collection, getDocs, query, where, doc, collectionGroup } from "firebase/firestore"; import { db } from "../../firebase/firebase-config"; const SavedItineraries = () => { @@ -291,10 +444,26 @@ const SavedItineraries = () => { const itinerariesRef = collection(db, "ItineraryCollection"); const q = query(itinerariesRef, where("user_id", "==", uid)); const querySnapshot = await getDocs(q); - const fetchedItineraries = querySnapshot.docs.map((doc) => ({ - id: doc.id, - ...doc.data(), - })); + + const fetchedItineraries = await Promise.all( + querySnapshot.docs.map(async (doc) => { + const itineraryData = doc.data(); + + // Fetch the days sub-collection for each itinerary + const daysRef = collection(doc.ref, "days"); + const daysSnapshot = await getDocs(daysRef); + const days = daysSnapshot.docs.map((dayDoc) => ({ + id: dayDoc.id, + ...dayDoc.data(), + })); + + return { + id: doc.id, + ...itineraryData, + days, // Attach the fetched days + }; + }) + ); setItineraries(fetchedItineraries); // Set fetched itineraries } catch (error) { @@ -359,27 +528,76 @@ const SavedItineraries = () => { Number of Days: {itinerary.numDays} - Activities: - {/* Handle undefined or empty days array */} + Day-by-Day Details: + {/* Display each day */} {itinerary.days && itinerary.days.length > 0 ? ( itinerary.days.map((day, index) => (
    - Day {day.dayNumber}:{" "} - {day.activities && day.activities.length > 0 ? ( - day.activities.map( - (activity, actIndex) => ( -
  • - {activity.name} at {activity.time} + + Day {day.dayNumber} + + + {/* Flights */} + {day.flights && day.flights.length > 0 && ( + <> + + Flights: + + {day.flights.map((flight, flightIndex) => ( +
  • + {flight.flightNumber} - Departs:{" "} + {flight.departure}, Arrives:{" "} + {flight.arrival}
  • - ) - ) - ) : ( -
  • No activities
  • + ))} + )} + + {/* Accommodations */} + {day.accommodation && + day.accommodation.length > 0 && ( + <> + + Accommodation: + + {day.accommodation.map( + (acc, accIndex) => ( +
  • + {acc.name} - Check-in:{" "} + {acc.checkin || "N/A"}, Checkout:{" "} + {acc.checkout || "N/A"} +
  • + ) + )} + + )} + + {/* Activities */} + {day.activities && + day.activities.length > 0 && ( + <> + + Activities: + + {day.activities.map( + (activity, actIndex) => ( +
  • + {activity.name} at {activity.time} +
  • + ) + )} + + )}
    )) ) : ( -
    No days available
    + No days available )}
    From 2f3cfb1157c28828a66191c5624baef898d21b42 Mon Sep 17 00:00:00 2001 From: SelenatorXo Date: Fri, 18 Oct 2024 16:03:06 +0200 Subject: [PATCH 5/5] Update saved itineraries --- .../src/components/dashboard/ItineraryForm.js | 2 +- .../components/dashboard/SavedItineraries.js | 495 ++++++++++++++---- 2 files changed, 380 insertions(+), 117 deletions(-) diff --git a/ai-trip-creator/src/components/dashboard/ItineraryForm.js b/ai-trip-creator/src/components/dashboard/ItineraryForm.js index 6c403b2..8b113f4 100644 --- a/ai-trip-creator/src/components/dashboard/ItineraryForm.js +++ b/ai-trip-creator/src/components/dashboard/ItineraryForm.js @@ -557,7 +557,7 @@ function ItineraryForm() { // Fetch activities for each end location await Promise.all( Locations.map(async (location) => { - const accommodationsRef = collection(db, "LikedActivities"); + const accommodationsRef = collection(db, "Activities"); const q = firestoreQuery( accommodationsRef, where( diff --git a/ai-trip-creator/src/components/dashboard/SavedItineraries.js b/ai-trip-creator/src/components/dashboard/SavedItineraries.js index 423bfe1..361a25b 100644 --- a/ai-trip-creator/src/components/dashboard/SavedItineraries.js +++ b/ai-trip-creator/src/components/dashboard/SavedItineraries.js @@ -1,99 +1,247 @@ +// // // // import React, { useState, useEffect } from "react"; +// // // // import { +// // // // Box, +// // // // Typography, +// // // // Card, +// // // // CardContent, +// // // // TextField, +// // // // Button, +// // // // Avatar, +// // // // CircularProgress, +// // // // FormControl, +// // // // ToggleButton, +// // // // ToggleButtonGroup, +// // // // List, +// // // // ListItem, +// // // // Container, +// // // // Paper, +// // // // Grid, +// // // // Drawer, +// // // // useTheme, +// // // // useMediaQuery, +// // // // Dialog, +// // // // DialogTitle, +// // // // DialogContent, +// // // // DialogActions, +// // // // IconButton, +// // // // CardMedia, +// // // // Slider, +// // // // } from "@mui/material"; +// // // // import DeleteIcon from '@mui/icons-material/Delete'; +// // // // import Carousel from 'react-material-ui-carousel'; +// // // // import Sidebar from "./sidebar"; +// // // // import { getAuth, onAuthStateChanged } from "firebase/auth"; +// // // // import { +// // // // doc, +// // // // getDoc, +// // // // setDoc, +// // // // collection, +// // // // getDocs, +// // // // query, +// // // // where, +// // // // deleteDoc, +// // // // } from "firebase/firestore"; +// // // // import { db } from "../../firebase/firebase-config"; +// // // // import "./dashboard.css"; +// // // // import ReactMarkdown from "react-markdown"; +// // // // import remarkGfm from "remark-gfm"; + +// // // // const SavedItineraries = () => { +// // // // const theme = useTheme(); +// // // // const isDarkMode = theme.palette.mode === "dark"; +// // // // const auth = getAuth(); +// // // // const isSmUp = useMediaQuery(theme.breakpoints.up("sm")); + +// // // // return ( +// // // // +// // // // {/* Sidebar */} +// // // // +// // // // +// // // // + +// // // // {/* Main Content */} +// // // // +// // // // +// // // // {/* Apply the same style as other headings */} +// // // //

    Saved Itineraries

    + +// // // // +// // // // +// // // // +// // // // +// // // // You don't have any saved itineraries yet. +// // // // +// // // // +// // // // +// // // // +// // // //
    +// // // //
    +// // // //
    +// // // // ); +// // // // }; + +// // // // export default SavedItineraries; + // // // import React, { useState, useEffect } from "react"; // // // import { // // // Box, // // // Typography, // // // Card, // // // CardContent, -// // // TextField, -// // // Button, -// // // Avatar, -// // // CircularProgress, -// // // FormControl, -// // // ToggleButton, -// // // ToggleButtonGroup, -// // // List, -// // // ListItem, // // // Container, // // // Paper, // // // Grid, // // // Drawer, // // // useTheme, // // // useMediaQuery, -// // // Dialog, -// // // DialogTitle, -// // // DialogContent, -// // // DialogActions, -// // // IconButton, -// // // CardMedia, -// // // Slider, +// // // CircularProgress, // // // } from "@mui/material"; -// // // import DeleteIcon from '@mui/icons-material/Delete'; -// // // import Carousel from 'react-material-ui-carousel'; // // // import Sidebar from "./sidebar"; // // // import { getAuth, onAuthStateChanged } from "firebase/auth"; -// // // import { -// // // doc, -// // // getDoc, -// // // setDoc, -// // // collection, -// // // getDocs, -// // // query, -// // // where, -// // // deleteDoc, -// // // } from "firebase/firestore"; +// // // import { collection, getDocs, query, where } from "firebase/firestore"; // // // import { db } from "../../firebase/firebase-config"; -// // // import "./dashboard.css"; -// // // import ReactMarkdown from "react-markdown"; -// // // import remarkGfm from "remark-gfm"; // // // const SavedItineraries = () => { -// // // const theme = useTheme(); -// // // const isDarkMode = theme.palette.mode === "dark"; +// // // const theme = useTheme(); +// // // const isDarkMode = theme.palette.mode === "dark"; +// // // const isSmUp = useMediaQuery(theme.breakpoints.up("sm")); +// // // const [userId, setUserId] = useState(null); +// // // const [itineraries, setItineraries] = useState([]); +// // // const [loading, setLoading] = useState(true); +// // // const [error, setError] = useState(""); + +// // // useEffect(() => { +// // // // Get the currently authenticated user // // // const auth = getAuth(); -// // // const isSmUp = useMediaQuery(theme.breakpoints.up("sm")); - -// // // return ( -// // // -// // // {/* Sidebar */} -// // // -// // // -// // // - -// // // {/* Main Content */} -// // // -// // // -// // // {/* Apply the same style as other headings */} -// // //

    Saved Itineraries

    - -// // // -// // // -// // // -// // // -// // // You don't have any saved itineraries yet. -// // // -// // // -// // // -// // // -// // //
    -// // //
    -// // //
    -// // // ); +// // // onAuthStateChanged(auth, async (user) => { +// // // if (user) { +// // // setUserId(user.uid); +// // // await fetchSavedItineraries(user.uid); +// // // } else { +// // // setLoading(false); +// // // setError("No user authenticated"); +// // // } +// // // }); +// // // }, []); + +// // // // Fetch itineraries from Firestore for the authenticated user +// // // const fetchSavedItineraries = async (uid) => { +// // // try { +// // // const itinerariesRef = collection(db, "ItineraryCollection"); +// // // const q = query(itinerariesRef, where("user_id", "==", uid)); +// // // const querySnapshot = await getDocs(q); +// // // const fetchedItineraries = querySnapshot.docs.map((doc) => ({ +// // // id: doc.id, +// // // ...doc.data(), +// // // })); + +// // // setItineraries(fetchedItineraries); +// // // } catch (error) { +// // // console.error("Error fetching itineraries: ", error); +// // // setError("Failed to load itineraries"); +// // // } finally { +// // // setLoading(false); +// // // } // // // }; +// // // // Render saved itineraries +// // // return ( +// // // +// // // {/* Sidebar */} +// // // +// // // +// // // + +// // // {/* Main Content */} +// // // +// // // +// // //

    Saved Itineraries

    + +// // // {loading ? ( +// // // +// // // +// // // +// // // ) : error ? ( +// // // {error} +// // // ) : itineraries.length === 0 ? ( +// // // You don't have any saved itineraries yet. +// // // ) : ( +// // // +// // // {itineraries.map((itinerary) => ( +// // // +// // // +// // // +// // // +// // // +// // // {itinerary.itineraryName} +// // // +// // // +// // // Destination: {itinerary.destination} +// // // +// // // +// // // Budget: {itinerary.budget} ZAR +// // // +// // // +// // // Number of Days: {itinerary.numDays} +// // // +// // // +// // // Activities: +// // // {itinerary.days.map((day, index) => ( +// // //
    +// // // Day {day.dayNumber}:{" "} +// // // {day.activities.length > 0 +// // // ? day.activities.map( +// // // (activity, actIndex) => ( +// // //
  • +// // // {activity.name} at {activity.time} +// // //
  • +// // // ) +// // // ) +// // // : "No activities"} +// // //
    +// // // ))} +// // //
    +// // //
    +// // //
    +// // //
    +// // //
    +// // // ))} +// // //
    +// // // )} +// // //
    +// // //
    +// // //
    +// // // ); +// // // }; + // // // export default SavedItineraries; // // import React, { useState, useEffect } from "react"; @@ -120,12 +268,11 @@ // // const isDarkMode = theme.palette.mode === "dark"; // // const isSmUp = useMediaQuery(theme.breakpoints.up("sm")); // // const [userId, setUserId] = useState(null); -// // const [itineraries, setItineraries] = useState([]); +// // const [itineraries, setItineraries] = useState([]); // Initialize as an empty array // // const [loading, setLoading] = useState(true); // // const [error, setError] = useState(""); // // useEffect(() => { -// // // Get the currently authenticated user // // const auth = getAuth(); // // onAuthStateChanged(auth, async (user) => { // // if (user) { @@ -149,7 +296,7 @@ // // ...doc.data(), // // })); -// // setItineraries(fetchedItineraries); +// // setItineraries(fetchedItineraries); // Set fetched itineraries // // } catch (error) { // // console.error("Error fetching itineraries: ", error); // // setError("Failed to load itineraries"); @@ -158,7 +305,6 @@ // // } // // }; -// // // Render saved itineraries // // return ( // // // // {/* Sidebar */} @@ -180,7 +326,7 @@ // // flexGrow={1} // // p={3} // // sx={{ ml: isSmUp ? "240px" : "0", overflowX: "hidden" }} -// // className="content" // Applying the content class from the CSS +// // className="content" // // > // // // //

    Saved Itineraries

    @@ -214,20 +360,27 @@ // // // // // // Activities: -// // {itinerary.days.map((day, index) => ( -// //
    -// // Day {day.dayNumber}:{" "} -// // {day.activities.length > 0 -// // ? day.activities.map( +// // {/* Handle undefined or empty days array */} +// // {itinerary.days && itinerary.days.length > 0 ? ( +// // itinerary.days.map((day, index) => ( +// //
    +// // Day {day.dayNumber}:{" "} +// // {day.activities && day.activities.length > 0 ? ( +// // day.activities.map( // // (activity, actIndex) => ( // //
  • // // {activity.name} at {activity.time} // //
  • // // ) // // ) -// // : "No activities"} -// //
    -// // ))} +// // ) : ( +// //
  • No activities
  • +// // )} +// //
    +// // )) +// // ) : ( +// //
    No days available
    +// // )} // //
    // // // // @@ -260,7 +413,7 @@ // } from "@mui/material"; // import Sidebar from "./sidebar"; // import { getAuth, onAuthStateChanged } from "firebase/auth"; -// import { collection, getDocs, query, where } from "firebase/firestore"; +// import { collection, getDocs, query, where, doc, collectionGroup } from "firebase/firestore"; // import { db } from "../../firebase/firebase-config"; // const SavedItineraries = () => { @@ -291,10 +444,26 @@ // const itinerariesRef = collection(db, "ItineraryCollection"); // const q = query(itinerariesRef, where("user_id", "==", uid)); // const querySnapshot = await getDocs(q); -// const fetchedItineraries = querySnapshot.docs.map((doc) => ({ -// id: doc.id, -// ...doc.data(), -// })); + +// const fetchedItineraries = await Promise.all( +// querySnapshot.docs.map(async (doc) => { +// const itineraryData = doc.data(); + +// // Fetch the days sub-collection for each itinerary +// const daysRef = collection(doc.ref, "days"); +// const daysSnapshot = await getDocs(daysRef); +// const days = daysSnapshot.docs.map((dayDoc) => ({ +// id: dayDoc.id, +// ...dayDoc.data(), +// })); + +// return { +// id: doc.id, +// ...itineraryData, +// days, // Attach the fetched days +// }; +// }) +// ); // setItineraries(fetchedItineraries); // Set fetched itineraries // } catch (error) { @@ -359,27 +528,76 @@ // Number of Days: {itinerary.numDays} // // -// Activities: -// {/* Handle undefined or empty days array */} +// Day-by-Day Details: +// {/* Display each day */} // {itinerary.days && itinerary.days.length > 0 ? ( // itinerary.days.map((day, index) => ( //
    -// Day {day.dayNumber}:{" "} -// {day.activities && day.activities.length > 0 ? ( -// day.activities.map( -// (activity, actIndex) => ( -//
  • -// {activity.name} at {activity.time} +// +// Day {day.dayNumber} +// + +// {/* Flights */} +// {day.flights && day.flights.length > 0 && ( +// <> +// +// Flights: +// +// {day.flights.map((flight, flightIndex) => ( +//
  • +// {flight.flightNumber} - Departs:{" "} +// {flight.departure}, Arrives:{" "} +// {flight.arrival} //
  • -// ) -// ) -// ) : ( -//
  • No activities
  • +// ))} +// // )} + +// {/* Accommodations */} +// {day.accommodation && +// day.accommodation.length > 0 && ( +// <> +// +// Accommodation: +// +// {day.accommodation.map( +// (acc, accIndex) => ( +//
  • +// {acc.name} - Check-in:{" "} +// {acc.checkin || "N/A"}, Checkout:{" "} +// {acc.checkout || "N/A"} +//
  • +// ) +// )} +// +// )} + +// {/* Activities */} +// {day.activities && +// day.activities.length > 0 && ( +// <> +// +// Activities: +// +// {day.activities.map( +// (activity, actIndex) => ( +//
  • +// {activity.name} at {activity.time} +//
  • +// ) +// )} +// +// )} //
    // )) // ) : ( -//
    No days available
    +// No days available // )} //
    // @@ -410,18 +628,19 @@ import { useTheme, useMediaQuery, CircularProgress, + IconButton, } from "@mui/material"; +import { Delete as DeleteIcon } from "@mui/icons-material"; import Sidebar from "./sidebar"; import { getAuth, onAuthStateChanged } from "firebase/auth"; -import { collection, getDocs, query, where, doc, collectionGroup } from "firebase/firestore"; +import { collection, getDocs, query, where, doc, deleteDoc, collectionGroup } from "firebase/firestore"; import { db } from "../../firebase/firebase-config"; const SavedItineraries = () => { const theme = useTheme(); - const isDarkMode = theme.palette.mode === "dark"; const isSmUp = useMediaQuery(theme.breakpoints.up("sm")); const [userId, setUserId] = useState(null); - const [itineraries, setItineraries] = useState([]); // Initialize as an empty array + const [itineraries, setItineraries] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); @@ -444,11 +663,11 @@ const SavedItineraries = () => { const itinerariesRef = collection(db, "ItineraryCollection"); const q = query(itinerariesRef, where("user_id", "==", uid)); const querySnapshot = await getDocs(q); - + const fetchedItineraries = await Promise.all( querySnapshot.docs.map(async (doc) => { const itineraryData = doc.data(); - + // Fetch the days sub-collection for each itinerary const daysRef = collection(doc.ref, "days"); const daysSnapshot = await getDocs(daysRef); @@ -456,7 +675,7 @@ const SavedItineraries = () => { id: dayDoc.id, ...dayDoc.data(), })); - + return { id: doc.id, ...itineraryData, @@ -474,6 +693,34 @@ const SavedItineraries = () => { } }; + // Delete itinerary from Firestore + const deleteItinerary = async (itineraryId) => { + try { + const itineraryRef = doc(db, "ItineraryCollection", itineraryId); + + // Fetch the 'days' sub-collection and delete each day + const daysRef = collection(itineraryRef, "days"); + const daysSnapshot = await getDocs(daysRef); + const deletePromises = daysSnapshot.docs.map((dayDoc) => + deleteDoc(dayDoc.ref) + ); + + // Wait for all the day documents to be deleted + await Promise.all(deletePromises); + + // Finally, delete the main itinerary document + await deleteDoc(itineraryRef); + + // Update state after deletion + setItineraries((prevItineraries) => + prevItineraries.filter((itinerary) => itinerary.id !== itineraryId) + ); + } catch (error) { + console.error("Error deleting itinerary: ", error); + setError("Failed to delete itinerary"); + } + }; + return ( {/* Sidebar */} @@ -515,18 +762,34 @@ const SavedItineraries = () => { - - {itinerary.itineraryName} - + + + {itinerary.itineraryName} + + deleteItinerary(itinerary.id)} + color="error" + > + + + + Destination: {itinerary.destination} + + {/* Budget Check: If it's an array, display as a range */} - Budget: {itinerary.budget} ZAR + Budget:{" "} + {Array.isArray(itinerary.budget) + ? `${itinerary.budget[0]} - ${itinerary.budget[1]} ZAR` + : `${itinerary.budget} ZAR`} + Number of Days: {itinerary.numDays} + Day-by-Day Details: {/* Display each day */}