Add ability to create new accounts to UI

This also incorporates a bunch of other changes needed to support adding
this.
This commit is contained in:
Aaron Lindsay 2015-07-04 08:28:09 -04:00
parent 7772f0bca5
commit 7ea9fb3b73
4 changed files with 323 additions and 20 deletions

View File

@ -2,25 +2,227 @@
var ListGroup = ReactBootstrap.ListGroup;
var ListGroupItem = ReactBootstrap.ListGroupItem;
var AccountList = React.createClass({
var Grid = ReactBootstrap.Grid;
var Row = ReactBootstrap.Row;
var Col = ReactBootstrap.Col;
var Button = ReactBootstrap.Button;
var ButtonGroup = ReactBootstrap.ButtonGroup;
var Glyphicon = ReactBootstrap.Glyphicon;
var Modal = ReactBootstrap.Modal;
var Combobox = ReactWidgets.Combobox;
const recursiveAccountDisplayInfo = function(account, prefix) {
var name = prefix + account.Name;
var accounts = [{AccountId: account.AccountId, Name: name}];
for (var i = 0; i < account.Children.length; i++)
accounts = accounts.concat(recursiveAccountDisplayInfo(account.Children[i], name + "/"));
return accounts
};
const getAccountDisplayList = function(account_list, includeRoot, rootName) {
var accounts = []
if (includeRoot)
accounts.push({AccountId: -1, Name: rootName});
for (var i = 0; i < account_list.length; i++) {
if (account_list[i].ParentAccountId == -1)
accounts = accounts.concat(recursiveAccountDisplayInfo(account_list[i], ""));
}
return accounts;
};
const AccountCombobox = React.createClass({
handleAccountChange: function(account) {
if (this.props.onSelect != null &&
account.hasOwnProperty('AccountId') &&
this.props.account_map.hasOwnProperty([account.AccountId])) {
this.props.onSelect(this.props.account_map[account.AccountId])
}
},
render: function() {
var accounts = getAccountDisplayList(this.props.accounts, true, "New Root Account");
return (
<Combobox
data={accounts}
valueField='AccountId'
textField='Name'
value={this.props.value}
onSelect={this.handleAccountChange}
ref="account" />
);
}
});
const NewAccountModal = React.createClass({
getInitialState: function() {
return {
security: 1,
parentaccountid: -1,
type: 1,
name: ""
};
},
handleCancel: function() {
if (this.props.onCancel != null)
this.props.onCancel();
},
handleChange: function() {
this.setState({
name: this.refs.name.getValue(),
});
},
handleSecurityChange: function(security) {
if (security.hasOwnProperty('SecurityId'))
this.setState({
security: security.SecurityId
});
},
handleTypeChange: function(type) {
if (type.hasOwnProperty('TypeId'))
this.setState({
type: type.TypeId
});
},
handleParentChange: function(parentAccount) {
this.setState({parentaccountid: parentAccount.AccountId});
},
handleSubmit: function() {
var a = new Account();
a.Name = this.state.name;
a.ParentAccountId = this.state.parentaccountid;
a.SecurityId = this.state.security;
a.Type = this.state.type;
this.handleSaveSettings(a);
},
handleSaveSettings: function(account) {
if (this.props.onSubmit != null)
this.props.onSubmit(account);
},
render: function() {
return (
<Modal show={this.props.show} onHide={this.handleCancel}>
<Modal.Header closeButton>
<Modal.Title>Create New Account</Modal.Title>
</Modal.Header>
<Modal.Body>
<form onSubmit={this.handleSubmit}
className="form-horizontal">
<Input type="text"
label="Name"
value={this.state.name}
onChange={this.handleChange}
ref="name"
labelClassName="col-xs-2"
wrapperClassName="col-xs-10"/>
<Input wrapperClassName="wrapper"
label="Parent Account"
labelClassName="col-xs-2"
wrapperClassName="col-xs-10">
<AccountCombobox
accounts={this.props.accounts}
account_map={this.props.account_map}
value={this.state.parentaccountid}
onSelect={this.handleParentChange}
ref="parent" />
</Input>
<Input wrapperClassName="wrapper"
label="Security"
labelClassName="col-xs-2"
wrapperClassName="col-xs-10">
<Combobox
data={this.props.securities}
valueField='SecurityId'
textField='Name'
value={this.state.security}
onSelect={this.handleSecurityChange}
ref="security" />
</Input>
<Input wrapperClassName="wrapper"
label="Account Type"
labelClassName="col-xs-2"
wrapperClassName="col-xs-10">
<Combobox
data={AccountTypeList}
valueField='TypeId'
textField='Name'
value={this.state.type}
onSelect={this.handleTypeChange}
ref="type" />
</Input>
</form>
</Modal.Body>
<Modal.Footer>
<ButtonGroup className="pull-right">
<Button onClick={this.handleCancel} bsStyle="warning">Cancel</Button>
<Button onClick={this.handleSubmit} bsStyle="success">Create Account</Button>
</ButtonGroup>
</Modal.Footer>
</Modal>
);
}
});
const AccountsTab = React.createClass({
getInitialState: function() {
return {
creatingNewAccount: false
};
},
handleNewAccount: function() {
this.setState({creatingNewAccount: true});
},
handleEditAccount: function() {
console.log("handleEditAccount");
},
handleDeleteAccount: function() {
console.log("handleDeleteAccount");
},
handleCreationCancel: function() {
this.setState({creatingNewAccount: false});
},
handleCreateAccount: function(account) {
if (this.props.onCreateAccount != null)
this.props.onCreateAccount(account);
this.setState({creatingNewAccount: false});
},
render: function() {
var accounts = this.props.accounts;
var account_map = this.props.account_map;
var listGroupItems;
for (var i = 0; i < accounts.length; i++) {
listGroupItems += <ListGroupItem>{accounts[i].Name}</ListGroupItem>;
}
var listGroupItems = accounts.map(function(account) {
return (
<ListGroupItem>{account.Name}</ListGroupItem>
);
});
return (
<ListGroup>
{listGroupItems}
</ListGroup>
<Grid fluid><Row>
<Col xs={2}>
<NewAccountModal
show={this.state.creatingNewAccount}
accounts={this.props.accounts}
account_map={this.props.account_map}
onCancel={this.handleCreationCancel}
onSubmit={this.handleCreateAccount}
securities={this.props.securities}/>
<ListGroup>
{listGroupItems}
</ListGroup>
<ButtonGroup className="pull-right">
<Button onClick={this.handleNewAccount} bsStyle="success">
<Glyphicon glyph='plus-sign' /></Button>
<Button onClick={this.handleEditAccount} bsStyle="primary">
<Glyphicon glyph='cog' /></Button>
<Button onClick={this.handleDeleteAccount} bsStyle="danger">
<Glyphicon glyph='trash' /></Button>
</ButtonGroup>
</Col><Col xs={10}>
blah
</Col>
</Row></Grid>
);
}
});

View File

@ -16,7 +16,7 @@ function User() {
this.Email = "";
}
var BogusPassword = "password";
const BogusPassword = "password";
User.prototype.toJSON = function() {
var json_obj = {};
@ -76,7 +76,55 @@ Session.prototype.isSession = function() {
this.UserId != empty_session.UserId;
}
var AccountType = {
const SecurityType = {
Banknote: 1,
Bond: 2,
Stock: 3,
MutualFund: 4
}
var SecurityTypeList = [];
for (var type in SecurityType) {
if (SecurityType.hasOwnProperty(type)) {
SecurityTypeList.push({'TypeId': SecurityType[type], 'Name': type});
}
}
function Security() {
this.SecurityId = -1;
this.Name = "";
this.Precision = -1;
this.Type = -1;
}
Security.prototype.toJSON = function() {
var json_obj = {};
json_obj.SecurityId = this.SecurityId;
json_obj.Name = this.Name;
json_obj.Precision = this.Precision;
json_obj.Type = this.Type;
return JSON.stringify(json_obj);
}
Security.prototype.fromJSON = function(json_input) {
var json_obj = getJSONObj(json_input);
if (json_obj.hasOwnProperty("SecurityId"))
this.SecurityId = json_obj.SecurityId;
if (json_obj.hasOwnProperty("Name"))
this.Name = json_obj.Name;
if (json_obj.hasOwnProperty("Precision"))
this.Precision = json_obj.Precision;
if (json_obj.hasOwnProperty("Type"))
this.Type = json_obj.Type;
}
Security.prototype.isSecurity = function() {
var empty_account = new Security();
return this.SecurityId != empty_account.SecurityId ||
this.Type != empty_account.Type;
}
const AccountType = {
Bank: 1,
Cash: 2,
Asset: 3,
@ -85,6 +133,12 @@ var AccountType = {
Income: 6,
Expense: 7
}
var AccountTypeList = [];
for (var type in AccountType) {
if (AccountType.hasOwnProperty(type)) {
AccountTypeList.push({'TypeId': AccountType[type], 'Name': type});
}
}
function Account() {
this.AccountId = -1;
@ -183,7 +237,7 @@ Split.prototype.isSplit = function() {
this.AccountId != empty_split.AccountId;
}
var TransactionStatus = {
const TransactionStatus = {
Entered: 1,
Cleared: 2,
Reconciled: 3,

View File

@ -1,5 +1,6 @@
div#content {
width: 95%;
height: 100%;
min-width: 75em;
max-width: 100em;
display: block;

View File

@ -1,5 +1,7 @@
// Import all the objects we want to use from ReactBootstrap
var Jumbotron = ReactBootstrap.Jumbotron;
var TabbedArea = ReactBootstrap.TabbedArea;
var TabPane = ReactBootstrap.TabPane;
var Panel = ReactBootstrap.Panel;
var ButtonGroup = ReactBootstrap.ButtonGroup;
@ -299,6 +301,8 @@ var MoneyGoApp = React.createClass({
user: new User(),
accounts: [],
account_map: {},
securities: [],
security_map: {},
error: new Error()
};
},
@ -345,6 +349,7 @@ var MoneyGoApp = React.createClass({
this.setState({session: s});
this.getUser();
this.getAccounts();
this.getSecurities();
}.bind(this),
error: this.ajaxError
});
@ -370,6 +375,35 @@ var MoneyGoApp = React.createClass({
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: {}});
@ -518,17 +552,29 @@ var MoneyGoApp = React.createClass({
mainContent = <AccountSettings user={this.state.user} onSettingsSubmitted={this.handleSettingsSubmitted} onCancel={this.handleGoHome}/>
} else {
if (this.state.user.isUser())
mainContent = <AccountList
accounts={this.state.accounts}
account_map={this.state.account_map}
onCreateAccount={this.handleCreateAccount}
onUpdateAccount={this.handleUpdateAccount}
onDeleteAccount={this.handleDeleteAccount} />
mainContent =
<TabbedArea defaultActiveKey='1'>
<TabPane tab="Accounts" eventKey='1'>
<AccountsTab
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} />
</TabPane>
<TabPane tab="Scheduled Transactions" eventKey='2'>Scheduled transactions go here...</TabPane>
<TabPane tab="Budgets" eventKey='3'>Budgets go here...</TabPane>
<TabPane tab="Reports" eventKey='4'>Reports go here...</TabPane>
</TabbedArea>
else
mainContent =
<Jumbotron>
<h1>Money<i>Go</i></h1>
<p><i>Go</i> manage your money.</p>
<center>
<h1>Money<i>Go</i></h1>
<p><i>Go</i> manage your money.</p>
</center>
</Jumbotron>
}