Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️ (typescript) Refactor Accounts/Balances to tsx and Remove ts-strict-ignore from Accounts/Account #4047

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
76 changes: 38 additions & 38 deletions packages/desktop-client/src/components/accounts/Account.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-strict-ignore
import React, {
PureComponent,
type MutableRefObject,
Expand Down Expand Up @@ -333,8 +332,8 @@ class AccountInternal extends PureComponent<
AccountInternalState
> {
paged: PagedQuery<TransactionEntity> | null;
rootQuery: Query;
currentQuery: Query;
rootQuery!: Query;
currentQuery!: Query;
table: TableRef;
unlisten?: () => void;
dispatchSelected?: (action: Actions) => void;
Expand Down Expand Up @@ -384,7 +383,7 @@ class AccountInternal extends PureComponent<
// first message referencing a non-deleted row so that we can
// highlight the row
//
let focusId: null | string;
let focusId: null | string = null;
if (
messages.every(msg => msg.dataset === 'transactions') &&
!messages.find(msg => msg.column === 'tombstone')
Expand Down Expand Up @@ -536,7 +535,7 @@ class AccountInternal extends PureComponent<
this.setState(
{
transactions: data,
transactionCount: this.paged?.totalCount,
transactionCount: this.paged?.totalCount ?? 0,
transactionsFiltered: isFiltered,
loading: false,
workingHard: false,
Expand Down Expand Up @@ -678,14 +677,13 @@ class AccountInternal extends PureComponent<
const account = this.props.accounts.find(
account => account.id === accountId,
);
return (
account &&
this.state.search === '' &&
this.state.filterConditions.length === 0 &&
(this.state.sort === null ||
(this.state.sort.field === 'date' &&
this.state.sort.ascDesc === 'desc'))
);
return account
? this.state.search === '' &&
this.state.filterConditions.length === 0 &&
(this.state.sort === null ||
(this.state.sort.field === 'date' &&
this.state.sort.ascDesc === 'desc'))
: false;
};

async calculateBalances() {
Expand Down Expand Up @@ -713,7 +711,7 @@ class AccountInternal extends PureComponent<
onSaveName = (name: string) => {
const accountNameError = validateAccountName(
name,
this.props.accountId,
this.props.accountId ?? '',
this.props.accounts,
);
if (accountNameError) {
Expand All @@ -722,7 +720,7 @@ class AccountInternal extends PureComponent<
const account = this.props.accounts.find(
account => account.id === this.props.accountId,
);
this.props.updateAccount({ ...account, name });
this.props.updateAccount({ ...account, name } as AccountEntity);
this.setState({ editingName: false, nameError: '' });
}
};
Expand Down Expand Up @@ -920,9 +918,9 @@ class AccountInternal extends PureComponent<
await this.refetchTransactions();
};

onReconcile = async (balance: number) => {
onReconcile = async (amount: number | null) => {
this.setState(({ showCleared }) => ({
reconcileAmount: balance,
reconcileAmount: amount,
showCleared: true,
prevShowCleared: showCleared,
}));
Expand Down Expand Up @@ -1301,14 +1299,16 @@ class AccountInternal extends PureComponent<

onConditionsOpChange = (value: 'and' | 'or') => {
this.setState({ filterConditionsOp: value });
this.setState({ filterId: { ...this.state.filterId, status: 'changed' } });
this.setState({
filterId: { ...this.state.filterId, status: 'changed' } as SavedFilter,
});
this.applyFilters([...this.state.filterConditions]);
if (this.state.search !== '') {
this.onSearch(this.state.search);
}
};

onReloadSavedFilter = (savedFilter: SavedFilter, item: string) => {
onReloadSavedFilter = (savedFilter: SavedFilter, item?: string) => {
if (item === 'reload') {
const [savedFilter] = this.props.savedFilters.filter(
f => f.id === this.state.filterId?.id,
Expand All @@ -1320,7 +1320,7 @@ class AccountInternal extends PureComponent<
this.setState({
filterConditionsOp: savedFilter.conditionsOp ?? 'and',
});
this.applyFilters([...savedFilter.conditions]);
this.applyFilters([...(savedFilter.conditions ?? [])]);
}
}
this.setState({ filterId: { ...this.state.filterId, ...savedFilter } });
Expand Down Expand Up @@ -1348,7 +1348,7 @@ class AccountInternal extends PureComponent<
filterId: {
...this.state.filterId,
status: this.state.filterId && 'changed',
},
} as SavedFilter,
});
if (this.state.search !== '') {
this.onSearch(this.state.search);
Expand All @@ -1365,7 +1365,7 @@ class AccountInternal extends PureComponent<
filterId: {
...this.state.filterId,
status: this.state.filterId && 'changed',
},
} as SavedFilter,
});
}
if (this.state.search !== '') {
Expand Down Expand Up @@ -1402,7 +1402,7 @@ class AccountInternal extends PureComponent<
filterId: {
...this.state.filterId,
status: this.state.filterId && 'changed',
},
} as SavedFilter,
});
this.applyFilters([...filterConditions, condition]);
}
Expand Down Expand Up @@ -1660,11 +1660,11 @@ class AccountInternal extends PureComponent<

