From fbb37ad2d9d00b92f4f76a47fa7dce9c44620e34 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Wed, 8 May 2019 11:35:57 +1000 Subject: [PATCH] Logins and logouts (sessions) are working --- package-lock.json | 158 +++++++++++++++++++++--------- package.json | 1 + server/accounts.js | 73 +++++++++++++- server/index.js | 5 + sql/create_database_structure.sql | 14 ++- sql/drop_everything.sql | 3 +- src/actions/accounts.js | 18 ++++ src/actions/actions.jsx | 7 -- src/components/pages/home.jsx | 29 +++++- src/components/panels/login.jsx | 131 +++++++++++++++++++++++++ src/components/panels/logout.jsx | 47 +++++++++ src/index.jsx | 14 ++- src/reducers/accounts.js | 29 ++++++ src/reducers/reducer.js | 8 ++ src/reducers/reducer.jsx | 14 --- 15 files changed, 477 insertions(+), 74 deletions(-) create mode 100644 src/actions/accounts.js delete mode 100644 src/actions/actions.jsx create mode 100644 src/components/panels/logout.jsx create mode 100644 src/reducers/accounts.js create mode 100644 src/reducers/reducer.js delete mode 100644 src/reducers/reducer.jsx diff --git a/package-lock.json b/package-lock.json index 9bae26d..6cd8aa6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1424,29 +1424,48 @@ "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" }, "body-parser": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", - "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", "requires": { - "bytes": "3.0.0", + "bytes": "3.1.0", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "~1.6.3", - "iconv-lite": "0.4.23", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.5.2", - "raw-body": "2.3.3", - "type-is": "~1.6.16" + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" }, "dependencies": { - "iconv-lite": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" } } }, @@ -1669,9 +1688,9 @@ "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" }, "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, "cacache": { "version": "11.3.2", @@ -2563,10 +2582,51 @@ "vary": "~1.1.2" }, "dependencies": { + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } } } }, @@ -3079,13 +3139,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3098,18 +3156,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -3212,8 +3267,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -3223,7 +3277,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3236,7 +3289,6 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3336,8 +3388,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -3347,7 +3398,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -3453,7 +3503,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5318,23 +5367,37 @@ "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" }, "raw-body": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", - "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.3", - "iconv-lite": "0.4.23", + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, "dependencies": { - "iconv-lite": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" } } }, @@ -6311,6 +6374,11 @@ "repeat-string": "^1.6.1" } }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", diff --git a/package.json b/package.json index e6384f5..e9790e7 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@babel/preset-react": "^7.0.0", "babel-loader": "^8.0.5", "bcrypt": "^3.0.6", + "body-parser": "^1.19.0", "dotenv": "^8.0.0", "express": "^4.16.4", "forever": "^1.0.0", diff --git a/server/accounts.js b/server/accounts.js index d5d3cdf..3c8862d 100644 --- a/server/accounts.js +++ b/server/accounts.js @@ -127,7 +127,78 @@ function verify(connection) { } } +function login(connection) { + return (req, res) => { + //formidable handles forms + let form = formidable.IncomingForm(); + + //parse form + form.parse(req, (err, fields) => { + if (err) throw err; + + //validate email, username and password + if (!validateEmail(fields.email) || fields.password.length < 8) { + res.write('

Invalid login data

'); + res.end(); + return; + } + + //find this email's information + let query = 'SELECT id, username, salt, hash FROM accounts WHERE email = ?;'; + connection.query(query, [fields.email], (err, results) => { + if (err) throw err; + + //found this email? + if (results.length === 0) { + res.status(400).write('Incorrect email or password'); + res.end(); + return; + } + + //gen a new hash from the salt and password + bcrypt.hash(fields.password, results[0].salt, (err, newHash) => { + if (err) throw err; + + //compare the passwords + if (results[0].hash !== newHash) { + res.status(400).write('Incorrect email or password'); + res.end(); + return; + } + + //create the new session + let rand = Math.floor(Math.random() * 100000); + + let query = 'INSERT INTO sessions (accountId, token) VALUES (?, ?);'; + connection.query(query, [results[0].id, rand], (err) => { + if (err) throw err; + + //send json containing the account info + res.status(200).json({ + id: results[0].id, + email: fields.email, + username: results[0].username, + token: rand + }); + }); + }); + }); + }); + } +} + +function logout(connection) { + return (req, res) => { + let query = 'DELETE FROM sessions WHERE sessions.accountId IN (SELECT accounts.id FROM accounts WHERE email = ?) AND token = ?;'; + connection.query(query, [req.body.email, req.body.token], (err) => { + if (err) throw err; + }); + } +} + module.exports = { signup: signup, - verify: verify + verify: verify, + login: login, + logout: logout }; \ No newline at end of file diff --git a/server/index.js b/server/index.js index 926451a..92619a3 100644 --- a/server/index.js +++ b/server/index.js @@ -5,8 +5,11 @@ require('dotenv').config(); let express = require('express'); let app = express(); let http = require('http').Server(app); +let bodyParser = require('body-parser'); let path = require('path'); +app.use(bodyParser.json()); + //database let { connectToDatabase } = require('./database.js'); let connection = connectToDatabase(); //uses .env @@ -15,6 +18,8 @@ let connection = connectToDatabase(); //uses .env let accounts = require('./accounts.js'); app.post('/signup', accounts.signup(connection)); app.get('/verify', accounts.verify(connection)); +app.post('/login', accounts.login(connection)); +app.post('/logout', accounts.logout(connection)); //static directories app.use('/styles', express.static(path.resolve(__dirname + '/../public/styles')) ); diff --git a/sql/create_database_structure.sql b/sql/create_database_structure.sql index ba29120..b7f4899 100644 --- a/sql/create_database_structure.sql +++ b/sql/create_database_structure.sql @@ -1,4 +1,4 @@ -CREATE TABLE signups ( +CREATE TABLE IF NOT EXISTS signups ( email VARCHAR(320) UNIQUE, username VARCHAR(100) UNIQUE, salt VARCHAR(50), @@ -7,7 +7,7 @@ CREATE TABLE signups ( verify INTEGER DEFAULT 0 ); -CREATE TABLE accounts ( +CREATE TABLE IF NOT EXISTS accounts ( id INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY UNIQUE, td TIMESTAMP DEFAULT CURRENT_TIMESTAMP(), @@ -17,3 +17,13 @@ CREATE TABLE accounts ( hash VARCHAR(100) ); +CREATE TABLE IF NOT EXISTS sessions ( + id INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY UNIQUE, + td TIMESTAMP DEFAULT CURRENT_TIMESTAMP(), + + accountId INTEGER UNSIGNED, + token INTEGER DEFAULT 0, + + CONSTRAINT FOREIGN KEY fk_accountId(accountId) REFERENCES accounts(id) ON UPDATE CASCADE ON DELETE CASCADE +); + diff --git a/sql/drop_everything.sql b/sql/drop_everything.sql index 6627951..847ec52 100644 --- a/sql/drop_everything.sql +++ b/sql/drop_everything.sql @@ -1,3 +1,4 @@ DROP TABLE signups; DROP TABLE accounts; -DROP TABLE profiles; +DROP TABLE sessions; +#DROP TABLE profiles; diff --git a/src/actions/accounts.js b/src/actions/accounts.js new file mode 100644 index 0000000..6388305 --- /dev/null +++ b/src/actions/accounts.js @@ -0,0 +1,18 @@ +export const LOGIN = 'LOGIN'; +export const LOGOUT = 'LOGOUT'; + +export function login(id, email, username, token) { + return { + type: LOGIN, + id: id, + email: email, + username: username, + token: token + }; +} + +export function logout() { + return { + type: LOGOUT + }; +} diff --git a/src/actions/actions.jsx b/src/actions/actions.jsx deleted file mode 100644 index 31a4400..0000000 --- a/src/actions/actions.jsx +++ /dev/null @@ -1,7 +0,0 @@ -export const ACTION_NAME = 'ACTION_NAME'; - -export function actionName() { - return { - type: ACTION_NAME - }; -} \ No newline at end of file diff --git a/src/components/pages/home.jsx b/src/components/pages/home.jsx index ee34c5e..d876fa6 100644 --- a/src/components/pages/home.jsx +++ b/src/components/pages/home.jsx @@ -5,6 +5,8 @@ import PropTypes from 'prop-types'; //panels import Signup from '../panels/signup.jsx'; +import Login from '../panels/login.jsx'; +import Logout from '../panels/logout.jsx'; class Home extends React.Component { constructor(props) { @@ -13,10 +15,33 @@ class Home extends React.Component { } render() { + //well this is goofy + let SidePanel; + + if (this.props.id) { + SidePanel = () => { + return ( +
+

You are logged in.

+ +
+ ); + }; + } else { + SidePanel = () => { + return ( +
+ + +
+ ); + }; + } + return (

This is the home page.

- +
); } @@ -24,7 +49,7 @@ class Home extends React.Component { function mapStoreToProps(store) { return { - // + id: store.account.id } } diff --git a/src/components/panels/login.jsx b/src/components/panels/login.jsx index e69de29..0d3a04d 100644 --- a/src/components/panels/login.jsx +++ b/src/components/panels/login.jsx @@ -0,0 +1,131 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { login } from '../../actions/accounts.js'; +import { validateEmail } from '../../../common/utilities.js'; + +class Login extends React.Component { + constructor(props) { + super(props); + this.state = { + email: '', + password: '', + warning: '' + }; + } + + render() { + let warningStyle = { + display: this.state.warning.length > 0 ? 'flex' : 'none' + }; + + return ( +
+

Login

+ +
+

{this.state.warning}

+
+ +
this.submit(e)}> +
+ + +
+ +
+ + +
+ + +
+
+ ); + } + + submit(e) { + e.preventDefault(); + + if (!this.validateInput()) { + return; + } + + //build the XHR + let form = e.target; + let formData = new FormData(form); + let xhr = new XMLHttpRequest(); + + xhr.onreadystatechange = () => { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + let json = JSON.parse(xhr.responseText); + this.props.login(json.id, json.email, json.username, json.token); + } + + else if (xhr.status === 400) { + this.setWarning(xhr.responseText); + } + } + }; + + //send the XHR + xhr.open('POST', form.action, true); + xhr.send(formData); + } + + validateInput(e) { + if (!validateEmail(this.state.email)) { + this.setWarning('Invalid Email'); + return false; + } + + if (this.state.password.length < 8) { + this.setWarning('Minimum password length is 8 characters'); + return false; + } + + return true; + } + + setWarning(s) { + this.setState({ + warning: s + }); + } + + clearInput() { + this.setState({ + email: '', + password: '', + warning: '' + }); + } + + updateEmail(evt) { + this.setState({ + email: evt.target.value + }); + } + + updatePassword(evt) { + this.setState({ + password: evt.target.value + }); + } +} + +function mapStoreToProps(store) { + return { + // + } +} + +function mapDispatchToProps(dispatch) { + return { + login: (id, email, username, token) => { dispatch(login(id, email, username, token)) } + } +} + +Login = connect(mapStoreToProps, mapDispatchToProps)(Login); + +export default Login; \ No newline at end of file diff --git a/src/components/panels/logout.jsx b/src/components/panels/logout.jsx new file mode 100644 index 0000000..2ee6c1c --- /dev/null +++ b/src/components/panels/logout.jsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { logout } from '../../actions/accounts.js'; + +class Logout extends React.Component { + constructor(props) { + super(props); + } + + render() { + return ( + + ); + } + + submit(e) { + e.preventDefault(); + + //build the XHR + let xhr = new XMLHttpRequest(); + xhr.open('POST', '/logout', true); + xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); + xhr.send(JSON.stringify({ + email: this.props.email, + token: this.props.token + })); + + this.props.logout(); + } +} + +function mapStoreToProps(store) { + return { + email: store.account.email, + token: store.account.token + } +} + +function mapDispatchToProps(dispatch) { + return { + logout: () => { dispatch(logout()) } + } +} + +Logout = connect(mapStoreToProps, mapDispatchToProps)(Logout); + +export default Logout; \ No newline at end of file diff --git a/src/index.jsx b/src/index.jsx index b891af4..6d23981 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -7,17 +7,27 @@ import thunk from 'redux-thunk'; import DevTools from './dev_tools.jsx'; import App from './components/app.jsx'; -import reducer from './reducers/reducer.jsx'; +import reducer from './reducers/reducer.js'; + +//persistence +let ITEM_NAME = 'account.kingdombattles'; +let account = localStorage.getItem(ITEM_NAME); +account = account ? JSON.parse(account) : {}; var store = createStore( reducer, - {}, //initial state + { account: account }, //initial state compose( applyMiddleware(thunk), DevTools.instrument() ) ); +//persistence +store.subscribe(() => { + localStorage.setItem(ITEM_NAME, JSON.stringify(store.getState().account)); +}); + //start the process ReactDOM.render( diff --git a/src/reducers/accounts.js b/src/reducers/accounts.js new file mode 100644 index 0000000..58a038c --- /dev/null +++ b/src/reducers/accounts.js @@ -0,0 +1,29 @@ +import { LOGIN, LOGOUT } from "../actions/accounts.js"; + +const initialStore = { + id: 0, + email: '', + username: '', + token: 0 +}; + +export function accountReducer(store = initialStore, action) { + switch(action.type) { + case LOGIN: + let newStore = JSON.parse(JSON.stringify(initialStore)); + + newStore.id = action.id; + newStore.email = action.email; + newStore.username = action.username; + newStore.token = action.token; + + return newStore; + + case LOGOUT: + return initialStore; + + default: + return store; + } +} + diff --git a/src/reducers/reducer.js b/src/reducers/reducer.js new file mode 100644 index 0000000..abaf44b --- /dev/null +++ b/src/reducers/reducer.js @@ -0,0 +1,8 @@ +import { combineReducers } from 'redux'; +import { accountReducer } from './accounts.js'; + +//compile all reducers together +export default combineReducers({ + account: accountReducer +}); + diff --git a/src/reducers/reducer.jsx b/src/reducers/reducer.jsx deleted file mode 100644 index a924476..0000000 --- a/src/reducers/reducer.jsx +++ /dev/null @@ -1,14 +0,0 @@ -import { ACTION_NAME } from "../actions/actions.jsx"; - -const initialState = {}; - -export default function reducer(state = initialState, action) { - switch(action.type) { - case ACTION_NAME: - //DO NOTHING - return state; - - default: - return state; - } -} \ No newline at end of file