diff --git a/README b/README
index 7570f70..3396e6b 100644
--- a/README
+++ b/README
@@ -10,4 +10,4 @@ Install browserify globally:
$ sudo npm install -g browserify
Next, install browserify, babel, react, react-bootstrap, react-widgets, globalize, and big.js in our directory using npm:
-$ npm install browserify react react-dom react-addons-update react-bootstrap react-widgets babelify babel-preset-react globalize cldr-data big.js
+$ npm install browserify react react-dom react-addons-update react-bootstrap react-widgets redux react-redux redux-thunk babelify babel-preset-react globalize cldr-data big.js keymirror
diff --git a/js/actions/AccountActions.js b/js/actions/AccountActions.js
new file mode 100644
index 0000000..661c919
--- /dev/null
+++ b/js/actions/AccountActions.js
@@ -0,0 +1,181 @@
+var AccountConstants = require('../constants/AccountConstants');
+
+var ErrorActions = require('ErrorActions');
+
+var models = require('../models.js');
+var Account = models.Account;
+var Error = models.Error;
+
+function fetchAccounts() {
+ return {
+ type: AccountConstants.FETCH_ACCOUNTS
+ }
+}
+
+function accountsFetched(accounts) {
+ return {
+ type: AccountConstants.ACCOUNTS_FETCHED,
+ accounts: accounts
+ }
+}
+
+function createAccount() {
+ return {
+ type: AccountConstants.CREATE_ACCOUNT
+ }
+}
+
+function accountCreated(account) {
+ return {
+ type: AccountConstants.ACCOUNT_CREATED,
+ account: account
+ }
+}
+
+function updateAccount() {
+ return {
+ type: AccountConstants.UPDATE_ACCOUNT
+ }
+}
+
+function accountUpdated(account) {
+ return {
+ type: AccountConstants.ACCOUNT_UPDATED,
+ account: account
+ }
+}
+
+function removeAccount() {
+ return {
+ type: AccountConstants.REMOVE_ACCOUNT
+ }
+}
+
+function accountRemoved(accountId) {
+ return {
+ type: AccountConstants.ACCOUNT_REMOVED,
+ accountId: accountId
+ }
+}
+
+function accountSelected(accountId) {
+ return {
+ type: AccountConstants.ACCOUNT_SELECTED,
+ accountId: accountId
+ }
+}
+
+function fetchAll() {
+ return function (dispatch) {
+ dispatch(fetchAccounts());
+
+ $.ajax({
+ type: "GET",
+ dataType: "json",
+ url: "account/",
+ success: function(data, status, jqXHR) {
+ var e = new Error();
+ var accounts = [];
+ e.fromJSON(data);
+ if (e.isError()) {
+ ErrorActions.serverError(e);
+ } else {
+ dispatch(accountsFetched(data.accounts.map(function(json) {
+ var a = new Account();
+ a.fromJSON(json);
+ return a;
+ })));
+ }
+ },
+ error: function(jqXHR, status, error) {
+ ErrorActions.ajaxError(e);
+ }
+ });
+ };
+}
+
+function create(account) {
+ return function (dispatch) {
+ dispatch(createAccount());
+
+ $.ajax({
+ type: "POST",
+ dataType: "json",
+ url: "account/",
+ data: {account: account.toJSON()},
+ success: function(data, status, jqXHR) {
+ var e = new Error();
+ e.fromJSON(data);
+ if (e.isError()) {
+ ErrorActions.serverError(e);
+ } else {
+ var a = new Account();
+ a.fromJSON(data);
+ dispatch(accountCreated(a));
+ }
+ },
+ error: function(jqXHR, status, error) {
+ ErrorActions.ajaxError(e);
+ }
+ });
+ };
+}
+
+function update(account) {
+ return function (dispatch) {
+ dispatch(updateAccount());
+
+ $.ajax({
+ type: "PUT",
+ dataType: "json",
+ url: "account/"+account.AccountId+"/",
+ data: {account: account.toJSON()},
+ success: function(data, status, jqXHR) {
+ var e = new Error();
+ e.fromJSON(data);
+ if (e.isError()) {
+ ErrorActions.serverError(e);
+ } else {
+ var a = new Account();
+ a.fromJSON(data);
+ dispatch(accountUpdated(a));
+ }
+ },
+ error: function(jqXHR, status, error) {
+ ErrorActions.ajaxError(e);
+ }
+ });
+ };
+}
+
+function remove(account) {
+ return function(dispatch) {
+ dispatch(removeAccount());
+
+ $.ajax({
+ type: "DELETE",
+ dataType: "json",
+ url: "account/"+account.AccountId+"/",
+ success: function(data, status, jqXHR) {
+ var e = new Error();
+ e.fromJSON(data);
+ if (e.isError()) {
+ ErrorActions.serverError(e);
+ } else {
+ dispatch(accountRemoved(account.AccountId));
+ }
+ },
+ error: function(jqXHR, status, error) {
+ ErrorActions.ajaxError(e);
+ }
+ });
+ };
+}
+
+module.exports = {
+ fetchAll: fetchAll,
+ create: create,
+ update: update,
+ remove: remove,
+ select: accountSelected
+};
diff --git a/js/actions/ErrorActions.js b/js/actions/ErrorActions.js
new file mode 100644
index 0000000..d75ea9b
--- /dev/null
+++ b/js/actions/ErrorActions.js
@@ -0,0 +1,27 @@
+var ErrorConstants = require('../constants/ErrorConstants');
+
+var models = require('../models.js');
+var Error = models.Error;
+
+function serverError(error) {
+ return {
+ type: ErrorConstants.ERROR_SERVER,
+ error: error
+ };
+}
+
+function ajaxError(error) {
+ var e = new Error();
+ e.ErrorId = 5;
+ e.ErrorString = "Request Failed: " + status + error;
+
+ return {
+ type: ErrorConstants.ERROR_AJAX,
+ error: e
+ };
+}
+
+module.exports = {
+ serverError: serverError,
+ ajaxError: ajaxError
+};
diff --git a/js/constants/AccountConstants.js b/js/constants/AccountConstants.js
new file mode 100644
index 0000000..e8940c2
--- /dev/null
+++ b/js/constants/AccountConstants.js
@@ -0,0 +1,13 @@
+var keyMirror = require('keymirror');
+
+module.exports = keyMirror({
+ FETCH_ACCOUNTS: null,
+ ACCOUNTS_FETCHED: null,
+ CREATE_ACCOUNT: null,
+ ACCOUNT_CREATED: null,
+ UPDATE_ACCOUNT: null,
+ ACCOUNT_UPDATED: null,
+ REMOVE_ACCOUNT: null,
+ ACCOUNT_REMOVED: null,
+ ACCOUNT_SELECTED: null
+});
diff --git a/js/constants/ErrorConstants.js b/js/constants/ErrorConstants.js
new file mode 100644
index 0000000..a793905
--- /dev/null
+++ b/js/constants/ErrorConstants.js
@@ -0,0 +1,8 @@
+var keyMirror = require('keymirror');
+
+module.exports = keyMirror({
+ ERROR_AJAX: null,
+ ERROR_SERVER: null,
+ ERROR_CLIENT: null,
+ ERROR_USER: null,
+});
diff --git a/js/main.js b/js/main.js
index f28e7ed..976cefd 100644
--- a/js/main.js
+++ b/js/main.js
@@ -1,10 +1,15 @@
var React = require('react');
var ReactDOM = require('react-dom');
+var Provider = require('react-redux').Provider;
+var Redux = require('redux');
+var ReduxThunk = require('redux-thunk').default;
+
var Globalize = require('globalize');
var globalizeLocalizer = require('react-widgets/lib/localizers/globalize');
var MoneyGoApp = require('./MoneyGoApp.js');
+var MoneyGoReducer = require('./reducers/MoneyGoReducer');
// Setup globalization for react-widgets
//Globalize.load(require("cldr-data").entireSupplemental());
@@ -19,5 +24,17 @@ Globalize.locale('en');
globalizeLocalizer(Globalize);
$(document).ready(function() {
- ReactDOM.render(, document.getElementById("content"));
+ var store = Redux.createStore(
+ MoneyGoReducer,
+ Redux.applyMiddleware(
+ ReduxThunk
+ )
+ );
+
+ ReactDOM.render(
+
+
+ ,
+ document.getElementById("content")
+ );
});
diff --git a/js/reducers/AccountReducer.js b/js/reducers/AccountReducer.js
new file mode 100644
index 0000000..16fb033
--- /dev/null
+++ b/js/reducers/AccountReducer.js
@@ -0,0 +1,27 @@
+var assign = require('object-assign');
+
+var AccountConstants = require('../constants/AccountConstants');
+
+module.exports = function(state = {}, action) {
+ switch (action.type) {
+ case AccountConstants.ACCOUNTS_FETCHED:
+ var accounts = {};
+ for (var i = 0; i < action.accounts.length; i++) {
+ var account = action.accounts[i];
+ accounts[account.AccountId] = account;
+ }
+ return accounts;
+ case AccountConstants.ACCOUNT_CREATED:
+ case AccountConstants.ACCOUNT_UPDATED:
+ var account = action.account;
+ return assign({}, state, {
+ [account.AccountId]: account
+ });
+ case AccountConstants.ACCOUNT_REMOVED:
+ var newstate = assign({}, state);
+ delete newstate[action.accountId];
+ return newstate;
+ default:
+ return state;
+ }
+};
diff --git a/js/reducers/MoneyGoReducer.js b/js/reducers/MoneyGoReducer.js
new file mode 100644
index 0000000..fdd8702
--- /dev/null
+++ b/js/reducers/MoneyGoReducer.js
@@ -0,0 +1,9 @@
+var Redux = require('redux');
+
+var AccountReducer = require('./AccountReducer');
+var SelectedAccountReducer = require('./SelectedAccountReducer');
+
+module.exports = Redux.combineReducers({
+ accounts: AccountReducer,
+ selectedAccount: SelectedAccountReducer
+});
diff --git a/js/reducers/SelectedAccountReducer.js b/js/reducers/SelectedAccountReducer.js
new file mode 100644
index 0000000..fa2f294
--- /dev/null
+++ b/js/reducers/SelectedAccountReducer.js
@@ -0,0 +1,20 @@
+var AccountConstants = require('../constants/AccountConstants');
+
+module.exports = function(state = -1, action) {
+ switch (action.type) {
+ case AccountConstants.ACCOUNTS_FETCHED:
+ for (var i = 0; i < action.accounts.length; i++) {
+ if (action.accounts[i].AccountId == state)
+ return state;
+ }
+ return -1;
+ case AccountConstants.ACCOUNT_REMOVED:
+ if (action.accountId == state)
+ return -1;
+ return state;
+ case AccountConstants.ACCOUNT_SELECTED:
+ return action.accountId;
+ default:
+ return state;
+ }
+};