-
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
24 changed files
with
568 additions
and
20,905 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 was deleted.
Oops, something went wrong.
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
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,115 @@ | ||
import React from "react"; | ||
import { Form, Button } 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 { Redirect } from "react-router-dom"; | ||
|
||
export class LoginForm extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
email: "", | ||
password: "", | ||
formErrors: {} | ||
}; | ||
} | ||
handleChange = event => { | ||
this.setState({ [event.target.name]: event.target.value }); | ||
}; | ||
|
||
handleSubmit = event => { | ||
event.preventDefault(); | ||
const formErrors = validateLoginForm(this.state.email, this.state.password); | ||
if (formErrors.length > 0) { | ||
this.setState({ | ||
formErrors: formErrors | ||
}); | ||
return null; | ||
} else { | ||
this.setState({ | ||
formErrors: [] | ||
}); | ||
} | ||
const { email, password } = this.state; | ||
const data = { email: email, password: password}; | ||
this.props.loginAction(data); | ||
}; | ||
|
||
render() { | ||
const { login_user } = this.props; | ||
const { errors } = login_user; | ||
const { formErrors } = this.state; | ||
|
||
return ( | ||
<div> | ||
{login_user.logged_in ? ( | ||
<Redirect to="/" /> | ||
) : ( | ||
<Form className="container" onSubmit={this.handleSubmit}> | ||
<h4 className="text-center">Sign In</h4> | ||
<Form.Group name="email"> | ||
<p className="text-danger general-warning"> | ||
{errors ? errors : null} | ||
</p> | ||
<Form.Label htmlFor="email">Email address</Form.Label> | ||
<div className="text-danger email-warning"> | ||
{formErrors[0] === "email" ? formErrors[1] : null} | ||
</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" ? formErrors[1] : null} | ||
</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"> | ||
Sign In | ||
</Button> | ||
</Form> | ||
)} | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
LoginForm.propTypes = { | ||
email: PropTypes.string, | ||
password: PropTypes.any, | ||
login_user: PropTypes.object.isRequired, | ||
loginAction: PropTypes.func.isRequired | ||
}; | ||
|
||
export const mapStateToProps = state => { | ||
return { | ||
login_user: state.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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,3 +31,6 @@ body { | |
text-align: right; | ||
padding: 10px; | ||
} | ||
.red-form-border { | ||
border: 1px solid red; | ||
} |
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,2 @@ | ||
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,2 @@ | ||
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,25 @@ | ||
import axiosConfig from '../../../axiosConfig'; | ||
import { LOGIN_SUCCESS, LOGIN_FAIL } from '../actionTypes'; | ||
|
||
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({ | ||
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,29 @@ | ||
import { LOGIN_SUCCESS, LOGIN_FAIL } from '../actionTypes'; | ||
|
||
const { REACT_APP_BASE_URL } = process.env; | ||
|
||
const loginAction = loginData => dispatch => fetch('http://localhost:8000/api/user/login/', { | ||
mode: 'cors', | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
body: JSON.stringify(loginData), | ||
}) | ||
.then(res => res.json()) | ||
.then((data) => { | ||
if (data.errors) { | ||
dispatch({ | ||
type: LOGIN_FAIL, | ||
payload: data.errors, | ||
}); | ||
} else { | ||
dispatch({ | ||
type: LOGIN_SUCCESS, | ||
payload: data.user, | ||
}); | ||
} | ||
}) | ||
.catch(error => 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; |
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,12 +1,6 @@ | ||
const initialState = { | ||
articles: [], | ||
notifications: [], | ||
followers: [], | ||
} | ||
import { combineReducers } from 'redux'; | ||
import loginReducer from './LoginReducer'; | ||
|
||
function rootReducer(state = initialState, action){ | ||
|
||
return state; | ||
}; | ||
|
||
export default rootReducer; | ||
export default combineReducers({ | ||
login_user: loginReducer, | ||
}); |
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,10 @@ | ||
import React from "react"; | ||
import { shallow } from "enzyme"; | ||
import Login from "../../components/Login"; | ||
|
||
describe("Login", () => { | ||
it("Should render correctly", () => { | ||
const wrapper = shallow(<Login />); | ||
expect(wrapper).toMatchSnapshot; | ||
}); | ||
}); |
Oops, something went wrong.