Skip to content

Commit

Permalink
Issue-494 | signup with email verification
Browse files Browse the repository at this point in the history
  • Loading branch information
snyaggarwal committed Jan 25, 2021
1 parent 913065b commit 19649f0
Show file tree
Hide file tree
Showing 6 changed files with 341 additions and 38 deletions.
4 changes: 4 additions & 0 deletions src/components/app/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import CollectionHome from '../collections/CollectionHome';
import OrgHome from '../orgs/OrgHome';
import UserHome from '../users/UserHome';
import Login from '../users/Login';
import SignupForm from '../users/SignupForm';
import EmailVerification from '../users/EmailVerification';
import UserOptions from '../users/UserOptions';
import { Link } from 'react-router-dom';
import { isAtGlobalSearch, isLoggedIn, getCurrentUser } from '../../common/utils';
Expand Down Expand Up @@ -202,6 +204,8 @@ class App extends Component {
{/* User Home */}
<Route path="/users/:user([a-zA-Z0-9\-\.\_]+)" component={UserHome} />
<Route exact path="/accounts/login" component={Login} />
<Route exact path="/accounts/signup" component={SignupForm} />
<Route exact path="/accounts/:user([a-zA-Z0-9\-\.\_]+)/verify/:token([a-zA-Z0-9\-\.\_]+)" component={EmailVerification} />
</Switch>
</div>

Expand Down
139 changes: 139 additions & 0 deletions src/components/users/EmailVerification.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import React from 'react';
import { Link } from 'react-router-dom';
import alertifyjs from 'alertifyjs';
import { Paper, Button, CircularProgress } from '@material-ui/core';
import MuiAlert from '@material-ui/lab/Alert';
import { get } from 'lodash';
import APIService from '../../services/APIService';
import { refreshCurrentUserCache } from '../../common/utils';

class EmailVerification extends React.Component {
constructor(props) {
super(props);
this.state = {
user: null,
isLoading: true,
username: props.match.params.user,
token: props.match.params.token,
failureMsg: null,
notFound: false,
}
}

componentDidMount() {
this.fetchUser()
}


fetchUser() {
const { username } = this.state
APIService.users(username).get().then(response => {
if(get(response, 'detail') === 'Not found.')
this.setState({notFound: true, isLoading: false})
else
this.setState({user: response.data, isLoading: false})
})
}

onSubmit() {
const { username, token } = this.state
APIService.users(username).verify(token).get().then(response => {
if(get(response, 'status') === 200 && get(response, 'data.token')) {
alertifyjs.success('Successfully Verified Email.')
this.afterLoginSuccess(response.data.token)
} else if(get(response, 'detail'))
this.setState({failureMsg: response.detail})
else
alertifyjs.error('Something bad happend')
})
}

afterLoginSuccess(token) {
localStorage.setItem('token', token)
this.cacheUserData()
}

cacheUserData() {
refreshCurrentUserCache(response => {
alertifyjs.success(`Successfully signed in as ${this.state.username}.`)
window.location.hash = '#' + response.data.url
})
}

getNotFoundDOM() {
return (
<MuiAlert elevation={6} variant="filled" severity="error">
Unable to verify the user. Either verification link expired or wrong. Please contact OCL Team.
</MuiAlert>
)
}

getAlreadyVerifiedDOM() {
return (
<MuiAlert elevation={6} variant="filled" severity="default">
This user is already verified. Please proceed to <Link to='/accounts/login'>SignIn</Link>.
</MuiAlert>
)
}

getFailureMsgDOM() {
return (
<MuiAlert elevation={6} variant="filled" severity="error">
{
this.state.failureMsg
}
</MuiAlert>
)
}

getConfirmEmailAddressDOM() {
const { user } = this.state;
return (
<React.Fragment>
<h1 style={{textAlign: 'center'}}>Confirm Email Address</h1>
<p>
{
`Please confirm that ${user.email} is an email address for user ${user.username}.`
}
</p>
<Button onClick={() => this.onSubmit()} variant='outlined' color='primary'>
Confirm
</Button>
</React.Fragment>
)
}

getDOM() {
const { user, notFound, failureMsg } = this.state;
if(notFound)
return this.getNotFoundDOM()
if(user.verified)
return this.getAlreadyVerifiedDOM()

if(failureMsg)
return this.getFailureMsgDOM()

return this.getConfirmEmailAddressDOM();
}

render() {
const { isLoading } = this.state;
return (
<div className='col-md-12' style={{marginTop: '25px'}}>
<div className='col-md-3' />
<div className='col-md-6'>
<Paper style={{padding: '25px'}} className='login-paper'>
{
isLoading ?
<CircularProgress /> :
this.getDOM()
}
</Paper>
</div>
<div className='col-md-3' />
</div>
);
}
}

export default EmailVerification;
90 changes: 53 additions & 37 deletions src/components/users/Login.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import React from 'react';
import { Link } from 'react-router-dom';
import alertifyjs from 'alertifyjs';
import { Paper, TextField, Button } from '@material-ui/core';
import { values, map, get } from 'lodash';
import APIService from '../../services/APIService';
import { refreshCurrentUserCache } from '../../common/utils';
import VerifyEmailMessage from './VerifyEmailMessage';

class Login extends React.Component {
constructor(props) {
super(props)
this.state = {
email: null,
verificationMsg: null,
username: '',
password: '',
serverError: null,
Expand All @@ -32,6 +36,8 @@ class Login extends React.Component {
APIService.users().login().post({username: username, password: password}).then(response => {
if(get(response, 'status') === 200 && get(response, 'data.token')) {
this.afterLoginSuccess(response.data.token)
} else if(get(response, 'detail', '').match('verification email')) {
this.setState({verificationMsg: response.detail, email: get(response, 'email')})
} else if(get(response, 'non_field_errors')) {
this.setState({serverError: values(response)})
} else {
Expand All @@ -54,50 +60,60 @@ class Login extends React.Component {
}

render() {
const { serverError } = this.state;
const { serverError, verificationMsg, email } = this.state;
return (
<div className='col-md-12' style={{marginTop: '25px'}}>
<div className='col-md-4' />
<div className='col-md-4'>
<div className='col-md-3' />
<div className='col-md-6'>
<Paper style={{padding: '10px'}} className='login-paper'>
<h1 style={{textAlign: 'center'}}>Sign In</h1>
{
serverError &&
<div className='col-md-12 alert-danger'>
<ul> {map(serverError, error => (<li key={error}>{error}</li>))} </ul>
</div>
}
<div className='col-md-12 no-side-padding'>
<form>
<div>
<TextField
required
id="username"
label="Username"
variant="outlined"
onChange={this.onFieldChange}
fullWidth
/>
</div>
<div style={{marginTop: '10px'}}>
<TextField
required
id="password"
label="Password"
variant="outlined"
type="password"
onChange={this.onFieldChange}
fullWidth
/>
</div>
<div style={{marginTop: '20px', textAlign: 'center', marginBottom: '20px'}}>
<Button onClick={this.handleSubmit} type='submit' color='primary' variant='contained'>Sign In</Button>

verificationMsg ?
<VerifyEmailMessage message={verificationMsg} email={email} />:
<React.Fragment>
<h1 style={{textAlign: 'center'}}>Sign In</h1>
{
serverError &&
<div className='col-md-12 alert-danger'>
<ul> {map(serverError, error => (<li key={error}>{error}</li>))} </ul>
</div>
}
<div className='col-md-12 no-side-padding'>
<form>
<div>
<TextField
required
id="username"
label="Username"
variant="outlined"
onChange={this.onFieldChange}
fullWidth
/>
</div>
<div style={{marginTop: '10px'}}>
<TextField
required
id="password"
label="Password"
variant="outlined"
type="password"
onChange={this.onFieldChange}
fullWidth
/>
</div>
<div style={{marginTop: '20px', textAlign: 'center', marginBottom: '20px'}}>
<Button onClick={this.handleSubmit} type='submit' color='primary' variant='contained'>Sign In</Button>
<div style={{marginTop: '15px'}}>
New User? <Link to="/accounts/signup">Sign Up</Link>
</div>
</div>
</form>
</div>
</form>
</div>
</React.Fragment>
}
</Paper>
</div>
<div className='col-md-4' />
<div className='col-md-3' />
</div>
)
}
Expand Down

0 comments on commit 19649f0

Please sign in to comment.