Error reporting for Sign In & Sign Up

This commit is contained in:
Andrew Revinsky (DART)
2016-09-13 01:54:56 +03:00
parent df4204f9a2
commit 0b39ba658a
32 changed files with 1882 additions and 2207 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -12,8 +12,8 @@
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css">
<!-- Optional theme --> <!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap-theme.min.css"><link href="/style.6d7a32b1405ea1bb2bdf.css" rel="stylesheet"></head> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap-theme.min.css"><link href="/style.6734b6ac5d23d61b8e5f.css" rel="stylesheet"></head>
<body><div id="root"></div><script src="/manifest.7d421cf4b17be2725a67.js"></script><script src="/vendor.c882d66445aebc52c21b.js"></script><script src="/style.6d7a32b1405ea1bb2bdf.js"></script><script src="/app.b0de56230554ae24a254.js"></script><script> <body><div id="root"></div><script src="/manifest.4fffd5bbc120d3bf86c4.js"></script><script src="/vendor.829a6cd5501868837732.js"></script><script src="/style.6734b6ac5d23d61b8e5f.js"></script><script src="/app.d5e626aaea52a2dac6cb.js"></script><script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
@@ -27,5 +27,5 @@
ga('send', 'pageview'); ga('send', 'pageview');
</script><!--{"files":{"publicPath":"/","chunks":{"manifest":{"size":0,"entry":"/manifest.7d421cf4b17be2725a67.js","hash":"7d421cf4b17be2725a67","css":[]},"vendor":{"size":1670874,"entry":"/vendor.c882d66445aebc52c21b.js","hash":"c882d66445aebc52c21b","css":[]},"style":{"size":122,"entry":"/style.6d7a32b1405ea1bb2bdf.js","hash":"6d7a32b1405ea1bb2bdf","css":["/style.6d7a32b1405ea1bb2bdf.css"]},"app":{"size":358241,"entry":"/app.b0de56230554ae24a254.js","hash":"b0de56230554ae24a254","css":[]}},"js":["/manifest.7d421cf4b17be2725a67.js","/vendor.c882d66445aebc52c21b.js","/style.6d7a32b1405ea1bb2bdf.js","/app.b0de56230554ae24a254.js"],"css":["/style.6d7a32b1405ea1bb2bdf.css"]},"options":{"template":"/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/html-webpack-plugin/lib/loader.js!/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/public/index.ejs","filename":"index.html","hash":false,"inject":false,"compile":true,"favicon":false,"minify":false,"cache":true,"showErrors":true,"chunks":"all","excludeChunks":[],"title":"Money Transfer App","xhtml":false,"description":"ES Money Transfer App","appMountId":"root","googleAnalytics":{"trackingId":"UA-XXXX-XX","pageViewOnLoad":true},"mobile":true}}--></body> </script><!--{"files":{"publicPath":"/","chunks":{"manifest":{"size":0,"entry":"/manifest.4fffd5bbc120d3bf86c4.js","hash":"4fffd5bbc120d3bf86c4","css":[]},"vendor":{"size":1670874,"entry":"/vendor.829a6cd5501868837732.js","hash":"829a6cd5501868837732","css":[]},"style":{"size":122,"entry":"/style.6734b6ac5d23d61b8e5f.js","hash":"6734b6ac5d23d61b8e5f","css":["/style.6734b6ac5d23d61b8e5f.css"]},"app":{"size":349686,"entry":"/app.d5e626aaea52a2dac6cb.js","hash":"d5e626aaea52a2dac6cb","css":[]}},"js":["/manifest.4fffd5bbc120d3bf86c4.js","/vendor.829a6cd5501868837732.js","/style.6734b6ac5d23d61b8e5f.js","/app.d5e626aaea52a2dac6cb.js"],"css":["/style.6734b6ac5d23d61b8e5f.css"]},"options":{"template":"/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/html-webpack-plugin/lib/loader.js!/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/public/index.ejs","filename":"index.html","hash":false,"inject":false,"compile":true,"favicon":false,"minify":false,"cache":true,"showErrors":true,"chunks":"all","excludeChunks":[],"title":"Money Transfer App","xhtml":false,"description":"ES Money Transfer App","appMountId":"root","googleAnalytics":{"trackingId":"UA-XXXX-XX","pageViewOnLoad":true},"mobile":true}}--></body>
</html> </html>

View File

