A meal planner app, built using React and Edamam API, in which user can get a list of recipe based on their diet and health. This project is created as part of General Assembly's Software Engineering Immersive program for its front-end development unit.
Try the app here!
- React 17
- react-router-dom
- react-beautiful-dnd
- react-error-boundary
- Material UI
- Tailwind CSS
Here are some wireframes that I first created when planning the app. Some feature, i.e. Save Modal and Save page are not implemented yet at the time of writing as I was overthinking my project which led to overcomplicating the project. There are some possibility that these features will be implemented in the future so do look out for it 😉
- User should be able to create a plan by filling in a form, and get their meal plan based on the number of days in the week they want to plan (min. 1 day, max. 7 days), how many meals they want to have in a day (breakfast-lunch-dinner or breakfast-lunch-dinner-snack-teatime), diet (e.g. balanced, low-fat), and health/allergy (e.g. egg-free, DASH, etc)
- User should be able to easily click on the available options in the form. As there is "none" option for diet and health, when user click "none", any other options that they choose should be unselected
- User should be able to rearrange their meal plan by dragging and dropping the meal cards in the Meal Planner page
- User should be able to view the ingredients, recipe, and nutritional value by double-clicking the meal card
- User should be able to read the list of groceries for their meals in the week
- User should be able to see whether they can find the ingredient in their favorite supermarket
- User should be able to quickly navigate through the plan using the Navigation bar in the Meal Planner page
-
Plan the whole thing, even though not everything gets implemented Spent the weekends searching and comparing multiple recipe API, including API from Spoonacular, Open Food API, Edamam API, Tasty API, and many more. I decided to use Edamam API, particularly the Recipe endpoint, for its extensive list of diet and health labels, as well as the nutritional value data. Then, I created the wireframe to visualize the app and create a component tree.
-
Fetching data from the API This step includes creating an account to get an API key, trying out the API, and using
Fetch APIin the script to get the data. As there's a 10,000 API call limit per month for the free version of Edamam API, I had to emulate the API call using a dummy API and copy the data I got from trying out the API so that I can work on the data presentation without having to call the API multiple times.Edamam API only returns 20 recipes per call, and to get another 20 recipes (so that there are more options to randomize from when generating lunch, dinner, snack, and teatime), I need to call the next page API specified in the data, as shown in the screenshot below

In order to do this, I created another state called
nextAPI, which is initialized with the object{ none: "" }, and useuseEffectwith the key as dependency.Data fetch is handled by
fetchData()function, which accepts 3 parameters:url: the API URLmealType: whether it's breakfast, lunch (which also includes dinner), or snack (includes teatime)callback: a function, which setsisLoadingtofalsewhen the next data is fetched
When there are changes to the
nextAPIkey, the code block in useEffect is run, and the next 20 recipes are fetched.You can refer to
/src/MealPlanner.json how this is implemented -
Create
Selectioncomponent andCreatepageThe first component that I built was the
Selectioncomponent, which is used later in the app to let users to choose from the available diet, health and allergy option. The data needed for this component are passed down fromCreatepage, which includes:title: the title that describes the selection, which will be rendered bySelectionLabeltypes: options that user can choose from (e.g. dairy-free, sugar-concious, etc)multiple: indicator whether user can select multiple options (boolean:trueif user can select multiple,falseif user can only select 1)id: identifier of theSelectioncomponentsetData: passed in function (asetState) that records user's selectionhasImage: whether there are icons (boolean:trueif there's icon together with the selection card,falseif there's no icon)
There are 2 components under
Selection:SelectionLabel: shows the title of the selection, e.g. "Diet" or "Health"SelectionCardGroup: a group of cards from which users can choose. This component rendersSelectableCardcomponent
In
SelectableCard, all the data is rendered in aCardifhasImageis true, and a roundeddivotherwise.When a
SelectableCardis clicked, it callshandleClickfunction defined inSelectableCardGroupwhere the selection logic resides. As we have asetStatefunction propped down fromCreatepage to the selection components assetData, we can callprops.setDatasave the selected option to the state and trigger re-rendering to mark rthe ones the user has selected by giving it a different background colorHere is the end product of the
Selectioncomponent after stylingselection-demo.mp4
DISCLAIMER: the icons are not mine, please refer to Reference section for the attribution
-
Meal plan logic Meal plan is generated in
MealPlancomponent, with the data propped down fromMealPlannerafter getting all the data. Recipe selection is done by choosing a random index based on the meal type (breakfast, lunch, etc) -
Show meal plan in the DOM The presentation is handled by
MealListandMealCardcomponent -
Show the recipe next to the meal plan Double-clicking the meal in the planner will render the recipe beside the meal plan section. The presentation is handled by
RecipeContainerandNutritionTablecomponents. -
Get the ingredients of the meals, and feed it to
Groceriescomponent -
Show the groceries list, as well as whether the item can be found in the supermarket To do this, I used the list of ingredients for all the recipes and used it as search term for the supermarket API. As I need to call the API multiple times based on the number of ingredients,
Promise.allfunction is useful so that I can wait for all data to be fetched and render everything at the same time. This is done inGroceryCardcomponent -
Create a navigation bar in the planner page Created anchor so that user can jump to different section of the plan (e.g. Meal Plan Day 1-7 and Groceries) without having to scroll too much
-
CSS and styling After all components can be displayed, it's time to do styling. For this project, I am using Tailwind CSS to replace some inline styling (thanks to my classmates who recommended it) and Material UI to create some components like Accordion, Table, Card, Box and Grid. I am referring to Wanderlog for the meal planner design.
In retrospect, I feel that I should have used an API that directly generates the meal plan instead of generating the meal plan on FE. This way the code can be much cleaner and safer
Final product:
full-demo-v2.mp4
DISCLAIMER: the icons are not mine, please refer to Reference section for the attribution
- Adding
_redirectsfile in the root of the project helps to solve routing issues on netlify (source: dev.to)
-
Groceries
- Use other platform's API so that the user can check if the item is available or cheaper elsewhere
- Groceries need to be categorized so that
egg,egg yolk, andeggsshould appear asegg - Increase accuracy of the search result after getting data from the API by evaluating the search result and implement additional logic
- Add groceries quantity based on the recipe
-
Add favorite recipe and plan
-
Search and change menu functionality
For this project, I am using Edamam API to get the recipes as well as the nutritional value for each recipe. As this application is targeted for people who would like to have a certain diet, Edamam API would be a good choice for this application because of its extensive diet and health label as well as the nutritional value analysis.
API from a supermarket in Singapore is used to retrieve groceries data, whether or not the item can be found in the supermarket
To use the app on your local environment:
- Clone this repo
git clone https://github.com/orlinromy/meal-prep.git
- Install npm packages
npm install
- Run the app
npm start
- Wanderlog for the planner page design reference
- Meal icons created by Freepik - Flaticon
- Mixer animated icons created by Freepik - Flaticon
- Salad icons created by Freepik - Flaticon
- English breakfast icons created by Freepik - Flaticon
- Dinner icons created by Eucalyp - Flaticon
- Whey icons created by Konkapp - Flaticon
- Fiber icons created by Flat Icons - Flaticon
- No fat icons created by Freepik - Flaticon
- Carbs icons created by surang - Flaticon
- Salt free icons created by Freepik - Flaticon
- Forbidden icons created by Freepik - Flaticon
- Cooking animated icons created by Freepik - Flaticon
- How to Add Drag and Drop in React with React Beautiful DnD
- GA SEI 37 Instructional Team and fellow comrades





