diff --git a/Code/frontend/src/App.js b/Code/frontend/src/App.js index ad6d9b80..df6c929f 100644 --- a/Code/frontend/src/App.js +++ b/Code/frontend/src/App.js @@ -1,200 +1,70 @@ -// -import recipeDB from "./apis/recipeDB"; -import React, { Component } from "react"; +import React, { useState } from "react"; import Nav from "./components/Navbar.js"; import Login from "./components/Login.js"; import { doSignInWithEmailAndPassword, doCreateUserWithEmailAndPassword, doSignOut } from "./firebase/auth"; import SearchBlock from "./components/SearchBlock.js"; +import { useAuth, AuthProvider } from "./contexts/authContext/index"; -// Main component of the project -class App extends Component { - // constructor for the App Component - constructor() { - super(); +const App = () => { + const { currentUser, userLoggedIn } = useAuth(); + const [showLoginModal, setShowLoginModal] = useState(false); - this.state = { - cuisine: "", - //NoIngredients : 0, - ingredients: new Set(), - recipeList: [], - recipeByNameList: [], - email: "", - flag: false, - isLoading: false, - isLoggedIn: false, - isProfileView: false, - showLoginModal: false, - userData: {} - }; - } - - handleBookMarks = () => { - this.setState({ - isProfileView: true - }) - } - - handleProfileView = () => { - this.setState({ - isProfileView: false - }) - } - - toggleLoginModal = () => { - this.setState((prevState) => ({ showLoginModal: !prevState.showLoginModal })); + const toggleLoginModal = () => { + setShowLoginModal(prev => !prev); }; - handleSignup = async (email, password) => { + const handleSignup = async (email, password) => { try { - const userCredential = await doCreateUserWithEmailAndPassword(email, password); - this.setState({ - isLoggedIn: true, - currentUser: userCredential.user, - showLoginModal: false, - }); + await doCreateUserWithEmailAndPassword(email, password); + setShowLoginModal(false); alert("Successfully Signed up!"); } catch (err) { console.log(err); alert(err.message); } - } + }; - // Handle user login - handleLogin = async (email, password) => { + const handleLogin = async (email, password) => { try { - const userCredential = await doSignInWithEmailAndPassword(email, password); - this.setState({ - isLoggedIn: true, - currentUser: userCredential.user, - showLoginModal: false, - }); + await doSignInWithEmailAndPassword(email, password); + setShowLoginModal(false); alert("Successfully logged in!"); } catch (err) { console.log(err); alert(err.message); } - } - - // Function to get the user input from the Form component on Submit action - handleSubmit = async (formDict) => { - this.setState({ - isLoading: true - }) - console.log(formDict) - this.setState({ - // cuisine: cuisineInput, - //NoIngredients: noIngredientsInput, - ingredients: formDict["ingredient"], - cuisine: formDict["cuisine"], - email: formDict["email_id"], - flag: formDict["flag"], - }); - - const mail = formDict["email_id"]; - const flag = formDict["flag"]; - const items = Array.from(formDict["ingredient"]); - const cuis = formDict["cuisine"]; - this.getRecipeDetails(items, cuis, mail, flag); - // alert(typeof(ingredientsInput["cuisine"])); - }; - - handleRecipesByName = (recipeName) => { - this.setState({ - isLoading: true - }) - recipeDB.get("/recipes/getRecipeByName", { - params: { - recipeName: recipeName - } - }).then(res => { - console.log(res.data); - this.setState({ - recipeByNameList: res.data.recipes, - isLoading: false - }) - }) - } - - getRecipeDetails = async (ingredient, cuis, mail, flag) => { - try { - const response = await recipeDB.get("/recipes", { - params: { - CleanedIngredients: ingredient, - Cuisine: cuis, - Email: mail, - Flag: flag, - }, - }); - this.setState({ - recipeList: response.data.recipes, - isLoading: false - }); - } catch (err) { - console.log(err); - } - }; + }; - // Handle logout - handleLogout = async () => { + const handleLogout = async () => { try { await doSignOut(); - this.setState({ - isLoggedIn: false, - showLoginModal: false, - currentUser: null, - }); alert("Logged out successfully"); } catch (err) { console.log(err); alert("Failed to log out"); } - } + }; + + return ( +
+
+ ); +}; - render() { - return ( -
-
- ); - } -} +const AppWithProvider = () => ( + + + +); -export default App; +export default AppWithProvider; \ No newline at end of file diff --git a/Code/frontend/src/components/Navbar.js b/Code/frontend/src/components/Navbar.js index 3d43e285..3605d958 100644 --- a/Code/frontend/src/components/Navbar.js +++ b/Code/frontend/src/components/Navbar.js @@ -55,7 +55,7 @@ export default function Nav(props) { - {props.currentUser ? ( + {props.userLoggedIn && props.currentUser ? ( diff --git a/Code/frontend/src/components/SearchBlock.js b/Code/frontend/src/components/SearchBlock.js index 57cbb4fa..5b74242e 100644 --- a/Code/frontend/src/components/SearchBlock.js +++ b/Code/frontend/src/components/SearchBlock.js @@ -7,6 +7,8 @@ import './css/misc.css'; import Tag from "./Tag"; import jsPDF from 'jspdf'; import { Oval } from "react-loader-spinner"; +import { bookmarkRecipe, unbookmarkRecipe, isRecipeBookmarked } from '../service/firestoreService'; +import { useAuth } from "../contexts/authContext/index"; const SearchBlock = (props) => { @@ -16,10 +18,10 @@ const SearchBlock = (props) => { const [items, setItems] = useState([]); const currentPage = useRef(1); const [loading, setLoading] = useState(false); - const [showingDetailed, setShowingDetailed] = useState(-1); - - const [detailedItem, setDetailedItem] = useState(); + const [detailedItem, setDetailedItem] = useState(null); + const [isBookmarked, setIsBookmarked] = useState(false); + const { userLoggedIn } = useAuth(); const onChange = (query) => { if (searchIngredients.length === 0) { @@ -69,6 +71,19 @@ const SearchBlock = (props) => { useEffect(() => { searchRecipes() }, [searchName, searchIngredients]); + useEffect(() => { + const checkBookmarkStatus = async () => { + if (detailedItem?.name) { + const status = await isRecipeBookmarked(detailedItem.name); + setIsBookmarked(status); + } + }; + + if (detailedItem) { + checkBookmarkStatus(); + } + }, [detailedItem]); + const loadMore = () => { if (loading) return; currentPage.current = currentPage.current + 1; @@ -83,14 +98,22 @@ const SearchBlock = (props) => { ingredients: items[index].ingredients, }; const response = await axios.post('https://get-detailed-recipe-3rhjd2q7dq-uc.a.run.app', data); - const allIngredients = response.data.ingredients.split('\n').map(ingredient => ingredient.trim()); - response.data.ingredients = allIngredients; setDetailedItem(response.data); } + const handleBookmark = async () => { + if (isBookmarked) { + await unbookmarkRecipe(detailedItem.name); + setIsBookmarked(false); + } else { + await bookmarkRecipe(detailedItem.name); + setIsBookmarked(true); + } + }; + const generatePDF = () => { const recipeName = detailedItem.name; - const ingredients = String(detailedItem.ingredients).split(',').map(ingredient => ingredient.trim()); + const ingredients = detailedItem.ingredients; const doc = new jsPDF(); doc.setFontSize(16); doc.text("Shopping List", 20, 20); @@ -100,7 +123,6 @@ const SearchBlock = (props) => { doc.setFontSize(12); let yOffset = 50; - console.log("inside generating pdf:"+ ingredients); ingredients.forEach((ingredient, index) => { doc.text(`${index + 1}. ${ingredient}`, 20, yOffset); yOffset += 10; @@ -168,7 +190,14 @@ const SearchBlock = (props) => {
{detailedItem.name}
{detailedItem.time}
- + {userLoggedIn && ( + + )}
{detailedItem.tags.map((tag, index) => { return {tag}; diff --git a/Code/frontend/src/firebase/firebase.js b/Code/frontend/src/firebase/firebase.js index 5bf37be1..cce50cd3 100644 --- a/Code/frontend/src/firebase/firebase.js +++ b/Code/frontend/src/firebase/firebase.js @@ -1,6 +1,7 @@ // Import the functions you need from the SDKs you need import { initializeApp } from "firebase/app"; -import { getAuth } from "firebase/auth" +import { getAuth } from "firebase/auth"; +import { getFirestore } from "firebase/firestore"; // TODO: Add SDKs for Firebase products that you want to use // https://firebase.google.com/docs/web/setup#available-libraries @@ -18,6 +19,7 @@ const firebaseConfig = { // Initialize Firebase const app = initializeApp(firebaseConfig); -const auth = getAuth(app) +const auth = getAuth(app); +const db = getFirestore(app); -export {app, auth}; \ No newline at end of file +export {app, auth, db}; \ No newline at end of file diff --git a/Code/frontend/src/service/firestoreService.js b/Code/frontend/src/service/firestoreService.js new file mode 100644 index 00000000..9a983b34 --- /dev/null +++ b/Code/frontend/src/service/firestoreService.js @@ -0,0 +1,34 @@ +import { doc, setDoc, deleteDoc, getDoc, onSnapshot } from "firebase/firestore"; +import { auth, db } from "../firebase/firebase"; + +// Function to bookmark a recipe by name +export const bookmarkRecipe = async (recipeName) => { + const user = auth.currentUser; + if (user) { + const documentId = `${user.uid}_${recipeName}`; + const bookmarkRef = doc(db, "bookmarks", documentId); + await setDoc(bookmarkRef, { userId: user.uid, recipeName }); + } +}; + +// Function to unbookmark a recipe by name +export const unbookmarkRecipe = async (recipeName) => { + const user = auth.currentUser; + if (user) { + const documentId = `${user.uid}_${recipeName}`; // Use the same documentId format + const bookmarkRef = doc(db, "bookmarks", documentId); + await deleteDoc(bookmarkRef); + } +}; + +// Function to check if a recipe is bookmarked +export const isRecipeBookmarked = async (recipeName) => { + const user = auth.currentUser; + if (user) { + const documentId = `${user.uid}_${recipeName}`; // Use the same documentId format + const bookmarkRef = doc(db, "bookmarks", documentId); + const bookmarkSnap = await getDoc(bookmarkRef); + return bookmarkSnap.exists(); + } + return false; // Return false if user is not logged in +}; \ No newline at end of file