diff --git a/src/App.tsx b/src/App.tsx index be547d9..e3dcd93 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,18 +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 { 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[], - }); return loading ? (
@@ -20,12 +15,8 @@ export const App: FC = () => {
) : ( - - + + ); 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/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/layouts/MainLayout.tsx b/src/layouts/MainLayout.tsx index c3a6294..5bc05bc 100644 --- a/src/layouts/MainLayout.tsx +++ b/src/layouts/MainLayout.tsx @@ -3,21 +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 = { - searchString: string; - setSearchString: React.Dispatch>; - setSearchResults: React.Dispatch< - React.SetStateAction<{ meals: MealSummary[] }> - >; -}; -const MainLayout: FC = ({ - searchString, - setSearchString, - setSearchResults, - children, -}) => { +const MainLayout: FC = ({ children }) => { const [showNav, setShowNav] = useState(false); const openNavClick: React.MouseEventHandler = (e) => { @@ -42,12 +29,7 @@ const MainLayout: FC = ({ <>
- - +
{children}
diff --git a/src/layouts/PageLayout.tsx b/src/layouts/PageLayout.tsx index 04e0f1c..9360977 100644 --- a/src/layouts/PageLayout.tsx +++ b/src/layouts/PageLayout.tsx @@ -1,8 +1,6 @@ import { FC } from "react"; -type Props = { - title: string; -}; +type Props = { title: string }; const PageLayout: FC = ({ title, children }) => (
diff --git a/src/router/AppRouter.tsx b/src/router/AppRouter.tsx index 9061ea5..260a676 100644 --- a/src/router/AppRouter.tsx +++ b/src/router/AppRouter.tsx @@ -3,20 +3,15 @@ import { Redirect, Route, Switch } from "react-router-dom"; import { buttonURL } from "../constants"; import { Categories } from "../containers/Categories"; import { Category } from "../containers/Category"; +import { Contact } from "../containers/Contact"; import { Home } from "../containers/Home"; import { Meal } from "../containers/Meal"; +import { NotFound } from "../containers/NotFound"; import { Profile } from "../containers/Profile"; import { Search } from "../containers/Search"; -import { Contact } from "../containers/Contact"; -import { NotFound } from "../containers/NotFound"; -import { MealSummary } from "../types/meal"; import { PrivateRoute } from "./PrivateRoute"; -type Props = { - searchString: string; - searchResults: { meals: MealSummary[] }; -}; -const AppRouter: FC = ({ searchString, searchResults }) => ( +const AppRouter: FC = () => ( @@ -37,7 +32,7 @@ const AppRouter: FC = ({ searchString, searchResults }) => ( - + diff --git a/src/store/meal/async.ts b/src/store/meal/async.ts index df09e01..c1c7727 100644 --- a/src/store/meal/async.ts +++ b/src/store/meal/async.ts @@ -23,3 +23,20 @@ export const fetchMeal = async (dispatch: Dispatch, id: string) => { dispatch({ type: "setMeal", payload: meal.meals }); }; + +export const fetchSearchResults = async ( + dispatch: Dispatch, + searchString: string +) => { + //TODO: refactor to use Meal client + const URI = createURI(searchString, "search"); + + const meals = await fetch(URI) + .then((response) => response.json()) + .catch((error) => console.warn(error + "url:" + URI)); + + dispatch({ + type: "setSearchResults", + payload: { search: meals.meals, searchString }, + }); +}; diff --git a/src/store/meal/index.tsx b/src/store/meal/index.tsx index b98ae56..9e2a068 100644 --- a/src/store/meal/index.tsx +++ b/src/store/meal/index.tsx @@ -1,10 +1,21 @@ //https://kentcdodds.com/blog/how-to-use-react-context-effectively import { createContext, FC, useContext, useReducer } from "react"; -import { MealApi } from "../../types/meal"; +import { MealApi, MealSummary } from "../../types/meal"; import { appReducer, Dispatch } from "./reducer"; -export type AppState = { meals: MealApi[] }; +export type AppState = { + meals: MealApi[]; + search: MealSummary[]; + searchString: string; +}; + +const initState = { + meals: [] as MealApi[], + search: [] as MealSummary[], + searchString: "", +}; + type ContextType = { state: AppState; dispatch: Dispatch } | undefined; const AppContext = createContext(undefined); @@ -18,7 +29,7 @@ export const useMeal = () => { }; export const AppProvider: FC = ({ children }) => { - const [state, dispatch] = useReducer(appReducer, { meals: [] as MealApi[] }); + const [state, dispatch] = useReducer(appReducer, initState); const value = { state, dispatch }; return {children}; }; diff --git a/src/store/meal/reducer.ts b/src/store/meal/reducer.ts index 9f3174e..f21c8d9 100644 --- a/src/store/meal/reducer.ts +++ b/src/store/meal/reducer.ts @@ -3,13 +3,15 @@ import { AppState } from "./index"; export const appReducer = (state: AppState, action: Action) => { switch (action.type) { case "setMeal": - return { meals: action.payload }; - case "fetchMeal": - return { meals: state.meals }; - case "fetchRandomMeal": - return { meals: state.meals }; - case "toggleFav": - return { meals: state.meals }; + return { ...state, meals: action.payload }; + case "setSearchResults": + return { + ...state, + search: action.payload.search, + searchString: action.payload.searchString, + }; + case "clearSearchResults": + return { ...state, search: [] }; default: { throw new Error(`Unhandled action type: ${action.type}`); } @@ -18,6 +20,7 @@ export const appReducer = (state: AppState, action: Action) => { export type Action = { payload?: any; - type: "setMeal" | "fetchMeal" | "fetchRandomMeal" | "toggleFav"; + type: "setMeal" | "setSearchResults" | "clearSearchResults"; }; + export type Dispatch = (action: Action) => void;