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) convert Balance.jsx to .tsx #3874

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React, { useRef } from 'react';
import React, { useRef, type ComponentProps } from 'react';
import { useTranslation } from 'react-i18next';

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 @@ -16,10 +17,23 @@ import { Text } from '../common/Text';
import { View } from '../common/View';
import { PrivacyFilter } from '../PrivacyFilter';
import { CellValue, CellValueText } from '../spreadsheet/CellValue';
import { type SheetFields, type SheetNames } from '../spreadsheet/index';
import { useFormat } from '../spreadsheet/useFormat';
import { useSheetValue } from '../spreadsheet/useSheetValue';

function DetailedBalance({ name, balance, isExactBalance = true }) {
import { type ReconcilingMessage } from './Reconcile';

type DetailedBalanceProps = {
name: string;
balance: number;
isExactBalance: boolean;
};

function DetailedBalance({
name,
balance,
isExactBalance = true,
}: DetailedBalanceProps) {
Copy link
Author

@cindywu cindywu Nov 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isExactBalance is intentionally and explicitly set to true because it seems that is what the original author intended.

const format = useFormat();
return (
<Text
Expand All @@ -42,32 +56,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-balance-${string}`>({
name: name as `selected-balance-${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(Array.isArray(rows) ? rows.map(r => r.id) : []);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this always returns an array

Copy link
Author

@cindywu cindywu Nov 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const ids = new Set((rows || []).map(r => r.id));

complains because useSheetValue doesn't always return an array. It can return a number.

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;

cindywu marked this conversation as resolved.
Show resolved Hide resolved
cindywu marked this conversation as resolved.
Show resolved Hide resolved
const { isLoading, schedules = [] } = useCachedSchedules();

Expand Down Expand Up @@ -114,7 +133,11 @@ function SelectedBalance({ selectedItems, account }) {
);
}

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

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

return (
Expand All @@ -126,34 +149,59 @@ function FilteredBalance({ filteredAmount }) {
);
}

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried setting

balanceQuery: Extract<
    Binding<'balance', `balance-query-${string}`>,
    { name: string; query?: Query }
  >;

but then packages/desktop-client/src/components/accounts/Account.tsx complains.

query: Query;
};
};

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

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

const uncleared = useSheetValue<'balance', `balance-query-${string}`>({
name: (balanceQuery.name + '-uncleared') as `balance-query-${string}`,
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}
isExactBalance
/>
<DetailedBalance
name={t('Uncleared total:')}
balance={uncleared ?? 0}
isExactBalance
/>
</View>
);
}

type BalancesProps = {
balanceQuery: ComponentProps<typeof ReconcilingMessage>['balanceQuery'];
showExtraBalances: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a Binding

Copy link
Author

@cindywu cindywu Nov 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What makes you say that? Do you have a suggested edit?

I am seeing this in a different file.

balanceQuery: { name: `balance-query-${string}`; query: Query };

Copy link
Author

@cindywu cindywu Nov 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is one way I could think of to set it as a Binding

balanceQuery: Extract<
    Binding<'balance', `balance-query-${string}`>,
    { name: string; query?: Query }
  >;

The root issue seems to be in

https://github.com/actualbudget/actual/blob/339fac280605bbd344ecb3387751a9ee43ffab69/packages/desktop-client/src/components/spreadsheet/index.ts#L81C1-L90C7

export type Binding<
  SheetName extends SheetNames,
  SheetFieldName extends SheetFields<SheetName>,
> =
  | SheetFieldName
  | {
      name: SheetFieldName;
      value?: Spreadsheets[SheetName][SheetFieldName];
      query?: Query;
    };

Possibly we could refactor this removing SheetFieldName as a potential type to be

export type Binding<
  SheetName extends SheetNames,
  SheetFieldName extends SheetFields<SheetName>,
> =
  {
      name: SheetFieldName;
      value?: Spreadsheets[SheetName][SheetFieldName];
      query?: Query;
    };

onToggleExtraBalances: () => void;
account: AccountEntity;
isFiltered: boolean;
filteredAmount: number;
};

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 +225,14 @@ export function Balances({
paddingBottom: 1,
}}
>
<CellValue binding={{ ...balanceQuery, value: 0 }} type="financial">
<CellValue
binding={{
name: balanceQuery.name as SheetFields<SheetNames>,
query: balanceQuery.query,
value: 0,
}}
type="financial"
>
{props => (
<CellValueText
{...props}
Expand Down
3 changes: 2 additions & 1 deletion packages/desktop-client/src/components/spreadsheet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ export type Spreadsheets = {
'uncategorized-balance': number;

// Balance fields
[key: `balance-query-${string}-cleared`]: number;
[key: `balance-query-${string}`]: number;
[key: `selected-balance-${string}`]: number;
};
};

Expand Down
6 changes: 6 additions & 0 deletions upcoming-release-notes/3874.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
category: Maintenance
authors: [cindywu]
---

Convert Balance.jsx to tsx
Loading