daily brush

This commit is contained in:
Ruidy Nemausat 2020-01-29 21:01:04 +01:00
parent 85f6f9efc1
commit 257c14fa90
28 changed files with 165 additions and 154 deletions

View file

@ -87,4 +87,3 @@ Free meal planner for cooks short on ideas! (like me …)
- Use ErrorBoundaries component ? - Use ErrorBoundaries component ?
- add sidenav on mobile - add sidenav on mobile
- contact form - contact form
- override Router with scoll to top function

View file

@ -25,6 +25,6 @@
], ],
"start_url": "/", "start_url": "/",
"display": "standalone", "display": "standalone",
"theme_color": "#000000", "theme_color": "#ee6e73",
"background_color": "#ffffff" "background_color": "#ffffff"
} }

View file

@ -1,41 +1,37 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { import { Router } from "./utils/router";
BrowserRouter as Router, import { Switch, Route, Redirect } from "react-router-dom";
Switch, import { HomePage } from "./pages/Home";
Route, import { MealPage } from "./pages/Meal";
Redirect import { SearchPage } from "./pages/Search";
} from "react-router-dom"; import { CategoryListPage } from "./pages/CategoryList";
import HomePage from "./pages/Home"; import { CategoryPage } from "./pages/Category";
import MealPage from "./pages/Meal"; import { NotFoundPage } from "./pages/NotFound";
import SearchPage from "./pages/Search"; import { Navbar } from "./components/Navbar";
import CategoryListPage from "./pages/CategoryList"; import { SearchBar } from "./components/SearchBar";
import CategoryPage from "./pages/Category"; import { Footer } from "./components/Footer";
import NotFound from "./pages/NotFound";
import Navbar from "./components/Navbar";
import SearchBar from "./components/SearchBar";
import Footer from "./components/Footer";
import "./index.css"; import "./index.css";
import { getData } from "./utils/methods";
const App = () => { export const App = () => {
const [searchString, setSearchString] = useState(""); const [searchString, setSearchString] = useState("");
const [categories, setCategories] = useState({ categories: [] }); const [categories, setCategories] = useState({ categories: [] });
const [searchResults, setSearchResults] = useState({ meals: [] }); const [searchResults, setSearchResults] = useState({ meals: [] });
// 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 = {
meals: [ meals: [
{ {
idMeal: "52837", idMeal: "52837",
strMeal: "Pilchard puttanesca", strMeal: "Chef's meal",
strDrinkAlternate: null, strDrinkAlternate: null,
strCategory: "Pasta", strCategory: "yummy",
strArea: "Italian", strArea: "Mine",
strInstructions: strInstructions:
"Cook the pasta following pack instructions.\r\n\r\nHeat the oil in a non-stick frying pan and cook the onion, garlic and chilli for 3-4 mins to soften. Stir in the tomato pur\u00e9e and cook for 1 min, then add the pilchards with their sauce. Cook, breaking up the fish with a wooden spoon, then add the olives and continue to cook for a few more mins.\r\n\r\nDrain the pasta and add to the pan with 2-3 tbsp of the cooking water. Toss everything together well, then divide between plates and serve, scattered with Parmesan.", "Cook the pasta following pack instructions.\r\n\r\nHeat the oil in a non-stick frying pan and cook the onion, garlic and chilli for 3-4 mins to soften. Stir in the tomato pur\u00e9e and cook for 1 min, then add the pilchards with their sauce. Cook, breaking up the fish with a wooden spoon, then add the olives and continue to cook for a few more mins.\r\n\r\nDrain the pasta and add to the pan with 2-3 tbsp of the cooking water. Toss everything together well, then divide between plates and serve, scattered with Parmesan.",
strMealThumb: strMealThumb: require("./images/breakfast.svg"),
"https://www.themealdb.com/images/media/meals/vvtvtr1511180578.jpg", // "https://www.themealdb.com/images/media/meals/vvtvtr1511180578.jpg",
strTags: null, strTags: null,
strYoutube: "https://www.youtube.com/watch?v=wqZzLAPmr9k", strYoutube: "#",
strIngredient1: "Spaghetti", strIngredient1: "Spaghetti",
strIngredient2: "Olive Oil", strIngredient2: "Olive Oil",
strIngredient3: "Onion", strIngredient3: "Onion",
@ -83,26 +79,6 @@ const App = () => {
}; };
const [meal, setMeal] = useState(mealDef); const [meal, setMeal] = useState(mealDef);
const createURI = (keyword, option) => {
const ROOT = "https://www.themealdb.com/api/json/v1/1/";
if (option === null) {
return `${ROOT}${keyword}.php`;
} else if (option === "filter") {
return `${ROOT}${option}.php?c=${keyword}`;
} else if (option === "lookup") {
return `${ROOT}${option}.php?i=${keyword}`;
} else if (option === "search") {
return `${ROOT}${option}.php?s=${keyword}`;
}
};
const getData = (keyword, set, option = null) => {
const URI = createURI(keyword, option);
fetch(URI)
.then(response => response.json())
.then(data => set(data));
};
const getRandomMeal = () => { const getRandomMeal = () => {
getData("random", setMeal); getData("random", setMeal);
}; };
@ -129,32 +105,24 @@ const App = () => {
return ( return (
<Router> <Router>
<Navbar handleClick={getRandomMeal} buttonUrl={buttonUrl} /> <Navbar handleClick={getRandomMeal} buttonUrl={buttonUrl} />
<div className="container"> <SearchBar
<SearchBar searchString={searchString}
searchString={searchString} handleChange={handleChange}
handleChange={handleChange} onSubmit={getSearchResults}
onSubmit={getSearchResults} />
/>
</div>
<Switch> <Switch>
<Route exact path="/"> <Route exact path="/">
<HomePage handleClick={getRandomMeal} buttonUrl={buttonUrl} /> <HomePage handleClick={getRandomMeal} buttonUrl={buttonUrl} />
</Route> </Route>
<Route exact path={buttonUrl}> <Route exact path={buttonUrl}>
<MealPage <MealPage meal={meal} getMeal={getRandomMeal} />
meal={meal}
getMeal={getRandomMeal}
// isLoading={isLoading}
/>
</Route> </Route>
<Route exact path="/categories"> <Route exact path="/categories">
<CategoryListPage <CategoryListPage
categories={categories} categories={categories}
getCategories={getCategories} getCategories={getCategories}
/> />
</Route> </Route>
<Route path="/categories/:strCategory/"> <Route path="/categories/:strCategory/">
<CategoryPage <CategoryPage
getData={getData} getData={getData}
@ -170,7 +138,7 @@ const App = () => {
/> />
</Route> </Route>
<Route path="/404"> <Route path="/404">
<NotFound handleClick={getRandomMeal} /> <NotFoundPage handleClick={getRandomMeal} />
</Route> </Route>
<Route path="/:idMeal"> <Route path="/:idMeal">
<MealPage meal={meal} getMeal={getMeal} /> <MealPage meal={meal} getMeal={getMeal} />
@ -183,5 +151,3 @@ const App = () => {
</Router> </Router>
); );
}; };
export default App;

View file

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
const CardEntry = props => { export const CardEntry = props => {
const { idMeal, strMeal, strMealThumb } = props.item; const { idMeal, strMeal, strMealThumb } = props.item;
return ( return (
<Link to={`${idMeal}`}> <Link to={`${idMeal}`}>
@ -22,4 +22,3 @@ const CardEntry = props => {
</Link> </Link>
); );
}; };
export default CardEntry;

View file

@ -12,7 +12,7 @@ const CategoryEntry = props => {
return ( return (
// <CardEntry item={meal} /> // <CardEntry item={meal} />
<Link to={`${url}/${strCategory}`}> <Link to={`${url}${strCategory}`}>
<li> <li>
<div className="row"> <div className="row">
<div className="col s12"> <div className="col s12">

View file

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
const CopyrightText = () => { export const CopyrightText = () => {
return ( return (
<span> <span>
© 2020 - Chef's - Made with{" "} © 2020 - Chef's - Made with{" "}
@ -10,5 +10,3 @@ const CopyrightText = () => {
</span> </span>
); );
}; };
export default CopyrightText;

View file

@ -1,8 +1,8 @@
import React from "react"; import React from "react";
import CopyrightText from "./CopyrightText"; import { CopyrightText } from "./CopyrightText";
import GitHubLink from "./GitHubLink"; import { GitHubLink } from "./GitHubLink";
const Footer = () => { export const Footer = () => {
return ( return (
<footer className="page-footer"> <footer className="page-footer">
<div className="footer-copyright"> <div className="footer-copyright">
@ -14,5 +14,3 @@ const Footer = () => {
</footer> </footer>
); );
}; };
export default Footer;

View file

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
const GitHubLink = () => { export const GitHubLink = () => {
return ( return (
<a <a
className="grey-text text-lighten-4 right" className="grey-text text-lighten-4 right"
@ -12,5 +12,3 @@ const GitHubLink = () => {
</a> </a>
); );
}; };
export default GitHubLink;

View file

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
const IngredientList = props => { export const IngredientList = props => {
const { ingredients } = props; const { ingredients } = props;
return ( return (
<div className="ingredientList"> <div className="ingredientList">
@ -15,4 +15,3 @@ const IngredientList = props => {
</div> </div>
); );
}; };
export default IngredientList;

View file

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
const Logo = () => { export const Logo = () => {
return ( return (
<div className="logo"> <div className="logo">
<Link to="/" className="brand-logo"> <Link to="/" className="brand-logo">
@ -12,5 +12,3 @@ const Logo = () => {
</div> </div>
); );
}; };
export default Logo;

View file

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
const MealPresentation = props => { export const MealPresentation = props => {
const { const {
mealName, mealName,
imgAddress, imgAddress,
@ -53,4 +53,3 @@ const MealPresentation = props => {
</div> </div>
); );
}; };
export default MealPresentation;

View file

@ -1,10 +1,10 @@
import React from "react"; import React from "react";
import Logo from "./Logo"; import { Logo } from "./Logo";
import RandomButton from "./RandomButton"; import { RandomButton } from "./RandomButton";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
const Navbar = props => { export const Navbar = props => {
return ( return (
<div className="row"> <div className="row">
<nav> <nav>
@ -70,5 +70,3 @@ const Navbar = props => {
</div> </div>
); );
}; };
export default Navbar;

View file

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
const PreLoader = () => { export const PreLoader = () => {
return ( return (
<div className="preloader-wrapper active"> <div className="preloader-wrapper active">
<div className="spinner-layer spinner-red-only"> <div className="spinner-layer spinner-red-only">
@ -17,5 +17,3 @@ const PreLoader = () => {
</div> </div>
); );
}; };
export default PreLoader;

View file

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
const RandomButton = props => { export const RandomButton = props => {
const classString = `waves-effect waves-light btn-${props.size}`; const classString = `waves-effect waves-light btn-${props.size}`;
return ( return (
<Link to={props.url}> <Link to={props.url}>
@ -15,5 +15,3 @@ const RandomButton = props => {
</Link> </Link>
); );
}; };
export default RandomButton;

View file

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
const Recipe = props => { export const Recipe = props => {
return ( return (
<div className="recipe"> <div className="recipe">
<h3>Instructions</h3> <h3>Instructions</h3>
@ -8,4 +8,3 @@ const Recipe = props => {
</div> </div>
); );
}; };
export default Recipe;

View file

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

View file

@ -1,9 +1,7 @@
import React from "react"; import React from "react";
import CardEntry from "./CardEntry"; import { CardEntry } from "./CardEntry";
const SearchResult = props => { export const SearchResult = props => {
const { meal } = props; const { meal } = props;
return <CardEntry item={meal} />; return <CardEntry item={meal} />;
}; };
export default SearchResult;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 556 KiB

View file

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import "./index.css"; import "./index.css";
import App from "./App"; import { App } from "./App";
import * as serviceWorker from "./serviceWorker"; import * as serviceWorker from "./serviceWorker";
ReactDOM.render(<App />, document.getElementById("root")); ReactDOM.render(<App />, document.getElementById("root"));

View file

@ -1,7 +1,7 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useParams, Link, Redirect } from "react-router-dom"; import { useParams, Link, Redirect } from "react-router-dom";
const CategoryPage = props => { export const CategoryPage = props => {
const [meals, setMeals] = useState({ meals: [] }); const [meals, setMeals] = useState({ meals: [] });
const { getData } = props; const { getData } = props;
const { strCategory } = useParams(); const { strCategory } = useParams();
@ -24,7 +24,7 @@ const CategoryPage = props => {
{meals.meals.map((meal, i) => ( {meals.meals.map((meal, i) => (
<li key={i}> <li key={i}>
{/* <CardEntry item={meal} /> */} {/* <CardEntry item={meal} /> */}
<Link to={`/meal/${meal.idMeal}`}> <Link to={`/${meal.idMeal}`}>
<div className="row"> <div className="row">
<div className="col s12 m6"> <div className="col s12 m6">
<div className="card "> <div className="card ">
@ -45,4 +45,3 @@ const CategoryPage = props => {
</div> </div>
); );
}; };
export default CategoryPage;

View file

@ -1,7 +1,7 @@
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import CategoryEntry from "../components/CategoryEntry"; import CategoryEntry from "../components/CategoryEntry";
const CategoryListPage = props => { export const CategoryListPage = props => {
const { categories } = props.categories; const { categories } = props.categories;
const { getCategories } = props; const { getCategories } = props;
@ -22,5 +22,3 @@ const CategoryListPage = props => {
</div> </div>
); );
}; };
export default CategoryListPage;

View file

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import RandomButton from "../components/RandomButton"; import { RandomButton } from "../components/RandomButton";
const HomePage = props => { export const HomePage = props => {
return ( return (
<div className="section "> <div className="section ">
<div className="container "> <div className="container ">
@ -12,10 +12,7 @@ const HomePage = props => {
</div> </div>
<div className="col s12 m6"> <div className="col s12 m6">
<img <img
// src={require("../images/breakfast.svg")}
// src={require("../images/Chef.svg")}
src={require("../images/healthy_options.svg")} src={require("../images/healthy_options.svg")}
// src={require("../images/special_event.svg")}
alt="hero_image" alt="hero_image"
width="100%" width="100%"
/> />
@ -25,5 +22,3 @@ const HomePage = props => {
</div> </div>
); );
}; };
export default HomePage;

View file

@ -1,11 +1,10 @@
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import MealPresentation from "../components/MealPresentation"; import { MealPresentation } from "../components/MealPresentation";
import IngredientList from "../components/IngredientList"; import { IngredientList } from "../components/IngredientList";
import Recipe from "../components/Recipe"; import { Recipe } from "../components/Recipe";
import { useParams, Redirect } from "react-router-dom"; import { useParams, Redirect } from "react-router-dom";
// import PreLoader from "../components/PreLoader";
const MealPage = props => { export const MealPage = props => {
const { getMeal } = props; const { getMeal } = props;
const { idMeal } = useParams(); const { idMeal } = useParams();
@ -43,7 +42,6 @@ const MealPage = props => {
} }
} }
// return isLoading ? <PreLoader /> : page;
return ( return (
<div className="container"> <div className="container">
<div className="row"> <div className="row">
@ -61,5 +59,3 @@ const MealPage = props => {
return <Redirect to="/404" />; return <Redirect to="/404" />;
} }
}; };
export default MealPage;

View file

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import RandomButton from "../components/RandomButton"; import { RandomButton } from "../components/RandomButton";
const NotFoundPage = props => { export const NotFoundPage = props => {
return ( return (
<div className="section"> <div className="section">
<div className="container center-align"> <div className="container center-align">
@ -17,5 +17,3 @@ const NotFoundPage = props => {
</div> </div>
); );
}; };
export default NotFoundPage;

View file

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import SearchResult from "../components/SearchResult"; import { SearchResult } from "../components/SearchResult";
const SearchPage = props => { export const SearchPage = props => {
let { meals } = props.searchResults; let { meals } = props.searchResults;
const { searchString } = props; const { searchString } = props;
if (meals === null) { if (meals === null) {
@ -12,7 +12,17 @@ const SearchPage = props => {
<div className="container"> <div className="container">
<h1>Search Results for: {searchString} </h1> <h1>Search Results for: {searchString} </h1>
{meals[0] === undefined ? ( {meals[0] === undefined ? (
<p> Nothing ! Create a component to illustrate emptiness</p> <div className="center-align">
<p>
No results to display, instead there is a picture of my breakfast.
</p>
<img
src={require("../images/breakfast.svg")}
alt="Nothing here!"
width="70%"
/>
<p></p>
</div>
) : ( ) : (
<ul> <ul>
{meals.map((meal, i) => ( {meals.map((meal, i) => (
@ -23,4 +33,3 @@ const SearchPage = props => {
</div> </div>
); );
}; };
export default SearchPage;

19
src/utils/methods.js Normal file
View file

@ -0,0 +1,19 @@
export const createURI = (keyword, option) => {
const ROOT = "https://www.themealdb.com/api/json/v1/1/";
if (option === null) {
return `${ROOT}${keyword}.php`;
} else if (option === "filter") {
return `${ROOT}${option}.php?c=${keyword}`;
} else if (option === "lookup") {
return `${ROOT}${option}.php?i=${keyword}`;
} else if (option === "search") {
return `${ROOT}${option}.php?s=${keyword}`;
}
};
export const getData = (keyword, set, option = null) => {
const URI = createURI(keyword, option);
fetch(URI)
.then(response => response.json())
.then(data => set(data));
};

51
src/utils/router.js Normal file
View file

@ -0,0 +1,51 @@
import React, { useMemo, useEffect } from "react";
import {
Router as RouterOriginal,
useParams,
useLocation,
useHistory,
useRouteMatch
} from "react-router-dom";
import queryString from "query-string";
import { createBrowserHistory } from "history";
export const history = createBrowserHistory();
export const Router = ({ children }) => {
return (
<RouterOriginal history={history}>
<ScrollToTop />
{children}
</RouterOriginal>
);
};
export const ScrollToTop = () => {
const location = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [location.pathname]);
return null;
};
export const useRouter = () => {
const params = useParams();
const location = useLocation();
const history = useHistory();
const match = useRouteMatch();
return useMemo(() => {
return {
push: history.push,
replace: history.replace,
pathname: location.pathname,
query: {
...queryString.parse(location.search),
...params
},
match,
location,
history
};
}, [params, match, location, history]);
};