mirror of
				https://github.com/aclindsa/moneygo.git
				synced 2025-11-03 18:13:27 -05:00 
			
		
		
		
	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:
		@@ -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>
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
div#content {
 | 
			
		||||
	width: 95%;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	min-width: 75em;
 | 
			
		||||
	max-width: 100em;
 | 
			
		||||
    display: block;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										62
									
								
								static/ui.js
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								static/ui.js
									
									
									
									
									
								
							@@ -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>
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user