mirror of
				https://github.com/aclindsa/moneygo.git
				synced 2025-11-03 18:13:27 -05:00 
			
		
		
		
	Move all components into 'components' subdirectory
This commit is contained in:
		
							
								
								
									
										41
									
								
								js/components/AccountCombobox.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								js/components/AccountCombobox.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
var React = require('react');
 | 
			
		||||
 | 
			
		||||
var Combobox = require('react-widgets').Combobox;
 | 
			
		||||
 | 
			
		||||
var getAccountDisplayList = require('../utils').getAccountDisplayList;
 | 
			
		||||
 | 
			
		||||
module.exports = React.createClass({
 | 
			
		||||
	displayName: "AccountCombobox",
 | 
			
		||||
	getDefaultProps: function() {
 | 
			
		||||
		return {
 | 
			
		||||
			includeRoot: true,
 | 
			
		||||
			disabled: false,
 | 
			
		||||
			rootName: "New Top-level Account"
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	handleAccountChange: function(account) {
 | 
			
		||||
		if (this.props.onChange != null &&
 | 
			
		||||
				account.hasOwnProperty('AccountId') &&
 | 
			
		||||
				(this.props.accounts.hasOwnProperty([account.AccountId]) ||
 | 
			
		||||
				 account.AccountId == -1)) {
 | 
			
		||||
			this.props.onChange(account)
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	render: function() {
 | 
			
		||||
		var accounts = getAccountDisplayList(this.props.accounts, this.props.accountChildren, this.props.includeRoot, this.props.rootName);
 | 
			
		||||
		var className = "";
 | 
			
		||||
		if (this.props.className)
 | 
			
		||||
			className = this.props.className;
 | 
			
		||||
		return (
 | 
			
		||||
			<Combobox
 | 
			
		||||
				data={accounts}
 | 
			
		||||
				valueField='AccountId'
 | 
			
		||||
				textField='Name'
 | 
			
		||||
				defaultValue={this.props.value}
 | 
			
		||||
				onChange={this.handleAccountChange}
 | 
			
		||||
				ref="account"
 | 
			
		||||
				disabled={this.props.disabled}
 | 
			
		||||
				className={className} />
 | 
			
		||||
	   );
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										952
									
								
								js/components/AccountRegister.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										952
									
								
								js/components/AccountRegister.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,952 @@
 | 
			
		||||
var React = require('react');
 | 
			
		||||
var ReactDOM = require('react-dom');
 | 
			
		||||
 | 
			
		||||
var react_update = require('react-addons-update');
 | 
			
		||||
 | 
			
		||||
var ReactBootstrap = require('react-bootstrap');
 | 
			
		||||
var Alert = ReactBootstrap.Alert;
 | 
			
		||||
var Modal = ReactBootstrap.Modal;
 | 
			
		||||
var Pagination = ReactBootstrap.Pagination;
 | 
			
		||||
var Label = ReactBootstrap.Label;
 | 
			
		||||
var Table = ReactBootstrap.Table;
 | 
			
		||||
var Grid = ReactBootstrap.Grid;
 | 
			
		||||
var Row = ReactBootstrap.Row;
 | 
			
		||||
var Col = ReactBootstrap.Col;
 | 
			
		||||
var Panel = ReactBootstrap.Panel;
 | 
			
		||||
var Form = ReactBootstrap.Form;
 | 
			
		||||
var FormGroup = ReactBootstrap.FormGroup;
 | 
			
		||||
var FormControl = ReactBootstrap.FormControl;
 | 
			
		||||
var InputGroup = ReactBootstrap.InputGroup;
 | 
			
		||||
var ControlLabel = ReactBootstrap.ControlLabel;
 | 
			
		||||
var HelpBlock = ReactBootstrap.HelpBlock;
 | 
			
		||||
var Button = ReactBootstrap.Button;
 | 
			
		||||
var ButtonGroup = ReactBootstrap.ButtonGroup;
 | 
			
		||||
var ButtonToolbar = ReactBootstrap.ButtonToolbar;
 | 
			
		||||
var ProgressBar = ReactBootstrap.ProgressBar;
 | 
			
		||||
var Glyphicon = ReactBootstrap.Glyphicon;
 | 
			
		||||
 | 
			
		||||
var ReactWidgets = require('react-widgets')
 | 
			
		||||
var DateTimePicker = ReactWidgets.DateTimePicker;
 | 
			
		||||
var Combobox = ReactWidgets.Combobox;
 | 
			
		||||
var DropdownList = ReactWidgets.DropdownList;
 | 
			
		||||
 | 
			
		||||
var Big = require('big.js');
 | 
			
		||||
 | 
			
		||||
var models = require('../models');
 | 
			
		||||
var Security = models.Security;
 | 
			
		||||
var Account = models.Account;
 | 
			
		||||
var Split = models.Split;
 | 
			
		||||
var Transaction = models.Transaction;
 | 
			
		||||
var TransactionStatus = models.TransactionStatus;
 | 
			
		||||
var TransactionStatusList = models.TransactionStatusList;
 | 
			
		||||
var TransactionStatusMap = models.TransactionStatusMap;
 | 
			
		||||
var Error = models.Error;
 | 
			
		||||
 | 
			
		||||
var getAccountDisplayName = require('../utils').getAccountDisplayName;
 | 
			
		||||
 | 
			
		||||
var AccountCombobox = require('./AccountCombobox');
 | 
			
		||||
 | 
			
		||||
const TransactionRow = React.createClass({
 | 
			
		||||
	handleClick: function(e) {
 | 
			
		||||
		const refs = ["date", "number", "description", "account", "status", "amount"];
 | 
			
		||||
		for (var ref in refs) {
 | 
			
		||||
			if (this.refs[refs[ref]] == e.target) {
 | 
			
		||||
				this.props.onEdit(this.props.transaction, refs[ref]);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	render: function() {
 | 
			
		||||
		var date = this.props.transaction.Date;
 | 
			
		||||
		var dateString = date.getFullYear() + "/" + (date.getMonth()+1) + "/" + date.getDate();
 | 
			
		||||
		var number = ""
 | 
			
		||||
		var accountName = "";
 | 
			
		||||
		var status = "";
 | 
			
		||||
		var security = this.props.securities[this.props.account.SecurityId];
 | 
			
		||||
 | 
			
		||||
		if (this.props.transaction.isTransaction()) {
 | 
			
		||||
			var thisAccountSplit;
 | 
			
		||||
			for (var i = 0; i < this.props.transaction.Splits.length; i++) {
 | 
			
		||||
				if (this.props.transaction.Splits[i].AccountId == this.props.account.AccountId) {
 | 
			
		||||
					thisAccountSplit = this.props.transaction.Splits[i];
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (this.props.transaction.Splits.length == 2) {
 | 
			
		||||
				var otherSplit = this.props.transaction.Splits[0];
 | 
			
		||||
				if (otherSplit.AccountId == this.props.account.AccountId)
 | 
			
		||||
					var otherSplit = this.props.transaction.Splits[1];
 | 
			
		||||
 | 
			
		||||
				if (otherSplit.AccountId == -1)
 | 
			
		||||
					var accountName = "Unbalanced " + this.props.securities[otherSplit.SecurityId].Symbol + " transaction";
 | 
			
		||||
				else
 | 
			
		||||
					var accountName = getAccountDisplayName(this.props.accounts[otherSplit.AccountId], this.props.accounts);
 | 
			
		||||
			} else {
 | 
			
		||||
				accountName = "--Split Transaction--";
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			var amount = security.Symbol + " " + thisAccountSplit.Amount.toFixed(security.Precision);
 | 
			
		||||
			var balance = security.Symbol + " " + this.props.transaction.Balance.toFixed(security.Precision);
 | 
			
		||||
			status = TransactionStatusMap[this.props.transaction.Status];
 | 
			
		||||
			number = thisAccountSplit.Number;
 | 
			
		||||
		} else {
 | 
			
		||||
			var amount = security.Symbol + " " + (new Big(0.0)).toFixed(security.Precision);
 | 
			
		||||
			var balance = security.Symbol + " " + (new Big(0.0)).toFixed(security.Precision);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return (
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td ref="date" onClick={this.handleClick}>{dateString}</td>
 | 
			
		||||
				<td ref="number" onClick={this.handleClick}>{number}</td>
 | 
			
		||||
				<td ref="description" onClick={this.handleClick}>{this.props.transaction.Description}</td>
 | 
			
		||||
				<td ref="account" onClick={this.handleClick}>{accountName}</td>
 | 
			
		||||
				<td ref="status" onClick={this.handleClick}>{status}</td>
 | 
			
		||||
				<td ref="amount" onClick={this.handleClick}>{amount}</td>
 | 
			
		||||
				<td>{balance}</td>
 | 
			
		||||
			</tr>);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AmountInput = React.createClass({
 | 
			
		||||
	_getInitialState: function(props) {
 | 
			
		||||
		// Ensure we can edit this without screwing up other copies of it
 | 
			
		||||
		var a;
 | 
			
		||||
		if (props.security)
 | 
			
		||||
			a = props.value.toFixed(props.security.Precision);
 | 
			
		||||
		else
 | 
			
		||||
			a = props.value.toString();
 | 
			
		||||
 | 
			
		||||
		return {
 | 
			
		||||
			LastGoodAmount: a,
 | 
			
		||||
			Amount: a
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	getInitialState: function() {
 | 
			
		||||
		 return this._getInitialState(this.props);
 | 
			
		||||
	},
 | 
			
		||||
	componentWillReceiveProps: function(nextProps) {
 | 
			
		||||
		if ((!nextProps.value.eq(this.props.value) &&
 | 
			
		||||
				!nextProps.value.eq(this.getValue())) ||
 | 
			
		||||
				nextProps.security !== this.props.security) {
 | 
			
		||||
			this.setState(this._getInitialState(nextProps));
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	componentDidMount: function() {
 | 
			
		||||
		ReactDOM.findDOMNode(this.refs.amount).onblur = this.onBlur;
 | 
			
		||||
	},
 | 
			
		||||
	onBlur: function() {
 | 
			
		||||
		var a;
 | 
			
		||||
		if (this.props.security)
 | 
			
		||||
			a = (new Big(this.getValue())).toFixed(this.props.security.Precision);
 | 
			
		||||
		else
 | 
			
		||||
			a = (new Big(this.getValue())).toString();
 | 
			
		||||
		this.setState({
 | 
			
		||||
			Amount: a
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	onChange: function() {
 | 
			
		||||
		this.setState({Amount: ReactDOM.findDOMNode(this.refs.amount).value});
 | 
			
		||||
		if (this.props.onChange)
 | 
			
		||||
			this.props.onChange();
 | 
			
		||||
	},
 | 
			
		||||
	getValue: function() {
 | 
			
		||||
		try {
 | 
			
		||||
			var value = ReactDOM.findDOMNode(this.refs.amount).value;
 | 
			
		||||
			var ret = new Big(value);
 | 
			
		||||
			this.setState({LastGoodAmount: value});
 | 
			
		||||
			return ret;
 | 
			
		||||
		} catch(err) {
 | 
			
		||||
			return new Big(this.state.LastGoodAmount);
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	render: function() {
 | 
			
		||||
		var symbol = "?";
 | 
			
		||||
		if (this.props.security)
 | 
			
		||||
			symbol = this.props.security.Symbol;
 | 
			
		||||
 | 
			
		||||
		return (
 | 
			
		||||
			<FormGroup validationState={this.props.validationState}>
 | 
			
		||||
				<InputGroup>
 | 
			
		||||
					<InputGroup.Addon>{symbol}</InputGroup.Addon>
 | 
			
		||||
					<FormControl type="text"
 | 
			
		||||
						value={this.state.Amount}
 | 
			
		||||
						onChange={this.onChange}
 | 
			
		||||
						ref="amount"/>
 | 
			
		||||
				</InputGroup>
 | 
			
		||||
			</FormGroup>
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AddEditTransactionModal = React.createClass({
 | 
			
		||||
	_getInitialState: function(props) {
 | 
			
		||||
		// Ensure we can edit this without screwing up other copies of it
 | 
			
		||||
		var t = props.transaction.deepCopy();
 | 
			
		||||
		return {
 | 
			
		||||
			errorAlert: [],
 | 
			
		||||
			transaction: t
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	getInitialState: function() {
 | 
			
		||||
		 return this._getInitialState(this.props);
 | 
			
		||||
	},
 | 
			
		||||
	componentWillReceiveProps: function(nextProps) {
 | 
			
		||||
		if (nextProps.show && !this.props.show) {
 | 
			
		||||
			this.setState(this._getInitialState(nextProps));
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	handleCancel: function() {
 | 
			
		||||
		if (this.props.onCancel != null)
 | 
			
		||||
			this.props.onCancel();
 | 
			
		||||
	},
 | 
			
		||||
	handleDescriptionChange: function() {
 | 
			
		||||
		this.setState({
 | 
			
		||||
			transaction: react_update(this.state.transaction, {
 | 
			
		||||
				Description: {$set: ReactDOM.findDOMNode(this.refs.description).value}
 | 
			
		||||
			})
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleDateChange: function(date, string) {
 | 
			
		||||
		if (date == null)
 | 
			
		||||
			return;
 | 
			
		||||
		this.setState({
 | 
			
		||||
			transaction: react_update(this.state.transaction, {
 | 
			
		||||
				Date: {$set: date}
 | 
			
		||||
			})
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleStatusChange: function(status) {
 | 
			
		||||
		if (status.hasOwnProperty('StatusId')) {
 | 
			
		||||
			this.setState({
 | 
			
		||||
				transaction: react_update(this.state.transaction, {
 | 
			
		||||
					Status: {$set: status.StatusId}
 | 
			
		||||
				})
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	handleAddSplit: function() {
 | 
			
		||||
		this.setState({
 | 
			
		||||
			transaction: react_update(this.state.transaction, {
 | 
			
		||||
				Splits: {$push: [new Split()]}
 | 
			
		||||
			})
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleDeleteSplit: function(split) {
 | 
			
		||||
		this.setState({
 | 
			
		||||
			transaction: react_update(this.state.transaction, {
 | 
			
		||||
				Splits: {$splice: [[split, 1]]}
 | 
			
		||||
			})
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleUpdateNumber: function(split) {
 | 
			
		||||
		var transaction = this.state.transaction;
 | 
			
		||||
		transaction.Splits[split] = react_update(transaction.Splits[split], {
 | 
			
		||||
			Number: {$set: ReactDOM.findDOMNode(this.refs['number-'+split]).value}
 | 
			
		||||
		});
 | 
			
		||||
		this.setState({
 | 
			
		||||
			transaction: transaction
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleUpdateMemo: function(split) {
 | 
			
		||||
		var transaction = this.state.transaction;
 | 
			
		||||
		transaction.Splits[split] = react_update(transaction.Splits[split], {
 | 
			
		||||
			Memo: {$set: ReactDOM.findDOMNode(this.refs['memo-'+split]).value}
 | 
			
		||||
		});
 | 
			
		||||
		this.setState({
 | 
			
		||||
			transaction: transaction
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleUpdateAccount: function(account, split) {
 | 
			
		||||
		var transaction = this.state.transaction;
 | 
			
		||||
		transaction.Splits[split] = react_update(transaction.Splits[split], {
 | 
			
		||||
			SecurityId: {$set: -1},
 | 
			
		||||
			AccountId: {$set: account.AccountId}
 | 
			
		||||
		});
 | 
			
		||||
		this.setState({
 | 
			
		||||
			transaction: transaction
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleUpdateAmount: function(split) {
 | 
			
		||||
		var transaction = this.state.transaction;
 | 
			
		||||
		transaction.Splits[split] = react_update(transaction.Splits[split], {
 | 
			
		||||
			Amount: {$set: new Big(this.refs['amount-'+split].getValue())}
 | 
			
		||||
		});
 | 
			
		||||
		this.setState({
 | 
			
		||||
			transaction: transaction
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleSubmit: function() {
 | 
			
		||||
		var errorString = ""
 | 
			
		||||
		var imbalancedSecurityList = this.state.transaction.imbalancedSplitSecurities(this.props.accounts);
 | 
			
		||||
		if (imbalancedSecurityList.length > 0)
 | 
			
		||||
			errorString = "Transaction must balance"
 | 
			
		||||
		for (var i = 0; i < this.state.transaction.Splits.length; i++) {
 | 
			
		||||
			var s = this.state.transaction.Splits[i];
 | 
			
		||||
			if (!(s.AccountId in this.props.accounts)) {
 | 
			
		||||
				errorString = "All accounts must be valid"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (errorString.length > 0) {
 | 
			
		||||
			this.setState({
 | 
			
		||||
				errorAlert: (<Alert className='saving-transaction-alert' bsStyle='danger'><strong>Error Saving Transaction:</strong> {errorString}</Alert>)
 | 
			
		||||
			});
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (this.props.onSubmit != null)
 | 
			
		||||
			this.props.onSubmit(this.state.transaction);
 | 
			
		||||
	},
 | 
			
		||||
	handleDelete: function() {
 | 
			
		||||
		if (this.props.onDelete != null)
 | 
			
		||||
			this.props.onDelete(this.state.transaction);
 | 
			
		||||
	},
 | 
			
		||||
	render: function() {
 | 
			
		||||
		var editing = this.props.transaction != null && this.props.transaction.isTransaction();
 | 
			
		||||
		var headerText = editing ? "Edit" : "Create New";
 | 
			
		||||
		var buttonText = editing ? "Save Changes" : "Create Transaction";
 | 
			
		||||
		var deleteButton = [];
 | 
			
		||||
		if (editing) {
 | 
			
		||||
			deleteButton = (
 | 
			
		||||
				<Button key={1} onClick={this.handleDelete} bsStyle="danger">Delete Transaction</Button>
 | 
			
		||||
		   );
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var imbalancedSecurityList = this.state.transaction.imbalancedSplitSecurities(this.props.accounts);
 | 
			
		||||
		var imbalancedSecurityMap = {};
 | 
			
		||||
		for (i = 0; i < imbalancedSecurityList.length; i++)
 | 
			
		||||
			imbalancedSecurityMap[imbalancedSecurityList[i]] = i;
 | 
			
		||||
 | 
			
		||||
		splits = [];
 | 
			
		||||
		for (var i = 0; i < this.state.transaction.Splits.length; i++) {
 | 
			
		||||
			var self = this;
 | 
			
		||||
			var s = this.state.transaction.Splits[i];
 | 
			
		||||
			var security = null;
 | 
			
		||||
			var amountValidation = undefined;
 | 
			
		||||
			var accountValidation = "";
 | 
			
		||||
			if (s.AccountId in this.props.accounts) {
 | 
			
		||||
				security = this.props.securities[this.props.accounts[s.AccountId].SecurityId];
 | 
			
		||||
			} else {
 | 
			
		||||
				if (s.SecurityId in this.props.securities) {
 | 
			
		||||
					security = this.props.securities[s.SecurityId];
 | 
			
		||||
				}
 | 
			
		||||
				accountValidation = "has-error";
 | 
			
		||||
			}
 | 
			
		||||
			if (security != null && security.SecurityId in imbalancedSecurityMap)
 | 
			
		||||
				amountValidation = "error";
 | 
			
		||||
 | 
			
		||||
			// Define all closures for calling split-updating functions
 | 
			
		||||
			var deleteSplitFn = (function() {
 | 
			
		||||
				var j = i;
 | 
			
		||||
				return function() {self.handleDeleteSplit(j);};
 | 
			
		||||
			})();
 | 
			
		||||
			var updateNumberFn = (function() {
 | 
			
		||||
				var j = i;
 | 
			
		||||
				return function() {self.handleUpdateNumber(j);};
 | 
			
		||||
			})();
 | 
			
		||||
			var updateMemoFn = (function() {
 | 
			
		||||
				var j = i;
 | 
			
		||||
				return function() {self.handleUpdateMemo(j);};
 | 
			
		||||
			})();
 | 
			
		||||
			var updateAccountFn = (function() {
 | 
			
		||||
				var j = i;
 | 
			
		||||
				return function(account) {self.handleUpdateAccount(account, j);};
 | 
			
		||||
			})();
 | 
			
		||||
			var updateAmountFn = (function() {
 | 
			
		||||
				var j = i;
 | 
			
		||||
				return function() {self.handleUpdateAmount(j);};
 | 
			
		||||
			})();
 | 
			
		||||
 | 
			
		||||
			var deleteSplitButton = [];
 | 
			
		||||
			if (this.state.transaction.Splits.length > 2) {
 | 
			
		||||
				deleteSplitButton = (
 | 
			
		||||
					<Col xs={1}><Button onClick={deleteSplitFn}
 | 
			
		||||
							bsStyle="danger">
 | 
			
		||||
							<Glyphicon glyph='trash' /></Button></Col>
 | 
			
		||||
				);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			splits.push((
 | 
			
		||||
				<Row key={s.SplitId == -1 ? (i+999) : s.SplitId}>
 | 
			
		||||
				<Col xs={1}><FormControl
 | 
			
		||||
					type="text"
 | 
			
		||||
					value={s.Number}
 | 
			
		||||
					onChange={updateNumberFn}
 | 
			
		||||
					ref={"number-"+i} /></Col>
 | 
			
		||||
				<Col xs={5}><FormControl
 | 
			
		||||
					type="text"
 | 
			
		||||
					value={s.Memo}
 | 
			
		||||
					onChange={updateMemoFn}
 | 
			
		||||
					ref={"memo-"+i} /></Col>
 | 
			
		||||
				<Col xs={3}><AccountCombobox
 | 
			
		||||
					accounts={this.props.accounts}
 | 
			
		||||
					accountChildren={this.props.accountChildren}
 | 
			
		||||
					value={s.AccountId}
 | 
			
		||||
					includeRoot={false}
 | 
			
		||||
					onChange={updateAccountFn}
 | 
			
		||||
					ref={"account-"+i}
 | 
			
		||||
					className={accountValidation}/></Col>
 | 
			
		||||
				<Col xs={2}><AmountInput type="text"
 | 
			
		||||
					value={s.Amount}
 | 
			
		||||
					security={security}
 | 
			
		||||
					onChange={updateAmountFn}
 | 
			
		||||
					ref={"amount-"+i}
 | 
			
		||||
					validationState={amountValidation}/></Col>
 | 
			
		||||
				{deleteSplitButton}
 | 
			
		||||
				</Row>
 | 
			
		||||
			));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return (
 | 
			
		||||
			<Modal show={this.props.show} onHide={this.handleCancel} bsSize="large">
 | 
			
		||||
				<Modal.Header closeButton>
 | 
			
		||||
					<Modal.Title>{headerText} Transaction</Modal.Title>
 | 
			
		||||
				</Modal.Header>
 | 
			
		||||
				<Modal.Body>
 | 
			
		||||
				<Form horizontal
 | 
			
		||||
						onSubmit={this.handleSubmit}>
 | 
			
		||||
					<FormGroup>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Date</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<DateTimePicker
 | 
			
		||||
							time={false}
 | 
			
		||||
							defaultValue={this.state.transaction.Date}
 | 
			
		||||
							onChange={this.handleDateChange} />
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
					<FormGroup>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Description</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<FormControl type="text"
 | 
			
		||||
							value={this.state.transaction.Description}
 | 
			
		||||
							onChange={this.handleDescriptionChange}
 | 
			
		||||
							ref="description"/>
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
					<FormGroup>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Status</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<Combobox
 | 
			
		||||
							data={TransactionStatusList}
 | 
			
		||||
							valueField='StatusId'
 | 
			
		||||
							textField='Name'
 | 
			
		||||
							defaultValue={this.state.transaction.Status}
 | 
			
		||||
							onSelect={this.handleStatusChange}
 | 
			
		||||
							ref="status" />
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
 | 
			
		||||
					<Grid fluid={true}><Row>
 | 
			
		||||
					<span className="split-header col-xs-1">#</span>
 | 
			
		||||
					<span className="split-header col-xs-5">Memo</span>
 | 
			
		||||
					<span className="split-header col-xs-3">Account</span>
 | 
			
		||||
					<span className="split-header col-xs-2">Amount</span>
 | 
			
		||||
					</Row>
 | 
			
		||||
					{splits}
 | 
			
		||||
					<Row>
 | 
			
		||||
						<span className="col-xs-11"></span>
 | 
			
		||||
						<Col xs={1}><Button onClick={this.handleAddSplit}
 | 
			
		||||
								bsStyle="success">
 | 
			
		||||
								<Glyphicon glyph='plus-sign' /></Button></Col>
 | 
			
		||||
					</Row>
 | 
			
		||||
					<Row>{this.state.errorAlert}</Row>
 | 
			
		||||
					</Grid>
 | 
			
		||||
				</Form>
 | 
			
		||||
				</Modal.Body>
 | 
			
		||||
				<Modal.Footer>
 | 
			
		||||
					<ButtonGroup>
 | 
			
		||||
						<Button onClick={this.handleCancel} bsStyle="warning">Cancel</Button>
 | 
			
		||||
						{deleteButton}
 | 
			
		||||
						<Button onClick={this.handleSubmit} bsStyle="success">{buttonText}</Button>
 | 
			
		||||
					</ButtonGroup>
 | 
			
		||||
				</Modal.Footer>
 | 
			
		||||
			</Modal>
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const ImportType = {
 | 
			
		||||
	OFX: 1,
 | 
			
		||||
	Gnucash: 2
 | 
			
		||||
};
 | 
			
		||||
var ImportTypeList = [];
 | 
			
		||||
for (var type in ImportType) {
 | 
			
		||||
	if (ImportType.hasOwnProperty(type)) {
 | 
			
		||||
		var name = ImportType[type] == ImportType.OFX ? "OFX/QFX" : type; //QFX is a special snowflake
 | 
			
		||||
		ImportTypeList.push({'TypeId': ImportType[type], 'Name': name});
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ImportTransactionsModal = React.createClass({
 | 
			
		||||
	getInitialState: function() {
 | 
			
		||||
		 return {
 | 
			
		||||
			importing: false,
 | 
			
		||||
			imported: false,
 | 
			
		||||
			importFile: "",
 | 
			
		||||
			importType: ImportType.Gnucash,
 | 
			
		||||
			uploadProgress: -1,
 | 
			
		||||
			error: null};
 | 
			
		||||
	},
 | 
			
		||||
	handleCancel: function() {
 | 
			
		||||
		this.setState(this.getInitialState());
 | 
			
		||||
		if (this.props.onCancel != null)
 | 
			
		||||
			this.props.onCancel();
 | 
			
		||||
	},
 | 
			
		||||
	handleImportChange: function() {
 | 
			
		||||
		this.setState({importFile: ReactDOM.findDOMNode(this.refs.importfile).value});
 | 
			
		||||
	},
 | 
			
		||||
	handleTypeChange: function(type) {
 | 
			
		||||
		this.setState({importType: type.TypeId});
 | 
			
		||||
	},
 | 
			
		||||
	handleSubmit: function() {
 | 
			
		||||
		if (this.props.onSubmit != null)
 | 
			
		||||
			this.props.onSubmit(this.props.account);
 | 
			
		||||
	},
 | 
			
		||||
	handleSetProgress: function(e) {
 | 
			
		||||
		if (e.lengthComputable) {
 | 
			
		||||
			var pct = Math.round(e.loaded/e.total*100);
 | 
			
		||||
			this.setState({uploadProgress: pct});
 | 
			
		||||
		} else {
 | 
			
		||||
			this.setState({uploadProgress: 50});
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	handleImportTransactions: function() {
 | 
			
		||||
		var file = this.refs.importfile.getInputDOMNode().files[0];
 | 
			
		||||
		var formData = new FormData();
 | 
			
		||||
		formData.append('importfile', file, this.state.importFile);
 | 
			
		||||
		var url = ""
 | 
			
		||||
		if (this.state.importType == ImportType.OFX)
 | 
			
		||||
			url = "account/"+this.props.account.AccountId+"/import/ofx";
 | 
			
		||||
		else if (this.state.importType == ImportType.Gnucash)
 | 
			
		||||
			url = "import/gnucash";
 | 
			
		||||
 | 
			
		||||
		this.setState({importing: true});
 | 
			
		||||
 | 
			
		||||
		$.ajax({
 | 
			
		||||
			type: "POST",
 | 
			
		||||
			url: url,
 | 
			
		||||
			data: formData,
 | 
			
		||||
			xhr: function() {
 | 
			
		||||
				var xhrObject = $.ajaxSettings.xhr();
 | 
			
		||||
				if (xhrObject.upload) {
 | 
			
		||||
					xhrObject.upload.addEventListener('progress', this.handleSetProgress, false);
 | 
			
		||||
				} else {
 | 
			
		||||
					console.log("File upload failed because !xhr.upload")
 | 
			
		||||
				}
 | 
			
		||||
				return xhrObject;
 | 
			
		||||
			}.bind(this),
 | 
			
		||||
			success: function(data, status, jqXHR) {
 | 
			
		||||
				var e = new Error();
 | 
			
		||||
				e.fromJSON(data);
 | 
			
		||||
				if (e.isError()) {
 | 
			
		||||
					var errString = e.ErrorString;
 | 
			
		||||
					if (e.ErrorId == 3 /* Invalid Request */) {
 | 
			
		||||
						errString = "Please check that the file you uploaded is valid and try again.";
 | 
			
		||||
					}
 | 
			
		||||
					this.setState({
 | 
			
		||||
						importing: false,
 | 
			
		||||
						error: errString
 | 
			
		||||
					});
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				this.setState({
 | 
			
		||||
					uploadProgress: 100,
 | 
			
		||||
					importing: false,
 | 
			
		||||
					imported: true
 | 
			
		||||
				});
 | 
			
		||||
			}.bind(this),
 | 
			
		||||
			error: function(e) {
 | 
			
		||||
				this.setState({importing: false});
 | 
			
		||||
				console.log("error handler", e);
 | 
			
		||||
			},
 | 
			
		||||
			// So jQuery doesn't try to process teh data or content-type
 | 
			
		||||
			cache: false,
 | 
			
		||||
			contentType: false,
 | 
			
		||||
			processData: false
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	render: function() {
 | 
			
		||||
		var accountNameLabel = "Performing global import:"
 | 
			
		||||
		if (this.props.account != null && this.state.importType != ImportType.Gnucash)
 | 
			
		||||
			accountNameLabel = "Importing to '" + getAccountDisplayName(this.props.account, this.props.accounts) + "' account:";
 | 
			
		||||
 | 
			
		||||
		// Display the progress bar if an upload/import is in progress
 | 
			
		||||
		var progressBar = [];
 | 
			
		||||
		if (this.state.importing && this.state.uploadProgress == 100) {
 | 
			
		||||
			progressBar = (<ProgressBar now={this.state.uploadProgress} active label="Importing transactions..." />);
 | 
			
		||||
		} else if (this.state.importing && this.state.uploadProgress != -1) {
 | 
			
		||||
			progressBar = (<ProgressBar now={this.state.uploadProgress} active label="Uploading... %(percent)s%" />);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Create panel, possibly displaying error or success messages
 | 
			
		||||
		var panel = [];
 | 
			
		||||
		if (this.state.error != null) {
 | 
			
		||||
			panel = (<Panel header="Error Importing Transactions" bsStyle="danger">{this.state.error}</Panel>);
 | 
			
		||||
		} else if (this.state.imported) {
 | 
			
		||||
			panel = (<Panel header="Successfully Imported Transactions" bsStyle="success">Your import is now complete.</Panel>);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Display proper buttons, possibly disabling them if an import is in progress
 | 
			
		||||
		var button1 = [];
 | 
			
		||||
		var button2 = [];
 | 
			
		||||
		if (!this.state.imported && this.state.error == null) {
 | 
			
		||||
			button1 = (<Button onClick={this.handleCancel} disabled={this.state.importing} bsStyle="warning">Cancel</Button>);
 | 
			
		||||
			button2 = (<Button onClick={this.handleImportTransactions} disabled={this.state.importing || this.state.importFile == ""} bsStyle="success">Import</Button>);
 | 
			
		||||
		} else {
 | 
			
		||||
			button1 = (<Button onClick={this.handleCancel} disabled={this.state.importing} bsStyle="success">OK</Button>);
 | 
			
		||||
		}
 | 
			
		||||
		var inputDisabled = (this.state.importing || this.state.error != null || this.state.imported) ? true : false;
 | 
			
		||||
 | 
			
		||||
		// Disable OFX/QFX imports if no account is selected
 | 
			
		||||
		var disabledTypes = false;
 | 
			
		||||
		if (this.props.account == null)
 | 
			
		||||
			disabledTypes = [ImportTypeList[ImportType.OFX - 1]];
 | 
			
		||||
 | 
			
		||||
		return (
 | 
			
		||||
			<Modal show={this.props.show} onHide={this.handleCancel} bsSize="small">
 | 
			
		||||
				<Modal.Header closeButton>
 | 
			
		||||
					<Modal.Title>Import Transactions</Modal.Title>
 | 
			
		||||
				</Modal.Header>
 | 
			
		||||
				<Modal.Body>
 | 
			
		||||
				<form onSubmit={this.handleImportTransactions}
 | 
			
		||||
						encType="multipart/form-data"
 | 
			
		||||
						ref="importform">
 | 
			
		||||
					<DropdownList
 | 
			
		||||
						data={ImportTypeList}
 | 
			
		||||
						valueField='TypeId'
 | 
			
		||||
						textField='Name'
 | 
			
		||||
						onSelect={this.handleTypeChange}
 | 
			
		||||
						defaultValue={this.state.importType}
 | 
			
		||||
						disabled={disabledTypes}
 | 
			
		||||
						ref="importtype" />
 | 
			
		||||
					<FormGroup>
 | 
			
		||||
						<ControlLabel>{accountNameLabel}</ControlLabel>
 | 
			
		||||
						<FormControl type="file"
 | 
			
		||||
							ref="importfile"
 | 
			
		||||
							disabled={inputDisabled}
 | 
			
		||||
							value={this.state.importFile}
 | 
			
		||||
							onChange={this.handleImportChange} />
 | 
			
		||||
						<HelpBlock>Select an OFX/QFX file to upload.</HelpBlock>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
				</form>
 | 
			
		||||
				{progressBar}
 | 
			
		||||
				{panel}
 | 
			
		||||
				</Modal.Body>
 | 
			
		||||
				<Modal.Footer>
 | 
			
		||||
					<ButtonGroup>
 | 
			
		||||
						{button1}
 | 
			
		||||
						{button2}
 | 
			
		||||
					</ButtonGroup>
 | 
			
		||||
				</Modal.Footer>
 | 
			
		||||
			</Modal>
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
module.exports = React.createClass({
 | 
			
		||||
	displayName: "AccountRegister",
 | 
			
		||||
	getInitialState: function() {
 | 
			
		||||
		return {
 | 
			
		||||
			importingTransactions: false,
 | 
			
		||||
			editingTransaction: false,
 | 
			
		||||
			selectedTransaction: new Transaction(),
 | 
			
		||||
			transactions: [],
 | 
			
		||||
			pageSize: 20,
 | 
			
		||||
			numPages: 0,
 | 
			
		||||
			currentPage: 0,
 | 
			
		||||
			height: 0
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	resize: function() {
 | 
			
		||||
		var div = ReactDOM.findDOMNode(this);
 | 
			
		||||
		this.setState({height: div.parentElement.clientHeight - 64});
 | 
			
		||||
	},
 | 
			
		||||
	componentDidMount: function() {
 | 
			
		||||
		this.resize();
 | 
			
		||||
		var self = this;
 | 
			
		||||
		$(window).resize(function() {self.resize();});
 | 
			
		||||
	},
 | 
			
		||||
	handleEditTransaction: function(transaction) {
 | 
			
		||||
		this.setState({
 | 
			
		||||
			selectedTransaction: transaction,
 | 
			
		||||
			editingTransaction: true
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleEditingCancel: function() {
 | 
			
		||||
		this.setState({
 | 
			
		||||
			editingTransaction: false
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleNewTransactionClicked: function() {
 | 
			
		||||
		var newTransaction = new Transaction();
 | 
			
		||||
		newTransaction.Status = TransactionStatus.Entered;
 | 
			
		||||
		newTransaction.Date = new Date();
 | 
			
		||||
		newTransaction.Splits.push(new Split());
 | 
			
		||||
		newTransaction.Splits.push(new Split());
 | 
			
		||||
		newTransaction.Splits[0].AccountId = this.props.accounts[this.props.selectedAccount].AccountId;
 | 
			
		||||
 | 
			
		||||
		this.setState({
 | 
			
		||||
			editingTransaction: true,
 | 
			
		||||
			selectedTransaction: newTransaction
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleImportClicked: function() {
 | 
			
		||||
		this.setState({
 | 
			
		||||
			importingTransactions: true
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleImportingCancel: function() {
 | 
			
		||||
		this.setState({
 | 
			
		||||
			importingTransactions: false
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	ajaxError: function(jqXHR, status, error) {
 | 
			
		||||
		var e = new Error();
 | 
			
		||||
		e.ErrorId = 5;
 | 
			
		||||
		e.ErrorString = "Request Failed: " + status + error;
 | 
			
		||||
		this.setState({error: e});
 | 
			
		||||
	},
 | 
			
		||||
	getTransactionPage: function(account, page) {
 | 
			
		||||
		$.ajax({
 | 
			
		||||
			type: "GET",
 | 
			
		||||
			dataType: "json",
 | 
			
		||||
			url: "account/"+account.AccountId+"/transactions?sort=date-desc&limit="+this.state.pageSize+"&page="+page,
 | 
			
		||||
			success: function(data, status, jqXHR) {
 | 
			
		||||
				var e = new Error();
 | 
			
		||||
				e.fromJSON(data);
 | 
			
		||||
				if (e.isError()) {
 | 
			
		||||
					this.setState({error: e});
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				var transactions = [];
 | 
			
		||||
				var balance = new Big(data.EndingBalance);
 | 
			
		||||
 | 
			
		||||
				for (var i = 0; i < data.Transactions.length; i++) {
 | 
			
		||||
					var t = new Transaction();
 | 
			
		||||
					t.fromJSON(data.Transactions[i]);
 | 
			
		||||
 | 
			
		||||
					t.Balance = balance.plus(0); // Make a copy of the current balance
 | 
			
		||||
					// Keep a talley of the running balance of these transactions
 | 
			
		||||
					for (var j = 0; j < data.Transactions[i].Splits.length; j++) {
 | 
			
		||||
						var split = data.Transactions[i].Splits[j];
 | 
			
		||||
						if (this.props.accounts[this.props.selectedAccount].AccountId == split.AccountId) {
 | 
			
		||||
							balance = balance.minus(split.Amount);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					transactions.push(t);
 | 
			
		||||
				}
 | 
			
		||||
				var a = new Account();
 | 
			
		||||
				a.fromJSON(data.Account);
 | 
			
		||||
 | 
			
		||||
				var pages = Math.ceil(data.TotalTransactions / this.state.pageSize);
 | 
			
		||||
 | 
			
		||||
				this.setState({
 | 
			
		||||
					transactions: transactions,
 | 
			
		||||
					numPages: pages
 | 
			
		||||
				});
 | 
			
		||||
			}.bind(this),
 | 
			
		||||
			error: this.ajaxError
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleSelectPage: function(event, selectedEvent) {
 | 
			
		||||
		var newpage = selectedEvent.eventKey - 1;
 | 
			
		||||
		// Don't do pages that don't make sense
 | 
			
		||||
		if (newpage < 0)
 | 
			
		||||
			newpage = 0;
 | 
			
		||||
		if (newpage >= this.state.numPages)
 | 
			
		||||
			newpage = this.state.numPages-1;
 | 
			
		||||
		if (newpage != this.state.currentPage) {
 | 
			
		||||
			if (this.props.selectedAccount != -1) {
 | 
			
		||||
				this.getTransactionPage(this.props.accounts[this.props.selectedAccount], newpage);
 | 
			
		||||
			}
 | 
			
		||||
			this.setState({currentPage: newpage});
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	onNewTransaction: function() {
 | 
			
		||||
		this.getTransactionPage(this.props.accounts[this.props.selectedAccount], this.state.currentPage);
 | 
			
		||||
	},
 | 
			
		||||
	onUpdatedTransaction: function() {
 | 
			
		||||
		this.getTransactionPage(this.props.accounts[this.props.selectedAccount], this.state.currentPage);
 | 
			
		||||
	},
 | 
			
		||||
	onDeletedTransaction: function() {
 | 
			
		||||
		this.getTransactionPage(this.props.accounts[this.props.selectedAccount], this.state.currentPage);
 | 
			
		||||
	},
 | 
			
		||||
	createNewTransaction: function(transaction) {
 | 
			
		||||
		$.ajax({
 | 
			
		||||
			type: "POST",
 | 
			
		||||
			dataType: "json",
 | 
			
		||||
			url: "transaction/",
 | 
			
		||||
			data: {transaction: transaction.toJSON()},
 | 
			
		||||
			success: function(data, status, jqXHR) {
 | 
			
		||||
				var e = new Error();
 | 
			
		||||
				e.fromJSON(data);
 | 
			
		||||
				if (e.isError()) {
 | 
			
		||||
					this.setState({error: e});
 | 
			
		||||
				} else {
 | 
			
		||||
					this.onNewTransaction();
 | 
			
		||||
				}
 | 
			
		||||
			}.bind(this),
 | 
			
		||||
			error: this.ajaxError
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	updateTransaction: function(transaction) {
 | 
			
		||||
		$.ajax({
 | 
			
		||||
			type: "PUT",
 | 
			
		||||
			dataType: "json",
 | 
			
		||||
			url: "transaction/"+transaction.TransactionId+"/",
 | 
			
		||||
			data: {transaction: transaction.toJSON()},
 | 
			
		||||
			success: function(data, status, jqXHR) {
 | 
			
		||||
				var e = new Error();
 | 
			
		||||
				e.fromJSON(data);
 | 
			
		||||
				if (e.isError()) {
 | 
			
		||||
					this.setState({error: e});
 | 
			
		||||
				} else {
 | 
			
		||||
					this.onUpdatedTransaction();
 | 
			
		||||
				}
 | 
			
		||||
			}.bind(this),
 | 
			
		||||
			error: this.ajaxError
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	deleteTransaction: function(transaction) {
 | 
			
		||||
		$.ajax({
 | 
			
		||||
			type: "DELETE",
 | 
			
		||||
			dataType: "json",
 | 
			
		||||
			url: "transaction/"+transaction.TransactionId+"/",
 | 
			
		||||
			success: function(data, status, jqXHR) {
 | 
			
		||||
				var e = new Error();
 | 
			
		||||
				e.fromJSON(data);
 | 
			
		||||
				if (e.isError()) {
 | 
			
		||||
					this.setState({error: e});
 | 
			
		||||
				} else {
 | 
			
		||||
					this.onDeletedTransaction();
 | 
			
		||||
				}
 | 
			
		||||
			}.bind(this),
 | 
			
		||||
			error: this.ajaxError
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleImportComplete: function() {
 | 
			
		||||
		this.setState({importingTransactions: false});
 | 
			
		||||
		this.getTransactionPage(this.props.accounts[this.props.selectedAccount], this.state.currentPage);
 | 
			
		||||
	},
 | 
			
		||||
	handleDeleteTransaction: function(transaction) {
 | 
			
		||||
		this.setState({
 | 
			
		||||
			editingTransaction: false
 | 
			
		||||
		});
 | 
			
		||||
		this.deleteTransaction(transaction);
 | 
			
		||||
	},
 | 
			
		||||
	handleUpdateTransaction: function(transaction) {
 | 
			
		||||
		this.setState({
 | 
			
		||||
			editingTransaction: false
 | 
			
		||||
		});
 | 
			
		||||
		if (transaction.TransactionId != -1) {
 | 
			
		||||
			this.updateTransaction(transaction);
 | 
			
		||||
		} else {
 | 
			
		||||
			this.createNewTransaction(transaction);
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	componentWillReceiveProps: function(nextProps) {
 | 
			
		||||
		if (nextProps.selectedAccount != this.props.selectedAccount) {
 | 
			
		||||
			this.setState({
 | 
			
		||||
				selectedTransaction: new Transaction(),
 | 
			
		||||
				transactions: [],
 | 
			
		||||
				currentPage: 0
 | 
			
		||||
			});
 | 
			
		||||
			if (nextProps.selectedAccount != -1)
 | 
			
		||||
				this.getTransactionPage(nextProps.accounts[nextProps.selectedAccount], 0);
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	render: function() {
 | 
			
		||||
		var name = "Please select an account";
 | 
			
		||||
		register = [];
 | 
			
		||||
 | 
			
		||||
		if (this.props.selectedAccount != -1) {
 | 
			
		||||
			name = this.props.accounts[this.props.selectedAccount].Name;
 | 
			
		||||
 | 
			
		||||
			var transactionRows = [];
 | 
			
		||||
			for (var i = 0; i < this.state.transactions.length; i++) {
 | 
			
		||||
				var t = this.state.transactions[i];
 | 
			
		||||
				transactionRows.push((
 | 
			
		||||
					<TransactionRow
 | 
			
		||||
						key={t.TransactionId}
 | 
			
		||||
						transaction={t}
 | 
			
		||||
						account={this.props.accounts[this.props.selectedAccount]}
 | 
			
		||||
						accounts={this.props.accounts}
 | 
			
		||||
						securities={this.props.securities}
 | 
			
		||||
						onEdit={this.handleEditTransaction}/>
 | 
			
		||||
				));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			var style = {height: this.state.height + "px"};
 | 
			
		||||
			register = (
 | 
			
		||||
				<div style={style} className="transactions-register">
 | 
			
		||||
				<Table bordered striped condensed hover>
 | 
			
		||||
					<thead><tr>
 | 
			
		||||
						<th>Date</th>
 | 
			
		||||
						<th>#</th>
 | 
			
		||||
						<th>Description</th>
 | 
			
		||||
						<th>Account</th>
 | 
			
		||||
						<th>Status</th>
 | 
			
		||||
						<th>Amount</th>
 | 
			
		||||
						<th>Balance</th>
 | 
			
		||||
					</tr></thead>
 | 
			
		||||
					<tbody>
 | 
			
		||||
						{transactionRows}
 | 
			
		||||
					</tbody>
 | 
			
		||||
				</Table>
 | 
			
		||||
				</div>
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var disabled = (this.props.selectedAccount == -1) ? true : false;
 | 
			
		||||
 | 
			
		||||
		return (
 | 
			
		||||
			<div className="transactions-container">
 | 
			
		||||
				<AddEditTransactionModal
 | 
			
		||||
					show={this.state.editingTransaction}
 | 
			
		||||
					transaction={this.state.selectedTransaction}
 | 
			
		||||
					accounts={this.props.accounts}
 | 
			
		||||
					accountChildren={this.props.accountChildren}
 | 
			
		||||
					onCancel={this.handleEditingCancel}
 | 
			
		||||
					onSubmit={this.handleUpdateTransaction}
 | 
			
		||||
					onDelete={this.handleDeleteTransaction}
 | 
			
		||||
					securities={this.props.securities} />
 | 
			
		||||
				<ImportTransactionsModal
 | 
			
		||||
					show={this.state.importingTransactions}
 | 
			
		||||
					account={this.props.accounts[this.props.selectedAccount]}
 | 
			
		||||
					accounts={this.props.accounts}
 | 
			
		||||
					onCancel={this.handleImportingCancel}
 | 
			
		||||
					onSubmit={this.handleImportComplete}/>
 | 
			
		||||
				<div className="transactions-register-toolbar">
 | 
			
		||||
				Transactions for '{name}'
 | 
			
		||||
				<ButtonToolbar className="pull-right">
 | 
			
		||||
					<ButtonGroup>
 | 
			
		||||
					<Pagination
 | 
			
		||||
						className="skinny-pagination"
 | 
			
		||||
						prev next first last ellipsis
 | 
			
		||||
						items={this.state.numPages}
 | 
			
		||||
						maxButtons={Math.min(5, this.state.numPages)}
 | 
			
		||||
						activePage={this.state.currentPage+1}
 | 
			
		||||
						onSelect={this.handleSelectPage} />
 | 
			
		||||
					</ButtonGroup>
 | 
			
		||||
					<ButtonGroup>
 | 
			
		||||
					<Button
 | 
			
		||||
							onClick={this.handleNewTransactionClicked}
 | 
			
		||||
							bsStyle="success"
 | 
			
		||||
							disabled={disabled}>
 | 
			
		||||
						<Glyphicon glyph='plus-sign' /> New Transaction
 | 
			
		||||
					</Button>
 | 
			
		||||
					<Button
 | 
			
		||||
							onClick={this.handleImportClicked}
 | 
			
		||||
							bsStyle="primary">
 | 
			
		||||
						<Glyphicon glyph='import' /> Import
 | 
			
		||||
					</Button>
 | 
			
		||||
					</ButtonGroup>
 | 
			
		||||
				</ButtonToolbar>
 | 
			
		||||
				</div>
 | 
			
		||||
				{register}
 | 
			
		||||
			</div>
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										158
									
								
								js/components/AccountSettingsModal.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								js/components/AccountSettingsModal.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,158 @@
 | 
			
		||||
var React = require('react');
 | 
			
		||||
 | 
			
		||||
var ReactDOM = require('react-dom');
 | 
			
		||||
 | 
			
		||||
var ReactBootstrap = require('react-bootstrap');
 | 
			
		||||
var Modal = ReactBootstrap.Modal;
 | 
			
		||||
var Button = ReactBootstrap.Button;
 | 
			
		||||
var ButtonGroup = ReactBootstrap.ButtonGroup;
 | 
			
		||||
var Form = ReactBootstrap.Form;
 | 
			
		||||
var FormGroup = ReactBootstrap.FormGroup;
 | 
			
		||||
var FormControl = ReactBootstrap.FormControl;
 | 
			
		||||
var ControlLabel = ReactBootstrap.ControlLabel;
 | 
			
		||||
var Col = ReactBootstrap.Col;
 | 
			
		||||
 | 
			
		||||
var User = require('../models').User;
 | 
			
		||||
 | 
			
		||||
module.exports = React.createClass({
 | 
			
		||||
	displayName: "AccountSettingsModal",
 | 
			
		||||
	_getInitialState: function(props) {
 | 
			
		||||
		return {error: "",
 | 
			
		||||
			name: props.user.Name,
 | 
			
		||||
			username: props.user.Username,
 | 
			
		||||
			email: props.user.Email,
 | 
			
		||||
			password: models.BogusPassword,
 | 
			
		||||
			confirm_password: models.BogusPassword,
 | 
			
		||||
			passwordChanged: false,
 | 
			
		||||
			initial_password: models.BogusPassword};
 | 
			
		||||
	},
 | 
			
		||||
	getInitialState: function() {
 | 
			
		||||
		 return this._getInitialState(this.props);
 | 
			
		||||
	},
 | 
			
		||||
	componentWillReceiveProps: function(nextProps) {
 | 
			
		||||
		if (nextProps.show && !this.props.show) {
 | 
			
		||||
			this.setState(this._getInitialState(nextProps));
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	passwordValidationState: function() {
 | 
			
		||||
		if (this.state.passwordChanged) {
 | 
			
		||||
			if (this.state.password.length >= 10)
 | 
			
		||||
				return "success";
 | 
			
		||||
			else if (this.state.password.length >= 6)
 | 
			
		||||
				return "warning";
 | 
			
		||||
			else
 | 
			
		||||
				return "error";
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	confirmPasswordValidationState: function() {
 | 
			
		||||
		if (this.state.confirm_password.length > 0) {
 | 
			
		||||
			if (this.state.confirm_password == this.state.password)
 | 
			
		||||
				return "success";
 | 
			
		||||
			else
 | 
			
		||||
				return "error";
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	handleCancel: function() {
 | 
			
		||||
		if (this.props.onCancel != null)
 | 
			
		||||
			this.props.onCancel();
 | 
			
		||||
	},
 | 
			
		||||
	handleChange: function() {
 | 
			
		||||
		if (ReactDOM.findDOMNode(this.refs.password).value != this.state.initial_password)
 | 
			
		||||
			this.setState({passwordChanged: true});
 | 
			
		||||
		this.setState({
 | 
			
		||||
			name: ReactDOM.findDOMNode(this.refs.name).value,
 | 
			
		||||
			username: ReactDOM.findDOMNode(this.refs.username).value,
 | 
			
		||||
			email: ReactDOM.findDOMNode(this.refs.email).value,
 | 
			
		||||
			password: ReactDOM.findDOMNode(this.refs.password).value,
 | 
			
		||||
			confirm_password: ReactDOM.findDOMNode(this.refs.confirm_password).value
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleSubmit: function(e) {
 | 
			
		||||
		var u = new User();
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
 | 
			
		||||
		u.UserId = this.props.user.UserId;
 | 
			
		||||
		u.Name = this.state.name;
 | 
			
		||||
		u.Username = this.state.username;
 | 
			
		||||
		u.Email = this.state.email;
 | 
			
		||||
		if (this.state.passwordChanged) {
 | 
			
		||||
			u.Password = this.state.password;
 | 
			
		||||
			if (u.Password != this.state.confirm_password) {
 | 
			
		||||
				this.setState({error: "Error: password do not match"});
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			u.Password = models.BogusPassword;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		this.props.onUpdateUser(u);
 | 
			
		||||
		this.props.onSubmit();
 | 
			
		||||
	},
 | 
			
		||||
	render: function() {
 | 
			
		||||
		return (
 | 
			
		||||
			<Modal show={this.props.show} onHide={this.handleCancel} bsSize="large">
 | 
			
		||||
				<Modal.Header closeButton>
 | 
			
		||||
					<Modal.Title>Edit Account Settings</Modal.Title>
 | 
			
		||||
				</Modal.Header>
 | 
			
		||||
				<Modal.Body>
 | 
			
		||||
				<span color="red">{this.state.error}</span>
 | 
			
		||||
				<Form horizontal onSubmit={this.handleSubmit}>
 | 
			
		||||
					<FormGroup>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Name</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<FormControl type="text"
 | 
			
		||||
								value={this.state.name}
 | 
			
		||||
								onChange={this.handleChange}
 | 
			
		||||
								ref="name"/>
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
					<FormGroup>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Username</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<FormControl type="text"
 | 
			
		||||
							value={this.state.username}
 | 
			
		||||
							onChange={this.handleChange}
 | 
			
		||||
							ref="username"/>
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
					<FormGroup>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Email</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<FormControl type="email"
 | 
			
		||||
							value={this.state.email}
 | 
			
		||||
							onChange={this.handleChange}
 | 
			
		||||
							ref="email"/>
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
					<FormGroup validationState={this.passwordValidationState()}>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Password</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<FormControl type="password"
 | 
			
		||||
							value={this.state.password}
 | 
			
		||||
							onChange={this.handleChange}
 | 
			
		||||
							ref="password"/>
 | 
			
		||||
						<FormControl.Feedback/>
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
					<FormGroup validationState={this.confirmPasswordValidationState()}>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Confirm Password</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<FormControl type="password"
 | 
			
		||||
							value={this.state.confirm_password}
 | 
			
		||||
							onChange={this.handleChange}
 | 
			
		||||
							ref="confirm_password"/>
 | 
			
		||||
						<FormControl.Feedback/>
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
				</Form>
 | 
			
		||||
				</Modal.Body>
 | 
			
		||||
				<Modal.Footer>
 | 
			
		||||
					<ButtonGroup>
 | 
			
		||||
						<Button onClick={this.handleCancel} bsStyle="warning">Cancel</Button>
 | 
			
		||||
						<Button onClick={this.handleSubmit} bsStyle="success">Save Settings</Button>
 | 
			
		||||
					</ButtonGroup>
 | 
			
		||||
				</Modal.Footer>
 | 
			
		||||
			</Modal>
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										486
									
								
								js/components/AccountsTab.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										486
									
								
								js/components/AccountsTab.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,486 @@
 | 
			
		||||
var React = require('react');
 | 
			
		||||
var ReactDOM = require('react-dom');
 | 
			
		||||
 | 
			
		||||
var ReactBootstrap = require('react-bootstrap');
 | 
			
		||||
var Grid = ReactBootstrap.Grid;
 | 
			
		||||
var Row = ReactBootstrap.Row;
 | 
			
		||||
var Col = ReactBootstrap.Col;
 | 
			
		||||
var Form = ReactBootstrap.Form;
 | 
			
		||||
var FormGroup = ReactBootstrap.FormGroup;
 | 
			
		||||
var FormControl = ReactBootstrap.FormControl;
 | 
			
		||||
var Checkbox = ReactBootstrap.Checkbox;
 | 
			
		||||
var ControlLabel = ReactBootstrap.ControlLabel;
 | 
			
		||||
var Button = ReactBootstrap.Button;
 | 
			
		||||
var ButtonGroup = ReactBootstrap.ButtonGroup;
 | 
			
		||||
var Glyphicon = ReactBootstrap.Glyphicon;
 | 
			
		||||
var ListGroup = ReactBootstrap.ListGroup;
 | 
			
		||||
var ListGroupItem = ReactBootstrap.ListGroupItem;
 | 
			
		||||
var Collapse = ReactBootstrap.Collapse;
 | 
			
		||||
var Alert = ReactBootstrap.Alert;
 | 
			
		||||
var Modal = ReactBootstrap.Modal;
 | 
			
		||||
var Collapse = ReactBootstrap.Collapse;
 | 
			
		||||
 | 
			
		||||
var Combobox = require('react-widgets').Combobox;
 | 
			
		||||
 | 
			
		||||
var models = require('../models');
 | 
			
		||||
var Security = models.Security;
 | 
			
		||||
var Account = models.Account;
 | 
			
		||||
var AccountTypeList = models.AccountTypeList;
 | 
			
		||||
 | 
			
		||||
var AccountCombobox = require('./AccountCombobox');
 | 
			
		||||
var AccountRegister = require('./AccountRegister');
 | 
			
		||||
 | 
			
		||||
const AddEditAccountModal = React.createClass({
 | 
			
		||||
	getInitialState: function() {
 | 
			
		||||
		var s = {
 | 
			
		||||
			accountid: -1,
 | 
			
		||||
			security: 1,
 | 
			
		||||
			parentaccountid: -1,
 | 
			
		||||
			type: 1,
 | 
			
		||||
			name: ""
 | 
			
		||||
		};
 | 
			
		||||
		if (this.props.editAccount != null) {
 | 
			
		||||
			s.accountid = this.props.editAccount.AccountId;
 | 
			
		||||
			s.name = this.props.editAccount.Name;
 | 
			
		||||
			s.security = this.props.editAccount.SecurityId;
 | 
			
		||||
			s.parentaccountid = this.props.editAccount.ParentAccountId;
 | 
			
		||||
			s.type = this.props.editAccount.Type;
 | 
			
		||||
		} else if (this.props.initialParentAccount != null) {
 | 
			
		||||
			s.security = this.props.initialParentAccount.SecurityId;
 | 
			
		||||
			s.parentaccountid = this.props.initialParentAccount.AccountId;
 | 
			
		||||
			s.type = this.props.initialParentAccount.Type;
 | 
			
		||||
		}
 | 
			
		||||
		return s;
 | 
			
		||||
	},
 | 
			
		||||
	handleCancel: function() {
 | 
			
		||||
		if (this.props.onCancel != null)
 | 
			
		||||
			this.props.onCancel();
 | 
			
		||||
	},
 | 
			
		||||
	handleChange: function() {
 | 
			
		||||
		this.setState({
 | 
			
		||||
			name: ReactDOM.findDOMNode(this.refs.name).value,
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	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();
 | 
			
		||||
 | 
			
		||||
		if (this.props.editAccount != null)
 | 
			
		||||
			a.AccountId = this.state.accountid;
 | 
			
		||||
		a.Name = this.state.name;
 | 
			
		||||
		a.ParentAccountId = this.state.parentaccountid;
 | 
			
		||||
		a.SecurityId = this.state.security;
 | 
			
		||||
		a.Type = this.state.type;
 | 
			
		||||
 | 
			
		||||
		if (this.props.onSubmit != null)
 | 
			
		||||
			this.props.onSubmit(a);
 | 
			
		||||
	},
 | 
			
		||||
	componentWillReceiveProps: function(nextProps) {
 | 
			
		||||
		if (nextProps.show && !this.props.show) {
 | 
			
		||||
			this.setState(this.getInitialState());
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	render: function() {
 | 
			
		||||
		var headerText = (this.props.editAccount != null) ? "Edit" : "Create New";
 | 
			
		||||
		var buttonText = (this.props.editAccount != null) ? "Save Changes" : "Create Account";
 | 
			
		||||
		var rootName = (this.props.editAccount != null) ? "Top-level Account" : "New Top-level Account";
 | 
			
		||||
		return (
 | 
			
		||||
			<Modal show={this.props.show} onHide={this.handleCancel}>
 | 
			
		||||
				<Modal.Header closeButton>
 | 
			
		||||
					<Modal.Title>{headerText} Account</Modal.Title>
 | 
			
		||||
				</Modal.Header>
 | 
			
		||||
				<Modal.Body>
 | 
			
		||||
				<Form horizontal onSubmit={this.handleSubmit}>
 | 
			
		||||
					<FormGroup>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Name</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<FormControl type="text"
 | 
			
		||||
							value={this.state.name}
 | 
			
		||||
							onChange={this.handleChange}
 | 
			
		||||
							ref="name"/>
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
					<FormGroup>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Parent Account</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<AccountCombobox
 | 
			
		||||
							accounts={this.props.accounts}
 | 
			
		||||
							accountChildren={this.props.accountChildren}
 | 
			
		||||
							value={this.state.parentaccountid}
 | 
			
		||||
							rootName={rootName}
 | 
			
		||||
							onChange={this.handleParentChange}
 | 
			
		||||
							ref="parent" />
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
					<FormGroup>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Security</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<Combobox
 | 
			
		||||
							data={this.props.security_list}
 | 
			
		||||
							valueField='SecurityId'
 | 
			
		||||
							textField={item => item.Name + " - " + item.Description}
 | 
			
		||||
							defaultValue={this.state.security}
 | 
			
		||||
							onChange={this.handleSecurityChange}
 | 
			
		||||
							ref="security" />
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
					<FormGroup>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Account Type</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<Combobox
 | 
			
		||||
							data={AccountTypeList}
 | 
			
		||||
							valueField='TypeId'
 | 
			
		||||
							textField='Name'
 | 
			
		||||
							defaultValue={this.state.type}
 | 
			
		||||
							onChange={this.handleTypeChange}
 | 
			
		||||
							ref="type" />
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
				</Form>
 | 
			
		||||
				</Modal.Body>
 | 
			
		||||
				<Modal.Footer>
 | 
			
		||||
					<ButtonGroup className="pull-right">
 | 
			
		||||
						<Button onClick={this.handleCancel} bsStyle="warning">Cancel</Button>
 | 
			
		||||
						<Button onClick={this.handleSubmit} bsStyle="success">{buttonText}</Button>
 | 
			
		||||
					</ButtonGroup>
 | 
			
		||||
				</Modal.Footer>
 | 
			
		||||
			</Modal>
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const DeleteAccountModal = React.createClass({
 | 
			
		||||
	getInitialState: function() {
 | 
			
		||||
		if (this.props.initialAccount != null)
 | 
			
		||||
			var accountid = this.props.initialAccount.AccountId;
 | 
			
		||||
		else if (this.props.accounts.length > 0)
 | 
			
		||||
			var accountid = this.props.accounts[0].AccountId;
 | 
			
		||||
		else
 | 
			
		||||
			var accountid = -1;
 | 
			
		||||
		return {error: "",
 | 
			
		||||
			accountid: accountid,
 | 
			
		||||
			checked: false,
 | 
			
		||||
			show: false};
 | 
			
		||||
	},
 | 
			
		||||
	handleCancel: function() {
 | 
			
		||||
		if (this.props.onCancel != null)
 | 
			
		||||
			this.props.onCancel();
 | 
			
		||||
	},
 | 
			
		||||
	handleChange: function(account) {
 | 
			
		||||
		this.setState({accountid: account.AccountId});
 | 
			
		||||
	},
 | 
			
		||||
	handleCheckboxClick: function() {
 | 
			
		||||
		this.setState({checked: !this.state.checked});
 | 
			
		||||
	},
 | 
			
		||||
	handleSubmit: function() {
 | 
			
		||||
		if (this.props.accounts.hasOwnProperty(this.state.accountid)) {
 | 
			
		||||
			if (this.state.checked) {
 | 
			
		||||
				if (this.props.onSubmit != null)
 | 
			
		||||
					this.props.onSubmit(this.props.accounts[this.state.accountid]);
 | 
			
		||||
			} else {
 | 
			
		||||
				this.setState({error: "You must confirm you wish to delete this account."});
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			this.setState({error: "You must select an account."});
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	componentWillReceiveProps: function(nextProps) {
 | 
			
		||||
		if (nextProps.show && !this.props.show) {
 | 
			
		||||
			this.setState(this.getInitialState());
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	render: function() {
 | 
			
		||||
		var checkbox = [];
 | 
			
		||||
		if (this.props.accounts.hasOwnProperty(this.state.accountid)) {
 | 
			
		||||
			var parentAccountId = this.props.accounts[this.state.accountid].ParentAccountId;
 | 
			
		||||
			var parentAccount = "will be deleted and any child accounts will become top-level accounts.";
 | 
			
		||||
			if (parentAccountId != -1)
 | 
			
		||||
				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;
 | 
			
		||||
			checkbox = (
 | 
			
		||||
				<FormGroup>
 | 
			
		||||
				<Col xsOffset={2} sm={10}>
 | 
			
		||||
				<Checkbox
 | 
			
		||||
					checked={this.state.checked ? "checked" : ""}
 | 
			
		||||
					onClick={this.handleCheckboxClick}>
 | 
			
		||||
					{warningString}
 | 
			
		||||
				</Checkbox>
 | 
			
		||||
				</Col>
 | 
			
		||||
				</FormGroup>);
 | 
			
		||||
		}
 | 
			
		||||
		var warning = [];
 | 
			
		||||
		if (this.state.error.length != "") {
 | 
			
		||||
			warning = (
 | 
			
		||||
				<Alert bsStyle="danger"><strong>Error: </strong>{this.state.error}</Alert>
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return (
 | 
			
		||||
			<Modal
 | 
			
		||||
				show={this.props.show}
 | 
			
		||||
				onHide={this.handleCancel}
 | 
			
		||||
				ref="modal">
 | 
			
		||||
				<Modal.Header closeButton>
 | 
			
		||||
					<Modal.Title>Delete Account</Modal.Title>
 | 
			
		||||
				</Modal.Header>
 | 
			
		||||
				<Modal.Body>
 | 
			
		||||
				{warning}
 | 
			
		||||
				<Form horizontal onSubmit={this.handleSubmit}>
 | 
			
		||||
					<FormGroup>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Delete Account</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<AccountCombobox
 | 
			
		||||
							includeRoot={false}
 | 
			
		||||
							accounts={this.props.accounts}
 | 
			
		||||
							accountChildren={this.props.accountChildren}
 | 
			
		||||
							value={this.state.accountid}
 | 
			
		||||
							onChange={this.handleChange}/>
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
					{checkbox}
 | 
			
		||||
				</Form>
 | 
			
		||||
				</Modal.Body>
 | 
			
		||||
				<Modal.Footer>
 | 
			
		||||
					<ButtonGroup className="pull-right">
 | 
			
		||||
						<Button onClick={this.handleCancel} bsStyle="warning">Cancel</Button>
 | 
			
		||||
						<Button onClick={this.handleSubmit} bsStyle="success">Delete Account</Button>
 | 
			
		||||
					</ButtonGroup>
 | 
			
		||||
				</Modal.Footer>
 | 
			
		||||
			</Modal>
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AccountTreeNode = React.createClass({
 | 
			
		||||
	getInitialState: function() {
 | 
			
		||||
		return {expanded: false};
 | 
			
		||||
	},
 | 
			
		||||
	handleToggle: function(e) {
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
		this.setState({expanded:!this.state.expanded});
 | 
			
		||||
	},
 | 
			
		||||
	handleChildSelect: function(account) {
 | 
			
		||||
		if (this.props.onSelect != null)
 | 
			
		||||
			this.props.onSelect(account);
 | 
			
		||||
	},
 | 
			
		||||
	handleSelect: function() {
 | 
			
		||||
		if (this.props.onSelect != null)
 | 
			
		||||
			this.props.onSelect(this.props.account);
 | 
			
		||||
	},
 | 
			
		||||
	render: function() {
 | 
			
		||||
		var glyph = this.state.expanded ? 'minus' : 'plus';
 | 
			
		||||
		var active = (this.props.selectedAccount != -1 &&
 | 
			
		||||
			this.props.account.AccountId == this.props.selectedAccount);
 | 
			
		||||
		var buttonStyle = active ? "info" : "link";
 | 
			
		||||
 | 
			
		||||
		var self = this;
 | 
			
		||||
		var children = this.props.accountChildren[this.props.account.AccountId].map(function(childId) {
 | 
			
		||||
			var account = self.props.accounts[childId];
 | 
			
		||||
			return (
 | 
			
		||||
				<AccountTreeNode
 | 
			
		||||
					key={account.AccountId}
 | 
			
		||||
					account={account}
 | 
			
		||||
					selectedAccount={self.props.selectedAccount}
 | 
			
		||||
					accounts={self.props.accounts}
 | 
			
		||||
					accountChildren={self.props.accountChildren}
 | 
			
		||||
					onSelect={self.handleChildSelect}/>
 | 
			
		||||
		   );
 | 
			
		||||
		});
 | 
			
		||||
		var accounttreeClasses = "accounttree"
 | 
			
		||||
		var expandButton = [];
 | 
			
		||||
		if (children.length > 0) {
 | 
			
		||||
			expandButton.push((
 | 
			
		||||
				<Button onClick={this.handleToggle}
 | 
			
		||||
						key={1}
 | 
			
		||||
						bsSize="xsmall"
 | 
			
		||||
						bsStyle="link"
 | 
			
		||||
						className="accounttree-expandbutton">
 | 
			
		||||
					<Glyphicon glyph={glyph} bsSize="xsmall"/>
 | 
			
		||||
				</Button>
 | 
			
		||||
			));
 | 
			
		||||
		} else {
 | 
			
		||||
			accounttreeClasses += "-nochildren";
 | 
			
		||||
		}
 | 
			
		||||
		return (
 | 
			
		||||
			<div className={accounttreeClasses}>
 | 
			
		||||
				{expandButton}
 | 
			
		||||
				<Button onClick={this.handleSelect}
 | 
			
		||||
						bsStyle={buttonStyle}
 | 
			
		||||
						className="accounttree-name">
 | 
			
		||||
					{this.props.account.Name}
 | 
			
		||||
				</Button>
 | 
			
		||||
				<Collapse in={this.state.expanded}>
 | 
			
		||||
					<div>
 | 
			
		||||
						{children}
 | 
			
		||||
					</div>
 | 
			
		||||
				</Collapse>
 | 
			
		||||
			</div>
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AccountTree = React.createClass({
 | 
			
		||||
	getInitialState: function() {
 | 
			
		||||
		return {height: 0};
 | 
			
		||||
	},
 | 
			
		||||
	handleSelect: function(account) {
 | 
			
		||||
		if (this.props.onSelect != null) {
 | 
			
		||||
			this.props.onSelect(account);
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	resize: function() {
 | 
			
		||||
		var div = ReactDOM.findDOMNode(this);
 | 
			
		||||
		this.setState({height: div.parentElement.clientHeight - 73});
 | 
			
		||||
	},
 | 
			
		||||
	componentDidMount: function() {
 | 
			
		||||
		this.resize();
 | 
			
		||||
		var self = this;
 | 
			
		||||
		$(window).resize(function() {self.resize();});
 | 
			
		||||
	},
 | 
			
		||||
	render: function() {
 | 
			
		||||
		var accounts = this.props.accounts;
 | 
			
		||||
 | 
			
		||||
		var children = [];
 | 
			
		||||
		for (var accountId in accounts) {
 | 
			
		||||
			if (accounts.hasOwnProperty(accountId) &&
 | 
			
		||||
					accounts[accountId].isRootAccount()) {
 | 
			
		||||
				children.push((<AccountTreeNode
 | 
			
		||||
					key={accounts[accountId].AccountId}
 | 
			
		||||
					account={accounts[accountId]}
 | 
			
		||||
					selectedAccount={this.props.selectedAccount}
 | 
			
		||||
					accounts={this.props.accounts}
 | 
			
		||||
					accountChildren={this.props.accountChildren}
 | 
			
		||||
					onSelect={this.handleSelect}/>));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var style = {height: this.state.height + "px"};
 | 
			
		||||
 | 
			
		||||
		return (
 | 
			
		||||
			<div className="accounttree-root" style={style} >
 | 
			
		||||
				{children}
 | 
			
		||||
			</div>
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
module.exports = React.createClass({
 | 
			
		||||
	displayName: "AccountsTab",
 | 
			
		||||
	getInitialState: function() {
 | 
			
		||||
		return {
 | 
			
		||||
			creatingNewAccount: false,
 | 
			
		||||
			editingAccount: false,
 | 
			
		||||
			deletingAccount: false
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	handleNewAccount: function() {
 | 
			
		||||
		this.setState({creatingNewAccount: true});
 | 
			
		||||
	},
 | 
			
		||||
	handleEditAccount: function() {
 | 
			
		||||
		this.setState({editingAccount: true});
 | 
			
		||||
	},
 | 
			
		||||
	handleDeleteAccount: function() {
 | 
			
		||||
		this.setState({deletingAccount: true});
 | 
			
		||||
	},
 | 
			
		||||
	handleCreationCancel: function() {
 | 
			
		||||
		this.setState({creatingNewAccount: false});
 | 
			
		||||
	},
 | 
			
		||||
	handleEditingCancel: function() {
 | 
			
		||||
		this.setState({editingAccount: false});
 | 
			
		||||
	},
 | 
			
		||||
	handleDeletionCancel: function() {
 | 
			
		||||
		this.setState({deletingAccount: false});
 | 
			
		||||
	},
 | 
			
		||||
	handleCreateAccount: function(account) {
 | 
			
		||||
		if (this.props.onCreateAccount != null)
 | 
			
		||||
			this.props.onCreateAccount(account);
 | 
			
		||||
		this.setState({creatingNewAccount: false});
 | 
			
		||||
	},
 | 
			
		||||
	handleUpdateAccount: function(account) {
 | 
			
		||||
		if (this.props.onUpdateAccount != null)
 | 
			
		||||
			this.props.onUpdateAccount(account);
 | 
			
		||||
		this.setState({editingAccount: false});
 | 
			
		||||
	},
 | 
			
		||||
	handleRemoveAccount: function(account) {
 | 
			
		||||
		if (this.props.onDeleteAccount != null)
 | 
			
		||||
			this.props.onDeleteAccount(account);
 | 
			
		||||
		this.setState({deletingAccount: false});
 | 
			
		||||
	},
 | 
			
		||||
	handleAccountSelected: function(account) {
 | 
			
		||||
		this.props.onSelectAccount(account.AccountId);
 | 
			
		||||
	},
 | 
			
		||||
	render: function() {
 | 
			
		||||
		var disabled = (this.props.selectedAccount == -1) ? true : false;
 | 
			
		||||
 | 
			
		||||
		var selectedAccount = null;
 | 
			
		||||
		if (this.props.accounts.hasOwnProperty(this.props.selectedAccount))
 | 
			
		||||
			selectedAccount = this.props.accounts[this.props.selectedAccount];
 | 
			
		||||
 | 
			
		||||
		return (
 | 
			
		||||
			<Grid fluid className="fullheight"><Row className="fullheight">
 | 
			
		||||
				<Col xs={2} className="fullheight account-column">
 | 
			
		||||
					<AddEditAccountModal
 | 
			
		||||
						show={this.state.creatingNewAccount}
 | 
			
		||||
						initialParentAccount={selectedAccount}
 | 
			
		||||
						accounts={this.props.accounts}
 | 
			
		||||
						accountChildren={this.props.accountChildren}
 | 
			
		||||
						onCancel={this.handleCreationCancel}
 | 
			
		||||
						onSubmit={this.handleCreateAccount}
 | 
			
		||||
						security_list={this.props.security_list}/>
 | 
			
		||||
					<AddEditAccountModal
 | 
			
		||||
						show={this.state.editingAccount}
 | 
			
		||||
						editAccount={selectedAccount}
 | 
			
		||||
						accounts={this.props.accounts}
 | 
			
		||||
						accountChildren={this.props.accountChildren}
 | 
			
		||||
						onCancel={this.handleEditingCancel}
 | 
			
		||||
						onSubmit={this.handleUpdateAccount}
 | 
			
		||||
						security_list={this.props.security_list}/>
 | 
			
		||||
					<DeleteAccountModal
 | 
			
		||||
						show={this.state.deletingAccount}
 | 
			
		||||
						initialAccount={selectedAccount}
 | 
			
		||||
						accounts={this.props.accounts}
 | 
			
		||||
						accountChildren={this.props.accountChildren}
 | 
			
		||||
						onCancel={this.handleDeletionCancel}
 | 
			
		||||
						onSubmit={this.handleRemoveAccount}/>
 | 
			
		||||
					<AccountTree
 | 
			
		||||
						accounts={this.props.accounts}
 | 
			
		||||
						accountChildren={this.props.accountChildren}
 | 
			
		||||
						selectedAccount={this.props.selectedAccount}
 | 
			
		||||
						onSelect={this.handleAccountSelected}/>
 | 
			
		||||
					<ButtonGroup className="account-buttongroup">
 | 
			
		||||
						<Button onClick={this.handleNewAccount} bsStyle="success">
 | 
			
		||||
							<Glyphicon glyph='plus-sign' /></Button>
 | 
			
		||||
						<Button onClick={this.handleEditAccount}
 | 
			
		||||
								bsStyle="primary" disabled={disabled}>
 | 
			
		||||
							<Glyphicon glyph='cog' /></Button>
 | 
			
		||||
						<Button onClick={this.handleDeleteAccount}
 | 
			
		||||
								bsStyle="danger" disabled={disabled}>
 | 
			
		||||
							<Glyphicon glyph='trash' /></Button>
 | 
			
		||||
					</ButtonGroup>
 | 
			
		||||
				</Col><Col xs={10} className="fullheight transactions-column">
 | 
			
		||||
					<AccountRegister
 | 
			
		||||
						selectedAccount={this.props.selectedAccount}
 | 
			
		||||
						accounts={this.props.accounts}
 | 
			
		||||
						accountChildren={this.props.accountChildren}
 | 
			
		||||
						securities={this.props.securities} />
 | 
			
		||||
				</Col>
 | 
			
		||||
			</Row></Grid>
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										97
									
								
								js/components/MoneyGoApp.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								js/components/MoneyGoApp.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,97 @@
 | 
			
		||||
var React = require('react');
 | 
			
		||||
 | 
			
		||||
var ReactBootstrap = require('react-bootstrap');
 | 
			
		||||
var Jumbotron = ReactBootstrap.Jumbotron;
 | 
			
		||||
var Tabs = ReactBootstrap.Tabs;
 | 
			
		||||
var Tab = ReactBootstrap.Tab;
 | 
			
		||||
var Modal = ReactBootstrap.Modal;
 | 
			
		||||
 | 
			
		||||
var TopBarContainer = require('../containers/TopBarContainer');
 | 
			
		||||
var NewUserForm = require('./NewUserForm');
 | 
			
		||||
var AccountSettingsModalContainer = require('../containers/AccountSettingsModalContainer');
 | 
			
		||||
var AccountsTabContainer = require('../containers/AccountsTabContainer');
 | 
			
		||||
 | 
			
		||||
module.exports = React.createClass({
 | 
			
		||||
	displayName: "MoneyGoApp",
 | 
			
		||||
	getInitialState: function() {
 | 
			
		||||
		return {
 | 
			
		||||
			hash: "home",
 | 
			
		||||
			showAccountSettingsModal: false
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	componentDidMount: function() {
 | 
			
		||||
		this.props.tryResumingSession();
 | 
			
		||||
		this.handleHashChange();
 | 
			
		||||
		if ("onhashchange" in window) {
 | 
			
		||||
			window.onhashchange = this.handleHashChange;
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	handleHashChange: function() {
 | 
			
		||||
		var hash = location.hash.replace(/^#/, '');
 | 
			
		||||
		if (hash.length == 0)
 | 
			
		||||
			hash = "home";
 | 
			
		||||
		if (hash != this.state.hash)
 | 
			
		||||
			this.setHash(hash);
 | 
			
		||||
	},
 | 
			
		||||
	setHash: function(hash) {
 | 
			
		||||
		location.hash = hash;
 | 
			
		||||
		if (this.state.hash != hash)
 | 
			
		||||
		this.setState({hash: hash});
 | 
			
		||||
	},
 | 
			
		||||
	handleAccountSettings: function() {
 | 
			
		||||
		this.setState({showAccountSettingsModal: true});
 | 
			
		||||
	},
 | 
			
		||||
	handleSettingsSubmitted: function(user) {
 | 
			
		||||
		this.setState({
 | 
			
		||||
			showAccountSettingsModal: false
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleSettingsCanceled: function() {
 | 
			
		||||
		this.setState({showAccountSettingsModal: false});
 | 
			
		||||
	},
 | 
			
		||||
	handleCreateNewUser: function() {
 | 
			
		||||
		this.setHash("new_user");
 | 
			
		||||
	},
 | 
			
		||||
	handleGoHome: function() {
 | 
			
		||||
		this.setHash("home");
 | 
			
		||||
	},
 | 
			
		||||
	render: function() {
 | 
			
		||||
		var mainContent;
 | 
			
		||||
		if (this.state.hash == "new_user") {
 | 
			
		||||
			mainContent = <NewUserForm onNewUser={this.handleGoHome} onCancel={this.handleGoHome}/>
 | 
			
		||||
		} else {
 | 
			
		||||
			if (this.props.user.isUser())
 | 
			
		||||
				mainContent = (
 | 
			
		||||
					<Tabs defaultActiveKey={1} id='mainNavigationTabs'>
 | 
			
		||||
						<Tab title="Accounts" eventKey={1} >
 | 
			
		||||
						<AccountsTabContainer
 | 
			
		||||
							className="fullheight" />
 | 
			
		||||
						</Tab>
 | 
			
		||||
						<Tab title="Scheduled Transactions" eventKey={2} >Scheduled transactions go here...</Tab>
 | 
			
		||||
						<Tab title="Budgets" eventKey={3} >Budgets go here...</Tab>
 | 
			
		||||
						<Tab title="Reports" eventKey={4} >Reports go here...</Tab>
 | 
			
		||||
					</Tabs>);
 | 
			
		||||
			else
 | 
			
		||||
				mainContent = (
 | 
			
		||||
					<Jumbotron>
 | 
			
		||||
						<center>
 | 
			
		||||
							<h1>Money<i>Go</i></h1>
 | 
			
		||||
							<p><i>Go</i> manage your money.</p>
 | 
			
		||||
						</center>
 | 
			
		||||
					</Jumbotron>);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return (
 | 
			
		||||
			<div className="fullheight ui">
 | 
			
		||||
				<TopBarContainer
 | 
			
		||||
					onCreateNewUser={this.handleCreateNewUser}
 | 
			
		||||
					onAccountSettings={this.handleAccountSettings} />
 | 
			
		||||
				{mainContent}
 | 
			
		||||
				<AccountSettingsModalContainer
 | 
			
		||||
					show={this.state.showAccountSettingsModal}
 | 
			
		||||
					onSubmit={this.handleSettingsSubmitted}
 | 
			
		||||
					onCancel={this.handleSettingsCanceled}/>
 | 
			
		||||
			</div>
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										165
									
								
								js/components/NewUserForm.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								js/components/NewUserForm.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,165 @@
 | 
			
		||||
var React = require('react');
 | 
			
		||||
var ReactDOM = require('react-dom');
 | 
			
		||||
 | 
			
		||||
var ReactBootstrap = require('react-bootstrap');
 | 
			
		||||
var Panel = ReactBootstrap.Panel;
 | 
			
		||||
var Form = ReactBootstrap.Form;
 | 
			
		||||
var FormGroup = ReactBootstrap.FormGroup;
 | 
			
		||||
var FormControl = ReactBootstrap.FormControl;
 | 
			
		||||
var ControlLabel = ReactBootstrap.ControlLabel;
 | 
			
		||||
var Col = ReactBootstrap.Col;
 | 
			
		||||
var Button = ReactBootstrap.Button;
 | 
			
		||||
var ButtonGroup = ReactBootstrap.ButtonGroup;
 | 
			
		||||
 | 
			
		||||
var models = require('../models');
 | 
			
		||||
var User = models.User;
 | 
			
		||||
var Error = models.Error;
 | 
			
		||||
 | 
			
		||||
module.exports = React.createClass({
 | 
			
		||||
	getInitialState: function() {
 | 
			
		||||
		return {error: "",
 | 
			
		||||
			name: "",
 | 
			
		||||
			username: "",
 | 
			
		||||
			email: "",
 | 
			
		||||
			password: "",
 | 
			
		||||
			confirm_password: "",
 | 
			
		||||
			passwordChanged: false,
 | 
			
		||||
			initial_password: ""};
 | 
			
		||||
	},
 | 
			
		||||
	passwordValidationState: function() {
 | 
			
		||||
		if (this.state.passwordChanged) {
 | 
			
		||||
			if (this.state.password.length >= 10)
 | 
			
		||||
				return "success";
 | 
			
		||||
			else if (this.state.password.length >= 6)
 | 
			
		||||
				return "warning";
 | 
			
		||||
			else
 | 
			
		||||
				return "error";
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	confirmPasswordValidationState: function() {
 | 
			
		||||
		if (this.state.confirm_password.length > 0) {
 | 
			
		||||
			if (this.state.confirm_password == this.state.password)
 | 
			
		||||
				return "success";
 | 
			
		||||
			else
 | 
			
		||||
				return "error";
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	handleCancel: function() {
 | 
			
		||||
		if (this.props.onCancel != null)
 | 
			
		||||
			this.props.onCancel();
 | 
			
		||||
	},
 | 
			
		||||
	handleChange: function() {
 | 
			
		||||
		if (ReactDOM.findDOMNode(this.refs.password).value != this.state.initial_password)
 | 
			
		||||
			this.setState({passwordChanged: true});
 | 
			
		||||
		this.setState({
 | 
			
		||||
			name: ReactDOM.findDOMNode(this.refs.name).value,
 | 
			
		||||
			username: ReactDOM.findDOMNode(this.refs.username).value,
 | 
			
		||||
			email: ReactDOM.findDOMNode(this.refs.email).value,
 | 
			
		||||
			password: ReactDOM.findDOMNode(this.refs.password).value,
 | 
			
		||||
			confirm_password: ReactDOM.findDOMNode(this.refs.confirm_password).value
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	handleSubmit: function(e) {
 | 
			
		||||
		var u = new User();
 | 
			
		||||
		var error = "";
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
 | 
			
		||||
		u.Name = this.state.name;
 | 
			
		||||
		u.Username = this.state.username;
 | 
			
		||||
		u.Email = this.state.email;
 | 
			
		||||
		u.Password = this.state.password;
 | 
			
		||||
		if (u.Password != this.state.confirm_password) {
 | 
			
		||||
			this.setState({error: "Error: password do not match"});
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		this.handleCreateNewUser(u);
 | 
			
		||||
	},
 | 
			
		||||
	handleCreateNewUser: function(user) {
 | 
			
		||||
		$.ajax({
 | 
			
		||||
			type: "POST",
 | 
			
		||||
			dataType: "json",
 | 
			
		||||
			url: "user/",
 | 
			
		||||
			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.props.onNewUser();
 | 
			
		||||
				}
 | 
			
		||||
			}.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() {
 | 
			
		||||
		var title = <h3>Create New User</h3>;
 | 
			
		||||
		return (
 | 
			
		||||
			<Panel header={title} bsStyle="info">
 | 
			
		||||
				<span color="red">{this.state.error}</span>
 | 
			
		||||
				<Form horizontal onSubmit={this.handleSubmit}>
 | 
			
		||||
					<FormGroup>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Name</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<FormControl type="text"
 | 
			
		||||
							value={this.state.name}
 | 
			
		||||
							onChange={this.handleChange}
 | 
			
		||||
							ref="name"/>
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
					<FormGroup>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Username</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<FormControl type="text"
 | 
			
		||||
							value={this.state.username}
 | 
			
		||||
							onChange={this.handleChange}
 | 
			
		||||
							ref="username"/>
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
					<FormGroup>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Email</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<FormControl type="email"
 | 
			
		||||
							value={this.state.email}
 | 
			
		||||
							onChange={this.handleChange}
 | 
			
		||||
							ref="email"/>
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
					<FormGroup validationState={this.passwordValidationState()}>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Password</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<FormControl type="password"
 | 
			
		||||
							value={this.state.password}
 | 
			
		||||
							onChange={this.handleChange}
 | 
			
		||||
							ref="password"/>
 | 
			
		||||
						<FormControl.Feedback/>
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
					<FormGroup validationState={this.confirmPasswordValidationState()}>
 | 
			
		||||
						<Col componentClass={ControlLabel} xs={2}>Confirm Password</Col>
 | 
			
		||||
						<Col xs={10}>
 | 
			
		||||
						<FormControl type="password"
 | 
			
		||||
							value={this.state.confirm_password}
 | 
			
		||||
							onChange={this.handleChange}
 | 
			
		||||
							ref="confirm_password"/>
 | 
			
		||||
						<FormControl.Feedback/>
 | 
			
		||||
						</Col>
 | 
			
		||||
					</FormGroup>
 | 
			
		||||
 | 
			
		||||
					<ButtonGroup className="pull-right">
 | 
			
		||||
						<Button onClick={this.handleCancel}
 | 
			
		||||
								bsStyle="warning">Cancel</Button>
 | 
			
		||||
						<Button type="submit"
 | 
			
		||||
								bsStyle="success">Create New User</Button>
 | 
			
		||||
					</ButtonGroup>
 | 
			
		||||
				</Form>
 | 
			
		||||
			</Panel>
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										123
									
								
								js/components/TopBar.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								js/components/TopBar.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,123 @@
 | 
			
		||||
var React = require('react');
 | 
			
		||||
 | 
			
		||||
var ReactBootstrap = require('react-bootstrap');
 | 
			
		||||
var Alert = ReactBootstrap.Alert;
 | 
			
		||||
var FormGroup = ReactBootstrap.FormGroup;
 | 
			
		||||
var FormControl = ReactBootstrap.FormControl;
 | 
			
		||||
var Button = ReactBootstrap.Button;
 | 
			
		||||
var DropdownButton = ReactBootstrap.DropdownButton;
 | 
			
		||||
var MenuItem = ReactBootstrap.MenuItem;
 | 
			
		||||
var Row = ReactBootstrap.Row;
 | 
			
		||||
var Col = ReactBootstrap.Col;
 | 
			
		||||
 | 
			
		||||
var ReactDOM = require('react-dom');
 | 
			
		||||
 | 
			
		||||
var User = require('../models').User;
 | 
			
		||||
 | 
			
		||||
const LoginBar = React.createClass({
 | 
			
		||||
	getInitialState: function() {
 | 
			
		||||
		return {username: '', password: ''};
 | 
			
		||||
	},
 | 
			
		||||
	onUsernameChange: function(e) {
 | 
			
		||||
		this.setState({username: e.target.value});
 | 
			
		||||
	},
 | 
			
		||||
	onPasswordChange: function(e) {
 | 
			
		||||
		this.setState({password: e.target.value});
 | 
			
		||||
	},
 | 
			
		||||
	handleSubmit: function(e) {
 | 
			
		||||
		var user = new User();
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
		user.Username = ReactDOM.findDOMNode(this.refs.username).value;
 | 
			
		||||
		user.Password = ReactDOM.findDOMNode(this.refs.password).value;
 | 
			
		||||
		this.props.onLogin(user);
 | 
			
		||||
	},
 | 
			
		||||
	handleNewUserSubmit: function(e) {
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
		this.props.onCreateNewUser();
 | 
			
		||||
	},
 | 
			
		||||
	render: function() {
 | 
			
		||||
		return (
 | 
			
		||||
			<form onSubmit={this.handleSubmit}>
 | 
			
		||||
			<FormGroup>
 | 
			
		||||
				<Row>
 | 
			
		||||
					<Col xs={4}></Col>
 | 
			
		||||
					<Col xs={2}>
 | 
			
		||||
						<Button bsStyle="link"
 | 
			
		||||
							onClick={this.handleNewUserSubmit}>Create New User</Button>
 | 
			
		||||
					</Col>
 | 
			
		||||
					<Col xs={2}>
 | 
			
		||||
						<FormControl type="text"
 | 
			
		||||
							placeholder="Username..."
 | 
			
		||||
							ref="username"/>
 | 
			
		||||
					</Col>
 | 
			
		||||
					<Col xs={2}>
 | 
			
		||||
						<FormControl type="password"
 | 
			
		||||
							placeholder="Password..."
 | 
			
		||||
							ref="password"/>
 | 
			
		||||
					</Col>
 | 
			
		||||
					<Col xs={2}>
 | 
			
		||||
						<Button type="submit" bsStyle="primary" block>
 | 
			
		||||
							Login</Button>
 | 
			
		||||
					</Col>
 | 
			
		||||
				</Row>
 | 
			
		||||
			</FormGroup>
 | 
			
		||||
			</form>
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const LogoutBar = React.createClass({
 | 
			
		||||
	handleOnSelect: function(key) {
 | 
			
		||||
		if (key == 1) {
 | 
			
		||||
			if (this.props.onAccountSettings != null)
 | 
			
		||||
				this.props.onAccountSettings();
 | 
			
		||||
		} else if (key == 2) {
 | 
			
		||||
			this.props.onLogout();
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	render: function() {
 | 
			
		||||
		var signedInString = "Signed in as "+this.props.user.Name;
 | 
			
		||||
		return (
 | 
			
		||||
			<FormGroup>
 | 
			
		||||
				<Row>
 | 
			
		||||
					<Col xs={2}><label className="control-label pull-left">Money<i>Go</i></label></Col>
 | 
			
		||||
					<Col xs={6}></Col>
 | 
			
		||||
					<Col xs={4}>
 | 
			
		||||
						<div className="pull-right">
 | 
			
		||||
						<DropdownButton id="logout-settings-dropdown" title={signedInString} onSelect={this.handleOnSelect} bsStyle="info">
 | 
			
		||||
							<MenuItem eventKey={1}>Account Settings</MenuItem>
 | 
			
		||||
							<MenuItem eventKey={2}>Logout</MenuItem>
 | 
			
		||||
						</DropdownButton>
 | 
			
		||||
						</div>
 | 
			
		||||
					</Col>
 | 
			
		||||
				</Row>
 | 
			
		||||
			</FormGroup>
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
module.exports = React.createClass({
 | 
			
		||||
	displayName: "TopBar",
 | 
			
		||||
	render: function() {
 | 
			
		||||
		var barContents;
 | 
			
		||||
		var errorAlert;
 | 
			
		||||
		if (!this.props.user.isUser())
 | 
			
		||||
			barContents = <LoginBar onLogin={this.props.onLogin} onCreateNewUser={this.props.onCreateNewUser} />;
 | 
			
		||||
		else
 | 
			
		||||
			barContents = <LogoutBar user={this.props.user} onLogout={this.props.onLogout} onAccountSettings={this.props.onAccountSettings}/>;
 | 
			
		||||
		if (this.props.error.isError())
 | 
			
		||||
			errorAlert =
 | 
			
		||||
					<Alert bsStyle="danger" onDismiss={this.props.onClearError}>
 | 
			
		||||
						<h4>Error!</h4>
 | 
			
		||||
						<p>Error {this.props.error.ErrorId}: {this.props.error.ErrorString}</p>
 | 
			
		||||
						<Button onClick={this.props.onClearError}>Clear</Button>
 | 
			
		||||
					</Alert>;
 | 
			
		||||
 | 
			
		||||
		return (
 | 
			
		||||
			<div>
 | 
			
		||||
				{barContents}
 | 
			
		||||
				{errorAlert}
 | 
			
		||||
			</div>
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
		Reference in New Issue
	
	Block a user