-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- create login form - users can log in - errors are displayed above the specific input fields and input fields have a red border if they are not validated - set up validation of input fields - configure axios - test loginReducer - test login validator function - tokens are stored in localStorage on successful login - add function for validating authentication tokens - add function for checking whether a user is logged in with valid jwt token - users are redirected on successful login to the homepage - logged in users cannot see the login form - test login form [starts #164046210]
- Loading branch information
Showing
23 changed files
with
696 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ | |
|
||
# misc | ||
.DS_Store | ||
.env | ||
.env.local | ||
.env.development.local | ||
.env.test.local | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import axios from 'axios'; | ||
|
||
const { REACT_APP_BASE_URL } = process.env; | ||
|
||
const axiosConfig = axios.create({ | ||
baseURL: REACT_APP_BASE_URL, | ||
headers: { | ||
'content-type': 'application/json', | ||
}, | ||
}); | ||
export default axiosConfig; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
import React from 'react'; | ||
import LoginForm from '../containers/LoginForm'; | ||
|
||
const Login = () => <div className="main-container">Login</div>; | ||
const Login = () => <div className="main-container"><LoginForm /></div>; | ||
export default Login; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
import React from "react"; | ||
import { Form, Button, Alert } from "react-bootstrap"; | ||
import PropTypes from "prop-types"; | ||
import loginAction from "../store/actions/authActions/LoginAction"; | ||
import { connect } from "react-redux"; | ||
import validateLoginForm from "../utils/validation"; | ||
import store from "../store/store"; | ||
import { REGISTER } from '../store/actions/actionTypes'; | ||
|
||
export class LoginForm extends React.Component { | ||
static propTypes = { | ||
email: PropTypes.string, | ||
password: PropTypes.any, | ||
login_user: PropTypes.object.isRequired, | ||
loginAction: PropTypes.func.isRequired | ||
}; | ||
|
||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
email: "", | ||
password: "", | ||
formErrors: {}, | ||
touched: false, | ||
show: true | ||
}; | ||
this.onAlertClose = this.onAlertClose.bind(this); | ||
} | ||
|
||
handleChange = event => { | ||
this.setState({ [event.target.name]: event.target.value, touched: true }); | ||
}; | ||
|
||
|
||
onAlertClose() { | ||
this.setState({ | ||
show: false | ||
}); | ||
} | ||
|
||
handleSubmit = event => { | ||
const { email, password } = this.state; | ||
event.preventDefault(); | ||
const formErrors = validateLoginForm(email, password); | ||
if (formErrors.length === 0) { | ||
this.setState({ | ||
formErrors: [] | ||
}); | ||
const data = { email, password }; | ||
this.props.loginAction(data); | ||
} else { | ||
this.setState({ | ||
formErrors: formErrors, | ||
touched: false | ||
}); | ||
} | ||
}; | ||
|
||
swapModal = () => { | ||
store.dispatch({ type: REGISTER }) | ||
} | ||
|
||
render() { | ||
const { login_user } = this.props; | ||
const { errors } = login_user; | ||
const { formErrors, touched } = this.state; | ||
|
||
return ( | ||
<div> | ||
<Form className="main-container" onSubmit={this.handleSubmit}> | ||
<Form.Group name="email"> | ||
{errors && ( | ||
<Alert | ||
dismissible | ||
variant="danger" | ||
show={this.state.show} | ||
onClick={this.onAlertClose} | ||
> | ||
<Alert.Heading> | ||
<small>{errors}</small> | ||
</Alert.Heading> | ||
</Alert> | ||
)} | ||
<Form.Label htmlFor="email">Email address</Form.Label> | ||
<div className="text-danger email-warning"> | ||
{(formErrors[0] === "email" && !touched) && formErrors[1]} | ||
</div> | ||
<p className="text-danger email-warning">{errors.email}</p> | ||
<Form.Control | ||
className={ | ||
formErrors[0] === "email" ? "red-form-border" : "email-input" | ||
} | ||
name="email" | ||
type="email" | ||
placeholder="Enter your email" | ||
onChange={this.handleChange} | ||
/> | ||
</Form.Group> | ||
<Form.Group name="password"> | ||
<Form.Label htmlFor="password">Password</Form.Label> | ||
<div className="text-danger password-warning"> | ||
{(formErrors[0] === "password" && !touched) && formErrors[1]} | ||
</div> | ||
<p className="text-danger password-warning">{errors.password}</p> | ||
<Form.Control | ||
className={ | ||
formErrors[0] === "password" | ||
? "red-form-border" | ||
: "password-input" | ||
} | ||
name="password" | ||
type="password" | ||
placeholder="Password" | ||
onChange={this.handleChange} | ||
/> | ||
</Form.Group> | ||
<Button variant="primary" type="submit" className="btn-one"> | ||
Sign In | ||
</Button> | ||
<p className="swap-modal-text">Don't have an account? <span className="swap-modal-span" onClick={this.swapModal}>Click here</span> to register.</p> | ||
</Form> | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
export const mapStateToProps = state => { | ||
const { login_user } = state; | ||
return { | ||
login_user | ||
}; | ||
}; | ||
|
||
export default connect( | ||
mapStateToProps, | ||
{ loginAction } | ||
)(LoginForm); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
import { configure } from 'enzyme'; | ||
import Adapter from 'enzyme-adapter-react-16'; | ||
|
||
require('jest-localstorage-mock'); | ||
|
||
configure({ adapter: new Adapter() }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
export const SHOW_MODAL = 'SHOW_MODAL'; | ||
export const REGISTER = 'REGISTER'; | ||
export const LOGIN = 'LOGIN'; | ||
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS'; | ||
export const LOGIN_FAIL = 'LOGIN_FAIL'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import axiosConfig from '../../../axiosConfig'; | ||
import { LOGIN_SUCCESS, LOGIN_FAIL } from '../actionTypes'; | ||
import ShowModal from '../changeFormAction'; | ||
|
||
const loginAction = loginData => dispatch => axiosConfig.request( | ||
{ | ||
method: 'post', | ||
url: '/user/login/', | ||
data: { user: loginData }, | ||
}, | ||
) | ||
.then((response) => { | ||
const { token } = response.data.user; | ||
window.localStorage.setItem('token', token); | ||
dispatch(ShowModal({ | ||
modalShow: false, | ||
})); | ||
dispatch({ | ||
type: LOGIN_SUCCESS, | ||
}); | ||
}) | ||
.catch((error) => { | ||
dispatch({ | ||
type: LOGIN_FAIL, | ||
payload: error.response.data.errors.error, | ||
}); | ||
}); | ||
|
||
export default loginAction; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { LOGIN_SUCCESS, LOGIN_FAIL } from '../actions/actionTypes'; | ||
import { isLoggedIn } from '../../utils/tokenValidator'; | ||
|
||
const initialState = { | ||
logged_in: !!isLoggedIn, | ||
errors: '', | ||
}; | ||
|
||
const loginReducer = (state = initialState, action) => { | ||
switch (action.type) { | ||
case LOGIN_SUCCESS: | ||
return { | ||
...state, | ||
logged_in: true, | ||
errors: '', | ||
}; | ||
case LOGIN_FAIL: | ||
return { | ||
...state, | ||
logged_in: false, | ||
errors: action.payload, | ||
}; | ||
default: | ||
return state; | ||
} | ||
}; | ||
|
||
export default loginReducer; |
Oops, something went wrong.