Account creation dialog, tidy

This commit is contained in:
Andrew Revinsky (DART)
2016-03-16 00:29:28 +03:00
parent c11f1b1a64
commit ba5077685e
27 changed files with 584 additions and 333 deletions

View File

@@ -17,7 +17,8 @@ import { ReduxRouter} from "redux-router";
//import { configure as reduxAuthConfigure, authStateReducer } from "redux-auth";
//import { authStateReducer } from "redux-auth";
import authStateReducer from "./reducers/auth";
import authStateReducer from './reducers/auth';
import appStateReducer from './reducers/data'
import { configure as reduxAuthConfigure } from './actions/configure';
//import { AuthGlobals } from "redux-auth/bootstrap-theme";
@@ -52,9 +53,8 @@ export function initialize({cookies, isServer, currentLocation, userAgent} = {})
const reducer = combineReducers({
auth: authStateReducer,
app: appStateReducer,
router: routerStateReducer
//demoButtons,
//demoUi
});
const routes = (

View File

@@ -35,7 +35,7 @@ export function authenticateError(errors) {
}
export function authenticate() {
export function authenticate(forceReread) {
return dispatch => {
dispatch(authenticateStart());
@@ -51,7 +51,7 @@ export function authenticate() {
const savedUser = retrieveUserData();
if (savedUser) {
if (savedUser && !forceReread) {
return rs(savedUser);
}

View File

@@ -1,9 +0,0 @@
import T from '../constants/ACTION_TYPES'
export function updateQuery(query) {
return {
type: T.DOCUMENT_LIST_VIEW.SET_QUERY,
query,
}
}

View File

@@ -1,60 +0,0 @@
import uuid from '../utils/uuid'
import documentValidator from '../validators/documentValidator'
import T from '../constants/ACTION_TYPES'
import * as navigation from './navigation'
export function updateChanges(id, data) {
return [
{
type: T.DOCUMENT_VIEW.UPDATE_DATA,
id,
data,
},
{
type: T.DOCUMENT_VIEW.REMOVE_STALE_ERRORS,
id,
errors: documentValidator(data),
},
]
}
export function clearChanges(id) {
return {
type: T.DOCUMENT_VIEW.CLEAR,
id,
}
}
export function cancelChanges(id) {
return [
clearChanges(id),
navigation.start('documentList'),
]
}
export function submitChanges(id) {
return (dispatch, getState) => {
const { view } = getState()
const data = view.document.unsavedChanges[id]
const errors = documentValidator(data)
if (errors) {
dispatch({
type: T.DOCUMENT_VIEW.SET_ERRORS,
id,
errors,
})
}
else {
const newId = id == 'new' ? uuid() : id
dispatch(navigation.start('documentEdit', {id: newId}))
dispatch(clearChanges(id))
dispatch({
type: T.DOCUMENT_DATA.UPDATE,
id: newId,
data,
})
}
}
}

View File

@@ -2,7 +2,62 @@
* Created by andrew on 27/02/16.
*/
import T from '../constants/ACTION_TYPES';
import { makeActionCreator } from '../utils/actions';
import * as api from '../utils/api';
import { authenticate } from './authenticate';
export function entityReceived(id, entity) {
return { type: T.ENTITIES.RECEIVED };
export const entityRequested = makeActionCreator(T.ENTITIES.REQUESTED, 'id');
export const entityReceived = makeActionCreator(T.ENTITIES.RECEIVED, 'id', 'entity');
export const accountsListRequested = makeActionCreator(T.ACCOUNTS.LIST_START);
export const accountsListReceived = makeActionCreator(T.ACCOUNTS.LIST_COMPLETE, 'data');
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, 'data');
//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 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 accountRefCreateError = makeActionCreator(T.ACCOUNTS.CREATE_REF_ERROR, 'error');
export const accountRefCreateFormUpdate = makeActionCreator(T.ACCOUNTS.CREATE_REF_FORM_UPDATE, 'key', 'value');
export function accountsList(userId) {
return dispatch => {
dispatch(accountsListRequested());
return api.apiRetrieveAccounts(userId)
.then(list => {
dispatch(accountsListReceived(list));
})
.catch(err => {
dispatch(accountsListError(err));
return Promise.resolve({ error: err });
})
};
}
export function accountCreate(customerId, payload) {
return dispatch => {
dispatch(accountCreateStart());
return api.apiCreateAccount(customerId, payload)
.then(({ accountId }) => {
dispatch(accountCreateComplete({
id: accountId,
...payload
}));
dispatch(entityReceived(accountId, payload));
return authenticate(true);
})
.catch(err => {
dispatch(accountCreateError(err));
return Promise.resolve({ error: err });
})
};
}

View File

@@ -24,34 +24,26 @@ export default defineActionTypes({
`,
ENTITIES: `
REQUESTED
RECEIVED
`,
DOCUMENT_LIST_VIEW: `
SET_QUERY
RECEIVED_LIST
`,
DOCUMENT_VIEW: `
UPDATE_DATA
SET_ERRORS
REMOVE_STALE_ERRORS
CLEAR
`,
/*
* Data model
*/
DOCUMENT_DATA: `
UPDATE
`,
/*
* Application
*/
NAVIGATION: `
START
COMPLETE
ACCOUNTS: `
LIST_START
LIST_COMPLETE
LIST_ERROR
LIST_REF_START
LIST_REF_COMPLETE
LIST_REF_ERROR
CREATE_START
CREATE_COMPLETE
CREATE_ERROR
CREATE_FORM_UPDATE
CREATE_REF_START
CREATE_REF_COMPLETE
CREATE_REF_ERROR
CREATE_REF_FORM_UPDATE
`
})

View File

@@ -2,16 +2,13 @@
* Created by andrew on 15/02/16.
*/
import React, {PropTypes} from "react";
//import auth from "redux-auth";
import * as BS from "react-bootstrap";
import { connect } from "react-redux";
import read from '../../utils/readProp';
import * as BS from "react-bootstrap";
import Input from "./Input";
import ButtonLoader from "./ButtonLoader";
//import { emailSignInFormUpdate, emailSignIn } from "redux-auth";
import { Glyphicon } from "react-bootstrap";
import { connect } from "react-redux";
import read from '../../utils/readProp';
import { emailSignInFormUpdate, emailSignIn } from "../../actions/signIn";
@@ -83,7 +80,7 @@ class EmailSignInForm extends React.Component {
<ButtonLoader loading={read(this.props.auth, 'signIn.loading', false)}
type="submit"
icon={<Glyphicon glyph="log-in" />}
icon={<BS.Glyphicon glyph="log-in" />}
className='email-sign-in-submit pull-right'
disabled={disabled}
onClick={this.handleSubmit.bind(this)}

View File

@@ -78,7 +78,7 @@ class EmailSignUpForm extends React.Component {
className="email-sign-up-email"
disabled={disabled}
value={read(this.props.auth, 'signUp.form.fname', '')}
errors={read(this.props.auth, 'signUp.errors.fname', {})}
errors={read(this.props.auth, 'signUp.errors.fname', [])}
onChange={this.handleInput.bind(this, "fname")}
{...this.props.inputProps.fname} />
@@ -88,7 +88,7 @@ class EmailSignUpForm extends React.Component {
className="email-sign-up-email"
disabled={disabled}
value={read(this.props.auth, 'signUp.form.lname', '')}
errors={read(this.props.auth, 'signUp.errors.lname', {})}
errors={read(this.props.auth, 'signUp.errors.lname', [])}
onChange={this.handleInput.bind(this, "lname")}
{...this.props.inputProps.lname} />
@@ -98,7 +98,7 @@ class EmailSignUpForm extends React.Component {
className="email-sign-up-email"
disabled={disabled}
value={read(this.props.auth, 'signUp.form.email', '')}
errors={read(this.props.auth, 'signUp.errors.email', {})}
errors={read(this.props.auth, 'signUp.errors.email', [])}
onChange={this.handleInput.bind(this, "email")}
{...this.props.inputProps.email} />
@@ -110,9 +110,10 @@ class EmailSignUpForm extends React.Component {
label="SSN"
placeholder="SSN"
className="email-sign-up-email"
bsSize="small"
disabled={disabled}
value={read(this.props.auth, 'signUp.form.ssn', '')}
errors={read(this.props.auth, 'signUp.errors.ssn', {})}
errors={read(this.props.auth, 'signUp.errors.ssn', [])}
onChange={this.handleInput.bind(this, "ssn")}
{...this.props.inputProps.ssn} />
@@ -120,9 +121,10 @@ class EmailSignUpForm extends React.Component {
label="Phone"
placeholder="Phone"
className="email-sign-up-email"
bsSize="small"
disabled={disabled}
value={read(this.props.auth, 'signUp.form.phoneNumber', '')}
errors={read(this.props.auth, 'signUp.errors.phoneNumber', {})}
errors={read(this.props.auth, 'signUp.errors.phoneNumber', [])}
onChange={this.handleInput.bind(this, "phoneNumber")}
{...this.props.inputProps.phoneNumber} />
@@ -130,9 +132,10 @@ class EmailSignUpForm extends React.Component {
label="Address 1"
placeholder="Address 1"
className="email-sign-up-email"
bsSize="small"
disabled={disabled}
value={read(this.props.auth, 'signUp.form.address1', '')}
errors={read(this.props.auth, 'signUp.errors.address1', {})}
errors={read(this.props.auth, 'signUp.errors.address1', [])}
onChange={this.handleInput.bind(this, "address1")}
{...this.props.inputProps.address1} />
@@ -140,9 +143,10 @@ class EmailSignUpForm extends React.Component {
label="Address 2"
placeholder="Address 2"
className="email-sign-up-email"
bsSize="small"
disabled={disabled}
value={read(this.props.auth, 'signUp.form.address2', '')}
errors={read(this.props.auth, 'signUp.errors.address2', {})}
errors={read(this.props.auth, 'signUp.errors.address2', [])}
onChange={this.handleInput.bind(this, "address2")}
{...this.props.inputProps.address2} />
@@ -150,6 +154,7 @@ class EmailSignUpForm extends React.Component {
label="City"
placeholder="City"
className="email-sign-up-email"
bsSize="small"
disabled={disabled}
value={read(this.props.auth, 'signUp.form.city', '')}
errors={read(this.props.auth, 'signUp.errors.city', {})}
@@ -160,9 +165,10 @@ class EmailSignUpForm extends React.Component {
label="State"
placeholder="State"
className="email-sign-up-email"
bsSize="small"
disabled={disabled}
value={read(this.props.auth, 'signUp.form.state', '')}
errors={read(this.props.auth, 'signUp.errors.state', {})}
errors={read(this.props.auth, 'signUp.errors.state', [])}
onChange={this.handleInput.bind(this, "state")}
{...this.props.inputProps.state} />
@@ -170,9 +176,10 @@ class EmailSignUpForm extends React.Component {
label="ZIP"
placeholder="ZIP"
className="email-sign-up-email"
bsSize="small"
disabled={disabled}
value={read(this.props.auth, 'signUp.form.zip', '')}
errors={read(this.props.auth, 'signUp.errors.zip', {})}
errors={read(this.props.auth, 'signUp.errors.zip', [])}
onChange={this.handleInput.bind(this, "zip")}
{...this.props.inputProps.zip} />

View File

@@ -8,11 +8,11 @@ class AuthInput extends React.Component {
static propTypes = {
label: PropTypes.string,
value: PropTypes.string,
errors: PropTypes.object
errors: PropTypes.array
};
static defaultProps = {
label: "",
label: '',
value: null,
errors: []
};
@@ -22,7 +22,8 @@ class AuthInput extends React.Component {
}
renderErrorList () {
if (this.props.errors.size) {
if (this.props.errors.length) {
return (
<div className='auth-error-message has-error'>
{this.props.errors.map((err, i) => {

View File

@@ -33,6 +33,10 @@ export const signUpReducer = (state = { ...signUpInitialState, form: {...signUpI
const { key, value } = action;
return {
...state,
errors: {
...(state.errors || {}),
[key]: []
},
form: {
...state.form,
[key]: value

View File

@@ -0,0 +1,128 @@
/**
* Created by andrew on 15/03/16.
*/
/**
* Created by andrew on 15/03/16.
*/
import T from '../../constants/ACTION_TYPES';
import { combineReducers } from 'redux';
const initialState = {
own: [],
other: [],
create: {
form: {},
loading: false,
errors: {}
}
};
const nodeInitialState = {
loading: false,
data: {}
};
const ownAccountsReducer = (state = [], action ) => {
switch (action.type) {
default: return state;
}
};
const otherAccountsReducer = (state = [], action ) => {
switch (action.type) {
default: return state;
}
};
const createAccountInitialState = {
form: {},
loading: false,
errors: {}
};
const createAccountReducer = (state = { ...createAccountInitialState }, action ) => {
switch(action.type) {
case T.ACCOUNTS.CREATE_START: {
return {
...state,
loading: true
};
}
case T.ACCOUNTS.CREATE_COMPLETE: {
return {
...createAccountInitialState
};
}
case T.ACCOUNTS.CREATE_ERROR: {
const { error = {} } = action;
return {
...state,
loading: false,
errors: {
...error
}
};
}
case T.ACCOUNTS.CREATE_FORM_UPDATE: {
const { key, value } = action;
return {
...state,
form: {
...state.form,
[key]: value
},
errors: {
...state.errors,
[key]: []
}
};
}
default:
return state;
}
};
export const accounts = combineReducers({
own: ownAccountsReducer,
other: otherAccountsReducer,
create: createAccountReducer
});
//export const accounts = (state = {...initialState}, action) => {
// switch(action.type) {
// case T.ACCOUNTS.LIST_START:
// case T.ACCOUNTS.LIST_COMPLETE:
// case T.ACCOUNTS.LIST_ERROR:
//
// //case T.ACCOUNTS.LIST_REF_START:
// case T.AUTH.AUTHENTICATE_COMPLETE:
// case T.AUTH.SIGN_IN_COMPLETE: {
// const { user } = action;
// const { toAccounts = [] } = user;
// return accounts(state, {
// type: T.ACCOUNTS.LIST_REF_COMPLETE, data: toAccounts
// });
// }
//
// case T.ACCOUNTS.LIST_REF_COMPLETE: {
// const { data = [] } = action;
// return {
// ...state,
// other: [
// ...data
// ]
// };
// }
// //case T.ACCOUNTS.LIST_REF_ERROR:
//
//
//
// case T.ACCOUNTS.CREATE_REF_START:
// case T.ACCOUNTS.CREATE_REF_COMPLETE:
// case T.ACCOUNTS.CREATE_REF_ERROR:
// case T.ACCOUNTS.CREATE_REF_FORM_UPDATE:
//
// default:
// return state;
// }
//};

View File

@@ -1,13 +0,0 @@
import typeReducers from '../../utils/typeReducers'
import ACTION_TYPES from '../../constants/ACTION_TYPES'
const defaultState = {}
export default typeReducers(ACTION_TYPES.DOCUMENT_DATA, defaultState, {
UPDATE: (state, {id, data}) => ({
...state,
[id]: { ...state[id], ...data },
})
})

View File

@@ -0,0 +1,43 @@
/**
* Created by andrew on 15/03/16.
*/
import T from '../../constants/ACTION_TYPES';
const initialState = {
};
const nodeInitialState = {
loading: false,
data: {}
};
export const entities = (state = {...initialState}, action) => {
switch(action.type) {
case T.ENTITIES.REQUESTED: {
const { id } = action;
return {
...state,
[id]: {
...nodeInitialState,
loading: true
}
}
}
case T.ENTITIES.RECEIVED: {
const { id, entity = {} } = action;
return {
...state,
[id]: {
...(state[id] || nodeInitialState),
loading: false,
data: {
...entity
}
}
}
}
case T.ENTITIES.RECEIVED_LIST:
default:
return state;
}
};

View File

@@ -0,0 +1,19 @@
/**
* Created by andrew on 15/03/16.
*/
/**
* Created by andrew on 25/02/16.
*/
import { combineReducers } from 'redux';
import { accounts } from './accounts';
import { transfers } from './transfers';
import { entities } from './entities';
const dataReducer = combineReducers({
accounts,
transfers,
entities
});
export default dataReducer;

View File

@@ -0,0 +1,46 @@
/**
* Created by andrew on 15/03/16.
*/
/**
* Created by andrew on 15/03/16.
*/
import T from '../../constants/ACTION_TYPES';
const initialState = {
};
const nodeInitialState = {
loading: false,
data: {}
};
export const transfers = (state = {...initialState}, action) => {
switch(action.type) {
case T.ENTITIES.REQUESTED: {
const { id } = action;
return {
...state,
[id]: {
...nodeInitialState,
loading: true
}
}
}
case T.ENTITIES.RECEIVED: {
const { id, entity = {} } = action;
return {
...state,
[id]: {
...(state[id] || nodeInitialState),
loading: false,
data: {
...entity
}
}
}
}
case T.ENTITIES.RECEIVED_LIST:
default:
return state;
}
};

View File

@@ -1,21 +0,0 @@
import { combineReducers } from 'redux'
import navigation from './navigationReducer'
import documentListView from './view/documentListViewReducer'
import documentView from './view/documentViewReducer'
import documentData from './data/documentDataReducer'
export default combineReducers({
navigation,
view: combineReducers({
documentList: documentListView,
document: documentView,
}),
data: combineReducers({
document: documentData,
}),
})

View File

@@ -1,19 +0,0 @@
import typeReducers from '../utils/typeReducers'
import ACTION_TYPES from '../constants/ACTION_TYPES'
const defaultState = {
transitioning: true,
location: null,
}
export default typeReducers(ACTION_TYPES.NAVIGATION, defaultState, {
START: () => ({
transitioning: true,
}),
COMPLETE: (state, {location}) => ({
transitioning: false,
location,
}),
})

View File

@@ -1,10 +0,0 @@
import typeReducers from '../../utils/typeReducers'
import ACTION_TYPES from '../../constants/ACTION_TYPES'
const defaultState = ''
export default typeReducers(ACTION_TYPES.DOCUMENT_LIST_VIEW, defaultState, {
SET_QUERY: (state, {query}) => query,
})

View File

@@ -1,53 +0,0 @@
import pick from 'object-pick'
import typeReducers from '../../utils/typeReducers'
import compact from '../../utils/compact'
import ACTION_TYPES from '../../constants/ACTION_TYPES'
const defaultState = {
unsavedChanges: {},
saveErrors: {},
}
export default typeReducers(ACTION_TYPES.DOCUMENT_VIEW, defaultState, {
// Update the current document data
UPDATE_DATA: (state, {id, data}) => ({
...state,
unsavedChanges: {
...state.unsavedChanges,
[id]: { ...state.unsavedChanges[id], ...data },
},
}),
// If there are fields marked as invalid which are now valid,
// mark them as valid
REMOVE_STALE_ERRORS: (state, {id, errors}) => ({
...state,
saveErrors: {
...state.saveErrors,
[id]: compact(pick(state.saveErrors[id], Object.keys(errors || {}))),
},
}),
// Set the errors to the passed in object
SET_ERRORS: (state, {id, errors}) => ({
...state,
saveErrors: {
...state.saveErrors,
[id]: errors
},
}),
// Remove errors/data for an id
CLEAR: (state, {id}) => ({
unsavedChanges: {
...state.unsavedChanges,
[id]: null,
},
saveErrors: {
...state.saveErrors,
[id]: null,
},
}),
})

View File

@@ -1,17 +0,0 @@
/**
* Created by andrew on 25/02/16.
*/
//import * as A from "../actions/auth";
import T from '../constants/ACTION_TYPES';
import {
authenticateStart,
authenticateComplete,
authenticateError
} from '../actions/auth';
export function configure(endpoint = {}, settings = {}) {
return dispatch => {
dispatch(authenticateStart());
};
};

View File

@@ -0,0 +1,12 @@
/**
* Created by andrew on 15/03/16.
*/
export function makeActionCreator(type, ...argNames) {
return function(...args) {
const action = { type };
argNames.forEach((arg, index) => {
action[argNames[index]] = args[index]
});
return action;
};
}

View File

@@ -45,7 +45,8 @@ export function apiGetCurrentUser() {
}).then(parseResponse);
}
export function apiCreateAccount(customerId, title, initialBalance) {
export function apiCreateAccount(customerId, {
title, balance: initialBalance, description }) {
//{
//"accountId": "0000015377cf131b-a250093f26850000"
//}
@@ -56,7 +57,24 @@ export function apiCreateAccount(customerId, title, initialBalance) {
"Content-Type": "application/json"
},
method: "post",
body: root.JSON.stringify({ customerId, title, initialBalance })
body: root.JSON.stringify({
customerId,
title,
initialBalance,
description })
}).then(parseResponse);
}
export function apiRetrieveAccounts(customerId) {
return fetch(getAccountsUrl(), {
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
},
method: "get",
body: {
customerId
}
}).then(parseResponse);
}
@@ -81,4 +99,5 @@ export function apiRetrieveUsers(search) {
email: search
}
}).then(parseResponse);
}
}

View File

@@ -115,20 +115,20 @@ export function getSessionEndpoint (k) {
// return `${getApiUrl(endpointKey)}${getSessionEndpoint(endpointKey).signOutPath}`
//}
export function getEmailSignInUrl (endpointKey) {
return `${getSessionEndpoint(endpointKey).emailSignInPath}`
export function getEmailSignInUrl () {
return `${getSessionEndpoint().emailSignInPath}`
}
export function getEmailSignUpUrl (endpointKey) {
return `${getSessionEndpoint(endpointKey).emailRegistrationPath}`
export function getEmailSignUpUrl () {
return `${getSessionEndpoint().emailRegistrationPath}`
}
export function getCurrentUserUrl (endpointKey) {
return `${getSessionEndpoint(endpointKey).currentUserPath}`
export function getCurrentUserUrl () {
return `${getSessionEndpoint().currentUserPath}`
}
export function getAccountsUrl (endpointKey) {
return `${getSessionEndpoint(endpointKey).accountsPath}`
export function getAccountsUrl () {
return `${getSessionEndpoint().accountsPath}`
}
/**

View File

@@ -1,10 +0,0 @@
import compact from '../utils/compact'
export default function documentValidator(data) {
return compact({
titleExists:
!data.title &&
"You must specify a title for your document",
})
}

View File

@@ -10,6 +10,8 @@ import Select from "react-select";
import * as Modals from './modals';
import IndexPanel from "./../components/partials/IndexPanel";
import * as A from '../actions/entities';
const resetModals = {
showAccountModal: false,
@@ -23,13 +25,6 @@ class MyAccounts extends React.Component {
super(...args);
this.state = { ...resetModals };
}
updateTheme (theme) {
//this.props.dispatch(updateDemoTheme(theme));
}
updateEndpoint (endpoint) {
//this.props.dispatch(updateDemoEndpoint(endpoint));
}
createAccountModal() {
this.setState({
@@ -37,7 +32,15 @@ class MyAccounts extends React.Component {
});
}
createAccountModalConfirmed() {
createAccountModalConfirmed(evt, payload) {
const {
id: customerId
} = this.props.auth.user.attributes;
this.props.dispatch(A.accountCreate(customerId, payload))
.then(this.close.bind(this));
}
@@ -52,9 +55,10 @@ class MyAccounts extends React.Component {
}
remove3rdPartyAccountModal() {
remove3rdPartyAccountModal(evt, evtKey) {
const account = null;
debugger;
const account = evtKey;
this.setState({
accountToRemove: account,
showDeleteAccountModal: true
@@ -78,6 +82,7 @@ class MyAccounts extends React.Component {
//</Tooltip>);
const user = this.props.auth.user.attributes;
const {
id: customerId,
email = '',
ssn = '',
name = {},
@@ -86,10 +91,8 @@ class MyAccounts extends React.Component {
toAccounts
} = user;
const {
firstName = '',
lastName = ''
} = name;
const firstName = name.firstName || '';
const lastName = name.lastName || '';
const {
city,
@@ -99,11 +102,25 @@ class MyAccounts extends React.Component {
zipCode
} = address;
const { showAccountModal, show3rdPartyAccountModal, showDeleteAccountModal } = this.state;
const { accountToRemove = null } = this.state;
const refAccountsData = this.props.app.accounts.other || [];
const refAccounts = refAccountsData.map((item, idx) => (
<tr key={`ref_${idx}`}>
<td><a href="#">${item.title}</a>{
(item.description) ? [
(<br />),
<span>{ item.description }</span>
]: null
}
</td>
<td><Button eventKey={item.id} bsStyle={"link"} onClick={this.remove3rdPartyAccountModal.bind(this)}>remove</Button>
</td>
</tr>
));
return (
<div>
<PageHeader>
@@ -142,7 +159,6 @@ class MyAccounts extends React.Component {
</IndexPanel>
</Row>
<Table>
<thead>
@@ -156,17 +172,14 @@ class MyAccounts extends React.Component {
<td><a href="#">Account Title #1</a></td>
<td>$100.00</td>
</tr>
<tr>
<td><a href="#">Account Title #2</a></td>
<td><Button bsStyle={"link"} onClick={this.remove3rdPartyAccountModal.bind(this)}>remove</Button>
</td>
</tr>
{ refAccounts }
</tbody>
</Table>
<Modals.NewAccountModal show={showAccountModal}
action={this.createAccountModalConfirmed.bind(this)}
account={ this.props.app.accounts.create }
onHide={this.close.bind(this)}
key={0} />
@@ -244,13 +257,8 @@ class MyAccounts extends React.Component {
</IndexPanel>
*/
export default connect(({auth, demoUi = new Map()}) => {
export default connect(({ auth, app }) => {
return ({
auth,
currentUserUid: auth.user && auth.user.attributes && auth.user.attributes.provider || "none",
currentUserProvider: auth.user && auth.user.attributes && auth.user.attributes.uid || "none",
currentUserEndpoint: "none",
//theme: demoUi.get("theme"),
pageEndpoint: null
auth, app
})
})(MyAccounts);

View File

@@ -6,12 +6,10 @@ import { PageHeader } from "react-bootstrap";
import { connect } from "react-redux";
//import ButtonLoader from "./ButtonLoader";
import { Input } from "react-bootstrap";
import * as BS from "react-bootstrap";
import {pushState} from "redux-router";
import ButtonLoader from "../controls/bootstrap/ButtonLoader";
//export {bootstrap, materialUi} from "./views";

View File

@@ -1,37 +1,171 @@
/**
* 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 { Link, IndexLink} from "react-router";
import React, { PropTypes } from "react";
import { connect } from "react-redux";
import Select from "react-select";
import * as BS from "react-bootstrap";
import Input from "../../controls/bootstrap/Input";
import ButtonLoader from "../../controls/bootstrap/ButtonLoader";
//import { PageHeader, OverlayTrigger, Modal, Tooltip, Grid, Col, Row, Nav, NavItem, ButtonGroup, Button, Table } from "react-bootstrap";
import { Link, IndexLink} from "react-router";
import read from '../../utils/readProp';
import { accountCreateFormUpdate, accountCreateError } from '../../actions/entities';
const formValidation = (payload) => ['title', 'balance', 'description'].reduce((memo, prop) => {
let result = [];
const value = (payload[prop] || '').replace(/(^\s+)|(\s+$)/g, '');
switch (prop) {
case 'title':
case 'balance':
if (/^$/.test(value)) {
result.push('required');
}
}
switch (prop) {
case 'balance':
if (!/\d+/.test(value)) {
result.push('need to be a number');
}
}
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 NewAccountModal extends React.Component {
render() {
return (<Modal show={this.props.show} onHide={this.props.onHide} key={0}>
<Modal.Header closeButton>
<Modal.Title>New Account</Modal.Title>
</Modal.Header>
<Modal.Body>
<form>
Title <br/>
Balance <br/>
Description
</form>
</Modal.Body>
<Modal.Footer>
<Button onClick={this.props.onHide}>Cancel</Button>
<Button bsStyle="primary" onClick={this.props.action}>Create</Button>
</Modal.Footer>
</Modal>);
static propTypes = {
inputProps: PropTypes.shape({
title: PropTypes.object,
balance: PropTypes.object,
description: PropTypes.object,
submit: PropTypes.object
}),
action: PropTypes.func,
account: PropTypes.object.isRequired
};
static defaultProps = {
inputProps: {
title: {},
balance: {},
description: {},
submit: {}
}
};
handleSubmit(event) {
event.preventDefault();
const payload = { ...this.props.account.form };
const validationErrors = formValidation(payload);
if (validationErrors.hasErrors) {
this.props.dispatch(accountCreateError(validationErrors));
return;
}
const { action } = this.props;
if (action) {
action(event, payload);
}
}
handleInput(key, val) {
this.props.dispatch(accountCreateFormUpdate(key, val));
}
render() {
const disabled = (
this.props.account.loading
);
const actionLabel = 'Create';
return (<BS.Modal show={this.props.show} onHide={this.props.onHide} key={0}>
<BS.Modal.Header closeButton>
<BS.Modal.Title>New Account</BS.Modal.Title>
</BS.Modal.Header>
<BS.Modal.Body>
<form className='account-create-form clearfix'
onSubmit={this.handleSubmit.bind(this)}>
<Input type="text"
className="account-create-title"
label="Title"
placeholder="Title"
name="title"
disabled={disabled}
value={read(this.props.account, 'form.title', '')}
errors={read(this.props.account, 'errors.title', [])}
onChange={this.handleInput.bind(this, "title")}
{...this.props.inputProps.title} />
<Input type="text"
className="account-create-balance"
label="Balance"
placeholder="Balance"
name="balance"
addonBefore={
(<BS.Glyphicon glyph="usd" />)
}
addonAfter=".00"
disabled={disabled}
value={read(this.props.account, 'form.balance', '')}
errors={read(this.props.account, 'errors.balance', [])}
onChange={this.handleInput.bind(this, 'balance')}
{...this.props.inputProps.balance} />
<Input type="textarea"
className="account-create-description"
label="Description"
placeholder="Description"
name="description"
disabled={disabled}
value={read(this.props.account, 'form.description', '')}
errors={read(this.props.account, 'errors.description', [])}
onChange={this.handleInput.bind(this, 'description')}
{...this.props.inputProps.description} />
</form>
</BS.Modal.Body>
<BS.Modal.Footer>
<BS.Button onClick={this.props.onHide}>Cancel</BS.Button>
<ButtonLoader loading={read(this.props.account, 'loading', false)}
type="submit"
bsStyle="primary"
icon={<BS.Glyphicon glyph="plus" />}
disabled={disabled}
onClick={this.handleSubmit.bind(this)}
{...this.props.inputProps.submit}>
{actionLabel}
</ButtonLoader>
</BS.Modal.Footer>
</BS.Modal>);
}
// className='account-create-submit pull-right'
}
const mapStateToProps = (state) => ({
//token: state.auth.token,
//userName: state.auth.userName,
//isAuthenticated: state.auth.isAuthenticated
});
const mapStateToProps = ({ }) => ({ });
export default connect(mapStateToProps)(NewAccountModal);