From dab57753a41deb6960e8319be25ce2fa8814e35e Mon Sep 17 00:00:00 2001 From: Rutvik Vishwas Kulkarni Date: Thu, 31 Oct 2024 17:55:33 -0400 Subject: [PATCH 1/2] Fix login logout issues --- Code/frontend/src/App.js | 208 ++++-------------- Code/frontend/src/components/Navbar.js | 2 +- Code/frontend/src/components/SearchBlock.js | 32 ++- Code/frontend/src/firebase/firebase.js | 8 +- Code/frontend/src/service/firestoreService.js | 46 ++++ 5 files changed, 116 insertions(+), 180 deletions(-) create mode 100644 Code/frontend/src/service/firestoreService.js 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..fb30ba45 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 } from '../service/firestoreService'; +import { useAuth } from "../contexts/authContext/index"; const SearchBlock = (props) => { @@ -16,10 +18,9 @@ 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 [isBookmarked, setIsBookmarked] = useState(false); const onChange = (query) => { if (searchIngredients.length === 0) { @@ -83,14 +84,23 @@ 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 () => { + await bookmarkRecipe("Tom yum soup"); + // 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 +110,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; @@ -109,6 +118,8 @@ const SearchBlock = (props) => { doc.save(`${recipeName}-shopping-list.pdf`); }; + const { userLoggedIn } = useAuth(); + return (
@@ -168,7 +179,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..f7728c46 --- /dev/null +++ b/Code/frontend/src/service/firestoreService.js @@ -0,0 +1,46 @@ +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; + const documentId = `${auth.currentUser.uid}_${recipeName}`; + const bookmarkRef = doc(db, "bookmarks", documentId); + await setDoc(bookmarkRef, { userId: auth.currentUser.uid, recipeName }); + // if (user) { + // const bookmarkRef = doc(db, "bookmarks"); + // await setDoc(bookmarkRef, { name: recipeName }); + // } +}; + +// // Function to unbookmark a recipe by name +// export const unbookmarkRecipe = async (recipeName) => { +// const user = auth.currentUser; +// if (user) { +// const bookmarkRef = doc(db, "users", user.uid, "bookmarks", recipeName); +// await deleteDoc(bookmarkRef); +// } +// }; + +// // Function to check if a recipe is bookmarked +// export const isRecipeBookmarked = async (recipeName) => { +// const user = auth.currentUser; +// if (user) { +// const bookmarkRef = doc(db, "users", user.uid, "bookmarks", recipeName); +// const bookmarkSnap = await getDoc(bookmarkRef); +// return bookmarkSnap.exists(); +// } +// return false; +// }; + +// Optional: function to listen for real-time bookmark status +// export const onBookmarkStatusChange = (recipeName, callback) => { +// const user = auth.currentUser; +// if (user) { +// const bookmarkRef = doc(db, "users", user.uid, "bookmarks", recipeName); +// return onSnapshot(bookmarkRef, (docSnap) => { +// callback(docSnap.exists()); +// }); +// } +// return () => {}; // Return a no-op function if not logged in +// }; \ No newline at end of file From 8498ad2c4bc66fe7298236c0a20f7f324c202f26 Mon Sep 17 00:00:00 2001 From: Rutvik Vishwas Kulkarni Date: Thu, 31 Oct 2024 18:30:52 -0400 Subject: [PATCH 2/2] Added functionality for a user to bookmark a recipe --- Code/frontend/src/components/SearchBlock.js | 37 +++++++---- Code/frontend/src/service/firestoreService.js | 62 ++++++++----------- 2 files changed, 49 insertions(+), 50 deletions(-) diff --git a/Code/frontend/src/components/SearchBlock.js b/Code/frontend/src/components/SearchBlock.js index fb30ba45..5b74242e 100644 --- a/Code/frontend/src/components/SearchBlock.js +++ b/Code/frontend/src/components/SearchBlock.js @@ -7,7 +7,7 @@ import './css/misc.css'; import Tag from "./Tag"; import jsPDF from 'jspdf'; import { Oval } from "react-loader-spinner"; -import { bookmarkRecipe } from '../service/firestoreService'; +import { bookmarkRecipe, unbookmarkRecipe, isRecipeBookmarked } from '../service/firestoreService'; import { useAuth } from "../contexts/authContext/index"; @@ -19,8 +19,9 @@ const SearchBlock = (props) => { 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) { @@ -70,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; @@ -88,14 +102,13 @@ const SearchBlock = (props) => { } const handleBookmark = async () => { - await bookmarkRecipe("Tom yum soup"); - // if (isBookmarked) { - // await unbookmarkRecipe(detailedItem.name); - // setIsBookmarked(false); - // } else { - // await bookmarkRecipe(detailedItem.name); - // setIsBookmarked(true); - // } + if (isBookmarked) { + await unbookmarkRecipe(detailedItem.name); + setIsBookmarked(false); + } else { + await bookmarkRecipe(detailedItem.name); + setIsBookmarked(true); + } }; const generatePDF = () => { @@ -118,8 +131,6 @@ const SearchBlock = (props) => { doc.save(`${recipeName}-shopping-list.pdf`); }; - const { userLoggedIn } = useAuth(); - return (
@@ -184,7 +195,7 @@ const SearchBlock = (props) => { onClick={handleBookmark} style={{ padding: '5px 5px', backgroundColor: '#A9A9A9', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer', transition: 'background-color 0.3s' }} > - Bookmark this recipe + {isBookmarked ? "Unbookmark this recipe" : "Bookmark this recipe"} )}
diff --git a/Code/frontend/src/service/firestoreService.js b/Code/frontend/src/service/firestoreService.js index f7728c46..9a983b34 100644 --- a/Code/frontend/src/service/firestoreService.js +++ b/Code/frontend/src/service/firestoreService.js @@ -4,43 +4,31 @@ import { auth, db } from "../firebase/firebase"; // Function to bookmark a recipe by name export const bookmarkRecipe = async (recipeName) => { const user = auth.currentUser; - const documentId = `${auth.currentUser.uid}_${recipeName}`; - const bookmarkRef = doc(db, "bookmarks", documentId); - await setDoc(bookmarkRef, { userId: auth.currentUser.uid, recipeName }); - // if (user) { - // const bookmarkRef = doc(db, "bookmarks"); - // await setDoc(bookmarkRef, { name: recipeName }); - // } + 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 bookmarkRef = doc(db, "users", user.uid, "bookmarks", recipeName); -// await deleteDoc(bookmarkRef); -// } -// }; - -// // Function to check if a recipe is bookmarked -// export const isRecipeBookmarked = async (recipeName) => { -// const user = auth.currentUser; -// if (user) { -// const bookmarkRef = doc(db, "users", user.uid, "bookmarks", recipeName); -// const bookmarkSnap = await getDoc(bookmarkRef); -// return bookmarkSnap.exists(); -// } -// return false; -// }; +// 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); + } +}; -// Optional: function to listen for real-time bookmark status -// export const onBookmarkStatusChange = (recipeName, callback) => { -// const user = auth.currentUser; -// if (user) { -// const bookmarkRef = doc(db, "users", user.uid, "bookmarks", recipeName); -// return onSnapshot(bookmarkRef, (docSnap) => { -// callback(docSnap.exists()); -// }); -// } -// return () => {}; // Return a no-op function if not logged in -// }; \ No newline at end of file +// 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