diff --git a/js-frontend/src/actions/entities.js b/js-frontend/src/actions/entities.js
index 37182a1..2778392 100644
--- a/js-frontend/src/actions/entities.js
+++ b/js-frontend/src/actions/entities.js
@@ -13,17 +13,15 @@ export const accountsListRequested = makeActionCreator(T.ACCOUNTS.LIST_START);
export const accountsListReceived = makeActionCreator(T.ACCOUNTS.LIST_COMPLETE, 'payload');
export const accountsListError = makeActionCreator(T.ACCOUNTS.LIST_ERROR, 'error');
-//export const accountsRefListRequested = makeActionCreator(T.ACCOUNTS.LIST_REF_START, 'id');
export const accountsRefListReceived = makeActionCreator(T.ACCOUNTS.LIST_REF_COMPLETE, 'payload');
-//export const accountsRefListError = makeActionCreator(T.ACCOUNTS.LIST_REF_ERROR, 'id');
export const accountCreateStart = makeActionCreator(T.ACCOUNTS.CREATE_START);
-export const accountCreateComplete = makeActionCreator(T.ACCOUNTS.CREATE_COMPLETE, 'accountId');
+export const accountCreateComplete = makeActionCreator(T.ACCOUNTS.CREATE_COMPLETE, 'payload');
export const accountCreateError = makeActionCreator(T.ACCOUNTS.CREATE_ERROR, 'error');
export const accountCreateFormUpdate = makeActionCreator(T.ACCOUNTS.CREATE_FORM_UPDATE, 'key', 'value');
-export const accountRefCreateStart = makeActionCreator(T.ACCOUNTS.CREATE_REF_START, 'data');
-export const accountRefCreateComplete = makeActionCreator(T.ACCOUNTS.CREATE_REF_COMPLETE, 'data');
+export const accountRefCreateStart = makeActionCreator(T.ACCOUNTS.CREATE_REF_START);
+export const accountRefCreateComplete = makeActionCreator(T.ACCOUNTS.CREATE_REF_COMPLETE, 'payload');
export const accountRefCreateError = makeActionCreator(T.ACCOUNTS.CREATE_REF_ERROR, 'error');
export const accountRefCreateFormUpdate = makeActionCreator(T.ACCOUNTS.CREATE_REF_FORM_UPDATE, 'key', 'value');
@@ -66,6 +64,26 @@ export function accountCreate(customerId, payload) {
};
}
+export function accountRefCreate(customerId, payload) {
+ return dispatch => {
+ dispatch(accountRefCreateStart());
+ return api.apiCreateRefAccount(customerId, payload)
+ .then(({ id }) => {
+ dispatch(accountRefCreateComplete({
+ ...payload,
+ id
+ }));
+ dispatch(entityReceived(id, payload));
+ return dispatch(authenticate(true));
+ })
+ .catch(err => {
+ debugger;
+ dispatch(accountRefCreateError(err));
+ return Promise.resolve({ error: err });
+ })
+ };
+}
+
@@ -151,7 +169,7 @@ export const createRefOwnerLookup = lookup => {
return { options: arr };
})
.catch(err => {
- dispatch(createRefOwnerLookupComplete(null));
+ dispatch(createRefOwnerLookupComplete([]));
return { options: [] };
});
};
@@ -160,10 +178,18 @@ export const createRefOwnerLookup = lookup => {
export const createRefAccountLookup = customerId => {
return dispatch => {
dispatch(createRefAccountLookupStart());
- return api.apiRetrieveUser(customerId)
+ return api.apiRetrieveAccounts(customerId)
.then(data => {
- debugger;
+ const arr = data.map(({ accountId, title }) => ({
+ value: accountId,
+ label: title
+ }));
+ dispatch(createRefAccountLookupComplete(arr));
+ return { options: arr };
+ })
+ .catch(err => {
dispatch(createRefAccountLookupComplete([]));
+ return { options: [] };
});
};
};
diff --git a/js-frontend/src/actions/signIn.js b/js-frontend/src/actions/signIn.js
index e4916ce..ab44d24 100644
--- a/js-frontend/src/actions/signIn.js
+++ b/js-frontend/src/actions/signIn.js
@@ -38,9 +38,7 @@ export function emailSignIn(body) {
return dispatch => {
// save previous endpoint key in case of failure
//var prevEndpointKey = getCurrentEndpointKey();
-
- const endpointKey = 'default';
-
+
// necessary for fetch to recognize the response as an api request
//setCurrentEndpointKey(endpointKey);
//var currentEndpointKey = getCurrentEndpointKey();
diff --git a/js-frontend/src/actions/signUp.js b/js-frontend/src/actions/signUp.js
index b78e72a..bd3a7f4 100644
--- a/js-frontend/src/actions/signUp.js
+++ b/js-frontend/src/actions/signUp.js
@@ -38,7 +38,9 @@ export function emailSignUp(body) {
.then(({data}) => {
dispatch(emailSignUpComplete(data));
const { email } = body;
- return dispatch(emailSignIn({ email }));
+ return new Promise((rs, rj) => {
+ dispatch(emailSignIn({ email })).then(rs).catch(rj);
+ });
})
.catch(({errors}) => dispatch(emailSignUpError(errors)));
diff --git a/js-frontend/src/components/DocumentForm.jsx b/js-frontend/src/components/DocumentForm.jsx
deleted file mode 100644
index 8255bf4..0000000
--- a/js-frontend/src/components/DocumentForm.jsx
+++ /dev/null
@@ -1,75 +0,0 @@
-import './DocumentForm.less'
-
-import React, {PropTypes} from 'react'
-import * as actions from '../actions/documentView'
-import { pacomoTransformer } from '../utils/pacomo'
-
-
-function updater(original, prop, fn) {
- return e => fn(Object.assign({}, original, {[prop]: e.target.value}))
-}
-
-function preventDefault(fn) {
- return e => {
- e.preventDefault()
- fn && fn(e)
- }
-}
-
-const errorMap = (error, i) =>
{error}
-
-const DocumentForm = ({
- data,
- errors,
- onUpdate,
- onSubmit,
- onCancel,
-}) =>
-
-
-DocumentForm.propTypes = {
- data: PropTypes.object.isRequired,
- errors: PropTypes.object,
- onUpdate: PropTypes.func.isRequired,
- onSubmit: PropTypes.func,
- onCancel: PropTypes.func.isRequired,
-}
-
-export default pacomoTransformer(DocumentForm)
diff --git a/js-frontend/src/components/DocumentForm.less b/js-frontend/src/components/DocumentForm.less
deleted file mode 100644
index 50de7f4..0000000
--- a/js-frontend/src/components/DocumentForm.less
+++ /dev/null
@@ -1,25 +0,0 @@
-.app-DocumentForm {
- width: 100%;
- padding: 5px;
-
- &-errors {
- list-style: none;
- padding: 0;
- margin: 0;
- }
- &-error {
- color: red;
- margin-bottom: 5px;
- }
-
- &-title,
- &-content {
- display: block;
- width: 100%;
- margin-bottom: 5px;
- }
-
- &-cancel {
- margin-right: 5px;
- }
-}
diff --git a/js-frontend/src/components/DocumentList.jsx b/js-frontend/src/components/DocumentList.jsx
deleted file mode 100644
index b091e98..0000000
--- a/js-frontend/src/components/DocumentList.jsx
+++ /dev/null
@@ -1,71 +0,0 @@
-import './DocumentList.less'
-
-import React, {PropTypes} from 'react'
-import * as actions from '../actions/documentListView'
-import { pacomoTransformer } from '../utils/pacomo'
-import Link from './Link'
-
-
-function mapValue(fn) {
- return e => fn(e.target.value)
-}
-
-const DocumentList = ({
- id: activeId,
- query,
- documents,
- onChangeQuery,
-}) =>
-
-
-
- {documents.map(([id, data]) =>
- -
-
- {data.title}
-
-
- )}
- -
-
- Add Document
-
-
-
-
-
-DocumentList.propTypes = {
- id: PropTypes.string,
- query: PropTypes.string,
- documents: PropTypes.array.isRequired,
- onChangeQuery: PropTypes.func.isRequired,
-}
-
-export default pacomoTransformer(DocumentList)
diff --git a/js-frontend/src/components/DocumentList.less b/js-frontend/src/components/DocumentList.less
deleted file mode 100644
index 94000bd..0000000
--- a/js-frontend/src/components/DocumentList.less
+++ /dev/null
@@ -1,33 +0,0 @@
-.app-DocumentList {
- width: 100%;
-
- &-header {
- width: 100%;
- padding: 5px;
- }
-
- &-query {
- width: 100%;
- }
-
- &-list {
- list-style: none;
- margin: 0;
- padding: 0;
- }
-
- &-document-item-active,
- &-add-item-active {
- background-color: #f0f0f0;
- }
-
- &-document-link,
- &-add-link {
- display: block;
- padding: 5px;
-
- &:hover {
- background-color: #f8f8f8;
- }
- }
-}
diff --git a/js-frontend/src/controls/bootstrap/AuxErrorLabel.js b/js-frontend/src/controls/bootstrap/AuxErrorLabel.js
new file mode 100644
index 0000000..2f76629
--- /dev/null
+++ b/js-frontend/src/controls/bootstrap/AuxErrorLabel.js
@@ -0,0 +1,53 @@
+/**
+ * Created by andrew on 15/02/16.
+ */
+import React, { PropTypes } from "react";
+import { Glyphicon } from "react-bootstrap";
+
+
+class AuxErrorLabel extends React.Component {
+
+ static propTypes = {
+ label: PropTypes.string,
+ errors: PropTypes.array
+ };
+
+ static defaultProps = {
+ label: '',
+ errors: []
+ };
+
+//
+ render () {
+ const { errors } = this.props;
+
+ if (errors.length) {
+ return (
+
+ { errors.map((err, i) => {
+ return (
+
+
+ {this.props.label} {err}
+
+ );
+ })}
+
+ );
+ } else {
+ return ;
+ }
+ }
+}
+
+export default AuxErrorLabel;
diff --git a/js-frontend/src/reducers/data/bookmarkAccount.js b/js-frontend/src/reducers/data/bookmarkAccount.js
index 9e4b145..9832829 100644
--- a/js-frontend/src/reducers/data/bookmarkAccount.js
+++ b/js-frontend/src/reducers/data/bookmarkAccount.js
@@ -85,10 +85,16 @@ export const bookmarkAccount = (state = {...initialState}, action) => {
...state.form,
[key]: value
};
+
+ const nextErrors = {
+ ...state.errors,
+ [key]: null
+ };
return {
...state,
accountsDisabled: nextAccountsDisabled,
- form: nextForm
+ form: nextForm,
+ errors: nextErrors
};
}
case T.ACCOUNTS.CREATE_REF_OWNER_LOOKUP_START:
diff --git a/js-frontend/src/utils/api.js b/js-frontend/src/utils/api.js
index dbb441c..86217fc 100644
--- a/js-frontend/src/utils/api.js
+++ b/js-frontend/src/utils/api.js
@@ -71,6 +71,23 @@ export function apiCreateAccount(customerId, {
}).then(parseResponse);
}
+export function apiCreateRefAccount(customerId, {
+ owner, account: accountId, title, description }) {
+
+ return fetch(`${getCustomersUrl()}/${customerId}/toaccounts`, {
+ headers: {
+ "Accept": "application/json",
+ "Content-Type": "application/json"
+ },
+ method: "post",
+ body: root.JSON.stringify({
+ owner,
+ id: accountId,
+ title,
+ description })
+ }).then(parseResponse);
+}
+
export function apiMakeTransfer(fromAccountId, {
account, amount, description }) {
@@ -146,7 +163,7 @@ export function apiRetrieveUsers(email) {
}
export function apiRetrieveUser(customerId) {
- return fetch(`${getCustomersUrl()}?${makeQuery({ customerId })}`, {
+ return fetch(`${getCustomersUrl()}/${ customerId }`, {
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
diff --git a/js-frontend/src/views/MyAccounts.js b/js-frontend/src/views/MyAccounts.js
index 2106a12..6672891 100644
--- a/js-frontend/src/views/MyAccounts.js
+++ b/js-frontend/src/views/MyAccounts.js
@@ -67,8 +67,20 @@ class MyAccounts extends React.Component {
});
}
- create3rdPartyAccountModalConfirmed() {
+ create3rdPartyAccountModalConfirmed(payload) {
+ const {
+ id: customerId
+ } = this.props.auth.user.attributes;
+ this.props.dispatch(A.accountRefCreate(customerId, payload))
+ .then(() => {
+ this.close.bind(this);
+ return this.props.dispatch(A.fetchOwnAccounts(customerId));
+ })
+ .catch(err => {
+ debugger;
+ this.props.dispatch(A.accountRefCreateError(err));
+ });
}
remove3rdPartyAccountModal(accountId, evt) {
diff --git a/js-frontend/src/views/SignUp.js b/js-frontend/src/views/SignUp.js
index 76b421e..6c79dd4 100644
--- a/js-frontend/src/views/SignUp.js
+++ b/js-frontend/src/views/SignUp.js
@@ -4,6 +4,9 @@
import React from "react";
//import { PageHeader } from "react-bootstrap";
import { connect } from "react-redux";
+import { pushState } from 'redux-router';
+import read from '../utils/readProp';
+
import { PageHeader, OverlayTrigger, Tooltip, Row, ButtonGroup, Table } from "react-bootstrap";
import * as BS from "react-bootstrap";
import { Link, IndexLink} from "react-router";
@@ -13,6 +16,22 @@ import EmailSignUpForm from "../controls/bootstrap/EmailSignUpForm";
export class SignUp extends React.Component {
+ checkRedirect(props) {
+ if (props.isAuthenticated) {
+ // redirect to login and add next param so we can redirect again after login
+ // const redirectAfterLogin = props.location.pathname;
+ props.dispatch(pushState(null, `/`));
+ }
+ }
+
+ componentWillMount() {
+ this.checkRedirect(this.props);
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.checkRedirect(nextProps);
+ }
+
render () {
return (
@@ -27,4 +46,9 @@ export class SignUp extends React.Component {
}
}
-export default connect(({routes}) => ({routes}))(SignUp);
\ No newline at end of file
+export default connect(({
+ routes,
+ app
+}) => ({routes,
+ isAuthenticated: read(app, 'auth.user.isSignedIn', false)
+}))(SignUp);
\ No newline at end of file
diff --git a/js-frontend/src/views/modals/Add3rdPartyAccountModal.js b/js-frontend/src/views/modals/Add3rdPartyAccountModal.js
index cedf216..f9024a7 100644
--- a/js-frontend/src/views/modals/Add3rdPartyAccountModal.js
+++ b/js-frontend/src/views/modals/Add3rdPartyAccountModal.js
@@ -2,9 +2,11 @@
* Created by andrew on 20/02/16.
*/
import React from "react";
-import { PageHeader, OverlayTrigger, Modal, Tooltip, Grid, Col, Row, Nav, NavItem, ButtonGroup, Button, Table } from "react-bootstrap";
+// import { PageHeader, OverlayTrigger, Modal, Tooltip, Grid, Col, Row, Nav, NavItem, ButtonGroup, Button, Table } from "react-bootstrap";
import * as BS from "react-bootstrap";
+import ButtonLoader from "../../controls/bootstrap/ButtonLoader";
import Input from "../../controls/bootstrap/Input";
+import AuxErrorLabel from "../../controls/bootstrap/AuxErrorLabel";
import read from '../../utils/readProp';
import { Link, IndexLink} from "react-router";
@@ -13,21 +15,66 @@ import Select from "react-select";
import * as A from '../../actions/entities';
+const formValidation = (payload) => ['owner', 'account', 'title', 'description'].reduce((memo, prop) => {
+ let result = [];
+ const value = (payload[prop] || '').replace(/(^\s+)|(\s+$)/g, '');
+
+ switch (prop) {
+ case 'owner':
+ case 'account':
+ case 'title':
+ if (/^$/.test(value)) {
+ result.push('required');
+ }
+ }
+
+ switch (prop) {
+ case 'description':
+ if (value.length > 400) {
+ result.push('need to less than 400 symbols long');
+ }
+ }
+
+ if (result.length) {
+ memo[prop] = result;
+ memo.hasErrors = true;
+ }
+ return memo;
+}, {});
+
+
export class Add3rdPartyAccountModal extends React.Component {
handleInput(key, value) {
this.props.dispatch(A.accountRefCreateFormUpdate(key, value));
switch(key) {
case 'owner':
- debugger;
if (value) {
this.props.dispatch(A.createRefAccountLookup(value));
} else {
- this.props.dispatch(A.createRefAccountLookupComplete({}));
+ this.props.dispatch(A.createRefAccountLookupComplete([]));
}
}
}
+ handleSubmit(evt) {
+ evt.preventDefault();
+
+ const payload = { ...this.props.data.form };
+
+ const validationErrors = formValidation(payload);
+ if (validationErrors.hasErrors) {
+ this.props.dispatch(A.accountRefCreateError(validationErrors));
+ return;
+ }
+
+ const { action } = this.props;
+
+ if (action) {
+ action(payload);
+ }
+ }
+
getOwnersOptions(input) {
if (!input) {
return Promise.resolve({ options: [] });
@@ -36,47 +83,59 @@ export class Add3rdPartyAccountModal extends React.Component {
}
render() {
+ const disabled = read(this.props.data, 'loading', false);
- const disabled = false;
-
- const ownersLookup = this.props.data.ownersLookup;
- const ownersOptions = ownersLookup.options;
- const ownersValue = ownersLookup.value;
- const ownersLoading = ownersLookup.loading;
-
-
- // onInputChange={this.ownerTypeIn.bind(this)}
- // value={ownersValue}
-
+ const ownersLoading = read(this.props.data, 'ownersLookup.loading', false);
return (
-
-
- Add 3rd Party Account
-
-
+
+
+ Add 3rd Party Account
+
+
-
-
-
-
-
-
+
+
+ Cancel
+ }
+ disabled={disabled}
+ onClick={this.handleSubmit.bind(this)}>
+ Add
+
+
+
);
}
}