const showEmptyMessage = !loading && !accountId && accounts.length === 0;

const isNameEditable =
accountId &&
accountId !== 'onbudget' &&
accountId !== 'offbudget' &&
accountId !== 'uncategorized';
const isNameEditable = accountId
? accountId !== 'onbudget' &&
accountId !== 'offbudget' &&
accountId !== 'uncategorized'
: false;

const balanceQuery = this.getBalanceQuery(accountId);

Expand All @@ -1687,9 +1687,9 @@ class AccountInternal extends PureComponent<
<View style={styles.page}>
<AccountHeader
tableRef={this.table}
editingName={editingName}
isNameEditable={isNameEditable}
workingHard={workingHard}
editingName={editingName ?? false}
isNameEditable={isNameEditable ?? false}
workingHard={workingHard ?? false}
account={account}
filterId={filterId}
savedFilters={this.props.savedFilters}
Expand All @@ -1698,15 +1698,15 @@ class AccountInternal extends PureComponent<
failedAccounts={failedAccounts}
accounts={accounts}
transactions={transactions}
showBalances={showBalances}
showExtraBalances={showExtraBalances}
showCleared={showCleared}
showReconciled={showReconciled}
showEmptyMessage={showEmptyMessage}
showBalances={showBalances ?? false}
showExtraBalances={showExtraBalances ?? false}
showCleared={showCleared ?? false}
showReconciled={showReconciled ?? false}
showEmptyMessage={showEmptyMessage ?? false}
balanceQuery={balanceQuery}
canCalculateBalance={this.canCalculateBalance}
canCalculateBalance={this?.canCalculateBalance ?? undefined}
filteredAmount={filteredAmount}
isFiltered={transactionsFiltered}
isFiltered={transactionsFiltered ?? false}
isSorted={this.state.sort !== null}
reconcileAmount={reconcileAmount}
search={this.state.search}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import { useHover } from 'usehooks-ts';

import { isPreviewId } from 'loot-core/shared/transactions';
import { useCachedSchedules } from 'loot-core/src/client/data-hooks/schedules';
import { q } from 'loot-core/src/shared/query';
import { q, type Query } from 'loot-core/src/shared/query';
import { getScheduledAmount } from 'loot-core/src/shared/schedules';
import { type AccountEntity } from 'loot-core/types/models';

import { useSelectedItems } from '../../hooks/useSelected';
import { SvgArrowButtonRight1 } from '../../icons/v2';
Expand All @@ -15,11 +16,22 @@ import { Button } from '../common/Button2';
import { Text } from '../common/Text';
import { View } from '../common/View';
import { PrivacyFilter } from '../PrivacyFilter';
import { type Binding } from '../spreadsheet';
import { CellValue, CellValueText } from '../spreadsheet/CellValue';
import { useFormat } from '../spreadsheet/useFormat';
import { useSheetValue } from '../spreadsheet/useSheetValue';

