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">
<!-- 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>
<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>
<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.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(){
(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)
@@ -27,5 +27,5 @@
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>

View File

@@ -76,7 +76,7 @@
/******/ script.charset = 'utf-8';
/******/ 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);
/******/ }
/******/ };
@@ -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 {
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:
/***/ function(module, exports, __webpack_require__) {
__webpack_require__(614);
module.exports = __webpack_require__(618);
__webpack_require__(611);
module.exports = __webpack_require__(615);
/***/ },
/***/ 614:
/***/ 611:
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/***/ 618:
/***/ 615:
/***/ function(module, exports) {
// 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 createLogger from 'redux-logger';
import { Route, IndexRoute, Link, IndexLink } from "react-router";
import { RouterContext } from 'react-router';
import { ReduxRouter} from "redux-router";
import { createHistory, createHashHistory, createMemoryHistory } from "history";
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 { configure as endpointsConfig } from './actions/configure';
import { visitLocation } from './actions/navigate';
import { requireAuthentication } from './components/AuthComponent';
import Container from "./components/partials/Container";
import MyAccounts from "./views/MyAccounts";
@@ -25,7 +27,8 @@ import SignUp from "./views/SignUp";
class App extends React.Component {
render() {
return (<Container>
return (
<Container>
{this.props.children}
</Container>);
}
@@ -38,12 +41,19 @@ export function initialize({cookies, isServer, currentLocation, userAgent} = {})
router: routerStateReducer
});
let dispatch = null;
const onEnter = (nextState) => {
const { location } = nextState;
dispatch && dispatch(visitLocation(location));
};
const routes = (
<Route path="/" component={App}>
<IndexRoute component={requireAuthentication(MyAccounts)} />
<Route path="signin" component={SignIn} />
<Route path="register" component={SignUp} />
<Route path="account/:accountId" component={requireAuthentication(Account)} />
<Route path="/" component={ App }>
<IndexRoute component={ requireAuthentication(MyAccounts) } />
<Route path="signin" component={ SignIn } onEnter={ onEnter } />
<Route path="register" component={ SignUp } />
<Route path="account/:accountId" component={ requireAuthentication(Account) } />
</Route>
);
@@ -60,6 +70,7 @@ export function initialize({cookies, isServer, currentLocation, userAgent} = {})
})
)(createStore)(reducer);
dispatch = store.dispatch;
/**
* 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) {
debugger;
return resp.data;
},
handleAccountUpdateResponse: function(resp) {
debugger;
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.
*/
import * as C from "../utils/constants";
import {
authenticate,
authenticateStart,
authenticateComplete,
authenticateError
} from "./authenticate";
import {
retrieveData,
} from "../utils/sessionStorage";
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 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.
*/
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 root from '../utils/root';
import { makeActionCreator } from '../utils/actions';
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 emailSignInStart = makeActionCreator(T.AUTH.SIGN_IN_START);

View File

