From 491a5c162437614dd0d1c7dde198257a387a31b9 Mon Sep 17 00:00:00 2001 From: TRISTAN ZVUNKA Date: Tue, 23 Jan 2024 19:03:22 +0100 Subject: [PATCH 1/3] database is now up to date :) --- backend/database/sample_data_injection.sql | 106 ------------- backend/database/schema.sql | 166 +++++++++++++++++---- 2 files changed, 136 insertions(+), 136 deletions(-) delete mode 100644 backend/database/sample_data_injection.sql diff --git a/backend/database/sample_data_injection.sql b/backend/database/sample_data_injection.sql deleted file mode 100644 index b0d02e1..0000000 --- a/backend/database/sample_data_injection.sql +++ /dev/null @@ -1,106 +0,0 @@ -#Inject testing data for DB -# CAUTION -# Please make sure you're in the right DB before launching script, if there is any data still existing, some rows could be duplicated. - -INSERT INTO user(username, email, firstname, lastname, birthdate, password, is_admin) -VALUES - ('tristanZ', 'tristan.zvunka@gmail.com','tristan','zvunka','1992-11-26', 'test1',1 ), - ('flavienG', 'flavien.gaujardd@gmail.com', 'flavien','giraud','1988-04-12', 'test2',1), - ('elieR', 'elie.rakoto@gmail.com','elie','Rakoto','1990-10-14','test3',0), - ('christopheC','christophe.bruno@gmail.com','Christophe','Bruno','1990-10-14','test4',1), - ('hugoD','hugo.durand@gmail.com','Hugo','Durand','1989-02-05','test5',0) -; - -INSERT INTO recipe (name,title, user_ID, prep_time, nb_people, difficulty,tag1, tag2,tag3 ) -VALUES - ('oeufs au plat', 'simple comme bonjour',1, 15, 1, 'facile', 'végétarien', 'sans gluten',NULL), - ('pâtes au beurre','la spécialité des étudiants!', 2, 25, 2, 'facile', 'végétarien', NULL,NULL), - ('religieuse au chocolat','pour les experts en pâtisserie', 5, 90, 2, 'difficile', 'dessert', 'gourmand',NULL), - ('ramen', 'Comment réussir un vrai ramen maison comme au Japon?', 2, 180, 2, 'difficile', 'japon', 'gourmand', 'soupe'), - ('cheeseburger', 'Créez votre propre cheeseburger maison!',3,45,2,'facile','burger','gourmand',NULL), - ('Les inimitables crêpes','Rapide et efficace, le tout en quelques étapes!', 5, 20, 4, 'facile', 'rapide', 'gourmand','dessert') - ; - -INSERT INTO ingredient (name, unit, kcal) -VALUES -('oeuf', 'pièce(s)', 20), -('beurre', 'grammes', 5), -('chocolat noir', 'grammes', 3), -('farine de blé', 'grammes', 1), -('pâtes', 'grammes', 2), -('nouilles udon', 'grammes',50), -('steak haché', 'pièce(s)',100), -('pain bun','pièce(s)', 40), -('cheddar', 'grammes', 200), -('tomate','pièce(s)',10), -('lait','centilitres',5), -('farine', 'grammes', 0.5) -; - -INSERT INTO instruction (description, recipe_ID) -VALUES - ("Préchauffez la poêle",1), - ("rajoutez le beurre dans la poêle",1), - ("cassez les oeufs et les versez dans la poêle sans les mélanger",1), - ("Une fois la texture souhaitée, disposez dans l'assiette", 1), - ("Faites chauffer l'équivalent de 3 volumes d'eau par volume de pâtes dans une casserole en ajoutant du sel",2), - ("Une fois que l'eau bout, insérez les pâtes dans l'eau frémissante et respectez le temps de cuisson indiquée sur le sachet",2), - ("Disposez les pâtes dans l'assiette avec le beurre et mélangez",2), - ("Savourez!",2), - ("mélangez les oeufs et le lait",6), - ("rajoutez la farine",6), - ("laissez reposer 3 heures au minimum", 6), - ("Disposez la pâte sur une poêle chaude",6) -; - -INSERT INTO material (name) -VALUES - ("Poêle"), - ("Casserole"), - ("Spatule en bois"), - ("Egouttoir") -; - -INSERT INTO recipe_material (recipe_ID,material_ID) -VALUES - (1,1), - (1,3), - (2,2), - (2,3), - (2,4) -; - -INSERT INTO tag (name) -VALUES - ('vegan'), - ('végétarien'), - ('sans gluten'), - ('Japon'), - ('Soupe'), - ('Burger'), - ('dessert') -; - - -INSERT INTO comment (description, user_ID, recipe_ID) -VALUES - ("Belle recette, merci !", 1, 1), - ("Il manque un peu de beurre à mon goût...", 2, 1), - ("J'ai pas eu besoin de spatule pour ça!",5,2) -; - -INSERT INTO recipe_ingredient (recipe_ID, ingredient_ID, quantity) -VALUES - (1,1,2), - (1,2,10), - (4,1,2), - (4,6,200), - (5,7,2), - (5, 8,2), - (5,9,200), - (5,10,1), - (6,1,6), - (6,2,20), - (6,10,20), - (6,11,200) -; \ No newline at end of file diff --git a/backend/database/schema.sql b/backend/database/schema.sql index a057644..843ee31 100644 --- a/backend/database/schema.sql +++ b/backend/database/schema.sql @@ -1,9 +1,10 @@ #Access to DB + USE eating_nam_nam; #Create tables for eating nam nam DB CREATE TABLE user ( - ID INT PRIMARY KEY NOT NULL AUTO_INCREMENT, + id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, username VARCHAR(20) UNIQUE NOT NULL, email VARCHAR(30) UNIQUE NOT NULL, firstname VARCHAR(20), @@ -16,7 +17,7 @@ CREATE TABLE user ( ); CREATE TABLE recipe ( ID INT PRIMARY KEY NOT NULL AUTO_INCREMENT, - user_ID INT NOT NULL, + user_id INT NOT NULL, name VARCHAR(80) NOT NULL, title VARCHAR(150) NOT NULL, prep_time INT NOT NULL, @@ -26,11 +27,13 @@ CREATE TABLE recipe ( tag1 VARCHAR(30), tag2 VARCHAR(30), tag3 VARCHAR(30), -FOREIGN KEY (user_ID) REFERENCES user(id) + is_verified BIT DEFAULT 0, + total_kcal INT NOT NULL, +FOREIGN KEY (user_id) REFERENCES user(id) ); CREATE TABLE ingredient ( - ID INT PRIMARY KEY NOT NULL AUTO_INCREMENT, + id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, name VARCHAR(50) NOT NULL, kcal INT NOT NULL, unit VARCHAR(20) NOT NULL @@ -38,56 +41,159 @@ CREATE TABLE ingredient CREATE TABLE fav ( - ID INT PRIMARY KEY NOT NULL AUTO_INCREMENT, - recipe_ID INT NOT NULL, - user_ID INT NOT NULL, - FOREIGN KEY (recipe_ID) REFERENCES recipe(ID), - FOREIGN KEY (user_ID) REFERENCES user(ID) + id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, + recipe_id INT NOT NULL, + user_id INT NOT NULL, + FOREIGN KEY (recipe_id) REFERENCES recipe(id), + FOREIGN KEY (user_id) REFERENCES user(id) ); CREATE TABLE comment ( - ID INT PRIMARY KEY NOT NULL AUTO_INCREMENT, + id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, description VARCHAR(500) NOT NULL, - user_ID INT NOT NULL, - recipe_ID INT NOT NULL, - FOREIGN KEY (user_ID) REFERENCES user(ID), - FOREIGN KEY (recipe_ID) REFERENCES recipe(ID) + user_id INT NOT NULL, + recipe_id INT NOT NULL, + FOREIGN KEY (user_id) REFERENCES user(id), + FOREIGN KEY (recipe_id) REFERENCES recipe(id) ); CREATE TABLE instruction ( - ID INT PRIMARY KEY NOT NULL AUTO_INCREMENT, + id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, description MEDIUMTEXT NOT NULL, - recipe_ID INT NOT NULL, - FOREIGN KEY (recipe_ID) REFERENCES recipe(ID) + recipe_id INT NOT NULL, + FOREIGN KEY (recipe_id) REFERENCES recipe(id) ); CREATE TABLE material ( - ID INT PRIMARY KEY NOT NULL AUTO_INCREMENT, + id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, name VARCHAR(50) ); CREATE TABLE recipe_material ( - ID INT PRIMARY KEY NOT NULL AUTO_INCREMENT, - recipe_ID INT NOT NULL, - material_ID INT NOT NULL, - FOREIGN KEY (recipe_ID) REFERENCES recipe(ID), - FOREIGN KEY (material_ID) REFERENCES material(ID) + id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, + recipe_id INT NOT NULL, + material_id INT NOT NULL, + FOREIGN KEY (recipe_id) REFERENCES recipe(id), + FOREIGN KEY (material_id) REFERENCES material(id) ); CREATE TABLE recipe_ingredient ( - ID INT PRIMARY KEY NOT NULL AUTO_INCREMENT, - recipe_ID INT NOT NULL, - ingredient_ID INT NOT NULL, + id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, + recipe_id INT NOT NULL, + ingredient_id INT NOT NULL, quantity INT NOT NULL, - FOREIGN KEY (recipe_ID) REFERENCES recipe(ID), - FOREIGN KEY (ingredient_ID) REFERENCES ingredient(ID) + FOREIGN KEY (recipe_id) REFERENCES recipe(id), + FOREIGN KEY (ingredient_id) REFERENCES ingredient(id) ); CREATE TABLE tag ( - ID INT PRIMARY KEY NOT NULL AUTO_INCREMENT, + id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, name VARCHAR(30) NOT NULL -) +); + +INSERT INTO user(username, email, firstname, lastname, birthdate, password, is_admin) +VALUES + ('tristanZ', 'tristan.zvunka@gmail.com','tristan','zvunka','1992-11-26', 'test1',1 ), + ('flavienG', 'flavien.gaujardd@gmail.com', 'flavien','giraud','1988-04-12', 'test2',1), + ('elieR', 'elie.rakoto@gmail.com','elie','Rakoto','1990-10-14','test3',0), + ('christopheC','christophe.bruno@gmail.com','Christophe','Bruno','1990-10-14','test4',1), + ('hugoD','hugo.durand@gmail.com','Hugo','Durand','1989-02-05','test5',0) +; + +INSERT INTO recipe (name,title, user_ID, prep_time, nb_people, difficulty,tag1, tag2,tag3,is_verified, total_kcal ) +VALUES + ('oeufs au plat', 'simple comme bonjour',1, 15, 1, 'facile', 'végétarien', 'sans gluten',NULL,true,200), + ('pâtes au beurre','la spécialité des étudiants!', 2, 25, 2, 'facile', 'végétarien', NULL,NULL,true,500), + ('religieuse au chocolat','pour les experts en pâtisserie', 5, 90, 2, 'difficile', 'dessert', 'gourmand',NULL,true,800), + ('ramen', 'Comment réussir un vrai ramen maison comme au Japon?', 2, 180, 2, 'difficile', 'japon', 'gourmand', 'soupe',true,400), + ('cheeseburger', 'Créez votre propre cheeseburger maison!',3,45,2,'facile','burger','gourmand',NULL,true,1200), + ('Les inimitables crêpes','Rapide et efficace, le tout en quelques étapes!', 5, 20, 4, 'facile', 'rapide', 'gourmand','dessert',true,400) +; + +INSERT INTO ingredient (name, unit, kcal) +VALUES +('oeuf', 'pièce(s)', 20), +('beurre', 'grammes', 5), +('chocolat noir', 'grammes', 3), +('farine de blé', 'grammes', 1), +('pâtes', 'grammes', 2), +('nouilles udon', 'grammes',50), +('steak haché', 'pièce(s)',100), +('pain bun','pièce(s)', 40), +('cheddar', 'grammes', 200), +('tomate','pièce(s)',10), +('lait','centilitres',5), +('farine', 'grammes', 0.5) +; + +INSERT INTO instruction (description, recipe_id) +VALUES + ("Préchauffez la poêle",1), + ("rajoutez le beurre dans la poêle",1), + ("cassez les oeufs et les versez dans la poêle sans les mélanger",1), + ("Une fois la texture souhaitée, disposez dans l'assiette", 1), + ("Faites chauffer l'équivalent de 3 volumes d'eau par volume de pâtes dans une casserole en ajoutant du sel",2), + ("Une fois que l'eau bout, insérez les pâtes dans l'eau frémissante et respectez le temps de cuisson indiquée sur le sachet",2), + ("Disposez les pâtes dans l'assiette avec le beurre et mélangez",2), + ("Savourez!",2), + ("mélangez les oeufs et le lait",6), + ("rajoutez la farine",6), + ("laissez reposer 3 heures au minimum", 6), + ("Disposez la pâte sur une poêle chaude",6) +; + +INSERT INTO material (name) +VALUES + ("Poêle"), + ("Casserole"), + ("Spatule en bois"), + ("Egouttoir") +; + +INSERT INTO recipe_material (recipe_id,material_id) +VALUES + (1,1), + (1,3), + (2,2), + (2,3), + (2,4) +; + +INSERT INTO tag (name) +VALUES + ('vegan'), + ('végétarien'), + ('sans gluten'), + ('Japon'), + ('Soupe'), + ('Burger'), + ('dessert') +; + + +INSERT INTO comment (description, user_id, recipe_id) +VALUES + ("Belle recette, merci !", 1, 1), + ("Il manque un peu de beurre à mon goût...", 2, 1), + ("J'ai pas eu besoin de spatule pour ça!",5,2) +; + +INSERT INTO recipe_ingredient (recipe_id, ingredient_id, quantity) +VALUES + (1,1,2), + (1,2,10), + (4,1,2), + (4,6,200), + (5,7,2), + (5, 8,2), + (5,9,200), + (5,10,1), + (6,1,6), + (6,2,20), + (6,10,20), + (6,11,200) +; From c2f3362bdc97ef7cc9628b684d4816f40aafab98 Mon Sep 17 00:00:00 2001 From: TRISTAN ZVUNKA Date: Tue, 23 Jan 2024 23:23:46 +0100 Subject: [PATCH 2/3] add routers for materials and ingredients --- backend/src/router.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/src/router.js b/backend/src/router.js index 1136bb1..e836542 100644 --- a/backend/src/router.js +++ b/backend/src/router.js @@ -67,6 +67,7 @@ router.post( // Import ingredientControllers module for handling item-related operations const IngredientControllers = require("./controllers/ingredientControllers"); +router.get("/ingredients", IngredientControllers.browse); // Route to get a list of items router.get("/ingredient/:id", IngredientControllers.read); // Route to get a specific item by ID router.get("/ingredientbyrecipe/:id", IngredientControllers.readByRecipe); // Route to get ingredients for a specific Recipe @@ -77,6 +78,7 @@ router.get("/ingredientbyrecipe/:id", IngredientControllers.readByRecipe); // Ro // Import materialControllers module for handling item-related operations const MaterialControllers = require("./controllers/materialControllers"); +router.get("/materials", MaterialControllers.browse); // Route to get a list of items router.get("/material/:id", MaterialControllers.read); // Route to get a specific item by ID router.get("/materialByRecipe/:id", MaterialControllers.readByRecipe); // Route to get materials for a specific Recipe From 43de9c98eff8a780c9b7628f947cc21bc6e3265d Mon Sep 17 00:00:00 2001 From: Flavien G <44913995+fgaujard@users.noreply.github.com> Date: Tue, 23 Jan 2024 23:56:20 +0100 Subject: [PATCH 3/3] Keep Session logged and block access if denied --- backend/src/controllers/authControllers.js | 29 +++++++++++++++++- backend/src/middleware/authMiddleware.js | 12 ++++---- backend/src/router.js | 14 ++++++--- frontend/src/main.jsx | 35 ++++++++++++++++++---- frontend/src/pages/Connexion.jsx | 2 ++ frontend/src/pages/Recipe.jsx | 22 +++++++++----- frontend/src/pages/RecipeList.jsx | 13 ++++---- frontend/src/pages/style/RecipeList.scss | 22 +++++++++----- 8 files changed, 111 insertions(+), 38 deletions(-) diff --git a/backend/src/controllers/authControllers.js b/backend/src/controllers/authControllers.js index 3261d57..3049a90 100644 --- a/backend/src/controllers/authControllers.js +++ b/backend/src/controllers/authControllers.js @@ -42,6 +42,7 @@ const login = async (req, res, next) => { try { // Verify if the username exist in the database const user = await tables.user.readByUsername(req.body.username); + console.info(user); if (user) { // Verify if the password match with the hashed in the database @@ -50,7 +51,7 @@ const login = async (req, res, next) => { if (verified) { // Create a token for open & keep the user session as logged const token = jwt.sign( - { username: user.username, is_admin: user.is_admin }, + { id: user.id, username: user.username, is_admin: user.is_admin }, process.env.APP_SECRET, { expiresIn: "1h" } ); @@ -72,11 +73,37 @@ const login = async (req, res, next) => { } }; +const verifyToken = async (req, res, next) => { + try { + const { token } = req.cookies; + + if (!token) { + res.status(401).json({ error: "No token founded" }); + } else { + const decoded = jwt.verify(token, process.env.APP_SECRET); + const user = await tables.user.read(decoded.id); + if (user) + res.status(200).json({ + success: "User is valid", + is_loggin: true, + is_admin: decoded.is_admin, + }); + else + res + .status(401) + .json({ error: "The token is invalid", is_loggin: false }); + } + } catch (err) { + next(err); + } +}; + module.exports = { // browse, readByUsername, readByEmail, login, + verifyToken, // edit, // add, // destroy, diff --git a/backend/src/middleware/authMiddleware.js b/backend/src/middleware/authMiddleware.js index cd05213..6bae066 100644 --- a/backend/src/middleware/authMiddleware.js +++ b/backend/src/middleware/authMiddleware.js @@ -24,20 +24,18 @@ const verifyToken = async (req, res, next) => { try { const { token } = req.cookies; - console.info(req.cookies); - - console.info(token); - if (!token) { res.status(401).json({ error: "No token founded" }); } else { const decoded = jwt.verify(token, process.env.APP_SECRET); + console.info(decoded); const user = await tables.user.read(decoded.id); - console.info({ user }); - next(); + console.info(user); + if (user) next(); + else res.status(401).json({ error: "The token is invalid" }); } } catch (err) { - res.status(401).json({ error: "The token is invalid" }); + res.status(401).json({ error: "Internal error" }); } }; diff --git a/backend/src/router.js b/backend/src/router.js index 1136bb1..206f1a6 100644 --- a/backend/src/router.js +++ b/backend/src/router.js @@ -24,15 +24,22 @@ const AuthControllers = require("./controllers/authControllers"); // Import the middleware for hash password in DB when a new user register const AuthMiddleware = require("./middleware/authMiddleware"); +router.post("/login", AuthControllers.login); +router.post("/users", AuthMiddleware.hashPwd, UserControllers.add); +router.get("/verify-token", AuthControllers.verifyToken); + +router.use(AuthMiddleware.verifyToken); + router.get("/users", UserControllers.browse); // Route to get a list of items router.get("/users/:id", UserControllers.read); // Route to get a specific item by ID -router.post("/users", AuthMiddleware.hashPwd, UserControllers.add); router.put( "/users/:id", uploadUsersAvatars.single("avatar"), UserControllers.edit -); // Route to update user +); + +// Route to update user router.post( "/users", AuthMiddleware.hashPwd, @@ -43,7 +50,6 @@ router.post( // Route to get specific items and block the register if they exists router.get("/username/:username", AuthControllers.readByUsername); router.get("/email/:email", AuthControllers.readByEmail); -router.post("/login", AuthControllers.login); /* ************************************************************************* */ // RECIPE @@ -52,7 +58,7 @@ router.post("/login", AuthControllers.login); // Import recipeControllers module for handling item-related operations const RecipeControllers = require("./controllers/recipeControllers"); -router.get("/recipes", AuthMiddleware.verifyToken, RecipeControllers.browse); // Route to get a list of items +router.get("/recipes", RecipeControllers.browse); // Route to get a list of items router.get("/recipes/:id", RecipeControllers.read); // Route to get a specific item by ID router.get("/recipebyuser/:id", RecipeControllers.readByUser); router.post( diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx index 727576d..ed4c576 100644 --- a/frontend/src/main.jsx +++ b/frontend/src/main.jsx @@ -20,17 +20,40 @@ const router = createBrowserRouter([ { path: "/recipes", element: , + loader: () => { + return Promise.all([ + axios.get(`${import.meta.env.VITE_BACKEND_URL}/api/recipes`, { + withCredentials: true, + }), + axios.get(`${import.meta.env.VITE_BACKEND_URL}/api/tags`, { + withCredentials: true, + }), + ]) + .then(([recipeResponse, tagsResponse]) => { + const recipe = recipeResponse.data; // Accédez aux données de la réponse + const tags = tagsResponse.data; // Accédez aux données de la réponse + return Promise.all([{ recipe }, { tags }]); + }) + .catch(() => { + // Gérez l'erreur ici (redirection vers "/connexion" par exemple) + window.location.href = "/connexion"; + }); + }, }, { path: "/recipes/:id", element: , loader: ({ params }) => { - return axios.get( - `${import.meta.env.VITE_BACKEND_URL}/api/recipes/${params.id}`, - { - withCredentials: true, - } - ); + return axios + .get( + `${import.meta.env.VITE_BACKEND_URL}/api/recipes/${params.id}`, + { + withCredentials: true, + } + ) + .catch(() => { + window.location.href = "/connexion"; + }); }, }, { diff --git a/frontend/src/pages/Connexion.jsx b/frontend/src/pages/Connexion.jsx index 204d7a6..98e5ede 100644 --- a/frontend/src/pages/Connexion.jsx +++ b/frontend/src/pages/Connexion.jsx @@ -2,6 +2,7 @@ import { useState } from "react"; import PropTypes from "prop-types"; import { ToastContainer, toast } from "react-toastify"; import axios from "axios"; + import { isValidUsername, isValidEmail, @@ -13,6 +14,7 @@ import { resetErrMsgPassConfSign, resetAllErrMsgSign, } from "./services/postUserValid"; + import "react-toastify/dist/ReactToastify.css"; import "./style/Connexion.scss"; diff --git a/frontend/src/pages/Recipe.jsx b/frontend/src/pages/Recipe.jsx index 6c11b38..d3dea71 100644 --- a/frontend/src/pages/Recipe.jsx +++ b/frontend/src/pages/Recipe.jsx @@ -13,14 +13,20 @@ function Recipe({ name, title, difficulty, id, image, tag1, tag2, tag3 }) {

