Hook (almost) everything up to Redux

This commit is contained in:
Aaron Lindsay 2016-10-05 13:36:47 -04:00
parent 071b7ff1e3
commit 6257e9193f
27 changed files with 626 additions and 373 deletions

View File

@ -16,13 +16,13 @@ module.exports = React.createClass({
handleAccountChange: function(account) { handleAccountChange: function(account) {
if (this.props.onChange != null && if (this.props.onChange != null &&
account.hasOwnProperty('AccountId') && account.hasOwnProperty('AccountId') &&
(this.props.account_map.hasOwnProperty([account.AccountId]) || (this.props.accounts.hasOwnProperty([account.AccountId]) ||
account.AccountId == -1)) { account.AccountId == -1)) {
this.props.onChange(account) this.props.onChange(account)
} }
}, },
render: function() { render: function() {
var accounts = getAccountDisplayList(this.props.accounts, this.props.includeRoot, this.props.rootName); var accounts = getAccountDisplayList(this.props.accounts, this.props.accountChildren, this.props.includeRoot, this.props.rootName);
var className = ""; var className = "";
if (this.props.className) if (this.props.className)
className = this.props.className; className = this.props.className;

View File

@ -62,7 +62,7 @@ const TransactionRow = React.createClass({
var number = "" var number = ""
var accountName = ""; var accountName = "";
var status = ""; var status = "";
var security = this.props.security_map[this.props.account.SecurityId]; var security = this.props.securities[this.props.account.SecurityId];
if (this.props.transaction.isTransaction()) { if (this.props.transaction.isTransaction()) {
var thisAccountSplit; var thisAccountSplit;
@ -78,9 +78,9 @@ const TransactionRow = React.createClass({
var otherSplit = this.props.transaction.Splits[1]; var otherSplit = this.props.transaction.Splits[1];
if (otherSplit.AccountId == -1) if (otherSplit.AccountId == -1)
var accountName = "Unbalanced " + this.props.security_map[otherSplit.SecurityId].Symbol + " transaction"; var accountName = "Unbalanced " + this.props.securities[otherSplit.SecurityId].Symbol + " transaction";
else else
var accountName = getAccountDisplayName(this.props.account_map[otherSplit.AccountId], this.props.account_map); var accountName = getAccountDisplayName(this.props.accounts[otherSplit.AccountId], this.props.accounts);
} else { } else {
accountName = "--Split Transaction--"; accountName = "--Split Transaction--";
} }
@ -277,12 +277,12 @@ const AddEditTransactionModal = React.createClass({
}, },
handleSubmit: function() { handleSubmit: function() {
var errorString = "" var errorString = ""
var imbalancedSecurityList = this.state.transaction.imbalancedSplitSecurities(this.props.account_map); var imbalancedSecurityList = this.state.transaction.imbalancedSplitSecurities(this.props.accounts);
if (imbalancedSecurityList.length > 0) if (imbalancedSecurityList.length > 0)
errorString = "Transaction must balance" errorString = "Transaction must balance"
for (var i = 0; i < this.state.transaction.Splits.length; i++) { for (var i = 0; i < this.state.transaction.Splits.length; i++) {
var s = this.state.transaction.Splits[i]; var s = this.state.transaction.Splits[i];
if (!(s.AccountId in this.props.account_map)) { if (!(s.AccountId in this.props.accounts)) {
errorString = "All accounts must be valid" errorString = "All accounts must be valid"
} }
} }
@ -312,7 +312,7 @@ const AddEditTransactionModal = React.createClass({
); );
} }
var imbalancedSecurityList = this.state.transaction.imbalancedSplitSecurities(this.props.account_map); var imbalancedSecurityList = this.state.transaction.imbalancedSplitSecurities(this.props.accounts);
var imbalancedSecurityMap = {}; var imbalancedSecurityMap = {};
for (i = 0; i < imbalancedSecurityList.length; i++) for (i = 0; i < imbalancedSecurityList.length; i++)
imbalancedSecurityMap[imbalancedSecurityList[i]] = i; imbalancedSecurityMap[imbalancedSecurityList[i]] = i;
@ -324,11 +324,11 @@ const AddEditTransactionModal = React.createClass({
var security = null; var security = null;
var amountValidation = undefined; var amountValidation = undefined;
var accountValidation = ""; var accountValidation = "";
if (s.AccountId in this.props.account_map) { if (s.AccountId in this.props.accounts) {
security = this.props.security_map[this.props.account_map[s.AccountId].SecurityId]; security = this.props.securities[this.props.accounts[s.AccountId].SecurityId];
} else { } else {
if (s.SecurityId in this.props.security_map) { if (s.SecurityId in this.props.securities) {
security = this.props.security_map[s.SecurityId]; security = this.props.securities[s.SecurityId];
} }
accountValidation = "has-error"; accountValidation = "has-error";
} }
@ -380,7 +380,7 @@ const AddEditTransactionModal = React.createClass({
ref={"memo-"+i} /></Col> ref={"memo-"+i} /></Col>
<Col xs={3}><AccountCombobox <Col xs={3}><AccountCombobox
accounts={this.props.accounts} accounts={this.props.accounts}
account_map={this.props.account_map} accountChildren={this.props.accountChildren}
value={s.AccountId} value={s.AccountId}
includeRoot={false} includeRoot={false}
onChange={updateAccountFn} onChange={updateAccountFn}
@ -569,7 +569,7 @@ const ImportTransactionsModal = React.createClass({
render: function() { render: function() {
var accountNameLabel = "Performing global import:" var accountNameLabel = "Performing global import:"
if (this.props.account != null && this.state.importType != ImportType.Gnucash) if (this.props.account != null && this.state.importType != ImportType.Gnucash)
accountNameLabel = "Importing to '" + getAccountDisplayName(this.props.account, this.props.account_map) + "' account:"; accountNameLabel = "Importing to '" + getAccountDisplayName(this.props.account, this.props.accounts) + "' account:";
// Display the progress bar if an upload/import is in progress // Display the progress bar if an upload/import is in progress
var progressBar = []; var progressBar = [];
@ -684,7 +684,7 @@ module.exports = React.createClass({
newTransaction.Date = new Date(); newTransaction.Date = new Date();
newTransaction.Splits.push(new Split()); newTransaction.Splits.push(new Split());
newTransaction.Splits.push(new Split()); newTransaction.Splits.push(new Split());
newTransaction.Splits[0].AccountId = this.props.selectedAccount.AccountId; newTransaction.Splits[0].AccountId = this.props.accounts[this.props.selectedAccount].AccountId;
this.setState({ this.setState({
editingTransaction: true, editingTransaction: true,
@ -731,7 +731,7 @@ module.exports = React.createClass({
// Keep a talley of the running balance of these transactions // Keep a talley of the running balance of these transactions
for (var j = 0; j < data.Transactions[i].Splits.length; j++) { for (var j = 0; j < data.Transactions[i].Splits.length; j++) {
var split = data.Transactions[i].Splits[j]; var split = data.Transactions[i].Splits[j];
if (this.props.selectedAccount.AccountId == split.AccountId) { if (this.props.accounts[this.props.selectedAccount].AccountId == split.AccountId) {
balance = balance.minus(split.Amount); balance = balance.minus(split.Amount);
} }
} }
@ -758,20 +758,20 @@ module.exports = React.createClass({
if (newpage >= this.state.numPages) if (newpage >= this.state.numPages)
newpage = this.state.numPages-1; newpage = this.state.numPages-1;
if (newpage != this.state.currentPage) { if (newpage != this.state.currentPage) {
if (this.props.selectedAccount != null) { if (this.props.selectedAccount != -1) {
this.getTransactionPage(this.props.selectedAccount, newpage); this.getTransactionPage(this.props.accounts[this.props.selectedAccount], newpage);
} }
this.setState({currentPage: newpage}); this.setState({currentPage: newpage});
} }
}, },
onNewTransaction: function() { onNewTransaction: function() {
this.getTransactionPage(this.props.selectedAccount, this.state.currentPage); this.getTransactionPage(this.props.accounts[this.props.selectedAccount], this.state.currentPage);
}, },
onUpdatedTransaction: function() { onUpdatedTransaction: function() {
this.getTransactionPage(this.props.selectedAccount, this.state.currentPage); this.getTransactionPage(this.props.accounts[this.props.selectedAccount], this.state.currentPage);
}, },
onDeletedTransaction: function() { onDeletedTransaction: function() {
this.getTransactionPage(this.props.selectedAccount, this.state.currentPage); this.getTransactionPage(this.props.accounts[this.props.selectedAccount], this.state.currentPage);
}, },
createNewTransaction: function(transaction) { createNewTransaction: function(transaction) {
$.ajax({ $.ajax({
@ -828,7 +828,7 @@ module.exports = React.createClass({
}, },
handleImportComplete: function() { handleImportComplete: function() {
this.setState({importingTransactions: false}); this.setState({importingTransactions: false});
this.getTransactionPage(this.props.selectedAccount, this.state.currentPage); this.getTransactionPage(this.props.accounts[this.props.selectedAccount], this.state.currentPage);
}, },
handleDeleteTransaction: function(transaction) { handleDeleteTransaction: function(transaction) {
this.setState({ this.setState({
@ -853,16 +853,16 @@ module.exports = React.createClass({
transactions: [], transactions: [],
currentPage: 0 currentPage: 0
}); });
if (nextProps.selectedAccount != null) if (nextProps.selectedAccount != -1)
this.getTransactionPage(nextProps.selectedAccount, 0); this.getTransactionPage(nextProps.accounts[nextProps.selectedAccount], 0);
} }
}, },
render: function() { render: function() {
var name = "Please select an account"; var name = "Please select an account";
register = []; register = [];
if (this.props.selectedAccount != null) { if (this.props.selectedAccount != -1) {
name = this.props.selectedAccount.Name; name = this.props.accounts[this.props.selectedAccount].Name;
var transactionRows = []; var transactionRows = [];
for (var i = 0; i < this.state.transactions.length; i++) { for (var i = 0; i < this.state.transactions.length; i++) {
@ -871,11 +871,9 @@ module.exports = React.createClass({
<TransactionRow <TransactionRow
key={t.TransactionId} key={t.TransactionId}
transaction={t} transaction={t}
account={this.props.selectedAccount} account={this.props.accounts[this.props.selectedAccount]}
accounts={this.props.accounts} accounts={this.props.accounts}
account_map={this.props.account_map}
securities={this.props.securities} securities={this.props.securities}
security_map={this.props.security_map}
onEdit={this.handleEditTransaction}/> onEdit={this.handleEditTransaction}/>
)); ));
} }
@ -901,7 +899,7 @@ module.exports = React.createClass({
); );
} }
var disabled = (this.props.selectedAccount == null) ? true : false; var disabled = (this.props.selectedAccount == -1) ? true : false;
return ( return (
<div className="transactions-container"> <div className="transactions-container">
@ -909,17 +907,15 @@ module.exports = React.createClass({
show={this.state.editingTransaction} show={this.state.editingTransaction}
transaction={this.state.selectedTransaction} transaction={this.state.selectedTransaction}
accounts={this.props.accounts} accounts={this.props.accounts}
account_map={this.props.account_map} accountChildren={this.props.accountChildren}
onCancel={this.handleEditingCancel} onCancel={this.handleEditingCancel}
onSubmit={this.handleUpdateTransaction} onSubmit={this.handleUpdateTransaction}
onDelete={this.handleDeleteTransaction} onDelete={this.handleDeleteTransaction}
securities={this.props.securities} securities={this.props.securities} />
security_map={this.props.security_map}/>
<ImportTransactionsModal <ImportTransactionsModal
show={this.state.importingTransactions} show={this.state.importingTransactions}
account={this.props.selectedAccount} account={this.props.accounts[this.props.selectedAccount]}
accounts={this.props.accounts} accounts={this.props.accounts}
account_map={this.props.account_map}
onCancel={this.handleImportingCancel} onCancel={this.handleImportingCancel}
onSubmit={this.handleImportComplete}/> onSubmit={this.handleImportComplete}/>
<div className="transactions-register-toolbar"> <div className="transactions-register-toolbar">

View File

@ -14,7 +14,6 @@ var Col = ReactBootstrap.Col;
var models = require('./models.js'); var models = require('./models.js');
var User = models.User; var User = models.User;
var Error = models.Error;
module.exports = React.createClass({ module.exports = React.createClass({
displayName: "AccountSettingsModal", displayName: "AccountSettingsModal",
@ -71,7 +70,6 @@ module.exports = React.createClass({
}, },
handleSubmit: function(e) { handleSubmit: function(e) {
var u = new User(); var u = new User();
var error = "";
e.preventDefault(); e.preventDefault();
u.UserId = this.props.user.UserId; u.UserId = this.props.user.UserId;
@ -88,31 +86,8 @@ module.exports = React.createClass({
u.Password = models.BogusPassword; u.Password = models.BogusPassword;
} }
this.handleSaveSettings(u); this.props.onUpdateUser(u);
}, this.props.onSubmit();
handleSaveSettings: function(user) {
$.ajax({
type: "PUT",
dataType: "json",
url: "user/"+user.UserId+"/",
data: {user: user.toJSON()},
success: function(data, status, jqXHR) {
var e = new Error();
e.fromJSON(data);
if (e.isError()) {
this.setState({error: e});
} else {
user.Password = "";
this.props.onSubmit(user);
}
}.bind(this),
error: function(jqXHR, status, error) {
var e = new Error();
e.ErrorId = 5;
e.ErrorString = "Request Failed: " + status + error;
this.setState({error: e});
}.bind(this),
});
}, },
render: function() { render: function() {
return ( return (

View File

@ -119,7 +119,7 @@ const AddEditAccountModal = React.createClass({
<Col xs={10}> <Col xs={10}>
<AccountCombobox <AccountCombobox
accounts={this.props.accounts} accounts={this.props.accounts}
account_map={this.props.account_map} accountChildren={this.props.accountChildren}
value={this.state.parentaccountid} value={this.state.parentaccountid}
rootName={rootName} rootName={rootName}
onChange={this.handleParentChange} onChange={this.handleParentChange}
@ -130,7 +130,7 @@ const AddEditAccountModal = React.createClass({
<Col componentClass={ControlLabel} xs={2}>Security</Col> <Col componentClass={ControlLabel} xs={2}>Security</Col>
<Col xs={10}> <Col xs={10}>
<Combobox <Combobox
data={this.props.securities} data={this.props.security_list}
valueField='SecurityId' valueField='SecurityId'
textField={item => item.Name + " - " + item.Description} textField={item => item.Name + " - " + item.Description}
defaultValue={this.state.security} defaultValue={this.state.security}
@ -188,10 +188,10 @@ const DeleteAccountModal = React.createClass({
this.setState({checked: !this.state.checked}); this.setState({checked: !this.state.checked});
}, },
handleSubmit: function() { handleSubmit: function() {
if (this.props.account_map.hasOwnProperty(this.state.accountid)) { if (this.props.accounts.hasOwnProperty(this.state.accountid)) {
if (this.state.checked) { if (this.state.checked) {
if (this.props.onSubmit != null) if (this.props.onSubmit != null)
this.props.onSubmit(this.props.account_map[this.state.accountid]); this.props.onSubmit(this.props.accounts[this.state.accountid]);
} else { } else {
this.setState({error: "You must confirm you wish to delete this account."}); this.setState({error: "You must confirm you wish to delete this account."});
} }
@ -206,11 +206,11 @@ const DeleteAccountModal = React.createClass({
}, },
render: function() { render: function() {
var checkbox = []; var checkbox = [];
if (this.props.account_map.hasOwnProperty(this.state.accountid)) { if (this.props.accounts.hasOwnProperty(this.state.accountid)) {
var parentAccountId = this.props.account_map[this.state.accountid].ParentAccountId; var parentAccountId = this.props.accounts[this.state.accountid].ParentAccountId;
var parentAccount = "will be deleted and any child accounts will become top-level accounts."; var parentAccount = "will be deleted and any child accounts will become top-level accounts.";
if (parentAccountId != -1) if (parentAccountId != -1)
parentAccount = "and any child accounts will be re-parented to: " + this.props.account_map[parentAccountId].Name; parentAccount = "and any child accounts will be re-parented to: " + this.props.accounts[parentAccountId].Name;
var warningString = "I understand that deleting this account cannot be undone and that all transactions " + parentAccount; var warningString = "I understand that deleting this account cannot be undone and that all transactions " + parentAccount;
checkbox = ( checkbox = (
@ -248,7 +248,7 @@ const DeleteAccountModal = React.createClass({
<AccountCombobox <AccountCombobox
includeRoot={false} includeRoot={false}
accounts={this.props.accounts} accounts={this.props.accounts}
account_map={this.props.account_map} accountChildren={this.props.accountChildren}
value={this.state.accountid} value={this.state.accountid}
onChange={this.handleChange}/> onChange={this.handleChange}/>
</Col> </Col>
@ -285,17 +285,20 @@ const AccountTreeNode = React.createClass({
}, },
render: function() { render: function() {
var glyph = this.state.expanded ? 'minus' : 'plus'; var glyph = this.state.expanded ? 'minus' : 'plus';
var active = (this.props.selectedAccount != null && var active = (this.props.selectedAccount != -1 &&
this.props.account.AccountId == this.props.selectedAccount.AccountId); this.props.account.AccountId == this.props.selectedAccount);
var buttonStyle = active ? "info" : "link"; var buttonStyle = active ? "info" : "link";
var self = this; var self = this;
var children = this.props.account.Children.map(function(account) { var children = this.props.accountChildren[this.props.account.AccountId].map(function(childId) {
var account = self.props.accounts[childId];
return ( return (
<AccountTreeNode <AccountTreeNode
key={account.AccountId} key={account.AccountId}
account={account} account={account}
selectedAccount={self.props.selectedAccount} selectedAccount={self.props.selectedAccount}
accounts={self.props.accounts}
accountChildren={self.props.accountChildren}
onSelect={self.handleChildSelect}/> onSelect={self.handleChildSelect}/>
); );
}); });
@ -334,11 +337,9 @@ const AccountTreeNode = React.createClass({
const AccountTree = React.createClass({ const AccountTree = React.createClass({
getInitialState: function() { getInitialState: function() {
return {selectedAccount: null, return {height: 0};
height: 0};
}, },
handleSelect: function(account) { handleSelect: function(account) {
this.setState({selectedAccount: account});
if (this.props.onSelect != null) { if (this.props.onSelect != null) {
this.props.onSelect(account); this.props.onSelect(account);
} }
@ -356,13 +357,17 @@ const AccountTree = React.createClass({
var accounts = this.props.accounts; var accounts = this.props.accounts;
var children = []; var children = [];
for (var i = 0; i < accounts.length; i++) { for (var accountId in accounts) {
if (accounts[i].isRootAccount()) if (accounts.hasOwnProperty(accountId) &&
accounts[accountId].isRootAccount()) {
children.push((<AccountTreeNode children.push((<AccountTreeNode
key={accounts[i].AccountId} key={accounts[accountId].AccountId}
account={accounts[i]} account={accounts[accountId]}
selectedAccount={this.state.selectedAccount} selectedAccount={this.props.selectedAccount}
accounts={this.props.accounts}
accountChildren={this.props.accountChildren}
onSelect={this.handleSelect}/>)); onSelect={this.handleSelect}/>));
}
} }
var style = {height: this.state.height + "px"}; var style = {height: this.state.height + "px"};
@ -379,7 +384,6 @@ module.exports = React.createClass({
displayName: "AccountsTab", displayName: "AccountsTab",
getInitialState: function() { getInitialState: function() {
return { return {
selectedAccount: null,
creatingNewAccount: false, creatingNewAccount: false,
editingAccount: false, editingAccount: false,
deletingAccount: false deletingAccount: false
@ -416,46 +420,48 @@ module.exports = React.createClass({
handleRemoveAccount: function(account) { handleRemoveAccount: function(account) {
if (this.props.onDeleteAccount != null) if (this.props.onDeleteAccount != null)
this.props.onDeleteAccount(account); this.props.onDeleteAccount(account);
this.setState({deletingAccount: false, this.setState({deletingAccount: false});
selectedAccount: null});
}, },
handleAccountSelected: function(account) { handleAccountSelected: function(account) {
this.setState({selectedAccount: account}); this.props.onSelectAccount(account.AccountId);
}, },
render: function() { render: function() {
var accounts = this.props.accounts; var disabled = (this.props.selectedAccount == -1) ? true : false;
var account_map = this.props.account_map;
var disabled = (this.state.selectedAccount == null) ? true : false; var selectedAccount = null;
if (this.props.accounts.hasOwnProperty(this.props.selectedAccount))
selectedAccount = this.props.accounts[this.props.selectedAccount];
return ( return (
<Grid fluid className="fullheight"><Row className="fullheight"> <Grid fluid className="fullheight"><Row className="fullheight">
<Col xs={2} className="fullheight account-column"> <Col xs={2} className="fullheight account-column">
<AddEditAccountModal <AddEditAccountModal
show={this.state.creatingNewAccount} show={this.state.creatingNewAccount}
initialParentAccount={this.state.selectedAccount} initialParentAccount={selectedAccount}
accounts={this.props.accounts} accounts={this.props.accounts}
account_map={this.props.account_map} accountChildren={this.props.accountChildren}
onCancel={this.handleCreationCancel} onCancel={this.handleCreationCancel}
onSubmit={this.handleCreateAccount} onSubmit={this.handleCreateAccount}
securities={this.props.securities}/> security_list={this.props.security_list}/>
<AddEditAccountModal <AddEditAccountModal
show={this.state.editingAccount} show={this.state.editingAccount}
editAccount={this.state.selectedAccount} editAccount={selectedAccount}
accounts={this.props.accounts} accounts={this.props.accounts}
account_map={this.props.account_map} accountChildren={this.props.accountChildren}
onCancel={this.handleEditingCancel} onCancel={this.handleEditingCancel}
onSubmit={this.handleUpdateAccount} onSubmit={this.handleUpdateAccount}
securities={this.props.securities}/> security_list={this.props.security_list}/>
<DeleteAccountModal <DeleteAccountModal
show={this.state.deletingAccount} show={this.state.deletingAccount}
initialAccount={this.state.selectedAccount} initialAccount={selectedAccount}
accounts={this.props.accounts} accounts={this.props.accounts}
account_map={this.props.account_map} accountChildren={this.props.accountChildren}
onCancel={this.handleDeletionCancel} onCancel={this.handleDeletionCancel}
onSubmit={this.handleRemoveAccount}/> onSubmit={this.handleRemoveAccount}/>
<AccountTree <AccountTree
accounts={accounts} accounts={this.props.accounts}
accountChildren={this.props.accountChildren}
selectedAccount={this.props.selectedAccount}
onSelect={this.handleAccountSelected}/> onSelect={this.handleAccountSelected}/>
<ButtonGroup className="account-buttongroup"> <ButtonGroup className="account-buttongroup">
<Button onClick={this.handleNewAccount} bsStyle="success"> <Button onClick={this.handleNewAccount} bsStyle="success">
@ -469,11 +475,10 @@ module.exports = React.createClass({
</ButtonGroup> </ButtonGroup>
</Col><Col xs={10} className="fullheight transactions-column"> </Col><Col xs={10} className="fullheight transactions-column">
<AccountRegister <AccountRegister
selectedAccount={this.state.selectedAccount} selectedAccount={this.props.selectedAccount}
accounts={this.props.accounts} accounts={this.props.accounts}
account_map={this.props.account_map} accountChildren={this.props.accountChildren}
securities={this.props.securities} securities={this.props.securities} />
security_map={this.props.security_map} />
</Col> </Col>
</Row></Grid> </Row></Grid>
); );

View File

@ -6,35 +6,21 @@ var Tabs = ReactBootstrap.Tabs;
var Tab = ReactBootstrap.Tab; var Tab = ReactBootstrap.Tab;
var Modal = ReactBootstrap.Modal; var Modal = ReactBootstrap.Modal;
var models = require('./models.js'); var TopBarContainer = require('./containers/TopBarContainer');
var User = models.User;
var Session = models.Session;
var Security = models.Security;
var Account = models.Account;
var Error = models.Error;
var TopBar = require('./TopBar.js');
var NewUserForm = require('./NewUserForm.js'); var NewUserForm = require('./NewUserForm.js');
var AccountSettingsModal = require('./AccountSettingsModal.js'); var AccountSettingsModalContainer = require('./containers/AccountSettingsModalContainer');
var AccountsTab = require('./AccountsTab.js'); var AccountsTabContainer = require('./containers/AccountsTabContainer');
module.exports = React.createClass({ module.exports = React.createClass({
displayName: "MoneyGoApp", displayName: "MoneyGoApp",
getInitialState: function() { getInitialState: function() {
return { return {
hash: "home", hash: "home",
session: new Session(),
user: new User(),
accounts: [],
account_map: {},
securities: [],
security_map: {},
error: new Error(),
showAccountSettingsModal: false showAccountSettingsModal: false
}; };
}, },
componentDidMount: function() { componentDidMount: function() {
this.getSession(); this.props.tryResumingSession();
this.handleHashChange(); this.handleHashChange();
if ("onhashchange" in window) { if ("onhashchange" in window) {
window.onhashchange = this.handleHashChange; window.onhashchange = this.handleHashChange;
@ -52,248 +38,34 @@ module.exports = React.createClass({
if (this.state.hash != hash) if (this.state.hash != hash)
this.setState({hash: hash}); this.setState({hash: hash});
}, },
ajaxError: function(jqXHR, status, error) {
var e = new Error();
e.ErrorId = 5;
e.ErrorString = "Request Failed: " + status + error;
this.setState({error: e});
},
getSession: function() {
$.ajax({
type: "GET",
dataType: "json",
url: "session/",
success: function(data, status, jqXHR) {
var e = new Error();
var s = new Session();
e.fromJSON(data);
if (e.isError()) {
if (e.ErrorId != 1 /* Not Signed In*/)
this.setState({error: e});
} else {
s.fromJSON(data);
}
this.setState({session: s});
this.getUser();
this.getAccounts();
this.getSecurities();
}.bind(this),
error: this.ajaxError
});
},
getUser: function() {
if (!this.state.session.isSession())
return;
$.ajax({
type: "GET",
dataType: "json",
url: "user/"+this.state.session.UserId+"/",
success: function(data, status, jqXHR) {
var e = new Error();
var u = new User();
e.fromJSON(data);
if (e.isError()) {
this.setState({error: e});
} else {
u.fromJSON(data);
}
this.setState({user: u});
}.bind(this),
error: this.ajaxError
});
},
getSecurities: function() {
if (!this.state.session.isSession()) {
this.setState({securities: [], security_map: {}});
return;
}
$.ajax({
type: "GET",
dataType: "json",
url: "security/",
success: function(data, status, jqXHR) {
var e = new Error();
var securities = [];
var security_map = {};
e.fromJSON(data);
if (e.isError()) {
this.setState({error: e});
} else {
for (var i = 0; i < data.securities.length; i++) {
var s = new Security();
s.fromJSON(data.securities[i]);
securities.push(s);
security_map[s.SecurityId] = s;
}
}
this.setState({securities: securities, security_map: security_map});
}.bind(this),
error: this.ajaxError
});
},
getAccounts: function() {
if (!this.state.session.isSession()) {
this.setState({accounts: [], account_map: {}});
return;
}
$.ajax({
type: "GET",
dataType: "json",
url: "account/",
success: function(data, status, jqXHR) {
var e = new Error();
var accounts = [];
var account_map = {};
e.fromJSON(data);
if (e.isError()) {
this.setState({error: e});
} else {
for (var i = 0; i < data.accounts.length; i++) {
var a = new Account();
a.fromJSON(data.accounts[i]);
accounts.push(a);
account_map[a.AccountId] = a;
}
//Populate Children arrays in account objects
for (var i = 0; i < accounts.length; i++) {
var a = accounts[i];
if (!a.isRootAccount())
account_map[a.ParentAccountId].Children.push(a);
}
}
this.setState({accounts: accounts, account_map: account_map});
}.bind(this),
error: this.ajaxError
});
},
handleErrorClear: function() {
this.setState({error: new Error()});
},
handleLoginSubmit: function(user) {
$.ajax({
type: "POST",
dataType: "json",
url: "session/",
data: {user: user.toJSON()},
success: function(data, status, jqXHR) {
var e = new Error();
e.fromJSON(data);
if (e.isError()) {
this.setState({error: e});
} else {
this.getSession();
this.setHash("home");
}
}.bind(this),
error: this.ajaxError
});
},
handleLogoutSubmit: function() {
this.setState({accounts: [], account_map: {}});
$.ajax({
type: "DELETE",
dataType: "json",
url: "session/",
success: function(data, status, jqXHR) {
var e = new Error();
e.fromJSON(data);
if (e.isError()) {
this.setState({error: e});
}
this.setState({session: new Session(), user: new User()});
}.bind(this),
error: this.ajaxError
});
},
handleAccountSettings: function() { handleAccountSettings: function() {
this.setState({showAccountSettingsModal: true}); this.setState({showAccountSettingsModal: true});
}, },
handleSettingsSubmitted: function(user) { handleSettingsSubmitted: function(user) {
this.setState({ this.setState({
user: user,
showAccountSettingsModal: false showAccountSettingsModal: false
}); });
}, },
handleSettingsCanceled: function(user) { handleSettingsCanceled: function() {
this.setState({showAccountSettingsModal: false}); this.setState({showAccountSettingsModal: false});
}, },
handleCreateNewUser: function() { handleCreateNewUser: function() {
this.setHash("new_user"); this.setHash("new_user");
}, },
handleGoHome: function(user) { handleGoHome: function() {
this.setHash("home"); this.setHash("home");
}, },
handleCreateAccount: function(account) {
$.ajax({
type: "POST",
dataType: "json",
url: "account/",
data: {account: account.toJSON()},
success: function(data, status, jqXHR) {
var e = new Error();
e.fromJSON(data);
if (e.isError()) {
this.setState({error: e});
} else {
this.getAccounts();
}
}.bind(this),
error: this.ajaxError
});
},
handleUpdateAccount: function(account) {
$.ajax({
type: "PUT",
dataType: "json",
url: "account/"+account.AccountId+"/",
data: {account: account.toJSON()},
success: function(data, status, jqXHR) {
var e = new Error();
e.fromJSON(data);
if (e.isError()) {
this.setState({error: e});
} else {
this.getAccounts();
}
}.bind(this),
error: this.ajaxError
});
},
handleDeleteAccount: function(account) {
$.ajax({
type: "DELETE",
dataType: "json",
url: "account/"+account.AccountId+"/",
success: function(data, status, jqXHR) {
var e = new Error();
e.fromJSON(data);
if (e.isError()) {
this.setState({error: e});
} else {
this.getAccounts();
}
}.bind(this),
error: this.ajaxError
});
},
render: function() { render: function() {
var mainContent; var mainContent;
if (this.state.hash == "new_user") { if (this.state.hash == "new_user") {
mainContent = <NewUserForm onNewUser={this.handleGoHome} onCancel={this.handleGoHome}/> mainContent = <NewUserForm onNewUser={this.handleGoHome} onCancel={this.handleGoHome}/>
} else { } else {
if (this.state.user.isUser()) if (this.props.user.isUser())
mainContent = ( mainContent = (
<Tabs defaultActiveKey={1} id='mainNavigationTabs'> <Tabs defaultActiveKey={1} id='mainNavigationTabs'>
<Tab title="Accounts" eventKey={1} > <Tab title="Accounts" eventKey={1} >
<AccountsTab <AccountsTabContainer
className="fullheight" className="fullheight" />
accounts={this.state.accounts}
account_map={this.state.account_map}
securities={this.state.securities}
security_map={this.state.security_map}
onCreateAccount={this.handleCreateAccount}
onUpdateAccount={this.handleUpdateAccount}
onDeleteAccount={this.handleDeleteAccount} />
</Tab> </Tab>
<Tab title="Scheduled Transactions" eventKey={2} >Scheduled transactions go here...</Tab> <Tab title="Scheduled Transactions" eventKey={2} >Scheduled transactions go here...</Tab>
<Tab title="Budgets" eventKey={3} >Budgets go here...</Tab> <Tab title="Budgets" eventKey={3} >Budgets go here...</Tab>
@ -311,18 +83,12 @@ module.exports = React.createClass({
return ( return (
<div className="fullheight ui"> <div className="fullheight ui">
<TopBar <TopBarContainer
error={this.state.error}
onErrorClear={this.handleErrorClear}
onLoginSubmit={this.handleLoginSubmit}
onCreateNewUser={this.handleCreateNewUser} onCreateNewUser={this.handleCreateNewUser}
user={this.state.user} onAccountSettings={this.handleAccountSettings} />
onAccountSettings={this.handleAccountSettings}
onLogoutSubmit={this.handleLogoutSubmit} />
{mainContent} {mainContent}
<AccountSettingsModal <AccountSettingsModalContainer
show={this.state.showAccountSettingsModal} show={this.state.showAccountSettingsModal}
user={this.state.user}
onSubmit={this.handleSettingsSubmitted} onSubmit={this.handleSettingsSubmitted}
onCancel={this.handleSettingsCanceled}/> onCancel={this.handleSettingsCanceled}/>
</div> </div>

View File

@ -29,7 +29,7 @@ const LoginBar = React.createClass({
e.preventDefault(); e.preventDefault();
user.Username = ReactDOM.findDOMNode(this.refs.username).value; user.Username = ReactDOM.findDOMNode(this.refs.username).value;
user.Password = ReactDOM.findDOMNode(this.refs.password).value; user.Password = ReactDOM.findDOMNode(this.refs.password).value;
this.props.onLoginSubmit(user); this.props.onLogin(user);
}, },
handleNewUserSubmit: function(e) { handleNewUserSubmit: function(e) {
e.preventDefault(); e.preventDefault();
@ -72,7 +72,7 @@ const LogoutBar = React.createClass({
if (this.props.onAccountSettings != null) if (this.props.onAccountSettings != null)
this.props.onAccountSettings(); this.props.onAccountSettings();
} else if (key == 2) { } else if (key == 2) {
this.props.onLogoutSubmit(); this.props.onLogout();
} }
}, },
render: function() { render: function() {
@ -102,15 +102,15 @@ module.exports = React.createClass({
var barContents; var barContents;
var errorAlert; var errorAlert;
if (!this.props.user.isUser()) if (!this.props.user.isUser())
barContents = <LoginBar onLoginSubmit={this.props.onLoginSubmit} onCreateNewUser={this.props.onCreateNewUser} />; barContents = <LoginBar onLogin={this.props.onLogin} onCreateNewUser={this.props.onCreateNewUser} />;
else else
barContents = <LogoutBar user={this.props.user} onLogoutSubmit={this.props.onLogoutSubmit} onAccountSettings={this.props.onAccountSettings}/>; barContents = <LogoutBar user={this.props.user} onLogout={this.props.onLogout} onAccountSettings={this.props.onAccountSettings}/>;
if (this.props.error.isError()) if (this.props.error.isError())
errorAlert = errorAlert =
<Alert bsStyle="danger" onDismiss={this.props.onErrorClear}> <Alert bsStyle="danger" onDismiss={this.props.onClearError}>
<h4>Error!</h4> <h4>Error!</h4>
<p>Error {this.props.error.ErrorId}: {this.props.error.ErrorString}</p> <p>Error {this.props.error.ErrorId}: {this.props.error.ErrorString}</p>
<Button onClick={this.props.onErrorClear}>Clear</Button> <Button onClick={this.props.onClearError}>Clear</Button>
</Alert>; </Alert>;
return ( return (

View File

@ -1,6 +1,6 @@
var AccountConstants = require('../constants/AccountConstants'); var AccountConstants = require('../constants/AccountConstants');
var ErrorActions = require('ErrorActions'); var ErrorActions = require('./ErrorActions');
var models = require('../models.js'); var models = require('../models.js');
var Account = models.Account; var Account = models.Account;
@ -75,7 +75,6 @@ function fetchAll() {
url: "account/", url: "account/",
success: function(data, status, jqXHR) { success: function(data, status, jqXHR) {
var e = new Error(); var e = new Error();
var accounts = [];
e.fromJSON(data); e.fromJSON(data);
if (e.isError()) { if (e.isError()) {
ErrorActions.serverError(e); ErrorActions.serverError(e);

View File

@ -21,7 +21,14 @@ function ajaxError(error) {
}; };
} }
function clearError() {
return {
type: ErrorConstants.CLEAR_ERROR,
};
}
module.exports = { module.exports = {
serverError: serverError, serverError: serverError,
ajaxError: ajaxError ajaxError: ajaxError,
clearError: clearError
}; };

View File

@ -0,0 +1,52 @@
var SecurityConstants = require('../constants/SecurityConstants');
var ErrorActions = require('./ErrorActions');
var models = require('../models.js');
var Security = models.Security;
var Error = models.Error;
function fetchSecurities() {
return {
type: SecurityConstants.FETCH_SECURITIES
}
}
function securitiesFetched(securities) {
return {
type: SecurityConstants.SECURITIES_FETCHED,
securities: securities
}
}
function fetchAll() {
return function (dispatch) {
dispatch(fetchSecurities());
$.ajax({
type: "GET",
dataType: "json",
url: "security/",
success: function(data, status, jqXHR) {
var e = new Error();
e.fromJSON(data);
if (e.isError()) {
ErrorActions.serverError(e);
} else {
dispatch(securitiesFetched(data.securities.map(function(json) {
var s = new Security();
s.fromJSON(json);
return s;
})));
}
},
error: function(jqXHR, status, error) {
ErrorActions.ajaxError(e);
}
});
};
}
module.exports = {
fetchAll: fetchAll
};

208
js/actions/UserActions.js Normal file
View File

@ -0,0 +1,208 @@
var UserConstants = require('../constants/UserConstants');
var AccountActions = require('./AccountActions');
var SecurityActions = require('./SecurityActions');
var ErrorActions = require('./ErrorActions');
var models = require('../models.js');
var User = models.User;
var Session = models.Session;
var Error = models.Error;
function loginUser() {
return {
type: UserConstants.LOGIN_USER
}
}
function userLoggedIn(session) {
return {
type: UserConstants.USER_LOGGEDIN,
session: session
}
}
function logoutUser() {
return {
type: UserConstants.LOGOUT_USER
}
}
function userLoggedOut() {
return {
type: UserConstants.USER_LOGGEDOUT
}
}
function fetchUser(userId) {
return {
type: UserConstants.FETCH_USER,
userId: userId
}
}
function userFetched(user) {
return {
type: UserConstants.USER_FETCHED,
user: user
}
}
function updateUser(user) {
return {
type: UserConstants.UPDATE_USER,
user: user
}
}
function userUpdated(user) {
return {
type: UserConstants.USER_UPDATED,
user: user
}
}
function fetch(userId) {
return function (dispatch) {
dispatch(fetchUser());
$.ajax({
type: "GET",
dataType: "json",
url: "user/"+userId+"/",
success: function(data, status, jqXHR) {
var e = new Error();
e.fromJSON(data);
if (e.isError()) {
ErrorActions.serverError(e);
} else {
var u = new User();
u.fromJSON(data);
dispatch(userFetched(u));
}
},
error: function(jqXHR, status, error) {
ErrorActions.ajaxError(e);
}
});
};
}
function initializeSession(dispatch, session) {
dispatch(userLoggedIn(session));
dispatch(fetch(session.UserId));
dispatch(AccountActions.fetchAll());
dispatch(SecurityActions.fetchAll());
}
function login(user) {
return function (dispatch) {
dispatch(loginUser());
$.ajax({
type: "POST",
dataType: "json",
url: "session/",
data: {user: user.toJSON()},
success: function(data, status, jqXHR) {
var e = new Error();
e.fromJSON(data);
if (e.isError()) {
ErrorActions.serverError(e);
} else {
var s = new Session();
s.fromJSON(data);
initializeSession(dispatch, s);
}
},
error: function(jqXHR, status, error) {
ErrorActions.ajaxError(e);
}
});
};
}
function tryResumingSession() {
return function (dispatch) {
$.ajax({
type: "GET",
dataType: "json",
url: "session/",
success: function(data, status, jqXHR) {
var e = new Error();
e.fromJSON(data);
if (e.isError()) {
if (e.ErrorId != 1 /* Not Signed In*/)
ErrorActions.serverError(e);
} else {
var s = new Session();
s.fromJSON(data);
dispatch(loginUser());
initializeSession(dispatch, s);
}
},
error: function(jqXHR, status, error) {
ErrorActions.ajaxError(e);
}
});
};
}
function logout() {
return function (dispatch) {
dispatch(logoutUser());
$.ajax({
type: "DELETE",
dataType: "json",
url: "session/",
success: function(data, status, jqXHR) {
var e = new Error();
e.fromJSON(data);
if (e.isError()) {
ErrorActions.serverError(e);
} else {
dispatch(userLoggedOut());
}
},
error: function(jqXHR, status, error) {
ErrorActions.ajaxError(e);
}
});
};
}
function update(user) {
return function (dispatch) {
dispatch(updateUser());
$.ajax({
type: "PUT",
dataType: "json",
url: "user/"+user.UserId+"/",
data: {user: user.toJSON()},
success: function(data, status, jqXHR) {
var e = new Error();
e.fromJSON(data);
if (e.isError()) {
ErrorActions.serverError(e);
} else {
var u = new User();
u.fromJSON(data);
dispatch(userUpdated(u));
}
},
error: function(jqXHR, status, error) {
ErrorActions.ajaxError(e);
}
});
};
}
module.exports = {
fetch: fetch,
login: login,
logout: logout,
update: update,
tryResumingSession: tryResumingSession
};

View File

@ -5,4 +5,5 @@ module.exports = keyMirror({
ERROR_SERVER: null, ERROR_SERVER: null,
ERROR_CLIENT: null, ERROR_CLIENT: null,
ERROR_USER: null, ERROR_USER: null,
CLEAR_ERROR: null
}); });

View File

@ -0,0 +1,12 @@
var keyMirror = require('keymirror');
module.exports = keyMirror({
FETCH_SECURITIES: null,
SECURITIES_FETCHED: null,
CREATE_SECURITY: null,
SECURITY_CREATED: null,
UPDATE_SECURITY: null,
SECURITY_UPDATED: null,
REMOVE_SECURITY: null,
SECURITY_REMOVED: null
});

View File

@ -0,0 +1,12 @@
var keyMirror = require('keymirror');
module.exports = keyMirror({
LOGIN_USER: null,
USER_LOGGEDIN: null,
LOGOUT_USER: null,
USER_LOGGEDOUT: null,
FETCH_USER: null,
USER_FETCHED: null,
UPDATE_USER: null,
USER_UPDATED: null
});

View File

@ -0,0 +1,21 @@
var connect = require('react-redux').connect;
var UserActions = require('../actions/UserActions');
var AccountSettingsModal = require('../AccountSettingsModal');
function mapStateToProps(state) {
return {
user: state.user
}
}
function mapDispatchToProps(dispatch) {
return {
onUpdateUser: function(user) {dispatch(UserActions.update(user))}
}
}
module.exports = connect(
mapStateToProps,
mapDispatchToProps
)(AccountSettingsModal)

View File

@ -0,0 +1,33 @@
var connect = require('react-redux').connect;
var AccountActions = require('../actions/AccountActions');
var AccountsTab = require('../AccountsTab');
function mapStateToProps(state) {
var security_list = [];
for (var securityId in state.securities) {
if (state.securities.hasOwnProperty(securityId))
security_list.push(state.securities[securityId]);
}
return {
accounts: state.accounts.map,
accountChildren: state.accounts.children,
securities: state.securities,
security_list: security_list,
selectedAccount: state.selectedAccount
}
}
function mapDispatchToProps(dispatch) {
return {
onCreateAccount: function(account) {dispatch(AccountActions.create(account))},
onUpdateAccount: function(account) {dispatch(AccountActions.update(account))},
onDeleteAccount: function(accountId) {dispatch(AccountActions.remove(accountId))},
onSelectAccount: function(accountId) {dispatch(AccountActions.select(accountId))}
}
}
module.exports = connect(
mapStateToProps,
mapDispatchToProps
)(AccountsTab)

View File

@ -0,0 +1,22 @@
var connect = require('react-redux').connect;
var UserActions = require('../actions/UserActions');
var MoneyGoApp = require('../MoneyGoApp');
function mapStateToProps(state) {
return {
user: state.user
}
}
function mapDispatchToProps(dispatch) {
return {
tryResumingSession: function() {dispatch(UserActions.tryResumingSession())},
}
}
module.exports = connect(
mapStateToProps,
mapDispatchToProps
)(MoneyGoApp)

View File

@ -0,0 +1,27 @@
var connect = require('react-redux').connect;
var UserActions = require('../actions/UserActions');
var ErrorActions = require('../actions/ErrorActions');
var TopBar = require('../TopBar');
function mapStateToProps(state) {
return {
user: state.user,
error: state.error
}
}
function mapDispatchToProps(dispatch) {
return {
onLogin: function(user) {dispatch(UserActions.login(user))},
onLogout: function() {dispatch(UserActions.logout())},
onUpdateUser: function(user) {dispatch(UserActions.update(user))},
onClearError: function() {dispatch(ErrorActions.clearError())}
}
}
module.exports = connect(
mapStateToProps,
mapDispatchToProps
)(TopBar)

View File

@ -8,7 +8,7 @@ var ReduxThunk = require('redux-thunk').default;
var Globalize = require('globalize'); var Globalize = require('globalize');
var globalizeLocalizer = require('react-widgets/lib/localizers/globalize'); var globalizeLocalizer = require('react-widgets/lib/localizers/globalize');
var MoneyGoApp = require('./MoneyGoApp.js'); var MoneyGoAppContainer = require('./containers/MoneyGoAppContainer');
var MoneyGoReducer = require('./reducers/MoneyGoReducer'); var MoneyGoReducer = require('./reducers/MoneyGoReducer');
// Setup globalization for react-widgets // Setup globalization for react-widgets
@ -33,7 +33,7 @@ $(document).ready(function() {
ReactDOM.render( ReactDOM.render(
<Provider store={store}> <Provider store={store}>
<MoneyGoApp /> <MoneyGoAppContainer />
</Provider>, </Provider>,
document.getElementById("content") document.getElementById("content")
); );

View File

@ -157,7 +157,6 @@ function Account() {
this.ParentAccountId = -1; this.ParentAccountId = -1;
this.Type = -1; this.Type = -1;
this.Name = ""; this.Name = "";
this.Children = []; // Not sent across JSON, just used internally
} }
Account.prototype.toJSON = function() { Account.prototype.toJSON = function() {

View File

@ -1,8 +1,26 @@
var assign = require('object-assign'); var assign = require('object-assign');
var AccountConstants = require('../constants/AccountConstants'); var AccountConstants = require('../constants/AccountConstants');
var UserConstants = require('../constants/UserConstants');
module.exports = function(state = {}, action) { function accountChildren(accounts) {
var children = {};
for (var accountId in accounts) {
if (accounts.hasOwnProperty(accountId)) {
var parentAccountId = accounts[accountId].ParentAccountId;
if (!children.hasOwnProperty(parentAccountId))
children[parentAccountId] = [];
if (!children.hasOwnProperty(accountId))
children[accountId] = [];
children[parentAccountId].push(accountId);
}
}
return children;
}
const initialState = {map: {}, children: {}};
module.exports = function(state = initialState, action) {
switch (action.type) { switch (action.type) {
case AccountConstants.ACCOUNTS_FETCHED: case AccountConstants.ACCOUNTS_FETCHED:
var accounts = {}; var accounts = {};
@ -10,17 +28,29 @@ module.exports = function(state = {}, action) {
var account = action.accounts[i]; var account = action.accounts[i];
accounts[account.AccountId] = account; accounts[account.AccountId] = account;
} }
return accounts; return {
map: accounts,
children: accountChildren(accounts)
};
case AccountConstants.ACCOUNT_CREATED: case AccountConstants.ACCOUNT_CREATED:
case AccountConstants.ACCOUNT_UPDATED: case AccountConstants.ACCOUNT_UPDATED:
var account = action.account; var account = action.account;
return assign({}, state, { var accounts = assign({}, state.map, {
[account.AccountId]: account [account.AccountId]: account
}); });
return {
map: accounts,
children: accountChildren(accounts)
};
case AccountConstants.ACCOUNT_REMOVED: case AccountConstants.ACCOUNT_REMOVED:
var newstate = assign({}, state); var accounts = assign({}, state.map);
delete newstate[action.accountId]; delete accounts[action.accountId];
return newstate; return {
map: accounts,
children: accountChildren(accounts)
};
case UserConstants.USER_LOGGEDOUT:
return initialState;
default: default:
return state; return state;
} }

View File

@ -0,0 +1,17 @@
var ErrorConstants = require('../constants/ErrorConstants');
var Error = require('../models').Error;
module.exports = function(state = new Error(), action) {
switch (action.type) {
case ErrorConstants.ERROR_AJAX:
case ErrorConstants.ERROR_SERVER:
case ErrorConstants.ERROR_CLIENT:
case ErrorConstants.ERROR_USER:
return action.error;
case ErrorConstants.CLEAR_ERROR:
return new Error();
default:
return state;
}
};

View File

@ -1,9 +1,17 @@
var Redux = require('redux'); var Redux = require('redux');
var UserReducer = require('./UserReducer');
var SessionReducer = require('./SessionReducer');
var AccountReducer = require('./AccountReducer'); var AccountReducer = require('./AccountReducer');
var SecurityReducer = require('./SecurityReducer');
var SelectedAccountReducer = require('./SelectedAccountReducer'); var SelectedAccountReducer = require('./SelectedAccountReducer');
var ErrorReducer = require('./ErrorReducer');
module.exports = Redux.combineReducers({ module.exports = Redux.combineReducers({
user: UserReducer,
session: SessionReducer,
accounts: AccountReducer, accounts: AccountReducer,
selectedAccount: SelectedAccountReducer securities: SecurityReducer,
selectedAccount: SelectedAccountReducer,
error: ErrorReducer
}); });

View File

@ -0,0 +1,30 @@
var assign = require('object-assign');
var SecurityConstants = require('../constants/SecurityConstants');
var UserConstants = require('../constants/UserConstants');
module.exports = function(state = {}, action) {
switch (action.type) {
case SecurityConstants.SECURITIES_FETCHED:
var securities = {};
for (var i = 0; i < action.securities.length; i++) {
var security = action.securities[i];
securities[security.SecurityId] = security;
}
return securities;
case SecurityConstants.SECURITY_CREATED:
case SecurityConstants.SECURITY_UPDATED:
var security = action.security;
return assign({}, state, {
[security.SecurityId]: security
});
case SecurityConstants.SECURITY_REMOVED:
var newstate = assign({}, state);
delete newstate[action.securityId];
return newstate;
case UserConstants.USER_LOGGEDOUT:
return {};
default:
return state;
}
};

View File

@ -1,4 +1,5 @@
var AccountConstants = require('../constants/AccountConstants'); var AccountConstants = require('../constants/AccountConstants');
var UserConstants = require('../constants/UserConstants');
module.exports = function(state = -1, action) { module.exports = function(state = -1, action) {
switch (action.type) { switch (action.type) {
@ -14,6 +15,8 @@ module.exports = function(state = -1, action) {
return state; return state;
case AccountConstants.ACCOUNT_SELECTED: case AccountConstants.ACCOUNT_SELECTED:
return action.accountId; return action.accountId;
case UserConstants.USER_LOGGEDOUT:
return -1;
default: default:
return state; return state;
} }

View File

@ -0,0 +1,14 @@
var UserConstants = require('../constants/UserConstants');
var Session = require('../models').Session;
module.exports = function(state = new Session(), action) {
switch (action.type) {
case UserConstants.USER_LOGGEDIN:
return action.session;
case UserConstants.USER_LOGGEDOUT:
return new Session();
default:
return state;
}
};

View File

@ -0,0 +1,15 @@
var UserConstants = require('../constants/UserConstants');
var User = require('../models').User;
module.exports = function(state = new User(), action) {
switch (action.type) {
case UserConstants.USER_FETCHED:
case UserConstants.USER_UPDATED:
return action.user;
case UserConstants.USER_LOGGEDOUT:
return new User();
default:
return state;
}
};

View File

@ -1,18 +1,19 @@
const recursiveAccountDisplayInfo = function(account, prefix) { const recursiveAccountDisplayInfo = function(account, account_map, accountChildren, prefix) {
var name = prefix + account.Name; var name = prefix + account.Name;
var accounts = [{AccountId: account.AccountId, Name: name}]; var accounts = [{AccountId: account.AccountId, Name: name}];
for (var i = 0; i < account.Children.length; i++) for (var i = 0; i < accountChildren[account.AccountId].length; i++)
accounts = accounts.concat(recursiveAccountDisplayInfo(account.Children[i], name + "/")); accounts = accounts.concat(recursiveAccountDisplayInfo(account_map[accountChildren[account.AccountId][i]], account_map, accountChildren, name + "/"));
return accounts return accounts
}; };
const getAccountDisplayList = function(account_list, includeRoot, rootName) { const getAccountDisplayList = function(account_map, accountChildren, includeRoot, rootName) {
var accounts = [] var accounts = []
if (includeRoot) if (includeRoot)
accounts.push({AccountId: -1, Name: rootName}); accounts.push({AccountId: -1, Name: rootName});
for (var i = 0; i < account_list.length; i++) { for (var accountId in account_map) {
if (account_list[i].isRootAccount()) if (account_map.hasOwnProperty(accountId) &&
accounts = accounts.concat(recursiveAccountDisplayInfo(account_list[i], "")); account_map[accountId].isRootAccount())
accounts = accounts.concat(recursiveAccountDisplayInfo(account_map[accountId], account_map, accountChildren, ""));
} }
return accounts; return accounts;
}; };