Skip to content

Commit 9112cc3

Browse files
pdotsaniLinda Pengdependabot-preview[bot]lpatmo
authored
WIP Update user registration flow (#168)
* Added pagination component with useQuery call connected * tested on mock data, working without useeffect * Pagination cleanup - ermoved Resources/Resources.js file, only show pagination component when there is no search term, and moved it down on the page * register and login api updated * login and registration apis working now, error handling tmp patch * [Security] Bump axios from 0.19.0 to 0.21.1 Bumps [axios](https://github.com/axios/axios) from 0.19.0 to 0.21.1. **This update includes a security fix.** - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v0.21.1/CHANGELOG.md) - [Commits](axios/axios@v0.19.0...v0.21.1) Signed-off-by: dependabot-preview[bot] <[email protected]> * Add constants file and differentiate between dev and prod for the API host URL * fixed tests * verify email post request working * error validation on verify email screen * Update src/components/Auth/SignUpForm.js Co-authored-by: Linda <[email protected]> * Add key to dependencies array for useEffect * Added explanatory text re: verifying email Co-authored-by: Linda Peng <[email protected]> Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Linda <[email protected]>
1 parent 2d41259 commit 9112cc3

File tree

8 files changed

+146
-117
lines changed

8 files changed

+146
-117
lines changed

src/App.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import Profile from './pages/Profile';
1515
import ResourceSubmit from './pages/Resources/ResourceSubmit';
1616
import ResourcePage from './pages/Resources/ResourcePage.js';
1717
import PrivateRoute from './PrivateRoute';
18+
import VerifyEmail from './components/Auth/VerifyEmail';
1819

1920
function App() {
2021
const [authTokens, setAuthTokens] = useState(
@@ -48,6 +49,9 @@ function App() {
4849
<Route path="/connect">
4950
<Connect />
5051
</Route>
52+
<Route path="/api/v1/auth/registration/verify-email">
53+
<VerifyEmail />
54+
</Route>
5155
<PrivateRoute path="/profile" component={Profile} />
5256
<Route
5357
path="/resources/:guid"

src/components/Auth/AuthForm.spec.js

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,24 +55,28 @@ describe('Signup', () => {
5555
username: 'Carolyne.Carter',
5656
token:
5757
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6IkNhcm9seW5lLkNhcnRlciIsImlhdCI6MTU4NDMzODQ4NiwiZXhwIjoxNTg0MzQyMDg2LCJ1c2VyX2lkIjo4MCwib3JpZ19pYXQiOjE1ODQzMzg0ODZ9.saO6OCOKV1uwHjTbM-iDGmhbkMNCnzrGFj4TBYnTv2E',
58-
first_name: 'Carolyne',
59-
last_name: 'Carter',
58+
// first_name: 'Carolyne',
59+
// last_name: 'Carter',
6060
61+
password1: 'password',
62+
password2: 'password',
6163
},
6264
});
6365

64-
userEvent.type(screen.getByLabelText(/username/i), 'Carolyne.Carter');
66+
userEvent.type(screen.getByLabelText('Username*'), 'Carolyne.Carter');
6567

66-
userEvent.type(screen.getByLabelText(/password/i), 'password');
68+
userEvent.type(screen.getByLabelText('Password*'), 'password');
69+
70+
userEvent.type(screen.getByLabelText('Confirm Password*'), 'password');
6771

6872
userEvent.type(
69-
screen.getByLabelText(/email/i),
73+
screen.getByLabelText('Email*'),
7074
7175
);
7276

73-
userEvent.type(screen.getByLabelText(/first name/i), 'Carolyne');
77+
// userEvent.type(screen.getByLabelText(/first name/i), 'Carolyne');
7478

75-
userEvent.type(screen.getByLabelText(/last name/i), 'Carter');
79+
// userEvent.type(screen.getByLabelText(/last name/i), 'Carter');
7680

7781
userEvent.click(screen.getByText('Sign Up'));
7882

@@ -129,15 +133,15 @@ describe('Login', () => {
129133
data: {
130134
token:
131135
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6IkNhcm9seW5lLkNhcnRlciIsImlhdCI6MTU4NDM0MDAyMiwiZXhwIjoxNTg0MzQzNjIyLCJ1c2VyX2lkIjo4MCwib3JpZ19pYXQiOjE1ODQzNDAwMjJ9.0zNlXPVAjkBjxUQjq4B0HXnvrez93H2pz6n2ROKWzzg',
132-
username: 'Carolyne.Carter',
136+
email: 'Carolyne.Carter@mail.com',
133137
},
134138
});
135139

136140
await act(async () =>
137-
userEvent.type(getByLabelText(/username/i), 'Carolyne.Carter')
141+
userEvent.type(getByLabelText(/email/i), 'Carolyne.Carter@mail.com')
138142
);
139143
await act(async () =>
140-
userEvent.type(getByLabelText(/username/i), 'Carolyne.Carter')
144+
userEvent.type(getByLabelText(/email/i), 'Carolyne.Carter@mail.com')
141145
);
142146

143147
await act(async () =>

src/components/Auth/LoginForm.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { useAuth } from './AuthContext';
66
import axios from 'axios';
77

88
const LoginForm = ({ toggleActiveForm }) => {
9-
const [username, setUsername] = useState(null);
9+
const [email, setEmail] = useState(null);
1010
const [password, setPassword] = useState(null);
1111
const [isLoggedIn, setIsLoggedIn] = useState(false);
1212
const [errorMessage, setErrorMessage] = useState(null);
@@ -16,18 +16,27 @@ const LoginForm = ({ toggleActiveForm }) => {
1616
const handleLogin = e => {
1717
e.preventDefault();
1818
const data = {
19-
username,
19+
email: email,
2020
password,
2121
};
2222
axios
23-
.post('/auth/obtain_token/', data)
23+
.post('http://localhost:8000/api/v1/auth/login/', data)
2424
.then(res => {
2525
auth.setAuthTokens(res.data);
2626
setIsLoggedIn(true);
2727
})
2828
.catch(error => {
2929
if (error.response) {
30-
setErrorMessage(error.response.data.non_field_errors[0]);
30+
// todo: display field error in input field
31+
if (error.response.data.email) {
32+
setErrorMessage(error.response.data.email[0]);
33+
} else if (error.response.data.password) {
34+
setErrorMessage(error.response.data.password[0]);
35+
} else if (error.response.data.non_field_errors) {
36+
setErrorMessage(error.response.data.non_field_errors[0]);
37+
} else {
38+
setErrorMessage('There was an error!');
39+
}
3140
} else {
3241
setErrorMessage('There was an error!');
3342
}
@@ -55,14 +64,14 @@ const LoginForm = ({ toggleActiveForm }) => {
5564
Log in
5665
</Box>
5766
<TextField
58-
id="username"
59-
label="username"
67+
id="email"
68+
label="Email"
6069
fullWidth
6170
required
6271
variant="outlined"
6372
margin="dense"
6473
type="text"
65-
onChange={e => setUsername(e.target.value)}
74+
onChange={e => setEmail(e.target.value)}
6675
/>
6776
<TextField
6877
id="password"

src/components/Auth/SignUpForm.js

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,26 @@ import axios from 'axios';
66
import { useAuth } from './AuthContext';
77
import { validationResolver, defaultValues } from './SignUpForm.schema';
88
import { Form, Field } from '../form';
9+
import { config } from '../../helpers/constants';
910

1011
const SignUpForm = ({ toggleActiveForm }) => {
1112
const [errorMessage, setErrorMessage] = useState(null);
1213
const [isLoggedIn, setIsLoggedIn] = useState(false);
13-
const referer = '/profile';
14+
const referer = '/api/v1/auth/registration/verify-email/';
1415
const auth = useAuth();
1516

16-
const onSubmit = ({ username, password, firstName, lastName, email }) => {
17+
const onSubmit = ({ username, password1, password2, email }) => {
1718
const data = {
1819
username,
19-
password,
2020
email,
21-
first_name: firstName,
22-
last_name: lastName,
21+
password1,
22+
password2,
2323
};
2424
axios
25-
.post('/auth/users/', data)
25+
.post(`${config.API_URL}/api/v1/auth/registration/`, data)
2626
.then(res => {
2727
auth.setAuthTokens(res.data);
2828
setIsLoggedIn(true);
29-
setErrorMessage('');
3029
})
3130
.catch(err => {
3231
console.error(err);
@@ -58,24 +57,6 @@ const SignUpForm = ({ toggleActiveForm }) => {
5857
Create an account
5958
</Box>
6059

61-
<Field
62-
as={TextField}
63-
fullWidth
64-
variant="outlined"
65-
margin="dense"
66-
name="firstName"
67-
label="First Name*"
68-
id="first-name"
69-
/>
70-
<Field
71-
as={TextField}
72-
fullWidth
73-
variant="outlined"
74-
margin="dense"
75-
name="lastName"
76-
label="Last Name"
77-
id="last-name"
78-
/>
7960
<Field
8061
as={TextField}
8162
fullWidth
@@ -99,10 +80,20 @@ const SignUpForm = ({ toggleActiveForm }) => {
9980
fullWidth
10081
variant="outlined"
10182
margin="dense"
102-
name="password"
83+
name="password1"
10384
label="Password*"
10485
type="password"
105-
id="password"
86+
id="password1"
87+
/>
88+
<Field
89+
as={TextField}
90+
fullWidth
91+
variant="outlined"
92+
margin="dense"
93+
name="password2"
94+
label="Confirm Password*"
95+
type="password"
96+
id="password2"
10697
/>
10798

10899
{errorMessage && <Box color="error.main"> {errorMessage}</Box>}

src/components/Auth/SignUpForm.schema.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,6 @@ import Joi from '@hapi/joi';
22
import { createValidationResolver } from '../form';
33

44
const schema = Joi.object({
5-
firstName: Joi.string()
6-
.required()
7-
.trim()
8-
.label('First Name'),
9-
lastName: Joi.string()
10-
.allow('')
11-
.trim()
12-
.label('Last Name'),
135
username: Joi.string()
146
.alphanum()
157
.min(3)
@@ -22,17 +14,23 @@ const schema = Joi.object({
2214
.required()
2315
.trim()
2416
.label('Email'),
25-
password: Joi.string()
17+
password1: Joi.string()
2618
.required()
2719
.label('Password'),
20+
password2: Joi.any()
21+
.valid(Joi.ref('password1'))
22+
.required()
23+
.label('Confirm Password')
24+
.options({ messages: { 'any.only': 'Passwords do not match' } }),
2825
});
2926

3027
const defaultValues = {
31-
firstName: '',
32-
lastName: '',
28+
// firstName: '',
29+
// lastName: '',
3330
username: '',
3431
email: '',
35-
password: '',
32+
password1: '',
33+
password2: '',
3634
};
3735

3836
const validationResolver = createValidationResolver(schema);

src/components/Auth/VerifyEmail.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React, { useEffect, useState } from 'react';
2+
import axios from 'axios';
3+
import { Link } from 'react-router-dom';
4+
import { config } from '../../helpers/constants';
5+
6+
const VerifyEmail = () => {
7+
const [verifyStatus, setVerifyStatus] = useState('');
8+
const [error, setError] = useState('');
9+
const urlParams = new URLSearchParams(window.location.search);
10+
const key = urlParams.get('key');
11+
12+
useEffect(() => {
13+
if (key) {
14+
axios
15+
.post(`${config.API_URL}/api/v1/auth/registration/verify-email/`, {
16+
key,
17+
})
18+
.then(resp => {
19+
if (resp.status === 200) {
20+
setVerifyStatus('Your email has been verified!');
21+
}
22+
})
23+
.catch(e => {
24+
console.error(e);
25+
setError(e.message);
26+
});
27+
} else {
28+
setError('There is no key in the URL.');
29+
}
30+
}, [key]);
31+
32+
return (
33+
<div>
34+
<div>
35+
{verifyStatus ? (
36+
<span>{`${verifyStatus}`}</span>
37+
) : (
38+
<p>
39+
Thank you for signing up! Please check your email to verify your
40+
account.
41+
</p>
42+
)}
43+
{error && <span style={{ color: 'red' }}>{`${error}`}</span>}
44+
<br />
45+
<Link to="/">Home</Link>
46+
</div>
47+
</div>
48+
);
49+
};
50+
51+
export default VerifyEmail;

0 commit comments

Comments
 (0)