function DetailedBalance({ name, balance, isExactBalance = true }) {
type DetailedBalanceProps = {
name: string;
balance: number;
isExactBalance?: boolean;
};

function DetailedBalance({
name,
balance,
isExactBalance = true,
}: DetailedBalanceProps) {
const format = useFormat();
return (
<Text
Expand All @@ -42,32 +54,37 @@ function DetailedBalance({ name, balance, isExactBalance = true }) {
);
}

function SelectedBalance({ selectedItems, account }) {
type SelectedBalanceProps = {
selectedItems: Set<string>;
account?: AccountEntity;
};

function SelectedBalance({ selectedItems, account }: SelectedBalanceProps) {
const { t } = useTranslation();

const name = `selected-balance-${[...selectedItems].join('-')}`;

const rows = useSheetValue({
name,
const rows = useSheetValue<'balance', `selected-transactions-${string}`>({
name: name as `selected-transactions-${string}`,
query: q('transactions')
.filter({
id: { $oneof: [...selectedItems] },
parent_id: { $oneof: [...selectedItems] },
})
.select('id'),
});
const ids = new Set((rows || []).map(r => r.id));
const ids = new Set((rows || []).map((r: { id: string }) => r.id));

const finalIds = [...selectedItems].filter(id => !ids.has(id));
let balance = useSheetValue({
name: name + '-sum',
let balance = useSheetValue<'balance', `selected-balance-${string}`>({
name: (name + '-sum') as `selected-balance-${string}`,
query: q('transactions')
.filter({ id: { $oneof: finalIds } })
.options({ splits: 'all' })
.calculate({ $sum: '$amount' }),
});

let scheduleBalance = null;
let scheduleBalance = 0;

const { isLoading, schedules = [] } = useCachedSchedules();

Expand Down Expand Up @@ -95,14 +112,10 @@ function SelectedBalance({ selectedItems, account }) {
}
}

if (balance == null) {
if (scheduleBalance == null) {
return null;
} else {
balance = scheduleBalance;
}
} else if (scheduleBalance != null) {
balance += scheduleBalance;
if (!balance && !scheduleBalance) {
return null;
} else {
balance = (balance ?? 0) + scheduleBalance;
}

return (
Expand All @@ -114,46 +127,67 @@ function SelectedBalance({ selectedItems, account }) {
);
}

function FilteredBalance({ filteredAmount }) {
type FilteredBalanceProps = {
filteredAmount?: number | null;
};

function FilteredBalance({ filteredAmount }: FilteredBalanceProps) {
const { t } = useTranslation();

return (
<DetailedBalance
name={t('Filtered balance:')}
balance={filteredAmount || 0}
balance={filteredAmount ?? 0}
isExactBalance={true}
/>
);
}

function MoreBalances({ balanceQuery }) {
type MoreBalancesProps = {
balanceQuery: { name: `balance-query-${string}`; query: Query };
};

function MoreBalances({ balanceQuery }: MoreBalancesProps) {
const { t } = useTranslation();

const cleared = useSheetValue({
name: balanceQuery.name + '-cleared',
const cleared = useSheetValue<'balance', `balance-query-${string}-cleared`>({
name: (balanceQuery.name + '-cleared') as `balance-query-${string}-cleared`,
query: balanceQuery.query.filter({ cleared: true }),
});
const uncleared = useSheetValue({
name: balanceQuery.name + '-uncleared',
const uncleared = useSheetValue<
'balance',
`balance-query-${string}-uncleared`
>({
name: (balanceQuery.name +
'-uncleared') as `balance-query-${string}-uncleared`,
query: balanceQuery.query.filter({ cleared: false }),
});

return (
<View style={{ flexDirection: 'row' }}>
<DetailedBalance name={t('Cleared total:')} balance={cleared} />
<DetailedBalance name={t('Uncleared total:')} balance={uncleared} />
<DetailedBalance name={t('Cleared total:')} balance={cleared ?? 0} />
<DetailedBalance name={t('Uncleared total:')} balance={uncleared ?? 0} />
</View>
);
}

type BalancesProps = {
balanceQuery: { name: `balance-query-${string}`; query: Query };
showExtraBalances: boolean;
onToggleExtraBalances: () => void;
account?: AccountEntity;
isFiltered: boolean;
filteredAmount?: number | null;
};

export function Balances({
balanceQuery,
showExtraBalances,
onToggleExtraBalances,
account,
isFiltered,
filteredAmount,
}) {
}: BalancesProps) {
const selectedItems = useSelectedItems();
const buttonRef = useRef(null);
const isButtonHovered = useHover(buttonRef);
Expand All @@ -177,7 +211,15 @@ export function Balances({
paddingBottom: 1,
}}
>
<CellValue binding={{ ...balanceQuery, value: 0 }} type="financial">
<CellValue
binding={
{ ...balanceQuery, value: 0 } as Binding<
'balance',
`balance-query-${string}`
>
}
type="financial"
>
{props => (
<CellValueText
{...props}
Expand Down
Loading
Loading