@@ -76,7 +76,7 @@
/******/ script.charset = 'utf-8'; /******/ script.charset = 'utf-8';
/******/ script.async = true; /******/ script.async = true;
/******/ /******/
/******/ script.src = __webpack_require__.p + "" + {"0":"b0de56230554ae24a254","1":"6d7a32b1405ea1bb2bdf","2":"c882d66445aebc52c21b"}[chunkId] + ".js"; /******/ script.src = __webpack_require__.p + "" + {"0":"d5e626aaea52a2dac6cb","1":"6734b6ac5d23d61b8e5f","2":"829a6cd5501868837732"}[chunkId] + ".js";
/******/ head.appendChild(script); /******/ head.appendChild(script);
/******/ } /******/ }
/******/ }; /******/ };
@@ -92,4 +92,4 @@
/******/ }) /******/ })
/************************************************************************/ /************************************************************************/
/******/ ([]); /******/ ([]);
//# sourceMappingURL=manifest.7d421cf4b17be2725a67.js.map //# sourceMappingURL=manifest.4fffd5bbc120d3bf86c4.js.map

View File

@@ -1 +1 @@
{"version":3,"sources":["webpack:///webpack/bootstrap cbccb464c1729e34dd25?"],"names":[],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAQ,oBAAoB;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAe;AACf;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,uDAA+C,iFAAiF;AAChI;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA","file":"manifest.7d421cf4b17be2725a67.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, callbacks = [];\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId])\n \t\t\t\tcallbacks.push.apply(callbacks, installedChunks[chunkId]);\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);\n \t\twhile(callbacks.length)\n \t\t\tcallbacks.shift().call(null, __webpack_require__);\n \t\tif(moreModules[0]) {\n \t\t\tinstalledModules[0] = 0;\n \t\t\treturn __webpack_require__(0);\n \t\t}\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// object to store loaded and loading chunks\n \t// \"0\" means \"already loaded\"\n \t// Array means \"loading\", array contains callbacks\n \tvar installedChunks = {\n \t\t3:0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n \t// This file contains only the entry chunk.\n \t// The chunk loading function for additional chunks\n \t__webpack_require__.e = function requireEnsure(chunkId, callback) {\n \t\t// \"0\" is the signal for \"already loaded\"\n \t\tif(installedChunks[chunkId] === 0)\n \t\t\treturn callback.call(null, __webpack_require__);\n\n \t\t// an array means \"currently loading\".\n \t\tif(installedChunks[chunkId] !== undefined) {\n \t\t\tinstalledChunks[chunkId].push(callback);\n \t\t} else {\n \t\t\t// start chunk loading\n \t\t\tinstalledChunks[chunkId] = [callback];\n \t\t\tvar head = document.getElementsByTagName('head')[0];\n \t\t\tvar script = document.createElement('script');\n \t\t\tscript.type = 'text/javascript';\n \t\t\tscript.charset = 'utf-8';\n \t\t\tscript.async = true;\n\n \t\t\tscript.src = __webpack_require__.p + \"\" + {\"0\":\"b0de56230554ae24a254\",\"1\":\"6d7a32b1405ea1bb2bdf\",\"2\":\"c882d66445aebc52c21b\"}[chunkId] + \".js\";\n \t\t\thead.appendChild(script);\n \t\t}\n \t};\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/\";\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap cbccb464c1729e34dd25\n **/"],"sourceRoot":""} {"version":3,"sources":["webpack:///webpack/bootstrap 931e2528f98ce8b6334a?"],"names":[],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAQ,oBAAoB;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAe;AACf;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,uDAA+C,iFAAiF;AAChI;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA","file":"manifest.4fffd5bbc120d3bf86c4.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, callbacks = [];\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId])\n \t\t\t\tcallbacks.push.apply(callbacks, installedChunks[chunkId]);\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);\n \t\twhile(callbacks.length)\n \t\t\tcallbacks.shift().call(null, __webpack_require__);\n \t\tif(moreModules[0]) {\n \t\t\tinstalledModules[0] = 0;\n \t\t\treturn __webpack_require__(0);\n \t\t}\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// object to store loaded and loading chunks\n \t// \"0\" means \"already loaded\"\n \t// Array means \"loading\", array contains callbacks\n \tvar installedChunks = {\n \t\t3:0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n \t// This file contains only the entry chunk.\n \t// The chunk loading function for additional chunks\n \t__webpack_require__.e = function requireEnsure(chunkId, callback) {\n \t\t// \"0\" is the signal for \"already loaded\"\n \t\tif(installedChunks[chunkId] === 0)\n \t\t\treturn callback.call(null, __webpack_require__);\n\n \t\t// an array means \"currently loading\".\n \t\tif(installedChunks[chunkId] !== undefined) {\n \t\t\tinstalledChunks[chunkId].push(callback);\n \t\t} else {\n \t\t\t// start chunk loading\n \t\t\tinstalledChunks[chunkId] = [callback];\n \t\t\tvar head = document.getElementsByTagName('head')[0];\n \t\t\tvar script = document.createElement('script');\n \t\t\tscript.type = 'text/javascript';\n \t\t\tscript.charset = 'utf-8';\n \t\t\tscript.async = true;\n\n \t\t\tscript.src = __webpack_require__.p + \"\" + {\"0\":\"d5e626aaea52a2dac6cb\",\"1\":\"6734b6ac5d23d61b8e5f\",\"2\":\"829a6cd5501868837732\"}[chunkId] + \".js\";\n \t\t\thead.appendChild(script);\n \t\t}\n \t};\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/\";\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap 931e2528f98ce8b6334a\n **/"],"sourceRoot":""}

