Skip to content

Commit

Permalink
Merge pull request #17 from sajidrsk/forgot-password-page-and-private…
Browse files Browse the repository at this point in the history
…-routing

- added forgot password page
- added private routing based on user is logged in or not
- added update email and password feature(gui not available yet)
- added sign out button
  • Loading branch information
sajidrsk committed Mar 23, 2021
2 parents 827e02c + dd1df68 commit cd54616
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 41 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,20 @@ import { RecipeContextProvider } from "./contexts/recipe-context";
import Home from "./containers/Home";
import Login from "./containers/Login";
import Signup from "./containers/Signup";
import ForgotPassword from "./containers/ForgotPassword";
import PrivateRoute from "./PrivateRoutes";

function App() {
const response =false;
return (
<SnackbarProvider maxSnack={3} autoHideDuration={2000} preventDuplicate>
<SnackbarProvider maxSnack={3} autoHideDuration={3000} preventDuplicate>
<AuthContextProvider>
<RecipeContextProvider>
<Router>
<Switch>
<PrivateRoute auth={response} exact path="/" component={Home} />
<PrivateRoute exact path="/" component={Home} />
<Route exact path="/signup" component={Signup} />
<Route exact path="/login" component={Login} />
<Route exact path="/forgot-password" component={ForgotPassword} />
</Switch>
</Router>
</RecipeContextProvider>
Expand Down
13 changes: 10 additions & 3 deletions src/PrivateRoutes.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import * as React from "react";
import { Route, Redirect } from "react-router-dom";

const PrivateRoute = ({ auth, component: Component, ...rest }) => {
import { useAuth } from "./contexts/auth-context";

const PrivateRoute = ({ component: Component, ...rest }) => {
const { currentUser } = useAuth();
return (
<Route
{...rest}
render={(props) => {
return auth ? <Component {...props} /> : <Redirect to="/login" />;
return currentUser ? (
<Component {...props} />
) : (
<Redirect to="/login" />
);
}}
/>
);
};

export default PrivateRoute;
export default PrivateRoute;
56 changes: 40 additions & 16 deletions src/components/RecipeList.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,53 @@
import React, { useContext } from "react";
import { Button } from "@material-ui/core";
import { useHistory } from "react-router-dom";

import Recipe from "./Recipe";
import { RecipeContext } from "../contexts/recipe-context";
import { useAuth } from "../contexts/auth-context";

export default function RecipeList({ recipes }) {
const { handleRecipeAdd } = useContext(RecipeContext);
const { logout } = useAuth();
const history = useHistory();

const handleLogout = async () => {
// setError("")
try {
await logout();
history.push("/login");
} catch {
// setError("Failed to log out")
}
};

return (
<div className="recipe-list">
<div className="recipe-list__grid">
{recipes.map((recipe) => {
return <Recipe key={recipe.id} {...recipe} />;
})}
</div>
<div className="recipe-list__add-recipe-btn-container">
<Button
size="small"
color="primary"
variant="contained"
onClick={handleRecipeAdd}
>
Add Recipe
</Button>
<>
<Button
size="small"
color="Secondary"
variant="contained"
onClick={handleLogout}
>
SignOut
</Button>
<div className="recipe-list">
<div className="recipe-list__grid">
{recipes.map((recipe) => {
return <Recipe key={recipe.id} {...recipe} />;
})}
</div>
<div className="recipe-list__add-recipe-btn-container">
<Button
size="small"
color="primary"
variant="contained"
onClick={handleRecipeAdd}
>
Add Recipe
</Button>
</div>
</div>
</div>
</>
);
}
139 changes: 139 additions & 0 deletions src/containers/ForgotPassword/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import React, { useState, useRef } from "react";
import { Link } from "react-router-dom";
import {
Avatar,
Button,
CssBaseline,
TextField,
Grid,
Box,
Typography,
Container,
Grow,
} from "@material-ui/core";
import LockOutlinedIcon from "@material-ui/icons/LockOutlined";
import { makeStyles } from "@material-ui/core/styles";
import { useSnackbar } from "notistack";

import { useAuth } from "../../contexts/auth-context";

function Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{`Copyright © Kitchen Recipe by Sajid ${new Date().getFullYear()}.`}
</Typography>
);
}

const useStyles = makeStyles((theme) => ({
paper: {
marginTop: theme.spacing(8),
display: "flex",
flexDirection: "column",
alignItems: "center",
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main,
},
form: {
width: "100%",
marginTop: theme.spacing(1),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
}));

const ForgotPassword = () => {
const classes = useStyles();
const { enqueueSnackbar } = useSnackbar();

const emailRef = useRef();
const { resetPassword } = useAuth();
const [loading, setLoading] = useState(false);

const handleSubmit = async (e) => {
e.preventDefault();

try {
setLoading(true);
await resetPassword(emailRef.current.value);

enqueueSnackbar("Password Reset Email Sent to Your Mail", {
anchorOrigin: {
vertical: "bottom",
horizontal: "center",
},
TransitionComponent: Grow,
variant: "success",
});
} catch (e) {
console.log(e);
enqueueSnackbar(e.message, {
anchorOrigin: {
vertical: "bottom",
horizontal: "center",
},
TransitionComponent: Grow,
variant: "error",
});
}

setLoading(false);
};

return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Password Reset
</Typography>
<form className={classes.form} noValidate onSubmit={handleSubmit}>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="email"
label="Email Address"
name="email"
autoComplete="email"
inputRef={emailRef}
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
disabled={loading}
>
Reset Password
</Button>
<Grid container justify="flex-end">
<Grid item xs>
<Button color="primary" to="/login" component={Link}>
{"Log In!"}
</Button>
</Grid>
<Grid item>
<Button color="primary" to="/signup" component={Link}>
{"Don't have an account? SignUp"}
</Button>
</Grid>
</Grid>
</form>
</div>
<Box mt={8}>
<Copyright />
</Box>
</Container>
);
};

export default ForgotPassword;
25 changes: 15 additions & 10 deletions src/containers/Login/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,16 @@ const Login = () => {
const emailRef = useRef();
const passwordRef = useRef();
const { login } = useAuth();
// const [loading, setLoading] = useState(false);
// const history = useHistory();
const [loading, setLoading] = useState(false);
const history = useHistory();

const handleSubmit = async (e) => {
e.preventDefault();

try {
// setLoading(true);
setLoading(true);
await login(emailRef.current.value, passwordRef.current.value);
// history.push("/");
history.push("/");
enqueueSnackbar("Login Successful", {
anchorOrigin: {
vertical: "bottom",
Expand All @@ -71,7 +71,8 @@ const Login = () => {
variant: "success",
});
} catch (e) {
enqueueSnackbar("Failed to Log In!", {
console.log(e);
enqueueSnackbar(e.message, {
anchorOrigin: {
vertical: "bottom",
horizontal: "center",
Expand All @@ -81,7 +82,7 @@ const Login = () => {
});
}

// setLoading(false);
setLoading(false);
};

return (
Expand Down Expand Up @@ -124,14 +125,18 @@ const Login = () => {
variant="contained"
color="primary"
className={classes.submit}
disabled={loading}
>
Sign In
</Button>
<Grid container justify="flex-end">
{/* <Grid item xs>
<Link to="#">Forgot password?</Link>
</Grid> */}
<Grid item>
<Grid item xs>
<Button color="primary" to="/forgot-password" component={Link}>
{"Forgot password?"}
</Button>
{/* <Link to="#">Forgot password?</Link> */}
</Grid>
<Grid item xs>
<Button color="primary" to="/signup" component={Link}>
{"Don't have an account? Sign Up"}
</Button>
Expand Down
11 changes: 6 additions & 5 deletions src/containers/Signup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ const SignUp = () => {
const passwordRef = useRef();
const passwordConfirmRef = useRef();
const { signup } = useAuth();
// const [loading, setLoading] = useState(false);
// const history = useHistory();
const [loading, setLoading] = useState(false);
const history = useHistory();

const handleSubmit = async (e) => {
e.preventDefault();
Expand All @@ -70,9 +70,9 @@ const SignUp = () => {
}

try {
// setLoading(true);
setLoading(true);
await signup(emailRef.current.value, passwordRef.current.value);
// history.push("/");
history.push("/");
enqueueSnackbar("SignUp Successful", {
anchorOrigin: {
vertical: "bottom",
Expand All @@ -92,7 +92,7 @@ const SignUp = () => {
});
}

// setLoading(false);
setLoading(false);
};

return (
Expand Down Expand Up @@ -169,6 +169,7 @@ const SignUp = () => {
</Grid>
</Grid>
<Button
disabled={loading}
type="submit"
fullWidth
variant="contained"
Expand Down
1 change: 0 additions & 1 deletion src/contexts/auth-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export const AuthContextProvider = ({ children }) => {
const [loading, setLoading] = useState(true);

function signup(email, password) {
console.log(email, password);
return auth.createUserWithEmailAndPassword(email, password);
}

Expand Down

0 comments on commit cd54616

Please sign in to comment.