diff --git a/ai-trip-creator/src/components/dashboard/ItineraryForm.js b/ai-trip-creator/src/components/dashboard/ItineraryForm.js index b466054..8b113f4 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); } @@ -555,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( @@ -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 diff --git a/ai-trip-creator/src/components/dashboard/SavedItineraries.js b/ai-trip-creator/src/components/dashboard/SavedItineraries.js index f7751d4..361a25b 100644 --- a/ai-trip-creator/src/components/dashboard/SavedItineraries.js +++ b/ai-trip-creator/src/components/dashboard/SavedItineraries.js @@ -1,97 +1,879 @@ +// // // // 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, +// // // Container, +// // // Paper, +// // // Grid, +// // // Drawer, +// // // useTheme, +// // // useMediaQuery, +// // // CircularProgress, +// // // } from "@mui/material"; +// // // import Sidebar from "./sidebar"; +// // // import { getAuth, onAuthStateChanged } from "firebase/auth"; +// // // import { collection, getDocs, query, where } 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([]); +// // // const [loading, setLoading] = useState(true); +// // // const [error, setError] = useState(""); + +// // // useEffect(() => { +// // // // Get the currently authenticated user +// // // const auth = getAuth(); +// // // 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"; +// // import { +// // Box, +// // Typography, +// // Card, +// // CardContent, +// // Container, +// // Paper, +// // Grid, +// // Drawer, +// // useTheme, +// // useMediaQuery, +// // CircularProgress, +// // } from "@mui/material"; +// // import Sidebar from "./sidebar"; +// // import { getAuth, onAuthStateChanged } from "firebase/auth"; +// // import { collection, getDocs, query, where } 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 [loading, setLoading] = useState(true); +// // const [error, setError] = useState(""); + +// // useEffect(() => { +// // const auth = getAuth(); +// // 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); // Set fetched itineraries +// // } catch (error) { +// // console.error("Error fetching itineraries: ", error); +// // setError("Failed to load itineraries"); +// // } finally { +// // setLoading(false); +// // } +// // }; + +// // 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: +// // {/* 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 days available
    +// // )} +// //
    +// //
    +// //
    +// //
    +// //
    +// // ))} +// //
    +// // )} +// //
    +// //
    +// //
    +// // ); +// // }; + +// // export default SavedItineraries; + +// import React, { useState, useEffect } from "react"; +// import { +// Box, +// Typography, +// Card, +// CardContent, +// Container, +// Paper, +// Grid, +// Drawer, +// useTheme, +// useMediaQuery, +// CircularProgress, +// } from "@mui/material"; +// import Sidebar from "./sidebar"; +// import { getAuth, onAuthStateChanged } from "firebase/auth"; +// import { collection, getDocs, query, where, doc, 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 [loading, setLoading] = useState(true); +// const [error, setError] = useState(""); + +// useEffect(() => { +// const auth = getAuth(); +// 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 = 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) { +// console.error("Error fetching itineraries: ", error); +// setError("Failed to load itineraries"); +// } finally { +// setLoading(false); +// } +// }; + +// 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} +// +// +// Day-by-Day Details: +// {/* Display each day */} +// {itinerary.days && itinerary.days.length > 0 ? ( +// itinerary.days.map((day, index) => ( +//
    +// +// Day {day.dayNumber} +// + +// {/* Flights */} +// {day.flights && day.flights.length > 0 && ( +// <> +// +// Flights: +// +// {day.flights.map((flight, flightIndex) => ( +//
  • +// {flight.flightNumber} - Departs:{" "} +// {flight.departure}, Arrives:{" "} +// {flight.arrival} +//
  • +// ))} +// +// )} + +// {/* 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 +// )} +//
    +//
    +//
    +//
    +//
    +// ))} +//
    +// )} +//
    +//
    +//
    +// ); +// }; + +// 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, + CircularProgress, IconButton, - CardMedia, - Slider, } from "@mui/material"; -import DeleteIcon from '@mui/icons-material/Delete'; -import Carousel from 'react-material-ui-carousel'; +import { Delete as DeleteIcon } from "@mui/icons-material"; 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, doc, deleteDoc, collectionGroup } 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 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(() => { 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 = 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) { + console.error("Error fetching itineraries: ", error); + setError("Failed to load itineraries"); + } finally { + setLoading(false); + } + }; + + // 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"); + } }; -export default SavedItineraries; \ No newline at end of file + 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} + + deleteItinerary(itinerary.id)} + color="error" + > + + + + + + Destination: {itinerary.destination} + + + {/* Budget Check: If it's an array, display as a range */} + + 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 */} + {itinerary.days && itinerary.days.length > 0 ? ( + itinerary.days.map((day, index) => ( +
    + + Day {day.dayNumber} + + + {/* Flights */} + {day.flights && day.flights.length > 0 && ( + <> + + Flights: + + {day.flights.map((flight, flightIndex) => ( +
  • + {flight.flightNumber} - Departs:{" "} + {flight.departure}, Arrives:{" "} + {flight.arrival} +
  • + ))} + + )} + + {/* 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 + )} +
    +
    +
    +
    +
    + ))} +
    + )} +
    +
    +
    + ); +}; + +export default SavedItineraries;