View File

@@ -438,4 +438,4 @@ body {
h1 { h1 {
margin-top: .5em; margin-top: .5em;
} }
/*# sourceMappingURL=style.6d7a32b1405ea1bb2bdf.css.map*/ /*# sourceMappingURL=style.6734b6ac5d23d61b8e5f.css.map*/

View File

@@ -1 +1 @@
{"version":3,"sources":[],"names":[],"mappings":"","file":"style.6d7a32b1405ea1bb2bdf.css","sourceRoot":""} {"version":3,"sources":[],"names":[],"mappings":"","file":"style.6734b6ac5d23d61b8e5f.css","sourceRoot":""}

View File

@@ -3,20 +3,20 @@ webpackJsonp([1,3],{
/***/ 0: /***/ 0:
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
__webpack_require__(614); __webpack_require__(611);
module.exports = __webpack_require__(618); module.exports = __webpack_require__(615);
/***/ }, /***/ },
/***/ 614: /***/ 611:
/***/ function(module, exports) { /***/ function(module, exports) {
// removed by extract-text-webpack-plugin // removed by extract-text-webpack-plugin
/***/ }, /***/ },
/***/ 618: /***/ 615:
/***/ function(module, exports) { /***/ function(module, exports) {
// removed by extract-text-webpack-plugin // removed by extract-text-webpack-plugin
@@ -24,4 +24,4 @@ webpackJsonp([1,3],{
/***/ } /***/ }
}); });
//# sourceMappingURL=style.6d7a32b1405ea1bb2bdf.js.map //# sourceMappingURL=style.6734b6ac5d23d61b8e5f.js.map

View File

@@ -1 +1 @@
{"version":3,"sources":["webpack:///./~/react-select/dist/react-select.css?","webpack:///./src/main.less?"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,0C;;;;;;;ACAA,0C","file":"style.6d7a32b1405ea1bb2bdf.js","sourcesContent":["// removed by extract-text-webpack-plugin\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/react-select/dist/react-select.css\n ** module id = 614\n ** module chunks = 1\n **/","// removed by extract-text-webpack-plugin\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/main.less\n ** module id = 618\n ** module chunks = 1\n **/"],"sourceRoot":""} {"version":3,"sources":["webpack:///./~/react-select/dist/react-select.css?","webpack:///./src/main.less?"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,0C;;;;;;;ACAA,0C","file":"style.6734b6ac5d23d61b8e5f.js","sourcesContent":["// removed by extract-text-webpack-plugin\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/react-select/dist/react-select.css\n ** module id = 611\n ** module chunks = 1\n **/","// removed by extract-text-webpack-plugin\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/main.less\n ** module id = 615\n ** module chunks = 1\n **/"],"sourceRoot":""}

View File

@@ -8,6 +8,7 @@ import { Provider, connect} from "react-redux";
import thunk from "redux-thunk"; import thunk from "redux-thunk";
import createLogger from 'redux-logger'; import createLogger from 'redux-logger';
import { Route, IndexRoute, Link, IndexLink } from "react-router"; import { Route, IndexRoute, Link, IndexLink } from "react-router";
import { RouterContext } from 'react-router';
import { ReduxRouter} from "redux-router"; import { ReduxRouter} from "redux-router";
import { createHistory, createHashHistory, createMemoryHistory } from "history"; import { createHistory, createHashHistory, createMemoryHistory } from "history";
import { pushState, routerStateReducer, reduxReactRouter as clientRouter} from "redux-router"; import { pushState, routerStateReducer, reduxReactRouter as clientRouter} from "redux-router";
@@ -16,6 +17,7 @@ import { reduxReactRouter as serverRouter } from "redux-router/server";
import mainReducer from './reducers'; import mainReducer from './reducers';
import { configure as endpointsConfig } from './actions/configure'; import { configure as endpointsConfig } from './actions/configure';
import { visitLocation } from './actions/navigate';
import { requireAuthentication } from './components/AuthComponent'; import { requireAuthentication } from './components/AuthComponent';
import Container from "./components/partials/Container"; import Container from "./components/partials/Container";
import MyAccounts from "./views/MyAccounts"; import MyAccounts from "./views/MyAccounts";
@@ -25,7 +27,8 @@ import SignUp from "./views/SignUp";
class App extends React.Component { class App extends React.Component {
render() { render() {
return (<Container> return (
<Container>
{this.props.children} {this.props.children}
</Container>); </Container>);
} }
@@ -38,12 +41,19 @@ export function initialize({cookies, isServer, currentLocation, userAgent} = {})
router: routerStateReducer router: routerStateReducer
}); });
let dispatch = null;
const onEnter = (nextState) => {
const { location } = nextState;
dispatch && dispatch(visitLocation(location));
};
const routes = ( const routes = (
<Route path="/" component={App}> <Route path="/" component={ App }>
<IndexRoute component={requireAuthentication(MyAccounts)} /> <IndexRoute component={ requireAuthentication(MyAccounts) } />
<Route path="signin" component={SignIn} /> <Route path="signin" component={ SignIn } onEnter={ onEnter } />
<Route path="register" component={SignUp} /> <Route path="register" component={ SignUp } />
<Route path="account/:accountId" component={requireAuthentication(Account)} /> <Route path="account/:accountId" component={ requireAuthentication(Account) } />
</Route> </Route>
); );
@@ -60,6 +70,7 @@ export function initialize({cookies, isServer, currentLocation, userAgent} = {})
}) })
)(createStore)(reducer); )(createStore)(reducer);
dispatch = store.dispatch;
/** /**
* The React Router 1.0 routes for both the server and the client. * The React Router 1.0 routes for both the server and the client.
@@ -85,13 +96,11 @@ export function initialize({cookies, isServer, currentLocation, userAgent} = {})
}, },
handleLoginResponse: function(resp) { handleLoginResponse: function(resp) {
debugger; debugger;
return resp.data; return resp.data;
}, },
handleAccountUpdateResponse: function(resp) { handleAccountUpdateResponse: function(resp) {
debugger; debugger;
return resp.data; return resp.data;
}, },

View File

@@ -1,27 +0,0 @@
/**
* Created by andrew on 25/02/16.
*/
export function configureStart({...props} = {}) {
return {
...props,
type: T.AUTH.CONFIGURE_START
};
}
export function configureComplete({config, ...props} = {}) {
return {
...props,
type: T.AUTH.CONFIGURE_COMPLETE,
config
};
}
export function configureError({errors, ...props} = {}) {
return {
...props,
type: T.AUTH.CONFIGURE_ERROR,
error: errors
};
}