{name}

{title}

-

{difficulty}

-

{tag1}

-

{tag2}

-

{tag3}

-
- -

En savoir plus

- +
+

{difficulty}

+
+
+

{tag1}

+

{tag2}

+

{tag3}

+
+
+ +

En savoir plus

+ +
+
diff --git a/frontend/src/pages/RecipeList.jsx b/frontend/src/pages/RecipeList.jsx index 9b1ef4e..6f776df 100644 --- a/frontend/src/pages/RecipeList.jsx +++ b/frontend/src/pages/RecipeList.jsx @@ -1,13 +1,14 @@ -import axios from "axios"; -import { useState, useEffect } from "react"; +import { useState } from "react"; +import { useLoaderData } from "react-router-dom"; import Recipe from "./Recipe"; import "./style/RecipeList.scss"; function RecipeList() { - const [allRecipe, setAllRecipe] = useState([]); - const [filters, setFilters] = useState([]); + const allRecipe = useLoaderData()[0].recipe; + const filters = useLoaderData()[1].tags; const [filtersRecipe, setFiltersRecipe] = useState(""); + /* useEffect(() => { const endpoints = [ "http://localhost:3310/api/recipes", @@ -26,10 +27,12 @@ function RecipeList() { console.info(recipe, tag); }) .catch(() => { - window.location.href = "/"; + window.location.href = "/connexion"; }); }, []); + */ + return (
diff --git a/frontend/src/pages/style/RecipeList.scss b/frontend/src/pages/style/RecipeList.scss index 98f835a..df5b6ad 100644 --- a/frontend/src/pages/style/RecipeList.scss +++ b/frontend/src/pages/style/RecipeList.scss @@ -29,9 +29,9 @@ list-style: none; background-color: $white-color; border-radius: 1.5rem; - height: 200px; - min-width: 300px; - max-width: 400px; + min-height: 200px; + min-width: 380px; + max-width: 420px; box-shadow: 0px 15px 20px rgba(0, 0, 0, 0.1); display: flex; @@ -53,10 +53,18 @@ } .desc-recipe { + padding: 0.25rem; margin: 0.5rem; width: 55%; display: flex; flex-direction: column; + justify-content: space-between; + + .recipe-bottom { + display: flex; + justify-content: space-between; + align-items: last baseline; + } h2 { font-size: medium; @@ -65,20 +73,20 @@ } p { font-size: small; - margin: 0.25rem 0.5rem 0.25rem 0; } .level-recipe { - margin: auto 0.25rem 0.25rem auto; + text-align: right; } .link-to { display: flex; - margin: 0.25rem 0.25rem 0.25rem auto; background-color: $orange-color; - padding-left: 0.5rem; + padding: 0.5rem; + margin: 0.25rem; border-radius: 1rem; text-align: right; + align-items: center; &:hover { background-color: #db9146; cursor: pointer;