Add new account dropdown with search to top bar

This commit is contained in:
Aaron Lindsay 2018-11-02 21:15:33 -04:00
parent 9dd32d4d14
commit a27bf82af3
7 changed files with 230 additions and 158 deletions

View File

@ -106,8 +106,8 @@ class TransactionRow extends React.Component {
<td ref="description" onClick={this.onClick}>{this.props.transaction.Description}</td>
<td ref="account" onClick={this.onClick}>{accountName}</td>
<td ref="status" onClick={this.onClick}>{status}</td>
<td ref="amount" onClick={this.onClick}>{amount}</td>
<td>{balance}</td>
<td className="amount-cell" ref="amount" onClick={this.onClick}>{amount}</td>
<td className="amount-cell">{balance}</td>
</tr>);
}
}
@ -722,7 +722,6 @@ class AccountRegister extends React.Component {
super();
this.state = {
newTransaction: null,
height: 0
};
this.onEditTransaction = this.handleEditTransaction.bind(this);
this.onEditingCancel = this.handleEditingCancel.bind(this);
@ -732,20 +731,11 @@ class AccountRegister extends React.Component {
this.onUpdateTransaction = this.handleUpdateTransaction.bind(this);
this.onDeleteTransaction = this.handleDeleteTransaction.bind(this);
}
resize() {
var div = ReactDOM.findDOMNode(this);
this.setState({height: div.parentElement.clientHeight - 64});
}
componentWillReceiveProps(nextProps) {
if (!nextProps.transactionPage.upToDate && nextProps.selectedAccount != -1) {
nextProps.onFetchTransactionPage(nextProps.accounts[nextProps.selectedAccount], nextProps.transactionPage.pageSize, nextProps.transactionPage.page);
}
}
componentDidMount() {
this.resize();
var self = this;
$(window).resize(function() {self.resize();});
}
handleEditTransaction(transaction) {
this.props.onSelectTransaction(transaction.TransactionId);
}
@ -826,9 +816,8 @@ class AccountRegister extends React.Component {
));
}
var style = {height: this.state.height + "px"};
register = (
<div style={style} className="transactions-register">
<div className="transactions-register">
<Table bordered striped condensed hover>
<thead><tr>
<th>Date</th>

View File

@ -155,23 +155,15 @@ class AccountsTab extends React.Component {
constructor() {
super();
this.state = {
creatingNewAccount: false,
editingAccount: false,
deletingAccount: false
};
this.onNewAccount = this.handleNewAccount.bind(this);
this.onEditAccount = this.handleEditAccount.bind(this);
this.onDeleteAccount = this.handleDeleteAccount.bind(this);
this.onCreationCancel = this.handleCreationCancel.bind(this);
this.onEditingCancel = this.handleEditingCancel.bind(this);
this.onDeletionCancel = this.handleDeletionCancel.bind(this);
this.onCreateAccount = this.handleCreateAccount.bind(this);
this.onUpdateAccount = this.handleUpdateAccount.bind(this);
this.onRemoveAccount = this.handleRemoveAccount.bind(this);
this.onAccountSelected = this.handleAccountSelected.bind(this);
}
handleNewAccount() {
this.setState({creatingNewAccount: true});
}
handleEditAccount() {
this.setState({editingAccount: true});
@ -179,20 +171,12 @@ class AccountsTab extends React.Component {
handleDeleteAccount() {
this.setState({deletingAccount: true});
}
handleCreationCancel() {
this.setState({creatingNewAccount: false});
}
handleEditingCancel() {
this.setState({editingAccount: false});
}
handleDeletionCancel() {
this.setState({deletingAccount: false});
}
handleCreateAccount(account) {
if (this.props.onCreateAccount != null)
this.props.onCreateAccount(account);
this.setState({creatingNewAccount: false});
}
handleUpdateAccount(account) {
if (this.props.onUpdateAccount != null)
this.props.onUpdateAccount(account);
@ -203,10 +187,6 @@ class AccountsTab extends React.Component {
this.props.onDeleteAccount(account);
this.setState({deletingAccount: false});
}
handleAccountSelected(account) {
this.props.onSelectAccount(account.AccountId);
this.props.onFetchTransactionPage(account, 20, 0);
}
render() {
var disabled = (this.props.selectedAccount == -1) ? true : false;
@ -215,71 +195,53 @@ class AccountsTab extends React.Component {
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.onCreationCancel}
onSubmit={this.onCreateAccount}
security_list={this.props.security_list}/>
<AddEditAccountModal
show={this.state.editingAccount}
editAccount={selectedAccount}
accounts={this.props.accounts}
accountChildren={this.props.accountChildren}
onCancel={this.onEditingCancel}
onSubmit={this.onUpdateAccount}
security_list={this.props.security_list}/>
<DeleteAccountModal
show={this.state.deletingAccount}
initialAccount={selectedAccount}
accounts={this.props.accounts}
accountChildren={this.props.accountChildren}
onCancel={this.onDeletionCancel}
onSubmit={this.onRemoveAccount}/>
<AccountTree
accounts={this.props.accounts}
accountChildren={this.props.accountChildren}
selectedAccount={this.props.selectedAccount}
onSelect={this.onAccountSelected}/>
<ButtonGroup className="account-buttongroup">
<Button onClick={this.onNewAccount} bsStyle="success">
<Glyphicon glyph='plus-sign' /></Button>
<Button onClick={this.onEditAccount}
bsStyle="primary" disabled={disabled}>
<Glyphicon glyph='cog' /></Button>
<Button onClick={this.onDeleteAccount}
bsStyle="danger" disabled={disabled}>
<Glyphicon glyph='trash' /></Button>
</ButtonGroup>
</Col><Col xs={10} className="fullheight transactions-column">
<AccountRegister
pageSize={20}
selectedAccount={this.props.selectedAccount}
accounts={this.props.accounts}
accountChildren={this.props.accountChildren}
securities={this.props.securities}
transactions={this.props.transactions}
transactionPage={this.props.transactionPage}
imports={this.props.imports}
onFetchAllAccounts={this.props.onFetchAllAccounts}
onFetchAllSecurities={this.props.onFetchAllSecurities}
onCreateTransaction={this.props.onCreateTransaction}
onUpdateTransaction={this.props.onUpdateTransaction}
onDeleteTransaction={this.props.onDeleteTransaction}
onSelectTransaction={this.props.onSelectTransaction}
onUnselectTransaction={this.props.onUnselectTransaction}
onFetchTransactionPage={this.props.onFetchTransactionPage}
onOpenImportModal={this.props.onOpenImportModal}
onCloseImportModal={this.props.onCloseImportModal}
onImportOFX={this.props.onImportOFX}
onImportOFXFile={this.props.onImportOFXFile}
onImportGnucash={this.props.onImportGnucash} />
</Col>
</Row></Grid>
<div>
<AddEditAccountModal
show={this.state.editingAccount}
editAccount={selectedAccount}
accounts={this.props.accounts}
accountChildren={this.props.accountChildren}
onCancel={this.onEditingCancel}
onSubmit={this.onUpdateAccount}
security_list={this.props.security_list}/>
<DeleteAccountModal
show={this.state.deletingAccount}
initialAccount={selectedAccount}
accounts={this.props.accounts}
accountChildren={this.props.accountChildren}
onCancel={this.onDeletionCancel}
onSubmit={this.onRemoveAccount}/>
<ButtonGroup className="account-buttongroup">
<Button onClick={this.onEditAccount}
bsStyle="primary" disabled={disabled}>
<Glyphicon glyph='cog' /> Edit Account</Button>
<Button onClick={this.onDeleteAccount}
bsStyle="danger" disabled={disabled}>
<Glyphicon glyph='trash' /> Delete Account</Button>
</ButtonGroup>
<AccountRegister
pageSize={20}
selectedAccount={this.props.selectedAccount}
accounts={this.props.accounts}
accountChildren={this.props.accountChildren}
securities={this.props.securities}
transactions={this.props.transactions}
transactionPage={this.props.transactionPage}
imports={this.props.imports}
onFetchAllAccounts={this.props.onFetchAllAccounts}
onFetchAllSecurities={this.props.onFetchAllSecurities}
onCreateTransaction={this.props.onCreateTransaction}
onUpdateTransaction={this.props.onUpdateTransaction}
onDeleteTransaction={this.props.onDeleteTransaction}
onSelectTransaction={this.props.onSelectTransaction}
onUnselectTransaction={this.props.onUnselectTransaction}
onFetchTransactionPage={this.props.onFetchTransactionPage}
onOpenImportModal={this.props.onOpenImportModal}
onCloseImportModal={this.props.onCloseImportModal}
onImportOFX={this.props.onImportOFX}
onImportOFXFile={this.props.onImportOFXFile}
onImportGnucash={this.props.onImportGnucash} />
</div>
);
}
}

View File

@ -1,10 +1,23 @@
var React = require('react');
var ReactDOM = require('react-dom');
var ReactBootstrap = require('react-bootstrap');
var Jumbotron = ReactBootstrap.Jumbotron;
var Tabs = ReactBootstrap.Tabs;
var Tab = ReactBootstrap.Tab;
var Nav = ReactBootstrap.Nav;
var NavDropdown = ReactBootstrap.NavDropdown;
var NavItem = ReactBootstrap.NavItem;
var Col = ReactBootstrap.Col;
var Row = ReactBootstrap.Row;
var Modal = ReactBootstrap.Modal;
var FormControl = ReactBootstrap.FormControl;
var InputGroup = ReactBootstrap.InputGroup;
var Button = ReactBootstrap.Button;
var Glyphicon = ReactBootstrap.Glyphicon;
var MenuItem = ReactBootstrap.MenuItem;
var SplitButton = ReactBootstrap.SplitButton;
var TopBarContainer = require('../containers/TopBarContainer');
var NewUserModalContainer = require('../containers/NewUserModalContainer');
@ -12,28 +25,43 @@ var AccountSettingsModalContainer = require('../containers/AccountSettingsModalC
var AccountsTabContainer = require('../containers/AccountsTabContainer');
var SecuritiesTabContainer = require('../containers/SecuritiesTabContainer');
var ReportsTabContainer = require('../containers/ReportsTabContainer');
var AddEditAccountModal = require('./AddEditAccountModal');
var AccountTree = require('./AccountTree');
var utils = require('../utils');
class MoneyGoApp extends React.Component {
constructor() {
super();
this.state = {
tab: 1,
accountFilter: "",
showNewUserModal: false,
showAccountSettingsModal: false
showSettingsModal: false,
creatingNewAccount: false
};
this.onShowSettings = this.handleShowSettings.bind(this);
this.onHideSettings = this.handleHideSettings.bind(this);
this.onShowNewUser = this.handleShowNewUser.bind(this);
this.onHideNewUser = this.handleHideNewUser.bind(this);
this.onSelectTab = this.handleSelectTab.bind(this);
this.onAccountSelected = this.handleAccountSelected.bind(this);
this.onNewAccount = this.handleNewAccount.bind(this);
this.onNewAccountCancel = this.handleNewAccountCancel.bind(this);
this.onCreateAccount = this.handleCreateAccount.bind(this);
this.onAccountFilterChange = this.handleAccountFilterChange.bind(this);
this.onClearAccountFilter = this.handleClearAccountFilter.bind(this);
}
componentDidMount() {
this.props.tryResumingSession();
this.props.fetchCurrencies();
}
handleShowSettings() {
this.setState({showAccountSettingsModal: true});
this.setState({showSettingsModal: true});
}
handleHideSettings(user) {
this.setState({showAccountSettingsModal: false});
this.setState({showSettingsModal: false});
}
handleShowNewUser() {
this.setState({showNewUserModal: true});
@ -41,27 +69,117 @@ class MoneyGoApp extends React.Component {
handleHideNewUser() {
this.setState({showNewUserModal: false});
}
handleSelectTab(key) {
console.log(key);
if (key != undefined) {
this.setState({tab: key});
}
}
handleAccountSelected(account) {
this.setState({
tab: 1,
accountFilter: ""});
this.props.onSelectAccount(account.AccountId);
this.props.onFetchTransactionPage(account, 20, 0);
}
handleNewAccount() {
this.setState({creatingNewAccount: true});
}
handleNewAccountCancel() {
this.setState({creatingNewAccount: false});
}
handleCreateAccount(account) {
this.props.onCreateAccount(account);
this.setState({creatingNewAccount: false});
}
handleAccountFilterChange() {
this.setState({accountFilter: ReactDOM.findDOMNode(this.refs.accountFilter).value});
}
handleClearAccountFilter() {
this.setState({accountFilter: ""});
}
render() {
var mainContent;
if (this.props.user.isUser())
if (this.props.user.isUser()) {
var accountElements = [];
if (this.state.accountFilter.length > 0) {
var filterRegex = new RegExp(this.state.accountFilter, "i")
for (var accountId in this.props.accounts) {
var account = this.props.accounts[accountId];
var fullName = utils.getAccountDisplayName(account, this.props.accounts);
if (fullName.match(filterRegex)) {
var clojure = function(self, account) {
return function() {
self.handleAccountSelected(account);
};
}(this, account);
accountElements.push((<MenuItem key={accountId} onSelect={clojure}>{fullName}</MenuItem>));
}
}
} else {
accountElements.push((<MenuItem key={1} divider />));
accountElements.push((<AccountTree key={2}
accounts={this.props.accounts}
accountChildren={this.props.accountChildren}
selectedAccount={this.props.selectedAccount}
onSelectAccount={this.onAccountSelected}
onSelectKey={1} />));
}
mainContent = (
<Tabs defaultActiveKey={1} id='mainNavigationTabs'>
<Tab title="Accounts" eventKey={1} >
<AccountsTabContainer
className="fullheight" />
</Tab>
<Tab title="Securities" eventKey={2} >
<SecuritiesTabContainer
className="fullheight" />
</Tab>
<Tab title="Scheduled Transactions" eventKey={3} >Scheduled transactions go here...</Tab>
<Tab title="Budgets" eventKey={4} >Budgets go here...</Tab>
<Tab title="Reports" eventKey={5} >
<ReportsTabContainer
className="fullheight" />
</Tab>
</Tabs>);
else
<Tab.Container id="main-ui-navigation" activeKey={this.state.tab} onSelect={this.onSelectTab}>
<Row className="clearfix">
<Col sm={12}>
<Nav bsStyle="tabs">
<NavDropdown eventKey={1} title="Accounts">
<MenuItem onSelect={this.onNewAccount}>New Account</MenuItem>
<MenuItem divider />
<MenuItem disabled className="account-filter-menuitem">
<InputGroup>
<FormControl
onKeyDown={function(e){if (e.key == " ") e.stopPropagation();}}
type="text"
placeholder="Search..."
value={this.state.accountFilter}
onChange={this.onAccountFilterChange}
ref="accountFilter" />
<InputGroup.Button>
<Button className="clear-account-filter" onClick={this.onClearAccountFilter}>
<Glyphicon glyph="remove"/>
</Button>
</InputGroup.Button>
</InputGroup>
</MenuItem>
{accountElements}
</NavDropdown>
<NavItem eventKey={2}>Securities</NavItem>
<NavItem eventKey={3}>Scheduled Transactions</NavItem>
<NavItem eventKey={4}>Budgets</NavItem>
<NavItem eventKey={5}>Reports</NavItem>
</Nav>
</Col>
<Col sm={12}>
<Tab.Content>
<Tab.Pane eventKey={1}>
<AccountsTabContainer/>
</Tab.Pane>
<Tab.Pane eventKey={2}>
<SecuritiesTabContainer/>
</Tab.Pane>
<Tab.Pane eventKey={3}>
Scheduled transactions go here...
</Tab.Pane>
<Tab.Pane eventKey={4}>
Budgets go here...
</Tab.Pane>
<Tab.Pane eventKey={5}>
<ReportsTabContainer/>
</Tab.Pane>
</Tab.Content>
</Col>
</Row>
</Tab.Container>);
} else {
mainContent = (
<Jumbotron>
<center>
@ -69,21 +187,30 @@ class MoneyGoApp extends React.Component {
<p><i>Go</i> manage your money.</p>
</center>
</Jumbotron>);
}
return (
<div className="fullheight ui">
<div className="ui">
<TopBarContainer
onCreateNewUser={this.onShowNewUser}
onAccountSettings={this.onShowSettings} />
onSettings={this.onShowSettings} />
{mainContent}
<NewUserModalContainer
show={this.state.showNewUserModal}
onSubmit={this.onHideNewUser}
onCancel={this.onHideNewUser}/>
<AccountSettingsModalContainer
show={this.state.showAccountSettingsModal}
show={this.state.showSettingsModal}
onSubmit={this.onHideSettings}
onCancel={this.onHideSettings}/>
<AddEditAccountModal
show={this.state.creatingNewAccount}
initialParentAccount={this.props.selectedAccount}
accounts={this.props.accounts}
accountChildren={this.props.accountChildren}
onCancel={this.onNewAccountCancel}
onSubmit={this.onCreateAccount}
security_list={this.props.security_list}/>
</div>
);
}

View File

@ -76,8 +76,8 @@ class LogoutBar extends React.Component {
}
handleOnSelect(key) {
if (key == 1) {
if (this.props.onAccountSettings != null)
this.props.onAccountSettings();
if (this.props.onSettings != null)
this.props.onSettings();
} else if (key == 2) {
this.props.onLogout();
}
@ -110,7 +110,7 @@ class TopBar extends React.Component {
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}/>;
barContents = <LogoutBar user={this.props.user} onLogout={this.props.onLogout} onSettings={this.props.onSettings}/>;
if (this.props.error.isError())
errorAlert =
<Alert bsStyle="danger" onDismiss={this.props.onClearError}>

View File

@ -23,7 +23,6 @@ function mapStateToProps(state) {
function mapDispatchToProps(dispatch) {
return {
onFetchAllAccounts: function() {dispatch(AccountActions.fetchAll())},
onCreateAccount: function(account) {dispatch(AccountActions.create(account))},
onUpdateAccount: function(account) {dispatch(AccountActions.update(account))},
onDeleteAccount: function(account) {dispatch(AccountActions.remove(account))},
onSelectAccount: function(accountId) {dispatch(AccountActions.select(accountId))},

View File

@ -1,13 +1,19 @@
var connect = require('react-redux').connect;
var UserActions = require('../actions/UserActions');
var AccountActions = require('../actions/AccountActions');
var TransactionActions = require('../actions/TransactionActions');
var SecurityTemplateActions = require('../actions/SecurityTemplateActions');
var MoneyGoApp = require('../components/MoneyGoApp');
function mapStateToProps(state) {
return {
user: state.user
user: state.user,
accounts: state.accounts.map,
accountChildren: state.accounts.children,
selectedAccount: state.selectedAccount,
security_list: state.securities.list,
}
}
@ -15,6 +21,9 @@ function mapDispatchToProps(dispatch) {
return {
tryResumingSession: function() {dispatch(UserActions.tryResumingSession())},
fetchCurrencies: function() {dispatch(SecurityTemplateActions.fetchCurrencies())},
onCreateAccount: function(account) {dispatch(AccountActions.create(account))},
onSelectAccount: function(accountId) {dispatch(AccountActions.select(accountId))},
onFetchTransactionPage: function(account, pageSize, page) {dispatch(TransactionActions.fetchPage(account, pageSize, page))},
}
}

View File

@ -1,22 +1,13 @@
@import url("reports.css");
html, body {
height: 100%;
}
div#content {
display: block;
width: 95%;
height: 100%;
min-width: 75em;
max-width: 100em;
margin: auto;
}
/* Keep the main windows sized to the full viewable height */
.fullheight {
height: 100%;
}
.ui {
display: flex;
flex-flow: column;
@ -34,11 +25,18 @@ div#content {
}
/* Tabs */
.nav-tabs {
margin-bottom: 15px;
}
#mainNavigationTabs .nav-tabs {
margin-bottom: 0px;
.account-filter-menuitem > a {
padding: 0px 5px !important;
}
.clear-account-filter {
height: 34px;
padding: 6px;
}
/* Style the account tree */
@ -49,6 +47,7 @@ div.accounttree-root-nochildren {
div.accounttree {
position: relative;
left: -24px;
white-space: nowrap;
}
div.accounttree-nochildren {
position: relative;
@ -67,38 +66,25 @@ div.accounttree-root div {
.accounttree-root {
display: block;
width: 100%;
height: 100%-100px;
overflow: auto;
margin-left: 5px;
}
.account-column {
padding: 15px 15px 43px 15px;
border-right: 1px solid #DDD;
border-left: 1px solid #DDD;
}
.account-buttongroup {
position: absolute;
right: 15px;
bottom: 15px;
.accounttree-expandbutton {
padding-bottom: 6px;
}
.transactions-container {
display: block;
width: 100%;
height: 100%;
}
.transactions-register {
display: block;
width: 100%;
height: 100%;
overflow: auto;
}
.transactions-column {
padding: 15px;
border-right: 1px solid #DDD;
}
.transactions-register-toolbar {
width: 100%;
height: 50px;
}
td.amount-cell {
white-space: nowrap;
}
.register-row-editing {