View File

@@ -1,32 +1,12 @@
/** /**
* Created by andrew on 26/02/16. * Created by andrew on 26/02/16.
*/ */
import * as C from "../utils/constants";
import { import {
authenticate, authenticate,
authenticateStart,
authenticateComplete,
authenticateError
} from "./authenticate"; } from "./authenticate";
import {
retrieveData,
} from "../utils/sessionStorage";
import {applyConfig} from "../utils/clientSettings"; import {applyConfig} from "../utils/clientSettings";
//import {
// showFirstTimeLoginSuccessModal,
// showFirstTimeLoginErrorModal,
// showPasswordResetSuccessModal,
// showPasswordResetErrorModal
//} from "./ui";
import getRedirectInfo from "../utils/parseUrl";
import { pushState } from "redux-router";
import root from '../utils/root';
export const SET_ENDPOINT_KEYS = "SET_ENDPOINT_KEYS"; export const SET_ENDPOINT_KEYS = "SET_ENDPOINT_KEYS";
export const STORE_CURRENT_ENDPOINT_KEY = "STORE_CURRENT_ENDPOINT_KEY"; export const STORE_CURRENT_ENDPOINT_KEY = "STORE_CURRENT_ENDPOINT_KEY";

View File

@@ -0,0 +1,7 @@
/**
* Created by andrew on 26/02/16.
*/
import T from '../constants/ACTION_TYPES';
import { makeActionCreator } from '../utils/actions';
export const visitLocation = makeActionCreator(T.LOCATION.ENTER, 'location');

View File

@@ -1,29 +0,0 @@
import T from '../constants/ACTION_TYPES'
import ROUTES from '../constants/ROUTES'
// `navigate` is used to facilitate changing routes within another action
// without rendering any other changes first
export function start(name, options) {
return dispatch => {
const currentURI = window.location.hash.substr(1)
const newURI = ROUTES.generate(name, options)
if (currentURI != newURI) {
dispatch({
type: T.NAVIGATION.START,
})
window.location.replace(
window.location.pathname + window.location.search + '#' + newURI
)
}
}
}
export function complete() {
return {
type: T.NAVIGATION.COMPLETE,
location: ROUTES.lookup(window.location.hash.substr(1)),
}
}

View File

