Created
June 1, 2022 00:44
-
-
Save josecarneiro/e6e9de9baf8fbb0647da52560283fd4f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState } from 'react'; | |
import foods from './foods.json'; | |
const MealBox = (props) => { | |
const [quantity, setQuantity] = useState(1); | |
const meal = props.meal; | |
const handleQuantityChange = (event) => { | |
const { value } = event.target; | |
setQuantity(Number(value)); | |
}; | |
const handleFormSubmission = (event) => { | |
event.preventDefault(); | |
props.onAddToTodaysMeals(meal, quantity); | |
}; | |
return ( | |
<div className="media"> | |
<img | |
src={meal.image} | |
className="img-thumbnail mr-3 mw-25 border-0" | |
style={{ maxWidth: '10em' }} | |
alt={meal.name} | |
/> | |
<div className="media-body align-self-center"> | |
<h5 className="mt-0 mb-1">{meal.name}</h5> | |
<small>{meal.calories} cal</small> | |
</div> | |
<form className="row align-self-center" onSubmit={handleFormSubmission}> | |
<input | |
className="form-control col-9" | |
type="number" | |
onChange={handleQuantityChange} | |
value={quantity} | |
/> | |
<button className="btn btn-primary col-3">+</button> | |
</form> | |
</div> | |
); | |
}; | |
const AddNewMealForm = (props) => { | |
const [name, setName] = useState(''); | |
const [calories, setCalories] = useState(0); | |
const [image, setImage] = useState(''); | |
const handleFormSubmission = (event) => { | |
event.preventDefault(); | |
props.onAddNewMeal({ name, calories, image }); | |
}; | |
return ( | |
<form onSubmit={handleFormSubmission}> | |
<label htmlFor="name-input">Meal Name</label> | |
<input | |
id="name-input" | |
type="text" | |
placeholder="Name" | |
name="name" | |
required | |
onChange={(event) => setName(event.target.value)} | |
value={name} | |
/> | |
<label htmlFor="calories-input">Number of Calories</label> | |
<input | |
id="calories-input" | |
type="number" | |
placeholder="Calories" | |
name="calories" | |
required | |
onChange={(event) => setCalories(event.target.valueAsNumber)} | |
value={calories} | |
/> | |
<label htmlFor="image-input">Image</label> | |
<input | |
id="image-input" | |
type="text" | |
placeholder="Image" | |
name="image" | |
required | |
onChange={(event) => setImage(event.target.value)} | |
value={image} | |
/> | |
<button>Confirm Meal</button> | |
</form> | |
); | |
}; | |
const Search = (props) => ( | |
<input | |
type="text" | |
placeholder="Search for any meal..." | |
value={props.query} | |
onChange={(event) => props.onQueryChange(event.target.value)} | |
/> | |
); | |
const TodaysMealsList = ({ meals }) => { | |
const total = meals.reduce( | |
(sum, meal) => sum + meal.calories * meal.quantity, | |
0 | |
); | |
return ( | |
<div> | |
<ul> | |
{meals.map((meal) => ( | |
<li> | |
{meal.quantity} - {meal.name} = {meal.calories * meal.quantity}{' '} | |
calories | |
</li> | |
))} | |
</ul> | |
<span>Total: {total} calories</span> | |
</div> | |
); | |
}; | |
const App = () => { | |
const [addNewMealActive, setAddNewMealActive] = useState(false); | |
const [query, setQuery] = useState(''); | |
const [meals, setMeals] = useState(foods); | |
const [todaysMeals, setTodaysMeals] = useState([]); | |
const handleMealAddition = (meal) => { | |
setMeals([meal, ...meals]); | |
setAddNewMealActive(false); | |
}; | |
const handleTodaysMealsAddition = (meal, quantity) => { | |
const existingMealInList = todaysMeals.find( | |
(todaysMeal) => todaysMeal.name === meal.name | |
); | |
if (existingMealInList) { | |
const updatedTodaysMeals = todaysMeals.map((todaysMeal) => { | |
if (todaysMeal === existingMealInList) { | |
return { | |
...meal, | |
quantity: quantity + existingMealInList.quantity, | |
}; | |
} else { | |
return todaysMeal; | |
} | |
}); | |
setTodaysMeals(updatedTodaysMeals); | |
} else { | |
setTodaysMeals([...todaysMeals, { ...meal, quantity }]); | |
} | |
}; | |
/* | |
If there is no search query, all meals should be rendered | |
If there is a search query, only meals in which name matches query | |
should be rendered | |
*/ | |
const filteredMeals = !query | |
? meals | |
: meals.filter((meal) => | |
meal.name.toLowerCase().includes(query.toLowerCase()) | |
); | |
return ( | |
<div> | |
<Search query={query} onQueryChange={(value) => setQuery(value)} /> | |
{(addNewMealActive && ( | |
<AddNewMealForm onAddNewMeal={handleMealAddition} /> | |
)) || ( | |
<button onClick={() => setAddNewMealActive(true)}>Add new meal</button> | |
)} | |
{filteredMeals.map((meal) => ( | |
<MealBox | |
key={meal.name} | |
meal={meal} | |
onAddToTodaysMeals={handleTodaysMealsAddition} | |
/> | |
))} | |
<TodaysMealsList meals={todaysMeals} /> | |
</div> | |
); | |
}; | |
export default App; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment