mirror of
https://github.com/rjNemo/meal_planner
synced 2026-06-06 02:26:49 +00:00
refactoring. Add MainLayout and MainRouter
This commit is contained in:
parent
47c9d5f4d9
commit
2a6f843d36
23 changed files with 309 additions and 249 deletions
7
TODO.md
7
TODO.md
|
|
@ -1,11 +1,14 @@
|
|||
# TO DO
|
||||
|
||||
- [ ] send message after contact form validation (confirm to sender and msg+info to admin)
|
||||
- [ ] Local storage of prefeernces
|
||||
- [ ] Firebase
|
||||
- [ ] Local storage of preferences
|
||||
- [ ] Firebase firestore and functions
|
||||
- [ ] Breadcrumb
|
||||
- [ ] Cookie bar
|
||||
- [ ] code cleanup (props and refactoring)
|
||||
- [ ] Back to top button
|
||||
- [ ] Close Sidebar at outside click
|
||||
- [ ] Take a look at some components [here](http://react-materialize.github.io/react-materialize/?path=/story/css-grid--default)
|
||||
- [ ] Decoupled application and data layers. Abstract such that the front end does not know where the data comes from.
|
||||
- [ ] Create PageLayout component
|
||||
- [ ] Use Css-in-Js
|
||||
|
|
|
|||
149
src/App.jsx
149
src/App.jsx
|
|
@ -1,24 +1,15 @@
|
|||
import React, { useState } from "react";
|
||||
import { Router } from "./utils/router";
|
||||
import { Switch, Route, Redirect } from "react-router-dom";
|
||||
|
||||
import { PreLoader } from "./components/PreLoader";
|
||||
|
||||
import { useAuth0 } from "./utils/auth0-spa";
|
||||
import { SearchController } from "./controllers/SearchController";
|
||||
import { ContactPage } from "./pages/Contact";
|
||||
import { NotFoundPage } from "./pages/NotFoundPage";
|
||||
import { Navbar } from "./components/Navbar";
|
||||
import { SearchBar } from "./components/SearchBar";
|
||||
import { Footer } from "./components/Footer";
|
||||
import { getData } from "./utils/methods";
|
||||
import history from "./utils/history";
|
||||
import { ProfileController } from "./controllers/ProfileController";
|
||||
import { PrivateRoute } from "./components/PrivateRoute";
|
||||
import { PreLoader } from "./components/PreLoader";
|
||||
import { SideNav } from "./components/SideNav";
|
||||
|
||||
import "./index.css";
|
||||
import { HomeController } from "./controllers/HomeController";
|
||||
import { MealController } from "./controllers/MealController";
|
||||
import { CategoryListController } from "./controllers/CategoryListController";
|
||||
import { CategoryController } from "./controllers/CategoryController";
|
||||
import MainLayout from "./layouts/MainLayout";
|
||||
import MainRouter from "./controllers/MainRouter";
|
||||
|
||||
export const App = () => {
|
||||
const { loading } = useAuth0();
|
||||
|
|
@ -85,6 +76,7 @@ export const App = () => {
|
|||
},
|
||||
],
|
||||
};
|
||||
|
||||
const [meal, setMeal] = useState(mealDef);
|
||||
|
||||
const getMeal = (id) => {
|
||||
|
|
@ -108,114 +100,33 @@ export const App = () => {
|
|||
|
||||
const buttonUrl = "/random";
|
||||
|
||||
const [showNav, setShowNav] = useState(false);
|
||||
const openNavClick = (ev) => {
|
||||
ev.preventDefault();
|
||||
setShowNav(true);
|
||||
document.addEventListener("keydown", handleEscKey);
|
||||
// document.addEventListener("click", handleOutsideClick);
|
||||
};
|
||||
const closeNavClick = (ev) => {
|
||||
ev.preventDefault();
|
||||
setShowNav(false);
|
||||
document.removeEventListener("keydown", handleEscKey);
|
||||
};
|
||||
const handleEscKey = (ev) => {
|
||||
if (ev.key === "Escape") {
|
||||
setShowNav(false);
|
||||
}
|
||||
};
|
||||
// const handleOutsideClick = ev => {
|
||||
// console.log(ev);
|
||||
// };
|
||||
|
||||
const links = ["categories", "contact"];
|
||||
|
||||
return loading ? (
|
||||
<div className="container center-align valign-wrapper">
|
||||
<PreLoader />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<Router history={history}>
|
||||
<header>
|
||||
<Navbar
|
||||
handleClick={getRandomMeal}
|
||||
buttonUrl={buttonUrl}
|
||||
openNavClick={openNavClick}
|
||||
links={links}
|
||||
/>
|
||||
|
||||
<SearchBar
|
||||
searchString={searchString}
|
||||
setSearchString={setSearchString}
|
||||
handleChange={handleChange}
|
||||
onSubmit={getSearchResults}
|
||||
setSearchResults={setSearchResults}
|
||||
/>
|
||||
<SideNav
|
||||
showNav={showNav}
|
||||
closeNavClick={closeNavClick}
|
||||
links={links}
|
||||
buttonUrl={buttonUrl}
|
||||
/>
|
||||
</header>
|
||||
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<HomeController buttonUrl={buttonUrl} />
|
||||
</Route>
|
||||
|
||||
<PrivateRoute exact path="/profile">
|
||||
<ProfileController />
|
||||
</PrivateRoute>
|
||||
|
||||
<Route exact path={buttonUrl}>
|
||||
<MealController
|
||||
meal={meal}
|
||||
getMeal={getMeal}
|
||||
getRandomMeal={getRandomMeal}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route exact path="/categories">
|
||||
<CategoryListController />
|
||||
</Route>
|
||||
|
||||
<Route path="/categories/:strCategory/">
|
||||
<CategoryController />
|
||||
</Route>
|
||||
|
||||
<Route exact path="/search">
|
||||
<SearchController
|
||||
searchString={searchString}
|
||||
searchResults={searchResults}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="/contact">
|
||||
<ContactPage />
|
||||
</Route>
|
||||
|
||||
<Route path="/404">
|
||||
<NotFoundPage handleClick={getRandomMeal} />
|
||||
</Route>
|
||||
|
||||
<Route path="/:id">
|
||||
<MealController
|
||||
meal={meal}
|
||||
getMeal={getMeal}
|
||||
getRandomMeal={getRandomMeal}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="*">
|
||||
<Redirect to="/404" />
|
||||
</Route>
|
||||
</Switch>
|
||||
|
||||
<Footer />
|
||||
</Router>
|
||||
</>
|
||||
<Router history={history}>
|
||||
<MainLayout
|
||||
buttonUrl={buttonUrl}
|
||||
meal={meal}
|
||||
getMeal={getMeal}
|
||||
getRandomMeal={getRandomMeal}
|
||||
searchString={searchString}
|
||||
searchResults={searchResults}
|
||||
setSearchResults={setSearchResults}
|
||||
handleChange={handleChange}
|
||||
setSearchString={setSearchString}
|
||||
getSearchResults={getSearchResults}
|
||||
>
|
||||
<MainRouter
|
||||
buttonUrl={buttonUrl}
|
||||
meal={meal}
|
||||
getMeal={getMeal}
|
||||
getRandomMeal={getRandomMeal}
|
||||
searchString={searchString}
|
||||
searchResults={searchResults}
|
||||
/>
|
||||
</MainLayout>
|
||||
</Router>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export const CardEntry = props => {
|
||||
const { idMeal, strMeal, strMealThumb } = props.item;
|
||||
export const CardEntry = ({ item }) => {
|
||||
const { idMeal, strMeal, strMealThumb } = item;
|
||||
return (
|
||||
<Link to={`${idMeal}`}>
|
||||
<li>
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ import React from "react";
|
|||
import { Link, useRouteMatch } from "react-router-dom";
|
||||
|
||||
const CategoryEntry = ({ category }) => {
|
||||
const { url } = useRouteMatch();
|
||||
|
||||
const {
|
||||
strCategory,
|
||||
strCategoryThumb
|
||||
strCategoryThumb,
|
||||
// strCategoryDescription
|
||||
} = category;
|
||||
|
||||
const { url } = useRouteMatch();
|
||||
|
||||
return (
|
||||
// <CardEntry item={meal} />
|
||||
<Link to={`${url}/${strCategory}`}>
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ import { CopyrightText } from "./CopyrightText";
|
|||
import { GitHubLink } from "./GitHubLink";
|
||||
import { FooterLink } from "./FooterLink";
|
||||
|
||||
export const Footer = () => {
|
||||
const links = ["categories", "random", "contact"];
|
||||
|
||||
export const Footer = ({ links }) => {
|
||||
return (
|
||||
<footer className="page-footer">
|
||||
<div className="row">
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import React from "react";
|
||||
|
||||
export const IngredientList = props => {
|
||||
const { ingredients } = props;
|
||||
export const IngredientList = ({ ingredients }) => {
|
||||
return (
|
||||
<div className="ingredientList">
|
||||
<table className="striped highlight responsive-table">
|
||||
|
|
|
|||
|
|
@ -3,17 +3,15 @@ import { Link } from "react-router-dom";
|
|||
|
||||
export const Logo = () => {
|
||||
return (
|
||||
<>
|
||||
<Link to="/" className="brand-logo">
|
||||
<img
|
||||
// className="responsive-img"
|
||||
src="/logo192.png"
|
||||
alt="chef's logo"
|
||||
height="30px"
|
||||
style={{ position: "relative", top: "5px" }}
|
||||
/>
|
||||
<span className="logo orange-text text-accent-4">Chef's</span>
|
||||
</Link>
|
||||
</>
|
||||
<Link to="/" className="brand-logo">
|
||||
<img
|
||||
// className="responsive-img"
|
||||
src="/logo192.png"
|
||||
alt="chef's logo"
|
||||
height="30px"
|
||||
style={{ position: "relative", top: "5px" }}
|
||||
/>
|
||||
<span className="logo orange-text text-accent-4">Chef's</span>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export const MealPresentation = (props) => {
|
||||
export const MealPresentation = ({ meal }) => {
|
||||
const {
|
||||
mealName,
|
||||
imgAddress,
|
||||
|
|
@ -10,7 +10,7 @@ export const MealPresentation = (props) => {
|
|||
mealArea,
|
||||
isFav,
|
||||
setIsFav,
|
||||
} = props.meal;
|
||||
} = meal;
|
||||
|
||||
return (
|
||||
<div className="row">
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import React from "react";
|
||||
|
||||
export const Recipe = props => {
|
||||
export const Recipe = ({ recipe }) => {
|
||||
return (
|
||||
<div className="recipe">
|
||||
<div className="divider"></div>
|
||||
<h3>Instructions</h3>
|
||||
<p className="flow-text">{props.recipe}</p>
|
||||
<p className="flow-text">{recipe}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,12 +6,13 @@ export const SearchBar = ({
|
|||
setSearchString,
|
||||
setSearchResults,
|
||||
handleChange,
|
||||
onSubmit
|
||||
onSubmit,
|
||||
}) => {
|
||||
const clearSearchBar = () => {
|
||||
setSearchString("");
|
||||
setSearchResults({ meals: [] });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="section">
|
||||
<div className="container">
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import React from "react";
|
||||
import { CardEntry } from "./CardEntry";
|
||||
|
||||
export const SearchResult = props => {
|
||||
const { meal } = props;
|
||||
export const SearchResult = ({ meal }) => {
|
||||
return <CardEntry item={meal} />;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,94 +11,92 @@ export const SideNav = ({
|
|||
closeNavClick,
|
||||
links,
|
||||
buttonUrl,
|
||||
handleClick
|
||||
handleClick,
|
||||
}) => {
|
||||
const { isAuthenticated, user } = useAuth0();
|
||||
let transformStyle = {
|
||||
transform: showNav ? "translateX(0%)" : "translateX(-105%)",
|
||||
transition: "0.5s"
|
||||
transition: "0.5s",
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ul id="slide-out" className="sidenav" style={transformStyle}>
|
||||
<li>
|
||||
<div className="user-view" style={{ height: "30vh" }}>
|
||||
<div className="background">
|
||||
<img
|
||||
// className="responsive-img"
|
||||
style={{
|
||||
position: "fixed" /* Sit on top of the page content */,
|
||||
width: "100%" /* Full width (cover the whole page) */,
|
||||
height: "30vh" /* Full width (cover the whole page) */,
|
||||
top: "0",
|
||||
left: "0",
|
||||
right: "0",
|
||||
bottom: "0",
|
||||
backgroundColor:
|
||||
"rgba(0,0,0,0.5)" /* Black background with opacity */,
|
||||
zIndex:
|
||||
"2" /* Specify a stack order in case you're using a different order for other elements */
|
||||
// cursor: "pointer" /* Add a pointer on hover */
|
||||
}}
|
||||
src={require("../images/special_event.svg")}
|
||||
alt="sidenav_background"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<i className="material-icons right" onClick={closeNavClick}>
|
||||
close
|
||||
</i>
|
||||
|
||||
{isAuthenticated ? (
|
||||
<Link to="/profile">
|
||||
<img className="circle" src={user.picture} alt="user_avatar" />
|
||||
<span className="white-text name">{user.name}</span>
|
||||
<span className="white-text email">{user.email}</span>
|
||||
</Link>
|
||||
) : (
|
||||
// <Link to="/profile">
|
||||
<img
|
||||
className="circle"
|
||||
src={require("../images/chef.svg")}
|
||||
alt="user_avatar"
|
||||
/>
|
||||
// </Link>
|
||||
)}
|
||||
<ul id="slide-out" className="sidenav" style={transformStyle}>
|
||||
<li>
|
||||
<div className="user-view" style={{ height: "30vh" }}>
|
||||
<div className="background">
|
||||
<img
|
||||
// className="responsive-img"
|
||||
style={{
|
||||
position: "fixed" /* Sit on top of the page content */,
|
||||
width: "100%" /* Full width (cover the whole page) */,
|
||||
height: "30vh" /* Full width (cover the whole page) */,
|
||||
top: "0",
|
||||
left: "0",
|
||||
right: "0",
|
||||
bottom: "0",
|
||||
backgroundColor:
|
||||
"rgba(0,0,0,0.5)" /* Black background with opacity */,
|
||||
zIndex:
|
||||
"2" /* Specify a stack order in case you're using a different order for other elements */,
|
||||
// cursor: "pointer" /* Add a pointer on hover */
|
||||
}}
|
||||
src={require("../images/special_event.svg")}
|
||||
alt="sidenav_background"
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<RandomButton
|
||||
handleClick={handleClick}
|
||||
url={buttonUrl}
|
||||
size="small"
|
||||
color="orange darken-2"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="#">
|
||||
{!isAuthenticated ? (
|
||||
<LogInButton color="orange lighten-1" />
|
||||
) : (
|
||||
<LogOutButton />
|
||||
)}
|
||||
</Link>
|
||||
</li>
|
||||
<i className="material-icons right" onClick={closeNavClick}>
|
||||
close
|
||||
</i>
|
||||
|
||||
<li>
|
||||
<div className="divider"></div>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="#" className="subheader">
|
||||
Navigation
|
||||
</Link>
|
||||
</li>
|
||||
{links.map((link, i) => (
|
||||
<FooterLink key={i} link={link} />
|
||||
))}
|
||||
{isAuthenticated && <FooterLink link="profile" />}
|
||||
</ul>
|
||||
</>
|
||||
{isAuthenticated ? (
|
||||
<Link to="/profile">
|
||||
<img className="circle" src={user.picture} alt="user_avatar" />
|
||||
<span className="white-text name">{user.name}</span>
|
||||
<span className="white-text email">{user.email}</span>
|
||||
</Link>
|
||||
) : (
|
||||
// <Link to="/profile">
|
||||
<img
|
||||
className="circle"
|
||||
src={require("../images/chef.svg")}
|
||||
alt="user_avatar"
|
||||
/>
|
||||
// </Link>
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<RandomButton
|
||||
handleClick={handleClick}
|
||||
url={buttonUrl}
|
||||
size="small"
|
||||
color="orange darken-2"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="#">
|
||||
{!isAuthenticated ? (
|
||||
<LogInButton color="orange lighten-1" />
|
||||
) : (
|
||||
<LogOutButton />
|
||||
)}
|
||||
</Link>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<div className="divider"></div>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="#" className="subheader">
|
||||
Navigation
|
||||
</Link>
|
||||
</li>
|
||||
{links.map((link, i) => (
|
||||
<FooterLink key={i} link={link} />
|
||||
))}
|
||||
{isAuthenticated && <FooterLink link="profile" />}
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { useParams, Redirect } from "react-router-dom";
|
|||
import { CategoryPage } from "../pages/CategoryPage";
|
||||
import { getData } from "../utils/methods";
|
||||
|
||||
export const CategoryController = props => {
|
||||
export const CategoryController = () => {
|
||||
const [meals, setMeals] = useState({ meals: [] });
|
||||
|
||||
const { strCategory } = useParams();
|
||||
|
|
@ -17,13 +17,9 @@ export const CategoryController = props => {
|
|||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{meals.meals === null ? (
|
||||
<Redirect to="/404" />
|
||||
) : (
|
||||
<CategoryPage meals={meals} strCategory={strCategory} />
|
||||
)}
|
||||
</>
|
||||
return meals.meals === null ? (
|
||||
<Redirect to="/404" />
|
||||
) : (
|
||||
<CategoryPage meals={meals} strCategory={strCategory} />
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import React from "react";
|
||||
|
||||
import { HomePage } from "../pages/HomePage";
|
||||
|
||||
export const HomeController = ({ buttonUrl }) => {
|
||||
|
|
|
|||
80
src/controllers/MainRouter.jsx
Normal file
80
src/controllers/MainRouter.jsx
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import React from "react";
|
||||
import { Switch, Route, Redirect } from "react-router-dom";
|
||||
|
||||
import { SearchController } from "../controllers/SearchController";
|
||||
import { HomeController } from "../controllers/HomeController";
|
||||
import { MealController } from "../controllers/MealController";
|
||||
import { CategoryController } from "../controllers/CategoryController";
|
||||
import { CategoryListController } from "../controllers/CategoryListController";
|
||||
import { ProfileController } from "../controllers/ProfileController";
|
||||
|
||||
import { ContactPage } from "../pages/Contact";
|
||||
import { NotFoundPage } from "../pages/NotFoundPage";
|
||||
|
||||
import { PrivateRoute } from "../components/PrivateRoute";
|
||||
|
||||
const MainRouter = ({
|
||||
buttonUrl,
|
||||
meal,
|
||||
getMeal,
|
||||
getRandomMeal,
|
||||
searchString,
|
||||
searchResults,
|
||||
}) => {
|
||||
return (
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<HomeController buttonUrl={buttonUrl} />
|
||||
</Route>
|
||||
|
||||
<PrivateRoute exact path="/profile">
|
||||
<ProfileController />
|
||||
</PrivateRoute>
|
||||
|
||||
<Route exact path={buttonUrl}>
|
||||
<MealController
|
||||
meal={meal}
|
||||
getMeal={getMeal}
|
||||
getRandomMeal={getRandomMeal}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route exact path="/categories">
|
||||
<CategoryListController />
|
||||
</Route>
|
||||
|
||||
<Route path="/categories/:strCategory/">
|
||||
<CategoryController />
|
||||
</Route>
|
||||
|
||||
<Route exact path="/search">
|
||||
<SearchController
|
||||
searchString={searchString}
|
||||
searchResults={searchResults}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="/contact">
|
||||
<ContactPage />
|
||||
</Route>
|
||||
|
||||
<Route path="/404">
|
||||
<NotFoundPage handleClick={getRandomMeal} />
|
||||
</Route>
|
||||
|
||||
<Route path="/:id">
|
||||
<MealController
|
||||
meal={meal}
|
||||
getMeal={getMeal}
|
||||
getRandomMeal={getRandomMeal}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="*">
|
||||
<Redirect to="/404" />
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainRouter;
|
||||
|
|
@ -4,7 +4,6 @@ import { useAuth0 } from "../utils/auth0-spa";
|
|||
import { MealPage } from "../pages/MealPage";
|
||||
import { NotFoundPage } from "../pages/NotFoundPage";
|
||||
import { useFirebase } from "../services/Firebase";
|
||||
// import Firebase from "../data/Firebase";
|
||||
|
||||
export const MealController = ({ meal, getMeal, getRandomMeal }) => {
|
||||
const { user, isAuthenticated } = useAuth0();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import React from "react";
|
||||
|
||||
import { SearchPage } from "../pages/SearchPage";
|
||||
|
||||
export const SearchController = ({ searchString, searchResults }) => {
|
||||
|
|
|
|||
75
src/layouts/MainLayout.jsx
Normal file
75
src/layouts/MainLayout.jsx
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import React, { useState } from "react";
|
||||
|
||||
import { Navbar } from "../components/Navbar";
|
||||
import { SearchBar } from "../components/SearchBar";
|
||||
import { Footer } from "../components/Footer";
|
||||
import { SideNav } from "../components/SideNav";
|
||||
|
||||
const MainLayout = ({
|
||||
buttonUrl,
|
||||
getRandomMeal,
|
||||
handleChange,
|
||||
searchString,
|
||||
setSearchString,
|
||||
getSearchResults,
|
||||
setSearchResults,
|
||||
children,
|
||||
}) => {
|
||||
const [showNav, setShowNav] = useState(false);
|
||||
|
||||
const links = ["categories", "contact"];
|
||||
const footerLinks = [...links, "random"];
|
||||
|
||||
const openNavClick = (ev) => {
|
||||
ev.preventDefault();
|
||||
setShowNav(true);
|
||||
document.addEventListener("keydown", handleEscKey);
|
||||
// document.addEventListener("click", handleOutsideClick);
|
||||
};
|
||||
|
||||
const closeNavClick = (ev) => {
|
||||
ev.preventDefault();
|
||||
setShowNav(false);
|
||||
document.removeEventListener("keydown", handleEscKey);
|
||||
};
|
||||
|
||||
const handleEscKey = (ev) => {
|
||||
if (ev.key === "Escape") {
|
||||
setShowNav(false);
|
||||
}
|
||||
};
|
||||
// const handleOutsideClick = ev => {
|
||||
// console.log(ev);
|
||||
// };
|
||||
|
||||
return (
|
||||
<>
|
||||
<header>
|
||||
<Navbar
|
||||
handleClick={getRandomMeal}
|
||||
buttonUrl={buttonUrl}
|
||||
openNavClick={openNavClick}
|
||||
links={links}
|
||||
/>
|
||||
|
||||
<SearchBar
|
||||
searchString={searchString}
|
||||
setSearchString={setSearchString}
|
||||
handleChange={handleChange}
|
||||
onSubmit={getSearchResults}
|
||||
setSearchResults={setSearchResults}
|
||||
/>
|
||||
<SideNav
|
||||
showNav={showNav}
|
||||
closeNavClick={closeNavClick}
|
||||
links={links}
|
||||
buttonUrl={buttonUrl}
|
||||
/>
|
||||
</header>
|
||||
{children}
|
||||
<Footer links={[...links, "random"]} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainLayout;
|
||||
|
|
@ -26,7 +26,6 @@ export const CategoryPage = ({ meals, strCategory }) => {
|
|||
))}
|
||||
</div>
|
||||
</ul>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { createContext, useContext } from "react";
|
||||
|
||||
// create a Firebase context to make state available anywhere in the App.
|
||||
const FirebaseContext = createContext(null);
|
||||
|
||||
export const useFirebase = () => useContext(FirebaseContext);
|
||||
export default FirebaseContext;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ const CONFIG = {
|
|||
measurementId: config.measurementId,
|
||||
};
|
||||
|
||||
// Firebase initializes the Application and provides method to interact with
|
||||
// Firebase services as auth and firestore.
|
||||
export default class Firebase {
|
||||
constructor() {
|
||||
app.initializeApp(CONFIG);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// This file centralize all Firebase related exports
|
||||
|
||||
import Firebase from "./firebase";
|
||||
import FirebaseContext, { useFirebase } from "./context";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// This must be set on the server using express
|
||||
// This must be set on the server using or firebase functions
|
||||
import { createTransport } from "nodemailer";
|
||||
import { mailPassword } from "./secret";
|
||||
import { mailAdress, mailPassword } from "./secret";
|
||||
|
||||
const myMail = "ruidy.nemausat@gmail.com";
|
||||
const myMail = mailAdress;
|
||||
const myPass = mailPassword;
|
||||
|
||||
const handleMail = (mailTo, subject, text) => {
|
||||
|
|
@ -10,18 +10,18 @@ const handleMail = (mailTo, subject, text) => {
|
|||
service: "gmail",
|
||||
auth: {
|
||||
user: myMail,
|
||||
pass: myPass
|
||||
}
|
||||
pass: myPass,
|
||||
},
|
||||
});
|
||||
|
||||
let mailOptions = {
|
||||
from: myMail,
|
||||
to: mailTo,
|
||||
subject: subject,
|
||||
text: text
|
||||
text: text,
|
||||
};
|
||||
|
||||
transporter.sendMail(mailOptions, function(error, info) {
|
||||
transporter.sendMail(mailOptions, function (error, info) {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Reference in a new issue