Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bookmark recipe #9

Merged
merged 2 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 39 additions & 169 deletions Code/frontend/src/App.js
Original file line number Diff line number Diff line change
@@ -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 (
<div>
<Nav
handleLogout={handleLogout}
currentUser={currentUser}
toggleLoginModal={toggleLoginModal}
userLoggedIn={userLoggedIn}
/>
{showLoginModal && (
<Login handleSignup={handleSignup} handleLogin={handleLogin} toggleLoginModal={toggleLoginModal} />
)}
<SearchBlock />
</div>
);
};

render() {
return (
<div>
<Nav
handleLogout={this.handleLogout}
handleBookMarks={this.handleBookMarks}
currentUser={this.state.currentUser}
toggleLoginModal={this.toggleLoginModal}
/>
{this.state.showLoginModal && (
<Login handleSignup={this.handleSignup} handleLogin={this.handleLogin} toggleLoginModal={this.toggleLoginModal} />
)}
<SearchBlock />
{/*
<>
{this.state.isProfileView ? (
<UserProfile handleProfileView={this.handleProfileView} currentUser={this.state.currentUser} />
) : (
<Tabs variant="soft-rounded" colorScheme="green">
<TabList ml={10}>
<Tab>Search Recipe</Tab>
<Tab>Search Recipe By Name</Tab>
</TabList>
<TabPanels>
<TabPanel>
<Box display="flex">
<Form sendFormData={this.handleSubmit} />
{this.state.isLoading ? <RecipeLoading /> : <RecipeList recipes={this.state.recipeList} />}
</Box>
</TabPanel>
<TabPanel>
<AddRecipe />
</TabPanel>
<TabPanel>
<SearchByRecipe sendRecipeData={this.handleRecipesByName} />
{this.state.isLoading ? <RecipeLoading /> : <RecipeList recipes={this.state.recipeByNameList} />}
</TabPanel>
</TabPanels>
</Tabs>
)}
</>
*/}
</div>
);
}
}
const AppWithProvider = () => (
<AuthProvider>
<App />
</AuthProvider>
);

export default App;
export default AppWithProvider;
2 changes: 1 addition & 1 deletion Code/frontend/src/components/Navbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export default function Nav(props) {
</Box>
<Flex alignItems={"center"}>
<Stack direction={"row"} spacing={7}>
{props.currentUser ? (
{props.userLoggedIn && props.currentUser ? (
<Menu>
<MenuButton as={Button} rounded={"full"} variant={"link"} cursor={"pointer"} minW={0}>
<Avatar size={"sm"} src={"https://avatars.dicebear.com/api/male/username.svg"} />
Expand Down
45 changes: 37 additions & 8 deletions Code/frontend/src/components/SearchBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -168,7 +190,14 @@ const SearchBlock = (props) => {
<div>{detailedItem.name}</div>
<div>{detailedItem.time}</div>
</div>

{userLoggedIn && (
<button
onClick={handleBookmark}
style={{ padding: '5px 5px', backgroundColor: '#A9A9A9', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer', transition: 'background-color 0.3s' }}
>
{isBookmarked ? "Unbookmark this recipe" : "Bookmark this recipe"}
</button>
)}
<div style={{ display: 'flex', marginTop: 5 }}>
{detailedItem.tags.map((tag, index) => {
return <Tag key={index}>{tag}</Tag>;
Expand Down
8 changes: 5 additions & 3 deletions Code/frontend/src/firebase/firebase.js
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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};
export {app, auth, db};
34 changes: 34 additions & 0 deletions Code/frontend/src/service/firestoreService.js
Original file line number Diff line number Diff line change
@@ -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
};
Loading