@@ -1,23 +1,11 @@
/** /**
* Created by andrew on 26/02/16. * Created by andrew on 26/02/16.
*/ */
import {
setCurrentEndpointKey,
getCurrentEndpointKey,
persistUserData
} from "../utils/sessionStorage";
import { entityReceived } from './entities';
import { storeCurrentEndpointKey } from "./configure";
//import { parseResponse } from "../utils/handleFetchResponse";
//import fetch from "../utils/fetch";
import { apiSignIn } from '../utils/api';
import { makeActionCreator } from '../utils/actions';
import T from '../constants/ACTION_TYPES'; import T from '../constants/ACTION_TYPES';
import { makeActionCreator } from '../utils/actions';
//import root from '../utils/root'; import { persistUserData } from "../utils/sessionStorage";
import { entityReceived } from './entities';
import { apiSignIn } from '../utils/api';
export const emailSignInFormUpdate = makeActionCreator(T.AUTH.SIGN_IN_FORM_UPDATE, 'key', 'value'); export const emailSignInFormUpdate = makeActionCreator(T.AUTH.SIGN_IN_FORM_UPDATE, 'key', 'value');
export const emailSignInStart = makeActionCreator(T.AUTH.SIGN_IN_START); export const emailSignInStart = makeActionCreator(T.AUTH.SIGN_IN_START);

View File

@@ -1,48 +1,34 @@
/** /**
* Created by andrew on 11/03/16. * Created by andrew on 11/03/16.
*/ */
import { import { push } from 'redux-router';
getEmailSignUpUrl import T from '../constants/ACTION_TYPES';
} from "../utils/sessionStorage"; import { makeActionCreator } from '../utils/actions';
import { entityReceived } from './entities';
import { storeCurrentEndpointKey } from "./configure";
//import { parseResponse } from "../utils/handleFetchResponse";
import { apiSignUp } from "../utils/api"; import { apiSignUp } from "../utils/api";
import { emailSignInFormUpdate } from './signIn'; import { emailSignInFormUpdate } from './signIn';
import { push } from 'redux-router';
import T from '../constants/ACTION_TYPES'; export const emailSignUpFormUpdate = makeActionCreator(T.AUTH.SIGN_UP_FORM_UPDATE, 'key', 'value');
export const emailSignUpStart = makeActionCreator(T.AUTH.SIGN_UP_START);
export const emailSignUpComplete = makeActionCreator(T.AUTH.SIGN_UP_COMPLETE, 'user');
export const emailSignUpError = makeActionCreator(T.AUTH.SIGN_UP_ERROR, 'error');
export function emailSignUpFormUpdate(key, value) {
return { type: T.AUTH.SIGN_UP_FORM_UPDATE, key, value };
}
export function emailSignUpStart() {
return { type: T.AUTH.SIGN_UP_START };
}
export function emailSignUpComplete(user) {
return { type: T.AUTH.SIGN_UP_COMPLETE, user };
}
export function emailSignUpError(errors) {
return { type: T.AUTH.SIGN_UP_ERROR, errors };
}
export function emailSignUp(body) { export function emailSignUp(body) {
return dispatch => { return dispatch => {
dispatch(emailSignUpStart()); dispatch(emailSignUpStart());
return apiSignUp(body) return apiSignUp(body)
.then(({data}) => { .then(({ data }) => {
dispatch(emailSignUpComplete(data)); dispatch(emailSignUpComplete(data));
const { email } = body; const { email } = body;
dispatch(emailSignInFormUpdate('email', email)); dispatch(emailSignInFormUpdate('email', email));
dispatch(push('/signin')); dispatch(push('/signin'));
}) })
.catch(({errors}) => dispatch(emailSignUpError(errors))); .catch(({ errors }) => {
dispatch(emailSignUpError({
errors
}))
});
}; };
} }

View File

@@ -1,7 +0,0 @@
import redirector from './redirector'
import renderer from './renderer'
export default [
redirector,
renderer,
]

View File

@@ -1,20 +0,0 @@
import * as navigation from '../actions/navigation'
import ROUTES from '../constants/ROUTES'
export default function redirector(state, dispatch) {
const {name, options} = state.navigation.location || {}
const currentURI = window.location.hash.substr(1)
const canonicalURI = name && ROUTES.generate(name, options)
if (canonicalURI && canonicalURI !== currentURI) {
// If the URL entered includes extra `/` characters, or otherwise
// differs from the canonical URL, navigate the user to the
// canonical URL (which will result in `complete` being called again)
dispatch(navigation.start(name, options))
}
else if (name == 'root') {
// If we've hit the root location, redirect the user to the main page
dispatch(navigation.start('documentList'))
}
}

View File

