From 342b3ed8348509879b58a3e41c4dfcf235a399c3 Mon Sep 17 00:00:00 2001 From: Kevin Hines <77130661+kevhines@users.noreply.github.com> Date: Thu, 24 Feb 2022 20:27:19 -0500 Subject: [PATCH] Forget password restructured (#140) * Moved changes frorm forget-password branch to a new branch to deal with restructured files - frontend * Moved changes frorm forget-password branch to a new branch to deal with restructured files - backend * modified users.controller to plan to send email from within the try and use a Response Type for cleaner error handling as per James * removed some old commented out bits * cleared form after submit takes place * button changes while loading * added type to resestPassword in users.controller and set error as nullin ForgetPassword.tsx set error as null in EmailInput to ease changes when error handeling is set inside EmailInput entirely --- client/src/features/Main.tsx | 5 + .../features/action/assets/SimpleSnackbar.tsx | 6 +- .../features/users/Auth/ForgotPassword.tsx | 130 ++++++++++++++++++ .../src/features/users/Auth/PasswordInput.tsx | 3 +- client/src/routes.tsx | 5 + server/src/users/users.controller.ts | 27 +++- 6 files changed, 172 insertions(+), 4 deletions(-) create mode 100644 client/src/features/users/Auth/ForgotPassword.tsx diff --git a/client/src/features/Main.tsx b/client/src/features/Main.tsx index a47c7828..b798b59a 100644 --- a/client/src/features/Main.tsx +++ b/client/src/features/Main.tsx @@ -30,6 +30,11 @@ function Main() { {/* users */} + (true); const handleClose = (event?: React.SyntheticEvent, reason?: string) => { isSetOpen(false); @@ -20,7 +22,7 @@ export default function SimpleSnackbar() { , ]} - message={You claimed this! } + message={{message}} /> ); diff --git a/client/src/features/users/Auth/ForgotPassword.tsx b/client/src/features/users/Auth/ForgotPassword.tsx new file mode 100644 index 00000000..3c98ccb9 --- /dev/null +++ b/client/src/features/users/Auth/ForgotPassword.tsx @@ -0,0 +1,130 @@ +import * as React from 'react'; +import Button from '@material-ui/core/Button'; +import Grid from '@material-ui/core/Grid'; +import Paper from '@material-ui/core/Paper'; +import { makeStyles } from '@material-ui/core/styles'; +import Typography from '@material-ui/core/Typography'; +import SimpleSnackbar from '../../action/assets/SimpleSnackbar'; + +import type { Theme } from '@material-ui/core/styles'; + +import EmailInput from './EmailInput'; + +const useStyles = makeStyles((theme: Theme) => { + const xPadding = 12; + const yPadding = 6; + const yMargin = 8; + + return { + paper: { + maxWidth: 821 - theme.spacing(xPadding), + maxHeight: 732 - theme.spacing(yPadding), + borderRadius: 10, + marginTop: theme.spacing(yMargin), + marginBottom: theme.spacing(yMargin), + paddingTop: theme.spacing(yPadding), + paddingBottom: theme.spacing(yPadding), + paddingLeft: theme.spacing(xPadding), + paddingRight: theme.spacing(xPadding), + margin: 'auto', + }, + header: { fontWeight: 'bold', marginBottom: 68 }, + button: { + borderRadius: 0, + height: 62, + textTransform: 'none', + }, + }; +}); + +interface UserLoginData { + email: string; +} + +const initialFormData: UserLoginData = { + email: '', +}; + +function ForgotPassword() { + const classes = useStyles(); + const [isLoading, setIsLoading] = React.useState(false); + const [showSnackbar, setShowSnackbar] = React.useState(false); + const [formData, setFormData] = React.useState(initialFormData); + const instructions = + "Enter your email and we'll send you a link to reset you password if you have an account."; + const emailResponse = + 'If this email exists as a user you will be sent an email to reset your password.'; + + const generateForm = () => { + return ( + +
+ + + +
+ ); + }; + + const handleChange = (evt: React.ChangeEvent): void => { + const { name, value }: { name: string; value: string } = evt.target; + setFormData((fData) => ({ + ...fData, + [name]: value, + })); + }; + + const handleSubmit = async (evt: React.FormEvent): Promise => { + evt.preventDefault(); + setIsLoading(true); + + await fetch('http://localhost:3001/api/users/reset_password', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(formData), + }); + + setIsLoading(false); + setShowSnackbar(true); + setFormData((fData) => ({ + ...fData, + email: '', + })); + }; + + return ( +
+ + + + + Forgot Your Password? + + + {showSnackbar ? emailResponse : instructions} + + {showSnackbar ? null : generateForm()} + + + + {showSnackbar ? : null} +
+ ); +} + +export default ForgotPassword; diff --git a/client/src/features/users/Auth/PasswordInput.tsx b/client/src/features/users/Auth/PasswordInput.tsx index 1a7880b4..a1179b27 100644 --- a/client/src/features/users/Auth/PasswordInput.tsx +++ b/client/src/features/users/Auth/PasswordInput.tsx @@ -12,6 +12,7 @@ import FormHelperText from '@material-ui/core/FormHelperText'; import type { Theme } from '@material-ui/core/styles'; import StyledLink from '../../../assets/sharedComponents/StyledLink'; +import routes from '../../../routes'; const useStyles = makeStyles((theme: Theme) => { return { @@ -62,7 +63,7 @@ function PasswordInput({
Password {/* to prop to be updated to use routes once page is set up */} - {showForgot && Forgot Password?} + {showForgot && Forgot Password?}
{error && {error}} diff --git a/client/src/routes.tsx b/client/src/routes.tsx index 1109b77d..3d7c2ca8 100644 --- a/client/src/routes.tsx +++ b/client/src/routes.tsx @@ -22,6 +22,7 @@ import OfferFormGoods from './features/action/offers/OfferFormGoods'; import OfferFormSkills from './features/action/offers/OfferFormSkills'; import ContactUs from './features/support/ContactUs'; import Help from './features/support/Help'; +import ForgotPassword from './features/users/Auth/ForgotPassword'; const routes = { Home: { @@ -52,6 +53,10 @@ const routes = { component: PrivacyPolicy, path: '/privacy-policy', }, + ForgotPassword: { + component: ForgotPassword, + path: '/forgot-password', + }, Login: { component: Login, path: '/login', diff --git a/server/src/users/users.controller.ts b/server/src/users/users.controller.ts index 51b43191..1f7e28a7 100644 --- a/server/src/users/users.controller.ts +++ b/server/src/users/users.controller.ts @@ -1,4 +1,16 @@ -import { Controller, Get, Post, Body, Patch, Param, Delete, ParseIntPipe } from '@nestjs/common'; +import { + Controller, + Get, + Post, + Body, + Patch, + Param, + Delete, + Request, + Response, + ParseIntPipe, +} from '@nestjs/common'; +import type { Response as ResponseT } from 'express'; import { UsersService } from './users.service'; import { User } from './entities/user.entity'; import { CreateUserDto } from './dto/create-user.dto'; @@ -17,6 +29,19 @@ export class UsersController { return user; } + @Post('reset_password') + async resetPassword( + @Request() req, + @Response({ passthrough: true }) response: ResponseT, + ): Promise { + try { + const user = await this.usersService.findByEmail(req.body.email); + //TODO send email the user + } catch (e) { + response.status(200).send(); + } + } + @Get(':id') async findOne(@Param('id', ParseIntPipe) id: number) { return this.usersService.findOne(id);