diff --git a/.gitignore b/.gitignore index a726254..fcdbad0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ examp_frontend/ postgres/db */.env +todo diff --git a/backend/backendServer.js b/backend/backendServer.js index df45732..2713b8c 100644 --- a/backend/backendServer.js +++ b/backend/backendServer.js @@ -21,8 +21,31 @@ app.get("/recipes", async (req, res) => { app.get("/recipe/:id", async (req, res) => { const id = req.params.id try { - const recipe = await db('recipes').where('id', '=', id).select('id', 'name', 'cuisine').first(); - res.json(recipe); + const recipeQuery = db('recipes').where('id', '=', id).select('id', 'name', 'cuisine'); + + const ingredientsQuery = db.from('recipe_ingredients as ri') + .join('ingredients as i', 'ri.ingredient_id', 'i.id') + .where('ri.recipe_id', id) + .select('i.name', 'ri.quantity', 'ri.unit'); + + const stepsQuery = db('recipe_steps').where('recipe_id', id).select('step_number', 'instruction'); + + const [recipe, ingredients, steps] = await Promise.all([recipeQuery, ingredientsQuery, stepsQuery]); + + const result = { + recipe: recipe[0], + ingredients: ingredients.map(ingredient => ({ + name: ingredient.name, + quantity: ingredient.quantity, + unit: ingredient.unit + })), + steps: steps.reduce((acc, step) => { + acc[step.step_number] = step.instruction; + return acc; + }, {}) + }; + + res.json(result); } catch (err) { console.log(err); res.status(500).json({ error: err.message }); @@ -30,12 +53,45 @@ app.get("/recipe/:id", async (req, res) => { }); app.post("/add-recipe", async (req, res) => { - const { name, cuisine } = req.body; + const { name, cuisine, ingredients, steps } = req.body; try { const [id] = await db('recipes').insert({ name: name, cuisine: cuisine }, ['id']) + + const existingIngredients = await db('ingredients').whereIn('name', ingredients.map(ing => ing.name)); + let ingredientData = []; + for (let ingredient of ingredients) { + const existingIngredient = existingIngredients.find(ing => ing.name === ingredient.name); + if (!existingIngredient) { + // create the ingredient if there is no entry + const [ingredientId] = await db('ingredients').insert({ + name: ingredient.name + }, ['id']); + ingredientData.push({ id: ingredientId, quantity: ingredient.quantity, unit: ingredient.unit }); + } else { + // if the ingredient exists use existing entry + ingredientData.push({ id: existingIngredient.id, quantity: ingredient.quantity, unit: ingredient.unit }); + } + } + + const ingredientInserts = ingredientData.map(ing => ({ + ingredient_id: ing.id, + quantity: ing.quantity, + unit: ing.unit, + recipe_id: id.id + })); + await db('recipe_ingredients').insert(ingredientInserts); + + // Step 4: Insert steps into recipe_steps + const stepInserts = Object.keys(steps).map(stepNumber => ({ + recipe_id: id.id, + step_number: parseInt(stepNumber), + instruction: steps[stepNumber] + })); + await db('recipe_steps').insert(stepInserts); + res.status(200).send({ message: "Recipe added", id: id.id }); } catch (err) { console.log(err); diff --git a/backend/migrations/20250708205938_create_ingredients_table.js b/backend/migrations/20250708205938_create_ingredients_table.js index 5a24465..55255ee 100644 --- a/backend/migrations/20250708205938_create_ingredients_table.js +++ b/backend/migrations/20250708205938_create_ingredients_table.js @@ -25,7 +25,7 @@ exports.up = function (knex) { table.increments('id').primary(); table.integer('recipe_id'); table.integer('step_number'); - table.string('instructions'); + table.string('instruction'); table.unique(['recipe_id', 'step_number']); table.index(['recipe_id']) table.timestamps(true, true); diff --git a/todo b/todo deleted file mode 100644 index 4e28e34..0000000 --- a/todo +++ /dev/null @@ -1,7 +0,0 @@ -todo: -add recipe redirect to recipe page. id is getting returned now. -make naming consistent and sensical of pages, functions, vars etc. -add are you sure modal to delete. -add delete to recipe page -Ensure Accessibility: Make sure you include attributes like aria-labelledby and aria-describedby for better accessibility. # i dont know what this means, but it might be a good idea to look into it or other accessability before finishing the project -