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