Files
actual-actualbudget/packages/desktop-client/src/components/mobile/accounts/AllAccountTransactions.tsx
Joel Jeremy Marquez 67d6592333 Add refetchOnSync option to useTransactions to refetch when a server sync event is emitted (#6936)
* Migrate setupTests.js to TypeScript with proper types (#6871)

* Initial plan

* Rename setupTests.js to setupTests.ts and add proper types

Co-authored-by: joel-jeremy <20313680+joel-jeremy@users.noreply.github.com>

* Extract Size type to avoid duplication

Co-authored-by: joel-jeremy <20313680+joel-jeremy@users.noreply.github.com>

* Add release note for setupTests TypeScript migration

Co-authored-by: joel-jeremy <20313680+joel-jeremy@users.noreply.github.com>

* Rename release note file to match PR number 6871

Co-authored-by: joel-jeremy <20313680+joel-jeremy@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: joel-jeremy <20313680+joel-jeremy@users.noreply.github.com>

* Delete setupTests PR release note

* Add refetchOnSync to useTransactions to refetch when a server sync event is emitted

* Add release note for useTransactions refetchOnSync feature (#6937)

* Initial plan

* Add release note for PR 6936

Co-authored-by: joel-jeremy <20313680+joel-jeremy@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: joel-jeremy <20313680+joel-jeremy@users.noreply.github.com>

* Coderabbit feedback

---------

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: joel-jeremy <20313680+joel-jeremy@users.noreply.github.com>
2026-02-12 00:16:37 +00:00

140 lines
4.8 KiB
TypeScript

import React, { useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { send } from 'loot-core/platform/client/fetch';
import type { Query } from 'loot-core/shared/query';
import { isPreviewId } from 'loot-core/shared/transactions';
import type { TransactionEntity } from 'loot-core/types/models';
import { TransactionListWithBalances } from '@desktop-client/components/mobile/transactions/TransactionListWithBalances';
import { SchedulesProvider } from '@desktop-client/hooks/useCachedSchedules';
import { useDateFormat } from '@desktop-client/hooks/useDateFormat';
import { useNavigate } from '@desktop-client/hooks/useNavigate';
import { usePreviewTransactions } from '@desktop-client/hooks/usePreviewTransactions';
import { getSchedulesQuery } from '@desktop-client/hooks/useSchedules';
import { useTransactions } from '@desktop-client/hooks/useTransactions';
import { useTransactionsSearch } from '@desktop-client/hooks/useTransactionsSearch';
import { collapseModals, pushModal } from '@desktop-client/modals/modalsSlice';
import * as queries from '@desktop-client/queries';
import { useDispatch } from '@desktop-client/redux';
import * as bindings from '@desktop-client/spreadsheet/bindings';
export function AllAccountTransactions() {
const schedulesQuery = useMemo(() => getSchedulesQuery(), []);
return (
<SchedulesProvider query={schedulesQuery}>
<TransactionListWithPreviews />
</SchedulesProvider>
);
}
function TransactionListWithPreviews() {
const { t } = useTranslation();
const baseTransactionsQuery = useCallback(
() => queries.transactions().options({ splits: 'all' }).select('*'),
[],
);
const [transactionsQuery, setTransactionsQuery] = useState<Query>(
baseTransactionsQuery(),
);
const {
transactions,
isPending: isTransactionsLoading,
isFetchingNextPage: isLoadingMoreTransactions,
fetchNextPage: fetchMoreTransactions,
} = useTransactions({
query: transactionsQuery,
});
const { previewTransactions, isLoading: isPreviewTransactionsLoading } =
usePreviewTransactions();
const dateFormat = useDateFormat() || 'MM/dd/yyyy';
const dispatch = useDispatch();
const navigate = useNavigate();
const { isSearching, search: onSearch } = useTransactionsSearch({
updateQuery: setTransactionsQuery,
resetQuery: () => setTransactionsQuery(baseTransactionsQuery()),
dateFormat,
});
const onOpenTransaction = useCallback(
(transaction: TransactionEntity) => {
if (!isPreviewId(transaction.id)) {
navigate(`/transactions/${transaction.id}`);
} else {
dispatch(
pushModal({
modal: {
name: 'scheduled-transaction-menu',
options: {
transactionId: transaction.id,
onPost: async transactionId => {
const parts = transactionId.split('/');
await send('schedule/post-transaction', { id: parts[1] });
dispatch(
collapseModals({
rootModalName: 'scheduled-transaction-menu',
}),
);
},
onSkip: async transactionId => {
const parts = transactionId.split('/');
await send('schedule/skip-next-date', { id: parts[1] });
dispatch(
collapseModals({
rootModalName: 'scheduled-transaction-menu',
}),
);
},
onComplete: async transactionId => {
const parts = transactionId.split('/');
await send('schedule/update', {
schedule: { id: parts[1], completed: true },
});
dispatch(
collapseModals({
rootModalName: 'scheduled-transaction-menu',
}),
);
},
},
},
}),
);
}
},
[dispatch, navigate],
);
const balanceBindings = useMemo(
() => ({
balance: bindings.allAccountBalance(),
}),
[],
);
const transactionsToDisplay = !isSearching
? // Do not render child transactions in the list, unless searching
previewTransactions.concat(transactions.filter(t => !t.is_child))
: transactions;
return (
<TransactionListWithBalances
isLoading={
isSearching ? isTransactionsLoading : isPreviewTransactionsLoading
}
transactions={transactionsToDisplay}
balance={balanceBindings.balance}
isLoadingMore={isLoadingMoreTransactions}
onLoadMore={fetchMoreTransactions}
searchPlaceholder={t('Search All Accounts')}
onSearch={onSearch}
onOpenTransaction={onOpenTransaction}
showMakeTransfer
/>
);
}