diff --git a/app/components/Login.jsx b/app/components/Login.jsx new file mode 100644 index 0000000..53a22bf --- /dev/null +++ b/app/components/Login.jsx @@ -0,0 +1,24 @@ +import React from 'react' + +export const Login = ({ login }) => ( +
{ + evt.preventDefault() + login(evt.target.username.value, evt.target.password.value) + } }> + + + +
+) + +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) \ No newline at end of file diff --git a/app/components/Login.test.jsx b/app/components/Login.test.jsx new file mode 100644 index 0000000..3ff0d11 --- /dev/null +++ b/app/components/Login.test.jsx @@ -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('', () => { + let root + beforeEach('render the root', () => + root = shallow() + ) + + 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) + }) +}) \ No newline at end of file diff --git a/app/main.jsx b/app/main.jsx index e2b6cd0..287112b 100644 --- a/app/main.jsx +++ b/app/main.jsx @@ -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 ( - + + + + , document.getElementById('main') ) \ No newline at end of file diff --git a/app/reducers/auth.jsx b/app/reducers/auth.jsx new file mode 100644 index 0000000..b809c3f --- /dev/null +++ b/app/reducers/auth.jsx @@ -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 \ No newline at end of file diff --git a/app/reducers/index.jsx b/app/reducers/index.jsx index 1eedf84..a81df20 100644 --- a/app/reducers/index.jsx +++ b/app/reducers/index.jsx @@ -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 diff --git a/app/store.jsx b/app/store.jsx index 80efadd..0fc8ac2 100644 --- a/app/store.jsx +++ b/app/store.jsx @@ -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()) diff --git a/package.json b/package.json index eb4d35b..3d3f04d 100644 --- a/package.json +++ b/package.json @@ -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", @@ -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", diff --git a/server/start.js b/server/start.js index f305f39..5a14bdf 100644 --- a/server/start.js +++ b/server/start.js @@ -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