@@ -1,48 +1,34 @@
/**
* Created by andrew on 11/03/16.
*/
import {
getEmailSignUpUrl
} from "../utils/sessionStorage";
import { entityReceived } from './entities';
import { storeCurrentEndpointKey } from "./configure";
//import { parseResponse } from "../utils/handleFetchResponse";
import { push } from 'redux-router';
import T from '../constants/ACTION_TYPES';
import { makeActionCreator } from '../utils/actions';
import { apiSignUp } from "../utils/api";
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) {
return dispatch => {
dispatch(emailSignUpStart());
return apiSignUp(body)
.then(({data}) => {
.then(({ data }) => {
dispatch(emailSignUpComplete(data));
const { email } = body;
dispatch(emailSignInFormUpdate('email', email));
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'
export default defineActionType({
LOCATION: {
ENTER: TODO_DEFINE
},
/*
* View model
*/

View File

@@ -24,24 +24,7 @@ import { emailSignInFormUpdate, emailSignIn } from "../../actions/signIn";
{...this.props.inputProps.password} />
*/
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: {}
}
};
export class EmailSignInForm extends React.Component {
handleInput (key, val) {
this.props.dispatch(emailSignInFormUpdate(key, val));
@@ -49,7 +32,8 @@ class EmailSignInForm extends React.Component {
handleSubmit (event) {
event.preventDefault();
let formData = { ...this.props.auth.signIn.form };
const formData = read(this.props.auth, 'signIn.form');
this.props.dispatch(emailSignIn(formData));
}
@@ -62,10 +46,8 @@ class EmailSignInForm extends React.Component {
);
//const error = read(this.props.auth, 'signIn.errors.email', null);
//debugger;
const formErrors = read(this.props.auth, 'signIn.errors.errors', '');
return (
<form className='redux-auth email-sign-in-form clearfix'
onSubmit={this.handleSubmit.bind(this)}>
@@ -75,7 +57,7 @@ class EmailSignInForm extends React.Component {
}}>
<AuxErrorLabel
label="Form:"
errors={formErrors.length ? [formErrors] : [] }
errors={ formErrors.length ? [ formErrors ] : [] }
/>
</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.
*/
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 ButtonLoader from "./ButtonLoader";
//import { emailSignUpFormUpdate, emailSignUp } from "redux-auth";
import IndexPanel from "./../../components/partials/IndexPanel";
import AuxErrorLabel from './AuxErrorLabel';
import { customerInfoMap } from '../../entities/formToPayloadMappers';
import read from '../../utils/readProp';
import { Glyphicon } from "react-bootstrap";
import { connect } from "react-redux";
import {emailSignUpFormUpdate, emailSignUp} from '../../actions/signUp';
import { emailSignUpFormUpdate, emailSignUp } from '../../actions/signUp';
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) {
this.props.dispatch(emailSignUpFormUpdate(key, val));
}
@@ -34,7 +22,7 @@ class EmailSignUpForm extends React.Component {
handleSubmit (event) {
event.preventDefault();
let formData = { ...this.props.auth.signUp.form };
const formData = read(this.props.auth, 'signUp.form');
this.props.dispatch(emailSignUp(customerInfoMap(formData)));
}
@@ -45,10 +33,21 @@ class EmailSignUpForm extends React.Component {
this.props.auth.signUp.loading
);
const formErrors = read(this.props.auth, 'signUp.errors.errors', '');
return (
<form className='redux-auth email-sign-up-form clearfix'
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">
<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 createFormReducer from '../createFormReducer';
export const signInReducer = createFormReducer([
const internalSignInReducer = createFormReducer([
T.AUTH.SIGN_IN_START,
T.AUTH.SIGN_IN_COMPLETE,
T.AUTH.SIGN_IN_ERROR,
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) {
return function(...args) {
const action = { type };
argNames.forEach((arg, index) => {
action[argNames[index]] = args[index]
});
return action;
return argNames.reduce((action, arg, index) => {
action[arg] = args[index];
return action;
}, { type });
};
}

View File

@@ -2,28 +2,24 @@
* Created by andrew on 12/02/16.
*/
import React from "react";
//import { PageHeader } from "react-bootstrap";
import { connect } from "react-redux";
import { PageHeader, OverlayTrigger, Tooltip, Grid, Col, Row, Nav, NavItem, ButtonGroup, Button, Table } 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 Input from "../controls/bootstrap/Input";
import { Money, moneyText } from '../components/Money';
import { TransfersTable } from '../components/TransfersTable';
import { Link, IndexLink} from "react-router";
import { Link, IndexLink } from "react-router";
import IndexPanel from "./../components/partials/IndexPanel";
import * as Modals from './modals';
import * as A from '../actions/entities';
import read from '../utils/readProp';
import { blocked } from '../utils/blockedExecution';
const resetModals = {
showAccountModal: false,
unsaved: false
@@ -162,7 +158,10 @@ export class Account extends React.Component {
if (!account) {
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 {
return spinnerResult;
}

View File

@@ -4,27 +4,21 @@
import React from "react";
import { PageHeader } from "react-bootstrap";
import { connect } from "react-redux";
//import ButtonLoader from "./ButtonLoader";
import * as BS from "react-bootstrap";
//import ButtonLoader from "../controls/bootstrap/ButtonLoader";
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";
import { pushState } from "redux-router";
import { EmailSignInForm } from "../controls/bootstrap/EmailSignInForm";
import read from '../utils/readProp';
export class SignIn extends React.Component {
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
//const redirectAfterLogin = this.props.location.pathname;
//this.props.dispatch(pushState(null, `/signin?next=${redirectAfterLogin}`));
@@ -40,16 +34,6 @@ export class SignIn extends React.Component {
}
render () {
const signInProps = {
inputProps: {
password: {
className: 'hide hidden',
style: { display: 'none' },
value: null,
disabled: true
}
}
};
return (
<BS.Well>

View File

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

View File

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