diff --git a/packages/desktop-client/src/components/accounts/Account.js b/packages/desktop-client/src/components/accounts/Account.js
index e20366d8da2..c2f2de4cabc 100644
--- a/packages/desktop-client/src/components/accounts/Account.js
+++ b/packages/desktop-client/src/components/accounts/Account.js
@@ -74,10 +74,19 @@ function EmptyMessage({ onAdd }) {
);
}
-function AllTransactions({ account = {}, transactions, filtered, children }) {
+function AllTransactions({
+ account = {},
+ transactions,
+ balances,
+ showBalances,
+ filtered,
+ children,
+}) {
const { id: accountId } = account;
let scheduleData = useCachedSchedules();
+ transactions ??= [];
+
let schedules = useMemo(
() =>
scheduleData
@@ -94,7 +103,7 @@ function AllTransactions({ account = {}, transactions, filtered, children }) {
let prependTransactions = useMemo(() => {
return schedules.map(schedule => ({
- id: 'preview/' + schedule.id,
+ id: `preview/${schedule.id}`,
payee: schedule._payee,
account: schedule._account,
amount: schedule._amount,
@@ -105,6 +114,36 @@ function AllTransactions({ account = {}, transactions, filtered, children }) {
}));
}, [schedules, accountId]);
+ let runningBalance = useMemo(() => {
+ if (!showBalances) {
+ return 0;
+ }
+
+ return balances && transactions?.length > 0
+ ? balances[transactions[0].id]?.balance ?? 0
+ : 0;
+ }, [showBalances, balances, transactions]);
+
+ let prependBalances = useMemo(() => {
+ if (!showBalances) {
+ return null;
+ }
+
+ // Reverse so we can calculate from earliest upcoming schedule.
+ let scheduledBalances = [...prependTransactions]
+ .reverse()
+ .map(scheduledTransaction => {
+ let amount =
+ (scheduledTransaction._inverse ? -1 : 1) *
+ scheduledTransaction.amount;
+ return {
+ balance: (runningBalance += amount),
+ id: scheduledTransaction.id,
+ };
+ });
+ return groupById(scheduledBalances);
+ }, [showBalances, prependTransactions, runningBalance]);
+
let allTransactions = useMemo(() => {
// Don't prepend scheduled transactions if we are filtering
if (!filtered && prependTransactions.length > 0) {
@@ -113,10 +152,18 @@ function AllTransactions({ account = {}, transactions, filtered, children }) {
return transactions;
}, [filtered, prependTransactions, transactions]);
+ let allBalances = useMemo(() => {
+ // Don't prepend scheduled transactions if we are filtering
+ if (!filtered && prependBalances && balances) {
+ return { ...prependBalances, ...balances };
+ }
+ return balances;
+ }, [filtered, prependBalances, balances]);
+
if (scheduleData == null) {
- return children(null);
+ return children(transactions, balances);
}
- return children(allTransactions);
+ return children(allTransactions, allBalances);
}
function getField(field) {
@@ -152,7 +199,7 @@ class AccountInternal extends PureComponent {
transactions: [],
transactionsCount: 0,
showBalances: props.showBalances,
- balances: [],
+ balances: null,
showCleared: props.showCleared,
editingName: false,
isAdding: false,
@@ -340,12 +387,11 @@ class AccountInternal extends PureComponent {
transactionsFiltered: isFiltered,
loading: false,
workingHard: false,
+ balances: this.state.showBalances
+ ? await this.calculateBalances()
+ : null,
},
() => {
- if (this.state.showBalances) {
- this.calculateBalances();
- }
-
if (firstLoad) {
this.table.current?.scrollToTop();
}
@@ -372,7 +418,7 @@ class AccountInternal extends PureComponent {
loading: true,
search: '',
showBalances: nextProps.showBalances,
- balances: [],
+ balances: null,
showCleared: nextProps.showCleared,
},
() => {
@@ -484,7 +530,7 @@ class AccountInternal extends PureComponent {
async calculateBalances() {
if (!this.canCalculateBalance()) {
- return;
+ return null;
}
let { data } = await runQuery(
@@ -494,7 +540,7 @@ class AccountInternal extends PureComponent {
.select([{ balance: { $sumOver: '$amount' } }]),
);
- this.setState({ balances: groupById(data) });
+ return groupById(data);
}
onAddTransaction = () => {
@@ -549,32 +595,36 @@ class AccountInternal extends PureComponent {
case 'toggle-balance':
if (this.state.showBalances) {
this.props.savePrefs({ ['show-balances-' + accountId]: false });
- this.setState({ showBalances: false, balances: [] });
+ this.setState({ showBalances: false, balances: null });
} else {
- this.setState({
- transactions: [],
- transactionCount: 0,
- filters: [],
- search: '',
- sort: [],
- showBalances: true,
- });
- this.fetchTransactions();
this.props.savePrefs({ ['show-balances-' + accountId]: true });
- this.calculateBalances();
+ this.setState(
+ {
+ transactions: [],
+ transactionCount: 0,
+ filters: [],
+ search: '',
+ sort: [],
+ showBalances: true,
+ },
+ () => {
+ this.fetchTransactions();
+ },
+ );
}
break;
case 'remove-sorting': {
- let filters = this.state.filters;
- this.setState({ sort: [] });
- if (filters.length > 0) {
- this.applyFilters([...filters]);
- } else {
- this.fetchTransactions();
- }
- if (this.state.search !== '') {
- this.onSearch(this.state.search);
- }
+ this.setState({ sort: [] }, () => {
+ let filters = this.state.filters;
+ if (filters.length > 0) {
+ this.applyFilters([...filters]);
+ } else {
+ this.fetchTransactions();
+ }
+ if (this.state.search !== '') {
+ this.onSearch(this.state.search);
+ }
+ });
break;
}
case 'toggle-cleared':
@@ -981,16 +1031,25 @@ class AccountInternal extends PureComponent {
this.currentQuery = this.rootQuery.filter({
[conditionsOpKey]: [...filters, ...customFilters],
});
- this.updateQuery(this.currentQuery, true);
- this.setState({ filters: conditions });
+
+ this.setState({ filters: conditions }, () => {
+ this.updateQuery(this.currentQuery, true);
+ });
} else {
- this.setState({ transactions: [], transactionCount: 0 });
- this.fetchTransactions();
- this.setState({ filters: conditions });
- }
+ this.setState(
+ {
+ transactions: [],
+ transactionCount: 0,
+ filters: conditions,
+ },
+ () => {
+ this.fetchTransactions();
- if (this.state.sort.length !== 0) {
- this.applySort();
+ if (this.state.sort.length !== 0) {
+ this.applySort();
+ }
+ },
+ );
}
};
@@ -1124,143 +1183,134 @@ class AccountInternal extends PureComponent {
- {allTransactions =>
- allTransactions == null ? null : (
- (this.dispatchSelected = dispatch)}
- >
-
- (
+ (this.dispatchSelected = dispatch)}
+ >
+
+
+
+
+
+ this.paged && this.paged.fetchNext()
+ }
+ accounts={accounts}
+ category={category}
+ categoryGroups={categoryGroups}
+ payees={payees}
+ balances={allBalances}
showBalances={showBalances}
- showExtraBalances={showExtraBalances}
showCleared={showCleared}
- showEmptyMessage={showEmptyMessage}
- balanceQuery={balanceQuery}
- canCalculateBalance={this.canCalculateBalance}
- isSorted={this.state.sort.length !== 0}
- reconcileAmount={reconcileAmount}
- search={this.state.search}
- filters={this.state.filters}
- conditionsOp={this.state.conditionsOp}
- savePrefs={this.props.savePrefs}
- onSearch={this.onSearch}
- onShowTransactions={this.onShowTransactions}
- onMenuSelect={this.onMenuSelect}
- onAddTransaction={this.onAddTransaction}
- onToggleExtraBalances={this.onToggleExtraBalances}
- onSaveName={this.onSaveName}
- onExposeName={this.onExposeName}
- onReconcile={this.onReconcile}
- onDoneReconciling={this.onDoneReconciling}
- onCreateReconciliationTransaction={
- this.onCreateReconciliationTransaction
+ showAccount={
+ !accountId ||
+ accountId === 'offbudget' ||
+ accountId === 'budgeted' ||
+ accountId === 'uncategorized'
+ }
+ isAdding={this.state.isAdding}
+ isNew={this.isNew}
+ isMatched={this.isMatched}
+ isFiltered={
+ this.state.search !== '' || this.state.filters.length > 0
}
- onSync={this.onSync}
- onImport={this.onImport}
- onBatchDelete={this.onBatchDelete}
- onBatchDuplicate={this.onBatchDuplicate}
- onBatchEdit={this.onBatchEdit}
- onBatchUnlink={this.onBatchUnlink}
- onCreateRule={this.onCreateRule}
- onUpdateFilter={this.onUpdateFilter}
- onClearFilters={this.onClearFilters}
- onReloadSavedFilter={this.onReloadSavedFilter}
- onCondOpChange={this.onCondOpChange}
- onDeleteFilter={this.onDeleteFilter}
- onApplyFilter={this.onApplyFilter}
- onScheduleAction={this.onScheduleAction}
+ dateFormat={dateFormat}
+ hideFraction={hideFraction}
+ addNotification={addNotification}
+ renderEmpty={() =>
+ showEmptyMessage ? (
+ replaceModal('add-account')} />
+ ) : !loading ? (
+
+ No transactions
+
+ ) : null
+ }
+ onChange={this.onTransactionsChange}
+ onRefetch={this.refetchTransactions}
+ onRefetchUpToRow={row =>
+ this.paged.refetchUpToRow(row, {
+ field: 'date',
+ order: 'desc',
+ })
+ }
+ onCloseAddTransaction={() =>
+ this.setState({ isAdding: false })
+ }
+ onCreatePayee={this.onCreatePayee}
/>
-
-
-
- this.paged && this.paged.fetchNext()
- }
- accounts={accounts}
- category={category}
- categoryGroups={categoryGroups}
- payees={payees}
- balances={
- showBalances && this.canCalculateBalance()
- ? balances
- : null
- }
- showCleared={showCleared}
- showAccount={
- !accountId ||
- accountId === 'offbudget' ||
- accountId === 'budgeted' ||
- accountId === 'uncategorized'
- }
- isAdding={this.state.isAdding}
- isNew={this.isNew}
- isMatched={this.isMatched}
- isFiltered={
- this.state.search !== '' || this.state.filters.length > 0
- }
- dateFormat={dateFormat}
- hideFraction={hideFraction}
- addNotification={addNotification}
- renderEmpty={() =>
- showEmptyMessage ? (
- replaceModal('add-account')}
- />
- ) : !loading ? (
-
- No transactions
-
- ) : null
- }
- onSort={this.onSort}
- sortField={this.state.sort.field}
- ascDesc={this.state.sort.ascDesc}
- onChange={this.onTransactionsChange}
- onRefetch={this.refetchTransactions}
- onRefetchUpToRow={row =>
- this.paged.refetchUpToRow(row, {
- field: 'date',
- order: 'desc',
- })
- }
- onCloseAddTransaction={() =>
- this.setState({ isAdding: false })
- }
- onCreatePayee={this.onCreatePayee}
- />
-
-
- )
- }
+
+
+ )}
);
}
diff --git a/packages/desktop-client/src/components/transactions/TransactionList.js b/packages/desktop-client/src/components/transactions/TransactionList.js
index 2e9b20b4968..96c4445b012 100644
--- a/packages/desktop-client/src/components/transactions/TransactionList.js
+++ b/packages/desktop-client/src/components/transactions/TransactionList.js
@@ -65,6 +65,7 @@ export default function TransactionList({
categoryGroups,
payees,
balances,
+ showBalances,
showCleared,
showAccount,
headerContent,
@@ -172,6 +173,7 @@ export default function TransactionList({
accounts={accounts}
categoryGroups={categoryGroups}
payees={payees}
+ showBalances={showBalances}
balances={balances}
showCleared={showCleared}
showAccount={showAccount}
diff --git a/packages/desktop-client/src/components/transactions/TransactionsTable.js b/packages/desktop-client/src/components/transactions/TransactionsTable.js
index 7df78b74e1b..56786f47803 100644
--- a/packages/desktop-client/src/components/transactions/TransactionsTable.js
+++ b/packages/desktop-client/src/components/transactions/TransactionsTable.js
@@ -1240,11 +1240,7 @@ const Transaction = memo(function Transaction(props) {
{showBalance && (
0}
showAccount={props.showAccount}
showCategory={props.showCategory}
- showBalance={!!props.balances}
+ showBalance={props.showBalances}
showCleared={props.showCleared}
scrollWidth={scrollWidth}
onSort={props.onSort}
@@ -1619,7 +1614,7 @@ function TransactionTableInner({
payees={props.payees || []}
showAccount={props.showAccount}
showCategory={props.showCategory}
- showBalance={!!props.balances}
+ showBalance={props.showBalances}
showCleared={props.showCleared}
dateFormat={dateFormat}
hideFraction={props.hideFraction}
diff --git a/upcoming-release-notes/1354.md b/upcoming-release-notes/1354.md
new file mode 100644
index 00000000000..555096a6932
--- /dev/null
+++ b/upcoming-release-notes/1354.md
@@ -0,0 +1,6 @@
+---
+category: Enhancements
+authors: [joel-jeremy]
+---
+
+Scheduled transactions for the month to show up in Account's running balance
|