From e8ac939fc9d97732e7b5e80485c98f6396d38c52 Mon Sep 17 00:00:00 2001 From: Ruidy Date: Mon, 5 Apr 2021 11:58:43 +0200 Subject: [PATCH] state (#9) * configure context * refactor * get meal with context * random button with context * async actions * refactor meal client --- src/App.tsx | 22 ++------- src/components/Navbar.tsx | 8 +--- src/components/RandomButton.tsx | 13 +++--- src/components/SearchBar.tsx | 26 ++++------- src/components/SideNav.tsx | 15 ++----- src/constants.ts | 1 + src/containers/Categories/index.tsx | 2 +- src/containers/Category/index.tsx | 4 +- src/containers/Home/index.tsx | 7 +-- src/containers/Meal/index.tsx | 31 ++++--------- src/containers/NotFound/index.tsx | 2 +- .../Search/components/SearchPage.tsx | 45 +++++++++---------- src/containers/Search/index.tsx | 17 +++---- src/index.jsx | 5 ++- src/layouts/MainLayout.tsx | 32 ++----------- src/layouts/PageLayout.tsx | 4 +- src/router/AppRouter.tsx | 13 ++---- src/services/api.ts | 26 +++++------ src/store/meal/async.ts | 23 ++++++++++ src/store/meal/index.tsx | 35 +++++++++++++++ src/store/meal/reducer.ts | 27 +++++++++++ 21 files changed, 175 insertions(+), 183 deletions(-) create mode 100644 src/store/meal/async.ts create mode 100644 src/store/meal/index.tsx create mode 100644 src/store/meal/reducer.ts diff --git a/src/App.tsx b/src/App.tsx index f364926..e3dcd93 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,24 +1,13 @@ -import { FC, useState } from "react"; +import { FC } from "react"; import { PreLoader } from "./components/PreLoader"; import "./index.css"; import MainLayout from "./layouts/MainLayout"; import { AppRouter } from "./router"; import { Router } from "./router/Router"; -import { getData } from "./services/api"; -import { MealSummary } from "./types/meal"; import { useAuth0 } from "./utils/auth0-spa"; export const App: FC = () => { const { loading } = useAuth0(); - const [searchString, setSearchString] = useState(""); - const [searchResults, setSearchResults] = useState({ - meals: [] as MealSummary[], - }); - const [_, setMeal] = useState(null); - - const getRandomMeal = () => { - getData("random", setMeal); - }; return loading ? (
@@ -26,13 +15,8 @@ export const App: FC = () => {
) : ( - - + + ); diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 1664965..4beee9f 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -8,12 +8,9 @@ import { Logo } from "./Logo"; import { LogOutButton } from "./LogOutButton"; import { RandomButton } from "./RandomButton"; -type Props = { - openNavClick: React.MouseEventHandler; - handleClick: () => void; -}; +type Props = { openNavClick: React.MouseEventHandler }; -export const Navbar: FC = ({ openNavClick, handleClick }) => { +export const Navbar: FC = ({ openNavClick }) => { const { isAuthenticated } = useAuth0(); return ( @@ -31,7 +28,6 @@ export const Navbar: FC = ({ openNavClick, handleClick }) => { )}
  • void; color?: string; }; -export const RandomButton: FC = ({ - url, - size = "large", - handleClick, - color, -}) => { +export const RandomButton: FC = ({ url, size = "large", color }) => { const classString = `waves-effect waves-light btn-${size} ${color}`; + const { dispatch } = useMeal(); return ( - diff --git a/src/components/SearchBar.tsx b/src/components/SearchBar.tsx index 64598f6..27e5033 100644 --- a/src/components/SearchBar.tsx +++ b/src/components/SearchBar.tsx @@ -1,30 +1,20 @@ -import React, { ChangeEvent, FC } from "react"; +import React, { ChangeEvent, FC, useState } from "react"; import { Link } from "react-router-dom"; -import { getData } from "../services/api"; -import { MealSummary } from "../types/meal"; +import { useMeal } from "../store/meal"; +import { fetchSearchResults } from "../store/meal/async"; -type Props = { - searchString: string; - setSearchString: React.Dispatch>; - setSearchResults: React.Dispatch< - React.SetStateAction<{ meals: MealSummary[] }> - >; -}; - -export const SearchBar: FC = ({ - searchString, - setSearchString, - setSearchResults, -}) => { +export const SearchBar: FC = () => { + const { dispatch } = useMeal(); + const [searchString, setSearchString] = useState(""); const getSearchResults: React.MouseEventHandler = (e) => { searchString === "" ? e.preventDefault() - : getData(searchString, setSearchResults, "search"); + : fetchSearchResults(dispatch, searchString); }; const clearSearchBar = () => { setSearchString(""); - setSearchResults({ meals: [] }); + dispatch({ type: "clearSearchResults" }); }; const handleChange = (e: ChangeEvent) => { diff --git a/src/components/SideNav.tsx b/src/components/SideNav.tsx index e661774..0ceb749 100644 --- a/src/components/SideNav.tsx +++ b/src/components/SideNav.tsx @@ -9,13 +9,9 @@ import { LogInButton } from "./LogInButton"; import { LogOutButton } from "./LogOutButton"; import { RandomButton } from "./RandomButton"; -type Props = { - showNav: boolean; - closeNavClick: React.MouseEventHandler; - handleClick: () => void; -}; +type Props = { showNav: boolean; closeNavClick: React.MouseEventHandler }; -export const SideNav: FC = ({ showNav, closeNavClick, handleClick }) => { +export const SideNav: FC = ({ showNav, closeNavClick }) => { const { isAuthenticated, user } = useAuth0(); let transformStyle = { transform: showNav ? "translateX(0%)" : "translateX(-105%)", @@ -65,12 +61,7 @@ export const SideNav: FC = ({ showNav, closeNavClick, handleClick }) => {
  • - +
  • diff --git a/src/constants.ts b/src/constants.ts index 1ab5cfb..ec872f8 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,2 +1,3 @@ +export const apiRoot = "https://www.themealdb.com/api/json/v1/1/"; export const buttonURL = "/random"; export const links = ["categories", "contact"]; diff --git a/src/containers/Categories/index.tsx b/src/containers/Categories/index.tsx index 5719e81..10bc2f6 100644 --- a/src/containers/Categories/index.tsx +++ b/src/containers/Categories/index.tsx @@ -7,7 +7,7 @@ export const Categories = () => { const [categories, setCategories] = useState({ categories: [] }); const getCategories = () => { - getData("categories", setCategories); + getData("categories").then((data) => setCategories(data)); }; useEffect(() => { diff --git a/src/containers/Category/index.tsx b/src/containers/Category/index.tsx index f86e781..fd64c84 100644 --- a/src/containers/Category/index.tsx +++ b/src/containers/Category/index.tsx @@ -8,8 +8,8 @@ export const Category: FC = () => { const [meals, setMeals] = useState({ meals: [] }); useEffect(() => { - const getMeals = () => getData(strCategory, setMeals, "filter"); - getMeals(); + const getMeals = () => getData(strCategory, "filter"); + getMeals().then((data) => setMeals(data)); }, [strCategory]); return !meals.meals ? ( diff --git a/src/containers/Home/index.tsx b/src/containers/Home/index.tsx index 6953139..f776bf2 100644 --- a/src/containers/Home/index.tsx +++ b/src/containers/Home/index.tsx @@ -8,12 +8,7 @@ export const Home: FC = () => (

    Chef's Online Cookbook

    - {}} - /> +
    hero_image diff --git a/src/containers/Meal/index.tsx b/src/containers/Meal/index.tsx index 853bc12..c7b1a7c 100644 --- a/src/containers/Meal/index.tsx +++ b/src/containers/Meal/index.tsx @@ -1,8 +1,8 @@ -import React, { FC, useEffect, useState } from "react"; +import { FC, useEffect, useState } from "react"; import { useParams } from "react-router-dom"; -import { getData } from "../../services/api"; import { useFirebase } from "../../services/Firebase"; -import { MealApi as MealType } from "../../types/meal"; +import { useMeal } from "../../store/meal"; +import { fetchMeal, fetchRandomMeal } from "../../store/meal/async"; import { useAuth0 } from "../../utils/auth0-spa"; import { NotFound } from "../NotFound"; import { MealPage } from "./components/MealPage"; @@ -12,31 +12,18 @@ export const Meal: FC = () => { // hooks const { user, isAuthenticated } = useAuth0(); const { id } = useParams<{ id: string }>(); + const { state, dispatch } = useMeal(); const fb = useFirebase(); // local state - const [meal, setMeal] = useState({ meals: [] as MealType[] }); const [isFav, setIsFav] = useState(); // variables - const mealItem = meal?.meals?.[0]; - - const getMeal = ( - id: string, - setMeal: React.Dispatch> - ) => { - getData(id, setMeal, "lookup"); - }; - - const getRandomMeal = ( - setMeal: React.Dispatch> - ) => { - getData("random", setMeal); - }; - + const mealItem = state.meals?.[0]; // effects /** Fetch meal from db */ useEffect(() => { - !id ? getRandomMeal(setMeal) : getMeal(id, setMeal); - }, [id]); + !id ? fetchRandomMeal(dispatch) : fetchMeal(dispatch, id); + }, [id, dispatch]); + /** Updates fav status in db */ useEffect(() => { if (isAuthenticated) { @@ -63,7 +50,7 @@ export const Meal: FC = () => { const item = buildMealProps(mealItem, isFav!); const ingredients = buildIngredientList(mealItem); - return !!meal?.meals ? ( + return !!state.meals ? ( ( />
    - {}} /> +
    diff --git a/src/containers/Search/components/SearchPage.tsx b/src/containers/Search/components/SearchPage.tsx index d9f4386..3c460f9 100644 --- a/src/containers/Search/components/SearchPage.tsx +++ b/src/containers/Search/components/SearchPage.tsx @@ -6,29 +6,26 @@ import { SearchResult } from "./SearchResult"; type Props = { searchString: string; - searchResults: { meals: MealSummary[] }; + searchResults: MealSummary[]; }; -export const SearchPage: FC = ({ searchString, searchResults }) => { - const { meals } = searchResults; - return ( - - {!meals ? ( -
    -

    - No results to display, instead there is a picture of my breakfast. -

    - Nothing here! -
    - ) : ( -
    -
      - {meals.map((meal, i) => ( - - ))} -
    -
    - )} -
    - ); -}; +export const SearchPage: FC = ({ searchString, searchResults }) => ( + + {!searchResults ? ( +
    +

    + No results to display, instead there is a picture of my breakfast. +

    + Nothing here! +
    + ) : ( +
    +
      + {searchResults.map((meal, i) => ( + + ))} +
    +
    + )} +
    +); diff --git a/src/containers/Search/index.tsx b/src/containers/Search/index.tsx index 181e596..abb94a1 100644 --- a/src/containers/Search/index.tsx +++ b/src/containers/Search/index.tsx @@ -1,12 +1,13 @@ import { FC } from "react"; -import { MealSummary } from "../../types/meal"; +import { useMeal } from "../../store/meal"; import { SearchPage } from "./components/SearchPage"; -type Props = { - searchString: string; - searchResults: { meals: MealSummary[] }; +export const Search: FC = () => { + const { state } = useMeal(); + return ( + + ); }; - -export const Search: FC = ({ searchString, searchResults }) => ( - -); diff --git a/src/index.jsx b/src/index.jsx index abf04eb..126a756 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -6,6 +6,7 @@ import * as serviceWorker from "./serviceWorker"; import { Auth0Provider } from "./utils/auth0-spa"; import history from "./utils/history"; import { FirebaseContext } from "./services/Firebase"; +import { AppProvider } from "./store/meal"; const onRedirectCallBack = (appState) => { history.push( @@ -24,7 +25,9 @@ ReactDOM.render( > {/* todo fix Firebase app*/} - + + + , document.getElementById("root") diff --git a/src/layouts/MainLayout.tsx b/src/layouts/MainLayout.tsx index bb28fdf..5bc05bc 100644 --- a/src/layouts/MainLayout.tsx +++ b/src/layouts/MainLayout.tsx @@ -3,23 +3,8 @@ import { Footer } from "../components/Footer"; import { Navbar } from "../components/Navbar"; import { SearchBar } from "../components/SearchBar"; import { SideNav } from "../components/SideNav"; -import { MealSummary } from "../types/meal"; -type Props = { - getRandomMeal: () => void; - searchString: string; - setSearchString: React.Dispatch>; - setSearchResults: React.Dispatch< - React.SetStateAction<{ meals: MealSummary[] }> - >; -}; -const MainLayout: FC = ({ - getRandomMeal, - searchString, - setSearchString, - setSearchResults, - children, -}) => { +const MainLayout: FC = ({ children }) => { const [showNav, setShowNav] = useState(false); const openNavClick: React.MouseEventHandler = (e) => { @@ -43,18 +28,9 @@ const MainLayout: FC = ({ return ( <>
    - - - - {}} - /> + + +
    {children}