From c2e03e6fc83b33b8826e2dbc9f53f40690a4b5b8 Mon Sep 17 00:00:00 2001 From: Tom Chestnut Date: Sun, 10 Oct 2021 16:56:48 -0400 Subject: [PATCH 01/10] Made ForgotPassword component --- frontend/src/components/ForgotPassword.js | 90 +++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 frontend/src/components/ForgotPassword.js diff --git a/frontend/src/components/ForgotPassword.js b/frontend/src/components/ForgotPassword.js new file mode 100644 index 0000000..f2d9a60 --- /dev/null +++ b/frontend/src/components/ForgotPassword.js @@ -0,0 +1,90 @@ +import React, { useEffect, useState } from 'react'; + +import Alert from './Alert'; +import Button from './Button'; +import Input from './Input'; +import URL from '../URL'; +import axios from 'axios'; +import { useHistory } from 'react-router-dom'; + +const PW_EMAIL_ENDPOINT = '/api/users/forgot_password/'; +const NEW_PW_ENDPOINT = '/api/users/new_password/'; + +const ForgotPassword = () => { + const history = useHistory(); + + const [loading, setLoading] = useState(false); + const [errorMsg, setErrorMsg] = useState(false); + const [formState, setFormState] = useState({ + password1: '', + password2: '', + }); + const { password1, password2 } = formState; + + const handleFormChange = e => { + const { name, value } = e.target; + setFormState({ + ...formState, + [name]: value, + }); + }; + + const sendNewPassword = newPassword => + axios.post(URL + NEW_PW_ENDPOINT, newPassword); + + const handleSubmit = async e => { + e.preventDefault(); + setLoading(true); + try { + if (password1 === password2) { + const response = await sendNewPassword(password2); + console.log('response:', response); + if (response.statusText === 'OK') { + history.push('/'); + } + } + if (password1 !== password2) { + setErrorMsg('The passwords do not match.'); + } + } catch (err) { + setErrorMsg(err.message); + console.error(err); + } + setLoading(false); + setFormState({ password1: '', password2: '' }); + }; + + return ( + <> +
+
+ + + + + +
+ {errorMsg && ( + +

{errorMsg}

+ Tap to dismiss. +
+ )} +
+ + ); +}; + +export default ForgotPassword; From 045e5bd2e2d294ee49cdbf374cb999252882fbca Mon Sep 17 00:00:00 2001 From: Tom Chestnut Date: Sun, 10 Oct 2021 21:00:26 -0400 Subject: [PATCH 02/10] Updated css for ForgotPassword --- frontend/src/assets/css/ForgotPassword.css | 62 ++++++++++++++++++++++ frontend/src/components/ForgotPassword.js | 9 ++-- 2 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 frontend/src/assets/css/ForgotPassword.css diff --git a/frontend/src/assets/css/ForgotPassword.css b/frontend/src/assets/css/ForgotPassword.css new file mode 100644 index 0000000..6239d80 --- /dev/null +++ b/frontend/src/assets/css/ForgotPassword.css @@ -0,0 +1,62 @@ +.password-container { + margin: 10vh auto 5vh; + padding: 100px 40px; + width: 80%; + display: flex; + flex-direction: column; + justify-content: space-between; + position: relative; + align-items: center; +} + +.password-container h1 { + font-size: 3rem; + margin: 0; + color: var(--textcolor); +} + +.password-container p { + font-size: 1.3rem; +} + +label, +input { + display: block; + margin: 5px 0; +} + +.password-container label { + color: var(--textcolor); + font-weight: 600; +} + +.password-container input { + background-color: #e8f0fe; + border-radius: 5px; + border: none; + padding: 8px 10px; + font-size: 1.2rem; + margin: 10px 0 20px; + width: 90%; + min-width: 200px; +} + +input:focus { + outline: none; +} + +.password-container button { + display: block; + margin: 20px 0px; + padding: 8px 20px; + font-size: 1.2rem; + cursor: pointer; + background-color: rgb(243, 233, 140); + border: none; + border-radius: 2px; + font-weight: 600; +} + +.password-container button:hover { + background-color: #f5e44f; +} diff --git a/frontend/src/components/ForgotPassword.js b/frontend/src/components/ForgotPassword.js index f2d9a60..15888c9 100644 --- a/frontend/src/components/ForgotPassword.js +++ b/frontend/src/components/ForgotPassword.js @@ -1,8 +1,8 @@ -import React, { useEffect, useState } from 'react'; +import '../assets/css/ForgotPassword.css'; + +import React, { useState } from 'react'; import Alert from './Alert'; -import Button from './Button'; -import Input from './Input'; import URL from '../URL'; import axios from 'axios'; import { useHistory } from 'react-router-dom'; @@ -56,7 +56,8 @@ const ForgotPassword = () => { return ( <> -
+
+

Reset password

Date: Tue, 12 Oct 2021 20:24:43 -0400 Subject: [PATCH 03/10] Added routing for the ForgotPassword page --- frontend/src/App.js | 150 ++++----- frontend/src/components/Login.js | 519 +++++++++++++++---------------- 2 files changed, 334 insertions(+), 335 deletions(-) diff --git a/frontend/src/App.js b/frontend/src/App.js index cc76183..4a63dfe 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,89 +1,89 @@ -import './App.css'; -import LandingPage from './pages/LandingPage'; -import Auth from './pages/Auth'; -import EmailVerify from './pages/EmailVerify'; +import "./App.css"; +import LandingPage from "./pages/LandingPage"; +import Auth from "./pages/Auth"; +import EmailVerify from "./pages/EmailVerify"; import { - BrowserRouter as Router, - Route, - Switch, - Redirect, -} from 'react-router-dom'; - -import Dashboard from './pages/Dashboard'; -import { useContext, useEffect, useState } from 'react'; -import AuthContext from './store/auth-context'; -import Modal from './components/Alert'; -import URL from './URL'; + BrowserRouter as Router, + Route, + Switch, + Redirect, +} from "react-router-dom"; +import Dashboard from "./pages/Dashboard"; +import { useContext, useEffect, useState } from "react"; +import AuthContext from "./store/auth-context"; +import Modal from "./components/Alert"; +import ForgotPassword from "./components/ForgotPassword"; +import URL from "./URL"; function App() { - const authCtx = useContext(AuthContext); - const [key, setKey] = useState(); - const [isError, setIsError] = useState(false) + const authCtx = useContext(AuthContext); + const [key, setKey] = useState(); + const [isError, setIsError] = useState(false); - useEffect(()=>{ + useEffect(() => { + var requestOptions = { + method: "GET", + redirect: "follow", + }; - var requestOptions = { - method: 'GET', - redirect: 'follow' - }; - - fetch(`${URL}/`, requestOptions) - .then(response => { - if(response.status!==404) - { - setIsError(true) - } - else - { - setIsError(false) - } - console.log(response); - return response; - }) - .catch(error => { - console.log(!!error) - if(error) - { - setIsError(true) - } - else - { - setIsError(false) - } - }); - },[]) + fetch(`${URL}/`, requestOptions) + .then(response => { + if (response.status !== 404) { + setIsError(true); + } else { + setIsError(false); + } + console.log(response); + return response; + }) + .catch(error => { + console.log(!!error); + if (error) { + setIsError(true); + } else { + setIsError(false); + } + }); + }, []); - return ( - - + return ( + + + + {authCtx.isLoggedIn ? ( + + ) : ( + + )} + - - {authCtx.isLoggedIn ? : - } - + {authCtx.isLoggedIn && ( + + + + )} - {authCtx.isLoggedIn && ( - - - - )} + {!authCtx.isLoggedIn && ( + + + + )} + + + - {!authCtx.isLoggedIn && ( - - - - )} - - - + - - - - - - ); + + + + + + ); } export default App; diff --git a/frontend/src/components/Login.js b/frontend/src/components/Login.js index 136086a..3ddf379 100644 --- a/frontend/src/components/Login.js +++ b/frontend/src/components/Login.js @@ -1,300 +1,299 @@ import { useContext, useState } from "react"; import "../assets/css/Login.css"; import "../assets/css/loader.css"; -import swal from "sweetalert"; import typing from "../assets/media/typing.gif"; import URL from "../URL"; import { useHistory } from "react-router"; +import { Link } from "react-router-dom"; import AuthContext from "../store/auth-context"; const Login = () => { - const authCtx = useContext(AuthContext); - const history = useHistory(); - const mq = window.matchMedia("(mix-width: 480px)"); + const authCtx = useContext(AuthContext); + const history = useHistory(); + const mq = window.matchMedia("(mix-width: 480px)"); - const [coverClass, setCoverClass] = useState("cover cover-register"); + const [coverClass, setCoverClass] = useState("cover cover-register"); - const forgetPasswordHandler = () => { - swal({ - text: "Take a deep breath and try to remember your password.", - confirmButtonColor: "#f5e44f", - confirmButtonText: "Yes, delete it!", - }); - }; + const [loading, setLoading] = useState(false); + const [created, setCreated] = useState(false); + const [error, setError] = useState({ + status: false, + body: "", + }); - const [loading, setLoading] = useState(false); - const [created, setCreated] = useState(false); - const [error, setError] = useState({ - status: false, - body: "", - }); + const [email, setEmail] = useState(""); + const emailChangeHandler = event => { + setEmail(event.target.value); + }; - const [email, setEmail] = useState(""); - const emailChangeHandler = (event) => { - setEmail(event.target.value); - }; + const [pass, setPass] = useState(""); + const passChangeHandler = event => { + setPass(event.target.value); + }; - const [pass, setPass] = useState(""); - const passChangeHandler = (event) => { - setPass(event.target.value); - }; + const [pass2, setPass2] = useState(""); + const pass2ChangeHandler = event => { + setPass2(event.target.value); + }; - const [pass2, setPass2] = useState(""); - const pass2ChangeHandler = (event) => { - setPass2(event.target.value); - }; + const [name, setName] = useState(""); + const nameChangeHandler = event => { + setName(event.target.value); + }; - const [name, setName] = useState(""); - const nameChangeHandler = (event) => { - setName(event.target.value); - }; + const [warning, setWarning] = useState({ + status: false, + body: "", + }); - const [warning, setWarning] = useState({ - status: false, - body: "", - }); + //Register handler + const registerHandler = e => { + e.preventDefault(); + setCreated(false); - //Register handler - const registerHandler = (e) => { - e.preventDefault(); - setCreated(false); + if (pass == pass2) { + setLoading(true); + setError({ + status: false, + body: "", + }); - if (pass == pass2) { - setLoading(true); - setError({ - status: false, - body: "", - }); + var myHeaders = new Headers(); + myHeaders.append("Content-Type", "application/json"); - var myHeaders = new Headers(); - myHeaders.append("Content-Type", "application/json"); + let registerDetails = JSON.stringify({ + email: email, + password: pass, + name: name, + }); - let registerDetails = JSON.stringify({ - email: email, - password: pass, - name: name, - }); + var requestOptions = { + method: "POST", + headers: myHeaders, + body: registerDetails, + redirect: "follow", + }; - var requestOptions = { - method: "POST", - headers: myHeaders, - body: registerDetails, - redirect: "follow", - }; + fetch(`${URL}/api/users/register/`, requestOptions) + .then(response => { + const data = response.json(); + setLoading(false); - fetch(`${URL}/api/users/register/`, requestOptions) - .then((response) => { - const data = response.json(); - setLoading(false); + if (response.status == 200) setCreated(true); + else setCreated(false); - if (response.status == 200) setCreated(true); - else setCreated(false); + return data; + }) + .then(result => { + console.log(result); - return data; - }) - .then((result) => { - console.log(result); + let firstkey = Object.keys(result)[0]; - let firstkey = Object.keys(result)[0]; + setError({ + status: true, + body: result[firstkey], + }); + }) + .catch(error => console.log("error", error)); + } else { + setError({ + status: true, + body: "The passwords dont match!", + }); + } + }; - setError({ - status: true, - body: result[firstkey], - }); - }) - .catch((error) => console.log("error", error)); - } else { - setError({ - status: true, - body: "The passwords dont match!", - }); - } - }; + // Login handler + const loginHandler = e => { + e.preventDefault(); + setLoading(true); - // Login handler - const loginHandler = (e) => { - e.preventDefault(); - setLoading(true); + var myHeaders = new Headers(); + myHeaders.append("Content-Type", "application/json"); - var myHeaders = new Headers(); - myHeaders.append("Content-Type", "application/json"); + let authDetails = JSON.stringify({ + email: email, + password: pass, + }); - let authDetails = JSON.stringify({ - email: email, - password: pass, - }); + var requestOptions = { + method: "POST", + headers: myHeaders, + body: authDetails, + redirect: "follow", + }; - var requestOptions = { - method: "POST", - headers: myHeaders, - body: authDetails, - redirect: "follow", - }; + fetch(`${URL}/api/auth/login/`, requestOptions) + .then(response => { + setLoading(false); + if (response.ok) { + return response.json(); + } + return Promise.reject(response); + }) + .then(result => { + authCtx.login(result.key); - fetch(`${URL}/api/auth/login/`, requestOptions) - .then((response) => { - setLoading(false) - if (response.ok) { - return response.json(); - } - return Promise.reject(response); - }) - .then((result) => { - authCtx.login(result.key); + if (result.key) history.replace("/dashboard"); - if (result.key) history.replace("/dashboard"); + let firstkey = Object.keys(result)[0]; - let firstkey = Object.keys(result)[0]; + setWarning({ + status: true, + body: result[firstkey], + }); - setWarning({ - status: true, - body: result[firstkey], - }); + if (result.key) + setWarning({ + status: true, + body: "Loggin successful", + }); + }) + .catch(error => { + error.json().then(result => { + let firstkey = Object.keys(result)[0]; - if (result.key) - setWarning({ - status: true, - body: "Loggin successful", - }); - }) - .catch((error) => { - error.json().then((result)=>{ - let firstkey = Object.keys(result)[0]; + setWarning({ + status: true, + body: result[firstkey], + }); + }); + }); + }; + var width = Math.max(window.screen.width); - setWarning({ - status: true, - body: result[firstkey], - }); - }); - }) - }; - var width = Math.max(window.screen.width); - - return ( -
- -
-

Welcome back

-

- New here?{" "} - { - setCoverClass("cover"); - setWarning({ status: false, body: "" }); - setError({ status: false, body: "" }); - }} - > - Create an account now! - -

