diff --git a/packages/desktop-client/src/components/mobile/accounts/AccountTransactions.tsx b/packages/desktop-client/src/components/mobile/accounts/AccountTransactions.tsx index a33e4a2827c..5a6c8308509 100644 --- a/packages/desktop-client/src/components/mobile/accounts/AccountTransactions.tsx +++ b/packages/desktop-client/src/components/mobile/accounts/AccountTransactions.tsx @@ -26,6 +26,7 @@ import { import { usePreviewTransactions, useTransactions, + useTransactionsSearch, } from 'loot-core/client/data-hooks/transactions'; import * as queries from 'loot-core/client/queries'; import { listen, send } from 'loot-core/platform/client/fetch'; @@ -231,7 +232,6 @@ function TransactionListWithPreviews({ const [transactionsQuery, setTransactionsQuery] = useState( baseTransactionsQuery(), ); - const [isSearching, setIsSearching] = useState(false); const { transactions, isLoading, @@ -276,25 +276,13 @@ function TransactionListWithPreviews({ }); }, [dispatch, reloadTransactions]); - const updateSearchQuery = useDebounceCallback( - useCallback( - searchText => { - if (searchText === '') { - setTransactionsQuery(baseTransactionsQuery()); - } else if (searchText) { - setTransactionsQuery(currentQuery => - queries.transactionsSearch(currentQuery, searchText, dateFormat), - ); - } - - setIsSearching(searchText !== ''); - }, - [setTransactionsQuery, baseTransactionsQuery, dateFormat], - ), - 150, - ); + const { isSearching, search } = useTransactionsSearch({ + updateQuery: setTransactionsQuery, + resetQuery: () => setTransactionsQuery(baseTransactionsQuery()), + dateFormat, + }); - const onSearch = useCallback(updateSearchQuery, [updateSearchQuery]); + const onSearch = useDebounceCallback(search, 150); const onOpenTransaction = useCallback( (transaction: TransactionEntity) => { diff --git a/packages/desktop-client/src/components/mobile/budget/CategoryTransactions.jsx b/packages/desktop-client/src/components/mobile/budget/CategoryTransactions.jsx index 3f7ffa548d5..087369c8d78 100644 --- a/packages/desktop-client/src/components/mobile/budget/CategoryTransactions.jsx +++ b/packages/desktop-client/src/components/mobile/budget/CategoryTransactions.jsx @@ -4,7 +4,10 @@ import { useDispatch } from 'react-redux'; import { useDebounceCallback } from 'usehooks-ts'; import { getPayees } from 'loot-core/client/actions'; -import { useTransactions } from 'loot-core/client/data-hooks/transactions'; +import { + useTransactions, + useTransactionsSearch, +} from 'loot-core/client/data-hooks/transactions'; import * as queries from 'loot-core/client/queries'; import { listen } from 'loot-core/platform/client/fetch'; import * as monthUtils from 'loot-core/shared/months'; @@ -65,23 +68,12 @@ export function CategoryTransactions({ category, month }) { }); }, [dispatch, reloadTransactions]); - const updateSearchQuery = useDebounceCallback( - useCallback( - searchText => { - if (searchText === '') { - setTransactionsQuery(baseTransactionsQuery()); - } else if (searchText) { - setTransactionsQuery(currentQuery => - queries.transactionsSearch(currentQuery, searchText, dateFormat), - ); - } - }, - [baseTransactionsQuery, dateFormat], - ), - 150, - ); - - const onSearch = useCallback(updateSearchQuery, [updateSearchQuery]); + const { search } = useTransactionsSearch({ + updateQuery: setTransactionsQuery, + resetQuery: () => setTransactionsQuery(baseTransactionsQuery()), + dateFormat, + }); + const onSearch = useDebounceCallback(search, 150); const onOpenTransaction = useCallback( transaction => { diff --git a/packages/loot-core/src/client/data-hooks/transactions.ts b/packages/loot-core/src/client/data-hooks/transactions.ts index ddbe0211949..78cbba82787 100644 --- a/packages/loot-core/src/client/data-hooks/transactions.ts +++ b/packages/loot-core/src/client/data-hooks/transactions.ts @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState, useMemo } from 'react'; +import { useEffect, useRef, useState, useMemo, useCallback } from 'react'; import { send } from '../../platform/client/fetch'; import { type Query } from '../../shared/query'; @@ -7,6 +7,7 @@ import { type ScheduleEntity, type TransactionEntity, } from '../../types/models'; +import * as queries from '../queries'; import { type PagedQuery, pagedQuery } from '../query-helpers'; import { type ScheduleStatuses, useCachedSchedules } from './schedules'; @@ -173,6 +174,45 @@ export function usePreviewTransactions(): UsePreviewTransactionsResult { }; } +type UseTransactionsSearchProps = { + updateQuery: (updateFn: (searchQuery: Query) => Query) => void; + resetQuery: () => void; + dateFormat: string; +}; + +type UseTransactionsSearchResult = { + isSearching: boolean; + search: (searchText: string) => void; +}; + +export function useTransactionsSearch({ + updateQuery, + resetQuery, + dateFormat, +}: UseTransactionsSearchProps): UseTransactionsSearchResult { + const [isSearching, setIsSearching] = useState(false); + + const updateSearchQuery = useCallback( + (searchText: string) => { + if (searchText === '') { + resetQuery(); + setIsSearching(false); + } else if (searchText) { + updateQuery(previousQuery => + queries.transactionsSearch(previousQuery, searchText, dateFormat), + ); + setIsSearching(true); + } + }, + [dateFormat, resetQuery, updateQuery], + ); + + return { + isSearching, + search: updateSearchQuery, + }; +} + function isForPreview(schedule: ScheduleEntity, statuses: ScheduleStatuses) { const status = statuses.get(schedule.id); return (