SearchBar & Page

This commit is contained in:
Ruidy Nemausat 2020-01-27 15:48:18 +01:00
parent 6a288f1246
commit a1462ed9e0
10 changed files with 113 additions and 87 deletions

View file

@ -2,6 +2,8 @@
Free meal planner for cooks short on ideas! (like me …) Free meal planner for cooks short on ideas! (like me …)
[Available on](https://chefs-meal-planner.onrender.com/)
## Features ## Features
- Random meal suggestion - Random meal suggestion
@ -52,6 +54,7 @@ Free meal planner for cooks short on ideas! (like me …)
- Notation system: know what are the most loved meals - Notation system: know what are the most loved meals
- Suggestions based on what your personal taste - Suggestions based on what your personal taste
- Recipes in Video - Recipes in Video
- Get a full menu (Starter, Main, Dessert + Cocktail)
## Supports ## Supports
@ -68,7 +71,7 @@ Free meal planner for cooks short on ideas! (like me …)
## Versions ## Versions
### Features in V.1 ### Features in V.0.1
- WebApp - WebApp
- Random meal suggestion - Random meal suggestion
@ -78,3 +81,4 @@ Free meal planner for cooks short on ideas! (like me …)
## TO DO ## TO DO
- put a preloader - put a preloader
- change favicon

View file

@ -5,7 +5,7 @@
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta name="description" content="Chef's Meal Planner" /> <meta name="description" content="Chef's | Meal Planner" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
@ -25,15 +25,15 @@
href="https://fonts.googleapis.com/icon?family=Material+Icons" href="https://fonts.googleapis.com/icon?family=Material+Icons"
/> />
<title>Chef's Meal Planner</title> <title>Chef's | Meal Planner</title>
</head> </head>
<body> <body>
<script> <!-- <script>
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function() {
var elems = document.querySelectorAll(".sidenav"); var elems = document.querySelectorAll(".sidenav");
var instances = M.Sidenav.init(elems, options); var instances = M.Sidenav.init(elems, options);
}); });
</script> </script> -->
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
</body> </body>

View file

@ -18,7 +18,7 @@
"sizes": "512x512" "sizes": "512x512"
} }
], ],
"start_url": ".", "start_url": "/",
"display": "standalone", "display": "standalone",
"theme_color": "#000000", "theme_color": "#000000",
"background_color": "#ffffff" "background_color": "#ffffff"

View file

