Skip to content

Commit

Permalink
Merge pull request #11 from SRN-SE-Fall24/bookmark
Browse files Browse the repository at this point in the history
Fetched and added Bookmarked recipes to the UI
  • Loading branch information
SharmeenMomin authored Nov 1, 2024
2 parents 7bae8be + b01da88 commit 9c8b83e
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 63 deletions.
9 changes: 8 additions & 1 deletion Code/frontend/src/App.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import React, { useState } from "react";
import Nav from "./components/Navbar.js";
import Login from "./components/Login.js";
import BookMarksRecipeList from "./components/BookMarksRecipeList.js";
import { doSignInWithEmailAndPassword, doCreateUserWithEmailAndPassword, doSignOut } from "./firebase/auth";
import SearchBlock from "./components/SearchBlock.js";
import { useAuth, AuthProvider } from "./contexts/authContext/index";

const App = () => {
const { currentUser, userLoggedIn } = useAuth();
const [showLoginModal, setShowLoginModal] = useState(false);
const [showBookmarks, setShowBookmarks] = useState(false);

const toggleLoginModal = () => {
setShowLoginModal(prev => !prev);
Expand Down Expand Up @@ -45,18 +47,23 @@ const App = () => {
}
};

const handleShowBookmarks = () => {
setShowBookmarks(true);
};

return (
<div>
<Nav
handleLogout={handleLogout}
currentUser={currentUser}
toggleLoginModal={toggleLoginModal}
userLoggedIn={userLoggedIn}
handleBookMarks={handleShowBookmarks}
/>
{showLoginModal && (
<Login handleSignup={handleSignup} handleLogin={handleLogin} toggleLoginModal={toggleLoginModal} />
)}
<SearchBlock />
{showBookmarks ? <BookMarksRecipeList /> : <SearchBlock />}
</div>
);
};
Expand Down
26 changes: 7 additions & 19 deletions Code/frontend/src/components/BookMarksRecipeCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,23 @@
Copyright (c) 2023 Pannaga Rao, Harshitha, Prathima, Karthik */

import React from "react";
import { Box, HStack, SimpleGrid, Card, CardHeader, Heading, Text, CardBody, CardFooter, Button, Image, Tag } from "@chakra-ui/react"
import recipeDB from "../apis/recipeDB";

import RecipeImage from "./RecipeImage";
import { Card, CardHeader, Heading, Text, CardBody, CardFooter, Button, Image, Tag } from "@chakra-ui/react"

const BookMarksRecipeCard = (props) => {
const handleClick = ()=> {
const handleClick = () => {
props.handler(props.recipe);
}

return (
<>
<Card onClick={handleClick} data-testid="recipeCard" _hover={{transform: "scale(1.05)", bg: "green.300", transitionDuration: "4" ,cursor: "pointer"}}>
<Card onClick={handleClick} data-testid="recipeCard" _hover={{ transform: "scale(1.05)", bg: "green.300", transitionDuration: "4", cursor: "pointer" }}>
<CardHeader>
<Heading data-testid="recipeName" size='md'>{props.recipe.TranslatedRecipeName}</Heading>
<Heading data-testid="recipeName" size='md'>{props.recipe.recipeName}</Heading>
</CardHeader>
<CardBody>
<Text data-testid="time">Cooking Time: {props.recipe.TotalTimeInMins} mins</Text>
<Text data-testid="rating">Rating: {props.recipe['Recipe-rating']}</Text>
<Text data-testid="diet">Diet Type: {props.recipe['Diet-type']}</Text>
<RecipeImage name={props.recipe.recipeName} height={300} width={200} />
</CardBody>
<Image
data-testid="recipeImg"
objectFit='cover'
src={props.recipe["image-url"]}
width={"90%"}
height={"40%"}
m={"auto"}
mb="2"
/>
</Card>
</>
)
Expand Down
78 changes: 42 additions & 36 deletions Code/frontend/src/components/BookMarksRecipeList.js
Original file line number Diff line number Diff line change
@@ -1,60 +1,65 @@
/* MIT License
Copyright (c) 2023 Pannaga Rao, Harshitha, Prathima, Karthik */
Copyright (c) 2023 Pannaga Rao, Harshitha, Prathima, Karthik */

import React, { useState } from "react";
import { Avatar, Flex, Modal, ModalBody, ModalCloseButton, ModalOverlay, ModalHeader, ModalFooter, ModalContent, Box, SimpleGrid, Text, Button } from "@chakra-ui/react"
import React, { useState, useEffect } from "react";
import { Flex, Modal, ModalBody, ModalCloseButton, ModalOverlay, ModalHeader, ModalFooter, ModalContent, Box, SimpleGrid, Text, Button } from "@chakra-ui/react";
import BookMarksRecipeCard from "./BookMarksRecipeCard";
import { fetchBookmarkedRecipes } from '../service/firestoreService';

// component to handle all the recipes
const BookMarksRecipeList = ({ recipes }) => {
// mapping each recipe item to the Recipe container
// const renderedRecipes = recipes.map((recipe) => {
// // return <Recipe key={recipe._id} recipe={recipe} />;
// return(

// )
// });
console.log(recipes)
// Component to handle displaying all bookmarked recipes
const BookMarksRecipeList = () => {
const [recipes, setRecipes] = useState([]);
const [isOpen, setIsOpen] = useState(false);
const [currentRecipe, setCurrentRecipe] = useState({});
var youtube_videos =
"https://www.youtube.com/results?search_query=" +
currentRecipe["TranslatedRecipeName"];

useEffect(() => {
// Fetch bookmarked recipes when the component mounts
const fetchRecipes = async () => {
const bookmarkedRecipes = await fetchBookmarkedRecipes();
setRecipes(bookmarkedRecipes);
};

fetchRecipes();
}, []);

const handleViewRecipe = (data) => {
setIsOpen(true)
console.log(data)
setIsOpen(true);
setCurrentRecipe(data);
}
};

const onClose = () => {
setIsOpen(false)
}
// all the recipes are being returned in the form of a table
setIsOpen(false);
};

return (
<>
<Box borderRadius={"lg"} border="1px" boxShadow={"10px"} borderColor={"gray.100"} fontFamily="regular" m={10} width={"94%"} p={5}>
<SimpleGrid spacing={5} templateColumns='repeat(auto-fill, minmax(250px, 1fr))'>
{recipes.length !==0 ? recipes.map((recipe) => (
<BookMarksRecipeCard handler={handleViewRecipe} recipe={recipe} />
)) : <Text data-testid="noResponseText" fontSize={"lg"} color={"gray"}>Searching for a recipe?</Text>}
{recipes.length !== 0 ? recipes.map((recipe) => (
<BookMarksRecipeCard key={recipe.recipeName} handler={handleViewRecipe} recipe={recipe} />
)) : (
<Text data-testid="noResponseText" fontSize={"lg"} color={"gray"}>
No bookmarked recipes found.
</Text>
)}
</SimpleGrid>
</Box>

{/* Modal for detailed view */}
<Modal size={"6xl"} isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent data-testid="recipeModal" >
<ModalHeader>{currentRecipe.TranslatedRecipeName}</ModalHeader>
<ModalContent data-testid="recipeModal">
<ModalHeader>{currentRecipe.recipeName}</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Flex >
<Avatar size="2xl" mr={2} mb={2} src={currentRecipe["image-url"]} />
<Flex>
<Box mt={4}>
<Text><Text as={"b"}>Cooking Time: </Text>{currentRecipe.TotalTimeInMins} mins</Text>
<Text><Text as={"b"}>Rating: </Text> {currentRecipe['Recipe-rating']}</Text>
<Text mb={2}><Text as={"b"}>Diet Type: </Text> {currentRecipe['Diet-type']}</Text>
<Text><Text as={"b"}>Cooking Time: </Text> {currentRecipe.cookingTime} </Text>
</Box>
</Flex>
<Text><Text as={"b"}>Instructions: </Text> {currentRecipe["TranslatedInstructions"]}</Text>
<Text color={"blue"}><Text color={"black"} as={"b"}>Video Url: </Text><a href={youtube_videos}>Youtube</a></Text>
<Text><Text as={"b"}>Instructions: </Text> {currentRecipe.ingredients} </Text>
<Text><Text as={"b"}>Instructions: </Text> {currentRecipe.steps} </Text>
</ModalBody>

<ModalFooter>
Expand All @@ -65,6 +70,7 @@ const BookMarksRecipeList = ({ recipes }) => {
</ModalContent>
</Modal>
</>
)
);
};
export default BookMarksRecipeList;

export default BookMarksRecipeList;
5 changes: 2 additions & 3 deletions Code/frontend/src/components/SearchBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ 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.map(ingredient => ingredient.trim());
response.data.ingredients = allIngredients;
console.log("detialed recipe:"+ JSON.stringify(response.data, null, 2));
setDetailedItem(response.data);
}

Expand All @@ -108,7 +107,7 @@ const SearchBlock = (props) => {
await unbookmarkRecipe(detailedItem.name);
setIsBookmarked(false);
} else {
await bookmarkRecipe(detailedItem.name);
await bookmarkRecipe(detailedItem);
setIsBookmarked(true);
}
};
Expand Down
29 changes: 25 additions & 4 deletions Code/frontend/src/service/firestoreService.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { doc, setDoc, deleteDoc, getDoc, onSnapshot } from "firebase/firestore";
import { doc, setDoc, deleteDoc, getDoc, collection, query, where, getDocs, onSnapshot } from "firebase/firestore";
import { auth, db } from "../firebase/firebase";

// Function to bookmark a recipe by name
export const bookmarkRecipe = async (recipeName) => {
export const bookmarkRecipe = async (recipe) => {
const user = auth.currentUser;
if (user) {
const documentId = `${user.uid}_${recipeName}`;
const documentId = `${user.uid}_${recipe.name}`;
const bookmarkRef = doc(db, "bookmarks", documentId);
await setDoc(bookmarkRef, { userId: user.uid, recipeName });
await setDoc(bookmarkRef, { userId: user.uid, recipeName: recipe.name, ingredients: recipe.ingredients, cookingTime: recipe.time, steps: recipe.process });
}
};

Expand All @@ -31,4 +31,25 @@ export const isRecipeBookmarked = async (recipeName) => {
return bookmarkSnap.exists();
}
return false; // Return false if user is not logged in
};

// Function to fetch all bookmarked recipes for the current user
export const fetchBookmarkedRecipes = async () => {
const user = auth.currentUser;
if (user) {
try {
const bookmarksRef = collection(db, "bookmarks");
const q = query(bookmarksRef, where("userId", "==", user.uid));
const querySnapshot = await getDocs(q);

// Return all recipes bookmarked by the user
return querySnapshot.docs.map((doc) => doc.data());
} catch (error) {
console.error("Error fetching bookmarked recipes: ", error);
return [];
}
} else {
console.warn("No user is logged in.");
return [];
}
};

0 comments on commit 9c8b83e

Please sign in to comment.