This commit is contained in:
Ruidy Nemausat 2020-01-30 22:18:39 +01:00
parent df80472fd7
commit fd3362a169
28 changed files with 136 additions and 23 deletions

View file

@ -71,6 +71,8 @@ Free meal planner for cooks short on ideas! (like me …)
- [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)
- Hosting: [Render](https://render.com/)
- Analytics : Google Analytics & Mixpanel
- Authentication : Firebase or Auth0
## Versions
@ -90,7 +92,7 @@ Free meal planner for cooks short on ideas! (like me …)
## TO DO
- add sidenav on mobile
- accounts v2
- accounts v2 (profile page)
- send message after contact form validation (confirm to sender and msg+info to admin)
- code cleanup (props and refactoring)
- 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/
- Use ErrorBoundaries component ?
- Back to top button
- Take a look at some components [here](http://react-materialize.github.io/react-materialize/?path=/story/css-grid--default)

View file

@ -1,6 +1,6 @@
{
"short_name": "Meal Planner",
"name": "Chef's Meal Planner",
"short_name": "Chef's",
"name": "Chef's | Meal Planner",
"icons": [
{
"src": "favicon.ico",
@ -27,4 +27,4 @@
"display": "standalone",
"theme_color": "#ee6e73",
"background_color": "#ffffff"
}
}

View file

@ -1,8 +1,8 @@
import React, { useState } from "react";
import { Router } from "./utils/router";
import { Switch, Route, Redirect } from "react-router-dom";
import { HomePage } from "./pages/Home";
import { MealPage } from "./pages/Meal";
import { Home } from "./pages/Home";
import { Meal } from "./pages/Meal";
import { SearchPage } from "./pages/Search";
import { CategoryListPage } from "./pages/CategoryList";
import { CategoryPage } from "./pages/Category";
@ -113,10 +113,10 @@ export const App = () => {
/>
<Switch>
<Route exact path="/">
<HomePage handleClick={getRandomMeal} buttonUrl={buttonUrl} />
<Home buttonUrl={buttonUrl} />
</Route>
<Route exact path={buttonUrl}>
<MealPage meal={meal} getMeal={getRandomMeal} />
<Meal meal={meal} getMeal={getRandomMeal} />
</Route>
<Route exact path="/categories">
<CategoryListPage
@ -145,7 +145,7 @@ export const App = () => {
<NotFoundPage handleClick={getRandomMeal} />
</Route>
<Route path="/:idMeal">
<MealPage meal={meal} getMeal={getMeal} />
<Meal meal={meal} getMeal={getMeal} />
</Route>
<Route path="*">
<Redirect to="/404" />

View file

@ -4,8 +4,8 @@ import { Link, useRouteMatch } from "react-router-dom";
const CategoryEntry = props => {
const {
strCategory,
strCategoryThumb,
strCategoryDescription
strCategoryThumb
// strCategoryDescription
} = props.category;
const { url } = useRouteMatch();

View file

@ -16,7 +16,6 @@ export const Navbar = props => {
{links.map((link, i) => (
<FooterLink i={i} link={link} />
))}
<li>
<RandomButton
handleClick={props.handleClick}

View file

@ -1,14 +1,14 @@
import React from "react";
import { Link } from "react-router-dom";
export const RandomButton = props => {
const classString = `waves-effect waves-light btn-${props.size}`;
export const RandomButton = ({ url, size, handleClick }) => {
const classString = `waves-effect waves-light btn-${size}`;
return (
<Link to={props.url}>
<Link to={url}>
<button
// className="waves-effect waves-light btn-small"
className={classString}
onClick={props.handleClick}
onClick={handleClick}
>
Random Recipe
</button>

View file

@ -15,10 +15,10 @@ div {
white-space: pre-wrap;
}
.background {
background-image: url(./images/Chef.svg);
/* width: 100%; */
}
/* .background {
background-image: url(./images/chef.svg);
width: 100%;
} */
.logo {
font-family: "Marck Script", cursive;

View file

@ -1,14 +1,14 @@
import React from "react";
import { RandomButton } from "../components/RandomButton";
export const HomePage = props => {
export const Home = ({ buttonUrl }) => {
return (
<div className="section ">
<div className="container ">
<div className="row">
<div className="col s12 m6">
<h1 className="logo">Chef's Online Cookbook</h1>
<RandomButton url={props.buttonUrl} size="large" />
<RandomButton url={buttonUrl} size="large" />
</div>
<div className="col s12 m6">
<img

View file

@ -4,7 +4,7 @@ import { IngredientList } from "../components/IngredientList";
import { Recipe } from "../components/Recipe";
import { useParams, Redirect } from "react-router-dom";
export const MealPage = props => {
export const Meal = props => {
const { getMeal } = props;
const { idMeal } = useParams();

111
src/utils/authentication.js Normal file
View 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];
};