- - - - - - - Forgot password? - - {warning.status ? ( - {warning.body} - ) : null} - - -
-
-
-

Register Now

-

- Existing User?{" "} - { - setCoverClass("cover cover-register"); - setWarning({ status: false, body: "" }); - setError({ status: false, body: "" }); - }} - > - Click here to login! - -

-
- - - - - - - - - {created ? ( - Account created! Please check your email and verify in order to login. - ) : error.status ? ( - {error.body} - ) : null} - {loading ? ( -
-
-
-
-
-
- ) : null} - -
-
-
- ); + return ( +
+ +
+

Welcome back

+

+ New here?{" "} + { + setCoverClass("cover"); + setWarning({ status: false, body: "" }); + setError({ status: false, body: "" }); + }} + > + Create an account now! + +

+
+ + + + + + Forgot password? + + {warning.status ? ( + + {warning.body} + + ) : null} + +
+
+
+ {" "} +
+
+

Register Now

+

+ Existing User?{" "} + { + setCoverClass("cover cover-register"); + setWarning({ status: false, body: "" }); + setError({ status: false, body: "" }); + }} + > + Click here to login! + +

+
+ + + + + + + + + {created ? ( + + Account created! Please check your email and verify + in order to login. + + ) : error.status ? ( + {error.body} + ) : null} + {loading ? ( +
+
+
+
+
+
+ ) : null} + +
+
+
+ ); }; export default Login; From c754da6db268977b2deefb97dae4651c2410913e Mon Sep 17 00:00:00 2001 From: Tom Chestnut Date: Tue, 12 Oct 2021 21:07:04 -0400 Subject: [PATCH 04/10] Updated "Forgot password" link and modal to send user to ForgotPassword page on confirm. --- frontend/src/assets/css/ForgotPassword.css | 16 +++++++++------- frontend/src/components/Login.js | 20 ++++++++++++++++---- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/frontend/src/assets/css/ForgotPassword.css b/frontend/src/assets/css/ForgotPassword.css index 6239d80..5e69c12 100644 --- a/frontend/src/assets/css/ForgotPassword.css +++ b/frontend/src/assets/css/ForgotPassword.css @@ -1,16 +1,11 @@ .password-container { - margin: 10vh auto 5vh; - padding: 100px 40px; - width: 80%; display: flex; flex-direction: column; justify-content: space-between; - position: relative; - align-items: center; } .password-container h1 { - font-size: 3rem; + font-size: 2.5rem; margin: 0; color: var(--textcolor); } @@ -19,6 +14,12 @@ font-size: 1.3rem; } +.password-container a { + color: rgb(243, 233, 140); + cursor: pointer; + font-weight: 600; +} + label, input { display: block; @@ -31,7 +32,8 @@ input { } .password-container input { - background-color: #e8f0fe; + background-color: rgba(139, 137, 137, 0.39); + color: #e8f0fe; border-radius: 5px; border: none; padding: 8px 10px; diff --git a/frontend/src/components/Login.js b/frontend/src/components/Login.js index 3ddf379..5c25f76 100644 --- a/frontend/src/components/Login.js +++ b/frontend/src/components/Login.js @@ -1,10 +1,10 @@ import { useContext, useState } from "react"; import "../assets/css/Login.css"; import "../assets/css/loader.css"; +import swal from "sweetalert"; import typing from "../assets/media/typing.gif"; import URL from "../URL"; import { useHistory } from "react-router"; -import { Link } from "react-router-dom"; import AuthContext from "../store/auth-context"; const Login = () => { @@ -14,6 +14,18 @@ const Login = () => { const [coverClass, setCoverClass] = useState("cover cover-register"); + const forgetPasswordHandler = () => { + swal({ + text: "Take a deep breath and try to remember your password.\nDo you still need to reset your password?", + confirmButtonColor: "#f5e44f", + confirmButtonText: "Yes, delete it!", + buttons: ["Nope!", "Yes!"], + }) + .then((value) => { + value ? history.push('/forgot-password') : swal.close() + }) + }; + const [loading, setLoading] = useState(false); const [created, setCreated] = useState(false); const [error, setError] = useState({ @@ -201,9 +213,9 @@ const Login = () => { onChange={passChangeHandler} value={pass} /> - - Forgot password? - + + Forgot password? + {warning.status ? ( {warning.body} From c9d0af64a53e5a9fc838a2f3e57a49048507eac5 Mon Sep 17 00:00:00 2001 From: Tom Chestnut Date: Tue, 12 Oct 2021 21:07:26 -0400 Subject: [PATCH 05/10] Updated ForgotPassword component --- frontend/src/components/ForgotPassword.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/ForgotPassword.js b/frontend/src/components/ForgotPassword.js index 15888c9..702f0c5 100644 --- a/frontend/src/components/ForgotPassword.js +++ b/frontend/src/components/ForgotPassword.js @@ -5,7 +5,7 @@ import React, { useState } from 'react'; import Alert from './Alert'; import URL from '../URL'; import axios from 'axios'; -import { useHistory } from 'react-router-dom'; +import { Link, useHistory } from 'react-router-dom'; const PW_EMAIL_ENDPOINT = '/api/users/forgot_password/'; const NEW_PW_ENDPOINT = '/api/users/new_password/'; @@ -58,6 +58,7 @@ const ForgotPassword = () => { <>

Reset password

+

Forgot your password? Reset it here.

{ onChange={handleFormChange} required /> +

+ + Remember your password? + +

From a73a52042564f96992e175b1606a200bff50db47 Mon Sep 17 00:00:00 2001 From: Tom Chestnut Date: Sat, 16 Oct 2021 00:32:33 -0400 Subject: [PATCH 06/10] Updated ForgotPassword to render different content based on is email has been verified or not --- frontend/src/components/ForgotPassword.js | 151 +++++++++++++++++----- 1 file changed, 117 insertions(+), 34 deletions(-) diff --git a/frontend/src/components/ForgotPassword.js b/frontend/src/components/ForgotPassword.js index 702f0c5..89fb93f 100644 --- a/frontend/src/components/ForgotPassword.js +++ b/frontend/src/components/ForgotPassword.js @@ -9,36 +9,69 @@ import { Link, useHistory } from 'react-router-dom'; const PW_EMAIL_ENDPOINT = '/api/users/forgot_password/'; const NEW_PW_ENDPOINT = '/api/users/new_password/'; +const UNVERIFIED_MSG = 'There was an issue verifying your email.' const ForgotPassword = () => { const history = useHistory(); + // use isEmailVerified to render the appropriate content + // null return emailForm, true return passwordForm, false return an error message on the page + const [isEmailVerified, setIsEmailVerified] = useState(null) const [loading, setLoading] = useState(false); const [errorMsg, setErrorMsg] = useState(false); - const [formState, setFormState] = useState({ + const [successMsg, setSuccessMsg] = useState(false); + const [emailState, setEmailState] = useState({ email: '' }) + const [passwordState, setPasswordState] = useState({ password1: '', password2: '', }); - const { password1, password2 } = formState; + const { password1, password2 } = passwordState; - const handleFormChange = e => { + const handleEmailChange = e => { + const { value } = e.target; + setEmailState({ email: value}) + } + + const handlePasswordChange = e => { const { name, value } = e.target; - setFormState({ - ...formState, + setPasswordState({ + ...passwordState, [name]: value, }); }; + const submitEmail = email => axios.post(URL + PW_EMAIL_ENDPOINT, email) + + const handleEmailSubmit = async e => { + e.preventDefault() + try { + if (!emailState.email) { + setErrorMsg('Enter a valid email address.'); + return; + } + const response = await submitEmail(emailState.email) + if (response.status !== 200) { + setIsEmailVerified('unverified') + setErrorMsg(response.statusText) + } + setSuccessMsg('Please check your email to reset for a link to reset your password.') + } catch (err) { + setIsEmailVerified('unverified') + setErrorMsg(err.message) + console.error(err) + } + setEmailState({email: ''}) + } + const sendNewPassword = newPassword => axios.post(URL + NEW_PW_ENDPOINT, newPassword); - const handleSubmit = async e => { + const handleNewPasswordSubmit = async e => { e.preventDefault(); setLoading(true); try { if (password1 === password2) { const response = await sendNewPassword(password2); - console.log('response:', response); if (response.statusText === 'OK') { history.push('/'); } @@ -51,44 +84,94 @@ const ForgotPassword = () => { console.error(err); } setLoading(false); - setFormState({ password1: '', password2: '' }); + setPasswordState({ password1: '', password2: '' }); }; + const emailForm = ( + <> +

Enter email

+

Enter your email to reset your password.

+ + + + + + ) + + const passwordForm = ( + <> +

Reset password

+

Forgot your password? Reset it here.

+
+ + + + +

+ + Remember your password? + +

+ +
+ + ) + + const errorMessage = ( + <> +

{UNVERIFIED_MSG}

+

+ window.location.reload()}> + Try again? + +

+ + ) + + + const renderContent = (isEmailVerified) => { + switch (isEmailVerified) { + case true: + return passwordForm; + case 'unverified': + return errorMessage; + default: + return emailForm; + } + } + return ( <>
-

Reset password

-

Forgot your password? Reset it here.

-
- - - - -

- - Remember your password? - -

- -
+ {renderContent(isEmailVerified)} {errorMsg && (

{errorMsg}

Tap to dismiss.
)} + {successMsg && ( + +

{successMsg}

+ Tap to dismiss. +
+ )}
); From b5f72a909d61665bfda538aacd8d0f329cfbaa6f Mon Sep 17 00:00:00 2001 From: Tom Chestnut Date: Sat, 16 Oct 2021 00:40:15 -0400 Subject: [PATCH 07/10] Added error-message class to css --- frontend/src/assets/css/ForgotPassword.css | 2 +- frontend/src/components/ForgotPassword.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/assets/css/ForgotPassword.css b/frontend/src/assets/css/ForgotPassword.css index 5e69c12..21d6158 100644 --- a/frontend/src/assets/css/ForgotPassword.css +++ b/frontend/src/assets/css/ForgotPassword.css @@ -4,7 +4,7 @@ justify-content: space-between; } -.password-container h1 { +.password-container h1, .error-message { font-size: 2.5rem; margin: 0; color: var(--textcolor); diff --git a/frontend/src/components/ForgotPassword.js b/frontend/src/components/ForgotPassword.js index 89fb93f..b0358e0 100644 --- a/frontend/src/components/ForgotPassword.js +++ b/frontend/src/components/ForgotPassword.js @@ -144,7 +144,6 @@ const ForgotPassword = () => { ) - const renderContent = (isEmailVerified) => { switch (isEmailVerified) { case true: From 2dea04ecaa0e13d9ed7785184ac79b16cb0e9bbf Mon Sep 17 00:00:00 2001 From: rdotjain Date: Sun, 17 Oct 2021 00:15:17 +0530 Subject: [PATCH 08/10] pass is_verified field in password reset response --- backend/users/views.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/backend/users/views.py b/backend/users/views.py index 1b1ca1c..fae206a 100644 --- a/backend/users/views.py +++ b/backend/users/views.py @@ -114,11 +114,19 @@ def post(self, request): if email is None: return Response({"detail": "email not provided"}, status=400) if get_user_model().objects.filter(email=email).exists(): + + # Check if the email is verified + user = get_user_model().objects.get(email=email) + if not user.is_active: + return Response( + {"detail": "email not verified", "is_verified": "false"}, status=400 + ) + from_mail = settings.EMAIL_HOST_USER to_mail = email send_reset_email(to_mail=to_mail, from_mail=from_mail) - return Response({"detail": "Email sent"}) + return Response({"detail": "Email sent", "is_verified": "true"}) else: return Response({"error": "Email not found"}, status=400) From 59fa7ae9364c5c5cb29f6b617db02735a73ae07b Mon Sep 17 00:00:00 2001 From: Tom Chestnut Date: Sun, 17 Oct 2021 01:28:40 -0400 Subject: [PATCH 09/10] Updated submitEmail function and added a CSS class --- frontend/src/assets/css/ForgotPassword.css | 6 +++- frontend/src/components/ForgotPassword.js | 32 ++++++++++++++-------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/frontend/src/assets/css/ForgotPassword.css b/frontend/src/assets/css/ForgotPassword.css index 21d6158..026edee 100644 --- a/frontend/src/assets/css/ForgotPassword.css +++ b/frontend/src/assets/css/ForgotPassword.css @@ -14,12 +14,16 @@ font-size: 1.3rem; } -.password-container a { +.password-container a, .try-again { color: rgb(243, 233, 140); cursor: pointer; font-weight: 600; } +.try-again:hover { + text-decoration: underline; +} + label, input { display: block; diff --git a/frontend/src/components/ForgotPassword.js b/frontend/src/components/ForgotPassword.js index b0358e0..82c8dec 100644 --- a/frontend/src/components/ForgotPassword.js +++ b/frontend/src/components/ForgotPassword.js @@ -7,7 +7,7 @@ import URL from '../URL'; import axios from 'axios'; import { Link, useHistory } from 'react-router-dom'; -const PW_EMAIL_ENDPOINT = '/api/users/forgot_password/'; +const FORGOT_PW_ENDPOINT = '/api/users/forgot_password/'; const NEW_PW_ENDPOINT = '/api/users/new_password/'; const UNVERIFIED_MSG = 'There was an issue verifying your email.' @@ -40,8 +40,12 @@ const ForgotPassword = () => { }); }; - const submitEmail = email => axios.post(URL + PW_EMAIL_ENDPOINT, email) - + const submitEmail = email => fetch(`${URL}${FORGOT_PW_ENDPOINT}`, { + method: 'POST', + 'Content-Type': 'application/json', + body: JSON.stringify(email), + }) + const handleEmailSubmit = async e => { e.preventDefault() try { @@ -50,6 +54,7 @@ const ForgotPassword = () => { return; } const response = await submitEmail(emailState.email) + console.log('response:', response) if (response.status !== 200) { setIsEmailVerified('unverified') setErrorMsg(response.statusText) @@ -87,6 +92,12 @@ const ForgotPassword = () => { setPasswordState({ password1: '', password2: '' }); }; + const submitBtn = ( + + ) + const emailForm = ( <>

Enter email

@@ -98,6 +109,7 @@ const ForgotPassword = () => { value={emailState.email} onChange={handleEmailChange} /> + {submitBtn} ) @@ -126,9 +138,7 @@ const ForgotPassword = () => { Remember your password?

- + {submitBtn} ) @@ -136,10 +146,8 @@ const ForgotPassword = () => { const errorMessage = ( <>

{UNVERIFIED_MSG}

-

- window.location.reload()}> - Try again? - +

+ window.location.reload()}>Try again?

) @@ -160,13 +168,13 @@ const ForgotPassword = () => {
{renderContent(isEmailVerified)} {errorMsg && ( - +

{errorMsg}

Tap to dismiss.
)} {successMsg && ( - +

{successMsg}

Tap to dismiss.
From 838d8ff26b9106c52b5aa40171df59036eab5339 Mon Sep 17 00:00:00 2001 From: Tom Chestnut Date: Sun, 17 Oct 2021 11:55:33 -0400 Subject: [PATCH 10/10] Fixed submitEmail request headers and body --- frontend/src/components/ForgotPassword.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/ForgotPassword.js b/frontend/src/components/ForgotPassword.js index 82c8dec..bbd3de4 100644 --- a/frontend/src/components/ForgotPassword.js +++ b/frontend/src/components/ForgotPassword.js @@ -42,8 +42,8 @@ const ForgotPassword = () => { const submitEmail = email => fetch(`${URL}${FORGOT_PW_ENDPOINT}`, { method: 'POST', - 'Content-Type': 'application/json', - body: JSON.stringify(email), + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ email: email }), }) const handleEmailSubmit = async e => {