Skip to content

Commit

Permalink
Merge 5e24128 into 8451dcb
Browse files Browse the repository at this point in the history
  • Loading branch information
mattwr18 committed Jan 16, 2019
2 parents 8451dcb + 5e24128 commit cd20689
Show file tree
Hide file tree
Showing 14 changed files with 321 additions and 4 deletions.
19 changes: 19 additions & 0 deletions src/actions/postLogInInfoAction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import axios from 'axios'
import { POST_LOGIN_INFO } from '../types'

export let getUser = user => ({ type: POST_LOGIN_INFO, payload: user })

export let postLogInInfo = props => dispatch => {
return axios({
method: 'post',
url: '/users/sign_in',
data: {
user: {
email: props.email,
password: props.password
}
}
}).then(response => {
dispatch(getUser(response.data))
})
}
17 changes: 17 additions & 0 deletions src/assets/LogIn.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.login-h1 {
margin-top: 70px !important;
}

.login-h4 {
margin-top: 150px !important;
}

.login-form {
margin-top: 20px !important;
}

.login-form .button {
background-color: #34495e !important;
color: white !important;
width: 50%;
}
6 changes: 6 additions & 0 deletions src/assets/iziToast.min.css

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions src/assets/iziToast.min.js

Large diffs are not rendered by default.

101 changes: 101 additions & 0 deletions src/containers/LogIn.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React, { Component, Fragment } from 'react'
import { Button, Form, Header, Grid, Checkbox } from 'semantic-ui-react'
import { connect } from 'react-redux'
import { postLogInInfo } from '../actions/postLogInInfoAction'
import iziToast from '../assets/iziToast.min.js'
import '../assets/iziToast.min.css'
import '../assets/LogIn.scss'

export class LogIn extends Component {
state = {
email: '',
password: ''
};

handleChange = (e, { name, value }) => this.setState({ [name]: value });
handleLogIn = async e => {
const { email, password } = this.state
e.preventDefault()
await this.props
.postLogInInfo({ email, password })
.then(() => {
this.props.history.push('/')
iziToast.show({
theme: 'light',
title: 'Success',
message: 'Welcome back, ' + `${this.props.users[0].name}`,
position: 'topRight',
color: 'green',
backgroundColor: 'lime',
timeout: 3000,
balloon: true
})
})
.catch(e => {
iziToast.show({
theme: 'light',
title: 'Sorry',
message: 'Username and/or Password do no match',
position: 'topRight',
color: 'red',
backgroundColor: 'lightcoral',
timeout: 3000,
balloon: true
})
})
};

render () {
const { password, email } = this.state
return (
<Fragment>
<Header as='h1' textAlign='center' className='login-h1'>
Log In
</Header>
<Header as='h4' textAlign='center' className='login-h4'>
Don't have an account? <a href='/signup'>Sign Up</a>
</Header>
<Header as='h4' textAlign='center'>
<a href='/users/password/new'>Forgot your password?</a>
</Header>
<Grid centered>
<Grid.Row>
<Grid.Column width={8}>
<Form
onSubmit={this.handleLogIn}
className='login-form'
size='large'
>
<Form.Input
label='Email'
placeholder='Email'
name='email'
value={email}
onChange={this.handleChange}
/>
<Form.Input
label='Password'
placeholder='Password'
name='password'
value={password}
onChange={this.handleChange}
type='password'
/>
<Form.Field>
<Checkbox label='Remember me' />
</Form.Field>
<Button type='submit'>Log In</Button>
</Form>
</Grid.Column>
</Grid.Row>
</Grid>
</Fragment>
)
}
}

const mapStateToProps = store => ({ users: store.users })
export default connect(
mapStateToProps,
{ postLogInInfo }
)(LogIn)
32 changes: 32 additions & 0 deletions src/fixtures/logIn.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export default [
{
id: 2,
email: 'premium@premi.um',
created_at: '2019-01-09T23:29:28.825Z',
updated_at: '2019-01-11T14:39:33.221Z',
first_name: 'Retha',
last_name: 'Dietrich',
display_email: null,
youtube_id: null,
slug: 'retha-dietrich',
display_profile: true,
latitude: null,
longitude: null,
country_name: 'Falkland Islands (malvinas)',
city: null,
region: null,
youtube_user_name: null,
github_profile_url: null,
display_hire_me: null,
bio: null,
receive_mailings: false,
country_code: 'FK',
timezone_offset: null,
status_count: 0,
deleted_at: null,
event_participation_count: 0,
can_see_dashboard: false,
skill_list: [],
title_list: []
}
]
1 change: 0 additions & 1 deletion src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>AgileVentures</title>
<meta name="viewport" content="width=device-width, initial-scale=1">