@@ -1,18 +0,0 @@
import React from 'react'
import ReactDOM from 'react-dom'
import Application from '../App'
// Store a reference to our application's root DOM node to prevent repeating
// this on every state update
const APP_NODE = document.getElementById('react-app')
export default function renderer(state, dispatch) {
// Don't re-render if we're in the process of navigating to a new page
if (!state.navigation.transitioning) {
ReactDOM.render(
<Application state={state} dispatch={dispatch} />,
APP_NODE
)
}
}

View File

@@ -1,6 +1,10 @@
import { TODO_DEFINE, defineActionType } from '../utils/defineActionTypes' import { TODO_DEFINE, defineActionType } from '../utils/defineActionTypes'
export default defineActionType({ export default defineActionType({
LOCATION: {
ENTER: TODO_DEFINE
},
/* /*
* View model * View model
*/ */

View File

@@ -24,24 +24,7 @@ import { emailSignInFormUpdate, emailSignIn } from "../../actions/signIn";
{...this.props.inputProps.password} /> {...this.props.inputProps.password} />
*/ */
class EmailSignInForm extends React.Component { export class EmailSignInForm extends React.Component {
static propTypes = {
endpoint: PropTypes.string,
inputProps: PropTypes.shape({
email: PropTypes.object,
password: PropTypes.object,
submit: PropTypes.object
})
};
static defaultProps = {
inputProps: {
email: {},
password: {},
submit: {}
}
};
handleInput (key, val) { handleInput (key, val) {
this.props.dispatch(emailSignInFormUpdate(key, val)); this.props.dispatch(emailSignInFormUpdate(key, val));
@@ -49,7 +32,8 @@ class EmailSignInForm extends React.Component {
handleSubmit (event) { handleSubmit (event) {
event.preventDefault(); event.preventDefault();
let formData = { ...this.props.auth.signIn.form };
const formData = read(this.props.auth, 'signIn.form');
this.props.dispatch(emailSignIn(formData)); this.props.dispatch(emailSignIn(formData));
} }
@@ -62,10 +46,8 @@ class EmailSignInForm extends React.Component {
); );
//const error = read(this.props.auth, 'signIn.errors.email', null); //const error = read(this.props.auth, 'signIn.errors.email', null);
//debugger;
const formErrors = read(this.props.auth, 'signIn.errors.errors', ''); const formErrors = read(this.props.auth, 'signIn.errors.errors', '');
return ( return (
<form className='redux-auth email-sign-in-form clearfix' <form className='redux-auth email-sign-in-form clearfix'
onSubmit={this.handleSubmit.bind(this)}> onSubmit={this.handleSubmit.bind(this)}>
@@ -75,7 +57,7 @@ class EmailSignInForm extends React.Component {
}}> }}>
<AuxErrorLabel <AuxErrorLabel
label="Form:" label="Form:"
errors={formErrors.length ? [formErrors] : [] } errors={ formErrors.length ? [ formErrors ] : [] }
/> />
</div> </div>
@@ -119,4 +101,21 @@ class EmailSignInForm extends React.Component {
} }
} }
export default connect(({app}) => ({auth: app.auth}))(EmailSignInForm); EmailSignInForm.propTypes = {
endpoint: PropTypes.string,
inputProps: PropTypes.shape({
email: PropTypes.object,
password: PropTypes.object,
submit: PropTypes.object
})
};
EmailSignInForm.defaultProps = {
inputProps: {
email: {},
password: {},
submit: {}
}
};
// export default connect(({app}) => ({auth: app.auth}))(EmailSignInForm);

View File

@@ -2,31 +2,19 @@
* Created by andrew on 15/02/16. * Created by andrew on 15/02/16.
*/ */
import React, {PropTypes} from "react"; import React, {PropTypes} from "react";
//import auth from "redux-auth"; import { connect } from "react-redux";
import { Glyphicon } from "react-bootstrap";
import Input from "./Input"; import Input from "./Input";
import ButtonLoader from "./ButtonLoader"; import ButtonLoader from "./ButtonLoader";
//import { emailSignUpFormUpdate, emailSignUp } from "redux-auth";
import IndexPanel from "./../../components/partials/IndexPanel"; import IndexPanel from "./../../components/partials/IndexPanel";
import AuxErrorLabel from './AuxErrorLabel';
import { customerInfoMap } from '../../entities/formToPayloadMappers'; import { customerInfoMap } from '../../entities/formToPayloadMappers';
import read from '../../utils/readProp'; import read from '../../utils/readProp';
import { emailSignUpFormUpdate, emailSignUp } from '../../actions/signUp';
import { Glyphicon } from "react-bootstrap";
import { connect } from "react-redux";
import {emailSignUpFormUpdate, emailSignUp} from '../../actions/signUp';
class EmailSignUpForm extends React.Component { class EmailSignUpForm extends React.Component {
getEndpoint () {
return (
this.props.endpoint ||
this.props.auth.getIn(["configure", "currentEndpointKey"]) ||
this.props.auth.getIn(["configure", "defaultEndpointKey"])
);
}
handleInput (key, val) { handleInput (key, val) {
this.props.dispatch(emailSignUpFormUpdate(key, val)); this.props.dispatch(emailSignUpFormUpdate(key, val));
} }
@@ -34,7 +22,7 @@ class EmailSignUpForm extends React.Component {
handleSubmit (event) { handleSubmit (event) {
event.preventDefault(); event.preventDefault();
let formData = { ...this.props.auth.signUp.form }; const formData = read(this.props.auth, 'signUp.form');
this.props.dispatch(emailSignUp(customerInfoMap(formData))); this.props.dispatch(emailSignUp(customerInfoMap(formData)));
} }
@@ -45,10 +33,21 @@ class EmailSignUpForm extends React.Component {
this.props.auth.signUp.loading this.props.auth.signUp.loading
); );
const formErrors = read(this.props.auth, 'signUp.errors.errors', '');
return ( return (
<form className='redux-auth email-sign-up-form clearfix' <form className='redux-auth email-sign-up-form clearfix'
onSubmit={this.handleSubmit.bind(this)}> onSubmit={this.handleSubmit.bind(this)}>
<div className="form-group" style={{
display: formErrors ? 'block' : 'none'
}}>
<AuxErrorLabel
label="Form:"
errors={ formErrors.length ? [ formErrors ] : [] }
/>
</div>
<IndexPanel header="basic"> <IndexPanel header="basic">
<Input type="text" <Input type="text"

View File

@@ -1,41 +0,0 @@
import { createStore, applyMiddleware } from 'redux'
import reduxThunk from 'redux-thunk'
import reduxMulti from 'redux-multi'
import { batchedSubscribe } from 'redux-batched-subscribe'
import * as navigation from './actions/navigation'
import actors from './actors'
import rootReducer from './reducers';
import { blocked } from './utils/blockedExecution';
// Add middleware to allow our action creators to return functions and arrays
const createStoreWithMiddleware = applyMiddleware(
reduxThunk,
reduxMulti
)(createStore);
// Ensure our listeners are only called once, even when one of the above
// middleware call the underlying store's `dispatch` multiple times
const createStoreWithBatching = batchedSubscribe(
fn => fn()
)(createStoreWithMiddleware);
// Create a store with our application reducer
const store = createStoreWithBatching(rootReducer)
// Handle changes to our store with a list of actor functions, but ensure
// that the actor sequence cannot be started by a dispatch from an actor
store.subscribe(blocked(() => {
for (let actor of actors) {
actor(store.getState(), store.dispatch)
}
}));
// Dispatch navigation events when the URL's hash changes, and when the
// application loads
function onHashChange() {
store.dispatch(navigation.complete())
}
window.addEventListener('hashchange', onHashChange, false);
onHashChange();

View File

@@ -4,9 +4,29 @@
import T from '../../constants/ACTION_TYPES'; import T from '../../constants/ACTION_TYPES';
import createFormReducer from '../createFormReducer'; import createFormReducer from '../createFormReducer';
export const signInReducer = createFormReducer([ const internalSignInReducer = createFormReducer([
T.AUTH.SIGN_IN_START, T.AUTH.SIGN_IN_START,
T.AUTH.SIGN_IN_COMPLETE, T.AUTH.SIGN_IN_COMPLETE,
T.AUTH.SIGN_IN_ERROR, T.AUTH.SIGN_IN_ERROR,
T.AUTH.SIGN_IN_FORM_UPDATE T.AUTH.SIGN_IN_FORM_UPDATE
]); ]);
export const signInReducer = (state, action) => {
switch (action.type) {
case T.LOCATION.ENTER: {
const { location } = action;
const { pathname } = location;
if (pathname == '/signin') {
return internalSignInReducer(state, {
type: T.AUTH.SIGN_IN_ERROR,
error: null
});
}
return state;
}
default: {
return internalSignInReducer(state, action);
}
}
};

View File

@@ -3,10 +3,9 @@
*/ */
export function makeActionCreator(type, ...argNames) { export function makeActionCreator(type, ...argNames) {
return function(...args) { return function(...args) {
const action = { type }; return argNames.reduce((action, arg, index) => {
argNames.forEach((arg, index) => { action[arg] = args[index];
action[argNames[index]] = args[index] return action;
}); }, { type });
return action;
}; };
} }

View File

@@ -2,28 +2,24 @@
* Created by andrew on 12/02/16. * Created by andrew on 12/02/16.
*/ */
import React from "react"; import React from "react";
//import { PageHeader } from "react-bootstrap";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { PageHeader, OverlayTrigger, Tooltip, Grid, Col, Row, Nav, NavItem, ButtonGroup, Button, Table } from "react-bootstrap"; import { PageHeader, OverlayTrigger, Tooltip, Grid, Col, Row, Nav, NavItem, ButtonGroup, Button, Table } from "react-bootstrap";
import * as BS from "react-bootstrap"; import * as BS from "react-bootstrap";
import Spinner from "react-loader"; // import Spinner from "react-loader";
import Select from "react-select"; import Select from "react-select";
import Input from "../controls/bootstrap/Input"; import Input from "../controls/bootstrap/Input";
import { Money, moneyText } from '../components/Money'; import { Money, moneyText } from '../components/Money';
import { TransfersTable } from '../components/TransfersTable'; import { TransfersTable } from '../components/TransfersTable';
import { Link, IndexLink} from "react-router"; import { Link, IndexLink } from "react-router";
import IndexPanel from "./../components/partials/IndexPanel"; import IndexPanel from "./../components/partials/IndexPanel";
import * as Modals from './modals'; import * as Modals from './modals';
import * as A from '../actions/entities'; import * as A from '../actions/entities';
import read from '../utils/readProp'; import read from '../utils/readProp';
import { blocked } from '../utils/blockedExecution'; import { blocked } from '../utils/blockedExecution';
const resetModals = { const resetModals = {
showAccountModal: false, showAccountModal: false,
unsaved: false unsaved: false
@@ -162,7 +158,10 @@ export class Account extends React.Component {
if (!account) { if (!account) {
if (errors.length) { if (errors.length) {
return (<h2>Error loading specified account</h2>); return (<div>
<h2>Error loading specified account</h2>
<div>Return <Link to="/">Home</Link> to pick another</div>
</div>);
} else { } else {
return spinnerResult; return spinnerResult;
} }

View File

@@ -4,27 +4,21 @@
import React from "react"; import React from "react";
import { PageHeader } from "react-bootstrap"; import { PageHeader } from "react-bootstrap";
import { connect } from "react-redux"; import { connect } from "react-redux";
//import ButtonLoader from "./ButtonLoader";
import * as BS from "react-bootstrap"; import * as BS from "react-bootstrap";
//import ButtonLoader from "../controls/bootstrap/ButtonLoader"; import { pushState } from "redux-router";
import { EmailSignInForm } from "../controls/bootstrap/EmailSignInForm";
import read from '../utils/readProp';
import {pushState} from "redux-router";
//export {bootstrap, materialUi} from "./views";
// bootstrap theme
//import { EmailSignInForm } from "redux-auth/bootstrap-theme";
import EmailSignInForm from "../controls/bootstrap/EmailSignInForm";
export class SignIn extends React.Component { export class SignIn extends React.Component {
checkRedirect(props) { checkRedirect(props) {
if (props.auth.user.isSignedIn) {
props.dispatch(pushState(null, props.location.query.next)); const isSignedIn = read(props.auth, 'user.isSignedIn');
if (isSignedIn) {
const nextLocation = read(props.location, 'query.next');
props.dispatch(pushState(null, nextLocation));
//// redirect to login and add next param so we can redirect again after login //// redirect to login and add next param so we can redirect again after login
//const redirectAfterLogin = this.props.location.pathname; //const redirectAfterLogin = this.props.location.pathname;
//this.props.dispatch(pushState(null, `/signin?next=${redirectAfterLogin}`)); //this.props.dispatch(pushState(null, `/signin?next=${redirectAfterLogin}`));
@@ -40,16 +34,6 @@ export class SignIn extends React.Component {
} }
render () { render () {
const signInProps = {
inputProps: {
password: {
className: 'hide hidden',
style: { display: 'none' },
value: null,
disabled: true
}
}
};
return ( return (
<BS.Well> <BS.Well>

View File

@@ -34,14 +34,10 @@ export class SignUp extends React.Component {
render () { render () {
return ( return (
<div> <BS.Well>
<PageHeader> <BS.PageHeader>Register</BS.PageHeader>
Register <EmailSignUpForm />
</PageHeader> </BS.Well>
<BS.Well>
<EmailSignUpForm />
</BS.Well>
</div>
); );
} }

View File

@@ -140,7 +140,7 @@ export class Add3rdPartyAccountModal extends React.Component {
options={read(this.props.data, 'accountsLookup.options', [])} options={read(this.props.data, 'accountsLookup.options', [])}
onChange={this.handleInput.bind(this, 'account')} /> onChange={this.handleInput.bind(this, 'account')} />
<AuxErrorLabel <AuxErrorLabel
label="Owner:" label="Account:"
errors={read(this.props.data, 'errors.account', [])} errors={read(this.props.data, 'errors.account', [])}
/> />
</div> </div>