Add loading indicator when loading more transactions in mobile transaction list (#3900)

* Add isLoadingMore property to useTransactions hook

* Release notes

* Start loading more earlier
This commit is contained in:
Joel Jeremy Marquez
2024-12-10 09:22:28 -08:00
committed by GitHub
parent 5104a1a563
commit e96b986ad0
6 changed files with 78 additions and 24 deletions

View File

@@ -236,6 +236,7 @@ function TransactionListWithPreviews({
transactions,
isLoading,
reload: reloadTransactions,
isLoadingMore,
loadMore: loadMoreTransactions,
} = useTransactions({
query: transactionsQuery,
@@ -269,7 +270,7 @@ function TransactionListWithPreviews({
tables.includes('category_mapping') ||
tables.includes('payee_mapping')
) {
reloadTransactions?.();
reloadTransactions();
}
if (tables.includes('payees') || tables.includes('payee_mapping')) {
@@ -326,6 +327,7 @@ function TransactionListWithPreviews({
balance={balanceQueries.balance}
balanceCleared={balanceQueries.cleared}
balanceUncleared={balanceQueries.uncleared}
isLoadingMore={isLoadingMore}
onLoadMore={loadMoreTransactions}
searchPlaceholder={`Search ${accountName}`}
onSearch={onSearch}

View File

@@ -40,6 +40,7 @@ export function CategoryTransactions({ category, month }) {
const {
transactions,
isLoading,
isLoadingMore,
loadMore: loadMoreTransactions,
reload: reloadTransactions,
} = useTransactions({
@@ -56,7 +57,7 @@ export function CategoryTransactions({ category, month }) {
tables.includes('category_mapping') ||
tables.includes('payee_mapping')
) {
reloadTransactions?.();
reloadTransactions();
}
if (tables.includes('payees') || tables.includes('payee_mapping')) {
@@ -112,6 +113,7 @@ export function CategoryTransactions({ category, month }) {
balanceUncleared={balanceUncleared}
searchPlaceholder={`Search ${category.name}`}
onSearch={onSearch}
isLoadingMore={isLoadingMore}
onLoadMore={loadMoreTransactions}
onOpenTransaction={onOpenTransaction}
/>

View File

@@ -6,10 +6,9 @@ import React, {
useState,
} from 'react';
import { ListBox, Section, Header, Collection } from 'react-aria-components';
import { useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux';
import { t } from 'i18next';
import { setNotificationInset } from 'loot-core/client/actions';
import { groupById, integerToCurrency } from 'loot-core/shared/util';
import * as monthUtils from 'loot-core/src/shared/months';
@@ -41,12 +40,32 @@ import { TransactionListItem } from './TransactionListItem';
const NOTIFICATION_BOTTOM_INSET = 75;
function Loading({ style, 'aria-label': ariaLabel }) {
return (
<View
aria-label={ariaLabel || 'Loading...'}
style={{
backgroundColor: theme.mobilePageBackground,
flex: 1,
justifyContent: 'center',
alignItems: 'center',
...style,
}}
>
<AnimatedLoading width={25} height={25} />
</View>
);
}
export function TransactionList({
isLoading,
transactions,
onOpenTransaction,
isLoadingMore,
onLoadMore,
}) {
const { t } = useTranslation();
const sections = useMemo(() => {
// Group by date. We can assume transactions is ordered
const sections = [];
@@ -83,29 +102,19 @@ export function TransactionList({
);
useScrollListener(({ hasScrolledToEnd }) => {
if (hasScrolledToEnd('down', 5)) {
if (hasScrolledToEnd('down', 100)) {
onLoadMore?.();
}
});
if (isLoading) {
return (
<View
aria-label={t('Loading...')}
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}
>
<AnimatedLoading width={25} height={25} />
</View>
);
return <Loading aria-label={t('Loading transactions...')} />;
}
return (
<>
<ListBox
aria-label="Transaction list"
aria-label={t('Transaction list')}
selectionMode={selectedTransactions.size > 0 ? 'multiple' : 'single'}
selectedKeys={selectedTransactions}
dependencies={[selectedTransactions]}
@@ -159,6 +168,17 @@ export function TransactionList({
</Section>
)}
</ListBox>
{isLoadingMore && (
<Loading
aria-label={t('Loading more transactions...')}
style={{
// Same height as transaction list item
height: 60,
}}
/>
)}
{selectedTransactions.size > 0 && (
<SelectedTransactionsFloatingActionBar transactions={transactions} />
)}

View File

@@ -65,6 +65,7 @@ export function TransactionListWithBalances({
balanceUncleared,
searchPlaceholder = 'Search...',
onSearch,
isLoadingMore,
onLoadMore,
onOpenTransaction,
onRefresh,
@@ -104,6 +105,7 @@ export function TransactionListWithBalances({
<TransactionList
isLoading={isLoading}
transactions={transactions}
isLoadingMore={isLoadingMore}
onLoadMore={onLoadMore}
onOpenTransaction={onOpenTransaction}
/>

View File

@@ -1,4 +1,4 @@
import { useEffect, useRef, useState, useMemo } from 'react';
import { useEffect, useRef, useState, useMemo, useCallback } from 'react';
import debounce from 'lodash/debounce';
@@ -24,10 +24,11 @@ type UseTransactionsProps = {
type UseTransactionsResult = {
transactions: ReadonlyArray<TransactionEntity>;
isLoading?: boolean;
isLoading: boolean;
error?: Error;
reload?: () => void;
loadMore?: () => void;
reload: () => void;
loadMore: () => void;
isLoadingMore: boolean;
};
export function useTransactions({
@@ -35,6 +36,7 @@ export function useTransactions({
options = { pageCount: 50 },
}: UseTransactionsProps): UseTransactionsResult {
const [isLoading, setIsLoading] = useState(true);
const [isLoadingMore, setIsLoadingMore] = useState(false);
const [error, setError] = useState<Error | undefined>(undefined);
const [transactions, setTransactions] = useState<
ReadonlyArray<TransactionEntity>
@@ -88,12 +90,32 @@ export function useTransactions({
};
}, [query]);
const loadMore = useCallback(async () => {
if (!pagedQueryRef.current) {
return;
}
setIsLoadingMore(true);
await pagedQueryRef.current
.fetchNext()
.catch(setError)
.finally(() => {
setIsLoadingMore(false);
});
}, []);
const reload = useCallback(() => {
pagedQueryRef.current?.run();
}, []);
return {
transactions,
isLoading,
error,
reload: pagedQueryRef.current?.run,
loadMore: pagedQueryRef.current?.fetchNext,
reload,
loadMore,
isLoadingMore,
};
}

View File

@@ -0,0 +1,6 @@
---
category: Enhancements
authors: [joel-jeremy]
---
Add loading indicator when loading more transactions in mobile transaction list.