</head>
<body>
<div id="root"></div>
Expand Down
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Provider } from 'react-redux'
import store from './store'
import { Container } from 'semantic-ui-react'
import Homepage from './components/homepage/Homepage'
import LogIn from './containers/LogIn'
import './assets/semantic.css'
import axios from 'axios'
axios.defaults.baseURL = 'https://develop.websiteone.agileventures.org/'
Expand All @@ -16,6 +17,7 @@ render(
<Container className='main-content'>
<Switch>
<Route path='/' exact component={Homepage} />
<Route path='/login' component={LogIn} />
<Route path='/users' component={UsersList} />
</Switch>
</Container>
Expand Down
4 changes: 3 additions & 1 deletion src/reducers/usersReducer.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { GET_USERS } from '../types'
import { GET_USERS, POST_LOGIN_INFO } from '../types'
import initialState from './initialState'

const usersReducer = (state = initialState.users, action) => {
switch (action.type) {
case GET_USERS:
return [ ...action.payload ]
case POST_LOGIN_INFO:
return [ ...action.payload ]
default:
return state
}
Expand Down
39 changes: 39 additions & 0 deletions src/tests/actions/postLogInInfoAction.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import moxios from 'moxios'
import thunk from 'redux-thunk'
import configureMockStore from 'redux-mock-store'
import { postLogInInfo } from '../../actions/postLogInInfoAction'
import { POST_LOGIN_INFO } from '../../types'
import logInResponse from '../../fixtures/logIn'

const middlewares = [thunk]
const mockStore = configureMockStore(middlewares)
let store

describe('postLogInInfo action', () => {
beforeEach(() => {
moxios.install()
store = mockStore({})
})

afterEach(() => {
moxios.uninstall()
})

it('posts login info to an external api', () => {
const expectedActions = [
{ type: POST_LOGIN_INFO, payload: logInResponse }
]
moxios.stubRequest('/users/sign_in', {
status: 200,
response: logInResponse
})

return store
.dispatch(
postLogInInfo({ email: 'premium@premi.um', password: 'premium123' })
)
.then(() => {
expect(store.getActions()).toEqual(expectedActions)
})
})
})
73 changes: 73 additions & 0 deletions src/tests/containers/LogIn.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from 'react'
import { LogIn } from '../../containers/LogIn'
import { mount } from 'enzyme'

describe('LogIn', () => {
const user = {
id: 1,
email: 'existing-user@example.com',
password: 'password'
}
const props = {
history: { push: jest.fn() },
postLogInInfo: jest.fn(
logInInfo =>
new Promise((resolve, reject) => {
if (
user.email === logInInfo.email &&
user.password === logInInfo.password
) {
resolve(user)
} else {
reject(new Error('Username and/or Password do no match'))
}
})
)
}
let wrapper = mount(<LogIn {...props} />)

it('should call handleLogIn and postLogInInfo when the form is submitted', () => {
const spy = jest.spyOn(wrapper.instance(), 'handleLogIn')
wrapper.instance().forceUpdate()
const emailInput = wrapper.find('input').filterWhere(item => {
return item.prop('name') === 'email'
})

const passwordInput = wrapper.find('input').filterWhere(item => {
return item.prop('name') === 'password'
})

emailInput.simulate('change', {
target: { value: 'existing-user@example.com' }
})

passwordInput.simulate('change', {
target: { value: 'password' }
})

const submitForm = wrapper.find('Form')
submitForm.simulate('submit')

expect(spy).toHaveBeenCalledTimes(1)
expect(wrapper.instance().props.postLogInInfo).toBeCalledTimes(1)
})

it('returns the user if postLogInInfo is called with the correct credentials', async () => {
expect.assertions(2)
const loggingInUser = await wrapper.instance().props.postLogInInfo({
email: 'existing-user@example.com',
password: 'password'
})
expect(loggingInUser).toEqual(user)
expect(wrapper.instance().props.history.push).toBeCalledTimes(1)
})

it('throws an error if postLogInInfo is called with incorrect credentials', async () => {
expect.assertions(1)
try {
await wrapper.instance().props.postLogInInfo({ email: '', password: '' })
} catch (e) {
expect(e).toEqual(Error('Username and/or Password do no match'))
}
})
})
13 changes: 11 additions & 2 deletions src/tests/reducers/usersReducer.test.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
import usersReducer from '../../reducers/usersReducer'
import { GET_USERS } from '../../types'
import { GET_USERS, POST_LOGIN_INFO } from '../../types'

describe('reduces users', () => {
it('defaults to empty projects if none are passed in', () => {
expect(usersReducer(undefined, {})).toEqual([])
})

it('reduces users', () => {
it('reduces users after getting them', () => {
expect(
usersReducer([], {
type: GET_USERS,
payload: ['User to be added to store']
})
).toEqual(['User to be added to store'])
})

it('reduces incoming user after successful login', () => {
expect(
usersReducer([], {
type: POST_LOGIN_INFO,
payload: ['User to be added to store']
})
).toEqual(['User to be added to store'])
})
})
11 changes: 11 additions & 0 deletions src/tests/store/store.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,15 @@ describe('Store', () => {
users: ['Run the tests']
})
})

it('should update after login', async () => {
await store.dispatch({
type: 'POST_LOGIN_INFO',
payload: ['Rerun them']
})

expect(store.getState()).toEqual({
users: ['Rerun them']
})
})
})
1 change: 1 addition & 0 deletions src/types/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const GET_USERS = 'GET_USERS'
export const POST_LOGIN_INFO = 'POST_LOGIN_INFO'

0 comments on commit cd20689

Please sign in to comment.