// Import all the objects we want to use from ReactBootstrap 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 Button = ReactBootstrap.Button; var ButtonToolbar = ReactBootstrap.ButtonToolbar; var DateTimePicker = ReactWidgets.DateTimePicker; 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]].getDOMNode() == 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.security_map[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]; var accountName = getAccountDisplayName(this.props.account_map[otherSplit.AccountId], this.props.account_map); } 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 ( {dateString} {number} {this.props.transaction.Description} {accountName} {status} {amount} {balance} ); } }); 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() { this.refs.amount.getInputDOMNode().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: this.refs.amount.getValue()}); if (this.props.onChange) this.props.onChange(); }, getValue: function() { try { var value = this.refs.amount.getValue(); 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 ( ); } }); 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 {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.addons.update(this.state.transaction, { Description: {$set: this.refs.description.getValue()} }) }); }, handleDateChange: function(date, string) { if (date == null) return; this.setState({ transaction: React.addons.update(this.state.transaction, { Date: {$set: date} }) }); }, handleStatusChange: function(status) { if (status.hasOwnProperty('StatusId')) { this.setState({ transaction: React.addons.update(this.state.transaction, { Status: {$set: status.StatusId} }) }); } }, handleAddSplit: function() { this.setState({ transaction: React.addons.update(this.state.transaction, { Splits: {$push: [new Split()]} }) }); }, handleDeleteSplit: function(split) { this.setState({ transaction: React.addons.update(this.state.transaction, { Splits: {$splice: [[split, 1]]} }) }); }, handleUpdateNumber: function(split) { var transaction = this.state.transaction; transaction.Splits[split] = React.addons.update(transaction.Splits[split], { Number: {$set: this.refs['number-'+split].getValue()} }); this.setState({ transaction: transaction }); }, handleUpdateMemo: function(split) { var transaction = this.state.transaction; transaction.Splits[split] = React.addons.update(transaction.Splits[split], { Memo: {$set: this.refs['memo-'+split].getValue()} }); this.setState({ transaction: transaction }); }, handleUpdateAccount: function(account, split) { var transaction = this.state.transaction; transaction.Splits[split] = React.addons.update(transaction.Splits[split], { AccountId: {$set: account.AccountId} }); this.setState({ transaction: transaction }); }, handleUpdateAmount: function(split) { var transaction = this.state.transaction; transaction.Splits[split] = React.addons.update(transaction.Splits[split], { Amount: {$set: new Big(this.refs['amount-'+split].getValue())} }); this.setState({ transaction: transaction }); }, handleSubmit: function() { 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 = ( ); } 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; if (this.props.account_map[s.AccountId]) security = this.props.security_map[this.props.account_map[s.AccountId].SecurityId]; // 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 = ( ); } splits.push(( {deleteSplitButton} )); } return ( {headerText} Transaction
# Memo Account Amount {splits}
{deleteButton}
); } }); const AccountRegister = React.createClass({ getInitialState: function() { return { editingTransaction: false, selectedTransaction: new Transaction(), transactions: [], pageSize: 20, numPages: 0, currentPage: 0, height: 0 }; }, resize: function() { var div = React.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.selectedAccount.AccountId; this.setState({ editingTransaction: true, selectedTransaction: newTransaction }); }, 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.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 != null) { this.getTransactionPage(this.props.selectedAccount, newpage); } this.setState({currentPage: newpage}); } }, onNewTransaction: function() { this.getTransactionPage(this.props.selectedAccount, this.state.currentPage); }, onUpdatedTransaction: function() { this.getTransactionPage(this.props.selectedAccount, this.state.currentPage); }, onDeletedTransaction: function() { this.getTransactionPage(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 }); }, 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 }); this.getTransactionPage(nextProps.selectedAccount, 0); } }, render: function() { var name = "Please select an account"; register = []; if (this.props.selectedAccount != null) { name = this.props.selectedAccount.Name; var transactionRows = []; for (var i = 0; i < this.state.transactions.length; i++) { var t = this.state.transactions[i]; transactionRows.push(( )); } var style = {height: this.state.height + "px"}; register = (
{transactionRows}
Date # Description Account Status Amount Balance
); } var disabled = (this.props.selectedAccount == null) ? "disabled" : ""; return (
Transactions for '{name}'
{register}
); } });