Skip to content

Commit

Permalink
Live coded redux auth.
Browse files Browse the repository at this point in the history
  • Loading branch information
queerviolet committed Nov 2, 2016
1 parent 17c9cd5 commit 33d9a88
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 12 deletions.
24 changes: 24 additions & 0 deletions app/components/Login.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react'

export const Login = ({ login }) => (
<form onSubmit={evt => {
evt.preventDefault()
login(evt.target.username.value, evt.target.password.value)
} }>
<input name="username" />
<input name="password" type="password" />
<input type="submit" value="Login" />
</form>
)

import {login} from 'APP/app/reducers/auth'
import {connect} from 'react-redux'

export default connect (
state => ({}),
dispatch => ({
login(username, password) {
return dispatch(login(username, password))
}
}),
) (Login)
27 changes: 27 additions & 0 deletions app/components/Login.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react'
import chai, {expect} from 'chai'
chai.use(require('chai-enzyme'))
import {shallow} from 'enzyme'

import {Login} from './Login'

describe('<Login />', () => {
let root
beforeEach('render the root', () =>
root = shallow(<Login/>)
)

it('shows a login form', () => {
expect(root.find('input[name="username"]')).to.have.length(1)
expect(root.find('input[name="password"]')).to.have.length(1)
})

it('shows a password field', () => {
expect(root.find('input[type="password"]')).to.have.length(1)
})

it('has a login button', () => {
const submit = root.find('input[type="submit"]')
expect(submit).to.have.length(1)
})
})
7 changes: 6 additions & 1 deletion app/main.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
'use strict'
import React from 'react'
import {Router, Route, IndexRedirect, browserHistory} from 'react-router'
import {render} from 'react-dom'
import { Provider } from 'react-redux'

import store from './store'
import Root from './components/Root'
import Login from './components/Login'

render (
<Provider store={store}>
<Root/>
<Router history={browserHistory}>
<Route path="/" component={Root} />
<Route path="/login" component={Login} />
</Router>
</Provider>,
document.getElementById('main')
)
35 changes: 35 additions & 0 deletions app/reducers/auth.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const reducer = (state=null, action) => {
switch(action.type) {
case AUTHENTICATED:
return action.user
}
return state
}

const AUTHENTICATED = 'AUTHENTICATED'
export const authenticated = user => ({
type: AUTHENTICATED, user
})

import axios from 'axios'

export const login = (username, password) =>
dispatch => {
const body = {username, password}
console.log('req body=', body)
return axios.post('/api/auth/local/login', body)
.then(() => dispatch(whoami()))
}

export const whoami = () =>
dispatch =>
axios.get('/api/auth/whoami')
.then(response => {
const user = response.data
if (!Object.keys(user).length) {
return dispatch(authenticated(null))
}
dispatch(authenticated(user))
})

export default reducer
10 changes: 3 additions & 7 deletions app/reducers/index.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { combineReducers } from 'redux'

const initialState = {}

const rootReducer = function(state = initialState, action) {
switch(action.type) {
default: return state
}
};
const rootReducer = combineReducers({
auth: require('./auth').default,
})

export default rootReducer
9 changes: 8 additions & 1 deletion app/store.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,11 @@ import rootReducer from './reducers'
import createLogger from 'redux-logger'
import thunkMiddleware from 'redux-thunk'

export default createStore(rootReducer, applyMiddleware(createLogger(), thunkMiddleware))
import {whoami} from './reducers/auth'

const store = createStore(rootReducer, applyMiddleware(createLogger(), thunkMiddleware))

export default store

// Set the auth info at start
store.dispatch(whoami())
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
},
"homepage": "https://github.com/queerviolet/bones#readme",
"dependencies": {
"axios": "^0.15.2",
"babel-preset-stage-2": "^6.18.0",
"bcrypt": "^0.8.7",
"body-parser": "^1.15.2",
Expand All @@ -47,6 +48,7 @@
"react": "^15.3.2",
"react-dom": "^15.3.2",
"react-redux": "^4.4.5",
"react-router": "^3.0.0",
"redux": "^3.6.0",
"redux-logger": "^2.7.0",
"redux-thunk": "^2.1.0",
Expand Down
6 changes: 3 additions & 3 deletions server/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ const pkg = require('APP')

const app = express()

if (!pkg.isProduction) {
// Logging middleware (dev & testing only)
if (!pkg.isProduction && !pkg.isTesting) {
// Logging middleware (dev only)
app.use(require('volleyball'))
}
}

module.exports = app
// We'll store the whole session in a cookie
Expand Down

0 comments on commit 33d9a88

Please sign in to comment.