@ -15,6 +15,7 @@ const App = () => {
// State Hooks // State Hooks
const [searchString, setSearchString] = useState(""); const [searchString, setSearchString] = useState("");
const [categories, setCategories] = useState({ categories: [] }); const [categories, setCategories] = useState({ categories: [] });
const [searchResults, setSearchResults] = useState({ meals: [] });
// const [isLoading, setIsLoading] = useState(true); For Preloader // const [isLoading, setIsLoading] = useState(true); For Preloader
// Default meal object. TODO: Find a better alternative … // Default meal object. TODO: Find a better alternative …
const mealDef = { const mealDef = {
@ -87,8 +88,11 @@ const App = () => {
return `${ROOT}${option}.php?c=${keyword}`; return `${ROOT}${option}.php?c=${keyword}`;
} else if (option === "lookup") { } else if (option === "lookup") {
return `${ROOT}${option}.php?i=${keyword}`; return `${ROOT}${option}.php?i=${keyword}`;
} else if (option === "search") {
return `${ROOT}${option}.php?s=${keyword}`;
} }
}; };
const getFromAPI = (keyword, set, option = null) => { const getFromAPI = (keyword, set, option = null) => {
const URI = createURI(keyword, option); const URI = createURI(keyword, option);
fetch(URI) fetch(URI)
@ -111,6 +115,10 @@ const App = () => {
getFromAPI("categories", setCategories); getFromAPI("categories", setCategories);
}; };
const getSearchResults = () => {
getFromAPI(searchString, setSearchResults, "search");
};
const handleChange = ev => { const handleChange = ev => {
const { value } = ev.target; const { value } = ev.target;
setSearchString(value); setSearchString(value);
@ -121,42 +129,30 @@ const App = () => {
<Router> <Router>
<Navbar handleClick={getRandomMeal} buttonUrl={buttonUrl} /> <Navbar handleClick={getRandomMeal} buttonUrl={buttonUrl} />
<div className="container"> <div className="container">
<SearchBar searchString={searchString} handleChange={handleChange} /> <SearchBar
searchString={searchString}
handleChange={handleChange}
onSubmit={getSearchResults}
/>
</div> </div>
<Switch> <Switch>
<Route <Route exact path="/">
exact <HomePage handleClick={getRandomMeal} buttonUrl={buttonUrl} />
path="/" </Route>
render={props => ( <Route exact path={buttonUrl}>
<HomePage <MealPage
{...props} meal={meal}
handleClick={getRandomMeal} getMeal={getRandomMeal}
buttonUrl={buttonUrl} // isLoading={isLoading}
/> />
)} </Route>
/> />
<Route <Route exact path="/categories">
exact <CategoryListPage
path={buttonUrl} categories={categories}
render={props => ( getCategories={getCategories}
<MealPage />
{...props} </Route>
meal={meal}
getMeal={getRandomMeal}
// isLoading={isLoading}
/>
)}
/>
<Route
exact
path="/categories"
render={props => (
<CategoryListPage
{...props}
categories={categories}
getCategories={getCategories}
/>
)}
/> />
<Route path="/categories/:strCategory/"> <Route path="/categories/:strCategory/">
<CategoryPage <CategoryPage
@ -166,13 +162,19 @@ const App = () => {
meal={meal} meal={meal}
/> />
</Route> </Route>
<Route exact path="/search">
<SearchPage
searchString={searchString}
searchResults={searchResults}
// getSearchResults={getSearchResults}
/>
</Route>
<Route path="/:idMeal"> <Route path="/:idMeal">
<MealPage meal={meal} getMeal={getMeal} /> <MealPage meal={meal} getMeal={getMeal} />
</Route> </Route>
<Route exact path="/search" component={SearchPage} /> <Route>
{/* We'll have to input searchResults somewhere */} <NotFound handleClick={getRandomMeal} />
<Route </Route>
render={props => <NotFound {...props} handleClick={getRandomMeal} />}
/> />
</Switch> </Switch>
<Footer /> <Footer />

View file

@ -1,15 +1,31 @@
import React from "react"; import React from "react";
import { Link } from "react-router-dom";
const SearchBar = props => { const SearchBar = props => {
return ( return (
<input <div className="row">
type="text" <input
name="search" className="input-field col s9"
value={props.searchString} type="text"
placeholder="Search a recipe" name="search"
onChange={props.handleChange} value={props.searchString}
//{onSubmit={props.handleSubmit} placeholder="Search a recipe"
/> onChange={props.handleChange}
/>
<Link to="/search">
<button
className="btn waves-effect waves-light right"
type="submit"
name="searchButton"
value="Search"
onClick={props.onSubmit}
>
{" "}
Search
<i class="material-icons right">send</i>
</button>
</Link>
</div>
); );
}; };
export default SearchBar; export default SearchBar;

View file

@ -0,0 +1,20 @@
import React from "react";
import { Link } from "react-router-dom";
const SearchResult = props => {
const { meal } = props;
const { idMeal, strMeal, strMealThumb } = meal;
return (
<div className="row">
<Link to={`${idMeal}`}>
<li key={props.i}>
<img src={strMealThumb} alt={strMeal} />
<h3>{strMeal}</h3>
</li>
</Link>
</div>
);
};
export default SearchResult;

View file

@ -1,16 +0,0 @@
import React from "react";
const SearchResultList = () => {
return (
<div>
<ul>
<li>Recipe #1</li>
<li>Recipe #2</li>
<li>Recipe #</li>
<li>Recipe #N</li>
</ul>
</div>
);
};
export default SearchResultList;

View file

@ -2,7 +2,7 @@ import React, { useEffect } from "react";
import CategoryEntry from "../components/CategoryEntry"; import CategoryEntry from "../components/CategoryEntry";
const CategoryListPage = props => { const CategoryListPage = props => {
const categories = props.categories.categories; const { categories } = props.categories;
const { getCategories } = props; const { getCategories } = props;
useEffect(() => { useEffect(() => {

View file

@ -47,10 +47,10 @@ const MealPage = props => {
return ( return (
<div className="container"> <div className="container">
<div className="row"> <div className="row">
<div className="col s6"> <div className="col s12 m6">
<MealPresentation meal={item} /> <MealPresentation meal={item} />
</div> </div>
<div className="col s6"> <div className="col s12 m6">
<IngredientList ingredients={ingredientList} /> <IngredientList ingredients={ingredientList} />
<Recipe recipe={strInstructions} /> <Recipe recipe={strInstructions} />
</div> </div>

View file

@ -1,18 +1,18 @@
import React, { Component } from "react"; import React from "react";
import SearchResultList from "../components/SearchResultList"; import SearchResult from "../components/SearchResult";
export default class SearchPage extends Component { const SearchPage = props => {
constructor(props) { const { meals } = props.searchResults;
super(props); const { searchString } = props;
this.initState = {};
this.state = this.initState; // console.log(meals[0]);
} return (
render() { <div className="container">
return ( <h1>Search Results for: {searchString} </h1>
<div> {meals.map((meal, i) => (
<h1>Search Results</h1> <SearchResult i={i} meal={meal} />
<SearchResultList /> ))}
</div> </div>
); );
} };
} export default SearchPage;