mirror of
https://github.com/rjNemo/meal_planner
synced 2026-06-12 13:26:45 +00:00
cleanup
This commit is contained in:
parent
df80472fd7
commit
fd3362a169
28 changed files with 136 additions and 23 deletions
|
|
@ -71,6 +71,8 @@ Free meal planner for cooks short on ideas! (like me …)
|
||||||
- [Materialize](https://materializecss.com) CSS librairy for styling
|
- [Materialize](https://materializecss.com) CSS librairy for styling
|
||||||
- Public API: [TheMealDb](https://www.themealdb.com/api.php) and [TheCocktailDb](https://www.thecocktaildb.com/api.php)
|
- Public API: [TheMealDb](https://www.themealdb.com/api.php) and [TheCocktailDb](https://www.thecocktaildb.com/api.php)
|
||||||
- Hosting: [Render](https://render.com/)
|
- Hosting: [Render](https://render.com/)
|
||||||
|
- Analytics : Google Analytics & Mixpanel
|
||||||
|
- Authentication : Firebase or Auth0
|
||||||
|
|
||||||
## Versions
|
## Versions
|
||||||
|
|
||||||
|
|
@ -90,7 +92,7 @@ Free meal planner for cooks short on ideas! (like me …)
|
||||||
## TO DO
|
## TO DO
|
||||||
|
|
||||||
- add sidenav on mobile
|
- add sidenav on mobile
|
||||||
- accounts v2
|
- accounts v2 (profile page)
|
||||||
- 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)
|
||||||
- code cleanup (props and refactoring)
|
- code cleanup (props and refactoring)
|
||||||
- put a preloader
|
- put a preloader
|
||||||
|
|
@ -99,3 +101,4 @@ Free meal planner for cooks short on ideas! (like me …)
|
||||||
- https://www.henriksommerfeld.se/error-handling-with-fetch/
|
- https://www.henriksommerfeld.se/error-handling-with-fetch/
|
||||||
- Use ErrorBoundaries component ?
|
- Use ErrorBoundaries component ?
|
||||||
- Back to top button
|
- Back to top button
|
||||||
|
- Take a look at some components [here](http://react-materialize.github.io/react-materialize/?path=/story/css-grid--default)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"short_name": "Meal Planner",
|
"short_name": "Chef's",
|
||||||
"name": "Chef's Meal Planner",
|
"name": "Chef's | Meal Planner",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "favicon.ico",
|
"src": "favicon.ico",
|
||||||
|
|
|
||||||
10
src/App.js
10
src/App.js
|
|
@ -1,8 +1,8 @@
|
||||||
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 { Switch, Route, Redirect } from "react-router-dom";
|
||||||
import { HomePage } from "./pages/Home";
|
import { Home } from "./pages/Home";
|
||||||
import { MealPage } from "./pages/Meal";
|
import { Meal } from "./pages/Meal";
|
||||||
import { SearchPage } from "./pages/Search";
|
import { SearchPage } from "./pages/Search";
|
||||||
import { CategoryListPage } from "./pages/CategoryList";
|
import { CategoryListPage } from "./pages/CategoryList";
|
||||||
import { CategoryPage } from "./pages/Category";
|
import { CategoryPage } from "./pages/Category";
|
||||||
|
|
@ -113,10 +113,10 @@ export const App = () => {
|
||||||
/>
|
/>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path="/">
|
<Route exact path="/">
|
||||||
<HomePage handleClick={getRandomMeal} buttonUrl={buttonUrl} />
|
<Home buttonUrl={buttonUrl} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route exact path={buttonUrl}>
|
<Route exact path={buttonUrl}>
|
||||||
<MealPage meal={meal} getMeal={getRandomMeal} />
|
<Meal meal={meal} getMeal={getRandomMeal} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route exact path="/categories">
|
<Route exact path="/categories">
|
||||||
<CategoryListPage
|
<CategoryListPage
|
||||||
|
|
@ -145,7 +145,7 @@ export const App = () => {
|
||||||
<NotFoundPage handleClick={getRandomMeal} />
|
<NotFoundPage handleClick={getRandomMeal} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/:idMeal">
|
<Route path="/:idMeal">
|
||||||
<MealPage meal={meal} getMeal={getMeal} />
|
<Meal meal={meal} getMeal={getMeal} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="*">
|
<Route path="*">
|
||||||
<Redirect to="/404" />
|
<Redirect to="/404" />
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import { Link, useRouteMatch } from "react-router-dom";
|
||||||
const CategoryEntry = props => {
|
const CategoryEntry = props => {
|
||||||
const {
|
const {
|
||||||
strCategory,
|
strCategory,
|
||||||
strCategoryThumb,
|
strCategoryThumb
|
||||||
strCategoryDescription
|
// strCategoryDescription
|
||||||
} = props.category;
|
} = props.category;
|
||||||
|
|
||||||
const { url } = useRouteMatch();
|
const { url } = useRouteMatch();
|
||||||
|
|
@ -16,7 +16,6 @@ export const Navbar = props => {
|
||||||
{links.map((link, i) => (
|
{links.map((link, i) => (
|
||||||
<FooterLink i={i} link={link} />
|
<FooterLink i={i} link={link} />
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<RandomButton
|
<RandomButton
|
||||||
handleClick={props.handleClick}
|
handleClick={props.handleClick}
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
export const RandomButton = props => {
|
export const RandomButton = ({ url, size, handleClick }) => {
|
||||||
const classString = `waves-effect waves-light btn-${props.size}`;
|
const classString = `waves-effect waves-light btn-${size}`;
|
||||||
return (
|
return (
|
||||||
<Link to={props.url}>
|
<Link to={url}>
|
||||||
<button
|
<button
|
||||||
// className="waves-effect waves-light btn-small"
|
// className="waves-effect waves-light btn-small"
|
||||||
className={classString}
|
className={classString}
|
||||||
onClick={props.handleClick}
|
onClick={handleClick}
|
||||||
>
|
>
|
||||||
Random Recipe
|
Random Recipe
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -15,10 +15,10 @@ div {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.background {
|
/* .background {
|
||||||
background-image: url(./images/Chef.svg);
|
background-image: url(./images/chef.svg);
|
||||||
/* width: 100%; */
|
width: 100%;
|
||||||
}
|
} */
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
font-family: "Marck Script", cursive;
|
font-family: "Marck Script", cursive;
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { RandomButton } from "../components/RandomButton";
|
import { RandomButton } from "../components/RandomButton";
|
||||||
|
|
||||||
export const HomePage = props => {
|
export const Home = ({ buttonUrl }) => {
|
||||||
return (
|
return (
|
||||||
<div className="section ">
|
<div className="section ">
|
||||||
<div className="container ">
|
<div className="container ">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col s12 m6">
|
<div className="col s12 m6">
|
||||||
<h1 className="logo">Chef's Online Cookbook</h1>
|
<h1 className="logo">Chef's Online Cookbook</h1>
|
||||||
<RandomButton url={props.buttonUrl} size="large" />
|
<RandomButton url={buttonUrl} size="large" />
|
||||||
</div>
|
</div>
|
||||||
<div className="col s12 m6">
|
<div className="col s12 m6">
|
||||||
<img
|
<img
|
||||||
|
|
@ -4,7 +4,7 @@ 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";
|
||||||
|
|
||||||
export const MealPage = props => {
|
export const Meal = props => {
|
||||||
const { getMeal } = props;
|
const { getMeal } = props;
|
||||||
const { idMeal } = useParams();
|
const { idMeal } = useParams();
|
||||||
|
|
||||||
111
src/utils/authentication.js
Normal file
111
src/utils/authentication.js
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
import React, { useState, useEffect, useContext, createContext } from "react";
|
||||||
|
import queryString from "query-string";
|
||||||
|
import * as firebase from "firebase/app";
|
||||||
|
import "firebase/auth";
|
||||||
|
|
||||||
|
if (!firebase.apps.length) {
|
||||||
|
// Replace with your own Firebase credentials
|
||||||
|
firebase.initializeApp({
|
||||||
|
apiKey: "AIzaSyBkkFF0XhNZeWuDmOfEhsgdfX1VBG7WTas",
|
||||||
|
authDomain: "divjoy-demo.firebaseapp.com",
|
||||||
|
projectId: "divjoy-demo",
|
||||||
|
appID: "divjoy-demo"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const authContext = createContext();
|
||||||
|
|
||||||
|
// Provider component that wraps your app and makes auth object ...
|
||||||
|
// ... available to any child component that calls useAuth().
|
||||||
|
export function ProvideAuth({ children }) {
|
||||||
|
const auth = useProvideAuth();
|
||||||
|
return <authContext.Provider value={auth}>{children}</authContext.Provider>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hook for child components to get the auth object ...
|
||||||
|
// ... update when it changes.
|
||||||
|
export const useAuth = () => {
|
||||||
|
return useContext(authContext);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Provider hook that creates auth object and handles state
|
||||||
|
function useProvideAuth() {
|
||||||
|
const [user, setUser] = useState(null);
|
||||||
|
|
||||||
|
const signin = (email, password) => {
|
||||||
|
return firebase
|
||||||
|
.auth()
|
||||||
|
.signInWithEmailAndPassword(email, password)
|
||||||
|
.then(response => {
|
||||||
|
setUser(response.user);
|
||||||
|
return response.user;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const signup = (email, password) => {
|
||||||
|
return firebase
|
||||||
|
.auth()
|
||||||
|
.createUserWithEmailAndPassword(email, password)
|
||||||
|
.then(response => {
|
||||||
|
setUser(response.user);
|
||||||
|
return response.user;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const signout = () => {
|
||||||
|
return firebase
|
||||||
|
.auth()
|
||||||
|
.signOut()
|
||||||
|
.then(() => {
|
||||||
|
setUser(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const sendPasswordResetEmail = email => {
|
||||||
|
return firebase
|
||||||
|
.auth()
|
||||||
|
.sendPasswordResetEmail(email)
|
||||||
|
.then(() => {
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmPasswordReset = (password, code) => {
|
||||||
|
// Get code from query string object
|
||||||
|
const resetCode = code || getFromQueryString("oobCode");
|
||||||
|
|
||||||
|
return firebase
|
||||||
|
.auth()
|
||||||
|
.confirmPasswordReset(resetCode, password)
|
||||||
|
.then(() => {
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Subscribe to user on mount
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribe = firebase.auth().onAuthStateChanged(user => {
|
||||||
|
if (user) {
|
||||||
|
setUser(user);
|
||||||
|
} else {
|
||||||
|
setUser(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Subscription unsubscribe function
|
||||||
|
return () => unsubscribe();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
user,
|
||||||
|
signin,
|
||||||
|
signup,
|
||||||
|
signout,
|
||||||
|
sendPasswordResetEmail,
|
||||||
|
confirmPasswordReset
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFromQueryString = key => {
|
||||||
|
return queryString.parse(window.location.search)[key];
|
||||||
|
};
|
||||||
Loading…
Reference in a new issue