diff options
Diffstat (limited to 'src/utils/hooks/use-posts-list')
| -rw-r--r-- | src/utils/hooks/use-posts-list/index.ts | 1 | ||||
| -rw-r--r-- | src/utils/hooks/use-posts-list/use-posts-list.test.ts | 24 | ||||
| -rw-r--r-- | src/utils/hooks/use-posts-list/use-posts-list.ts | 66 |
3 files changed, 91 insertions, 0 deletions
diff --git a/src/utils/hooks/use-posts-list/index.ts b/src/utils/hooks/use-posts-list/index.ts new file mode 100644 index 0000000..664c142 --- /dev/null +++ b/src/utils/hooks/use-posts-list/index.ts @@ -0,0 +1 @@ +export * from './use-posts-list'; diff --git a/src/utils/hooks/use-posts-list/use-posts-list.test.ts b/src/utils/hooks/use-posts-list/use-posts-list.test.ts new file mode 100644 index 0000000..1d11111 --- /dev/null +++ b/src/utils/hooks/use-posts-list/use-posts-list.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from '@jest/globals'; +import { act, renderHook } from '@testing-library/react'; +import { getArticles } from '../../../services/graphql'; +import { usePostsList } from './use-posts-list'; + +describe('usePostsList', () => { + it('can return the first new result index when loading more posts', async () => { + const perPage = 5; + const { result } = renderHook(() => + usePostsList({ fetcher: getArticles, perPage }) + ); + + expect.assertions(2); + + expect(result.current.firstNewResultIndex).toBeUndefined(); + + await act(async () => { + await result.current.loadMore(); + }); + + // Assuming there is more than one page. + expect(result.current.firstNewResultIndex).toBe(perPage + 1); + }); +}); diff --git a/src/utils/hooks/use-posts-list/use-posts-list.ts b/src/utils/hooks/use-posts-list/use-posts-list.ts new file mode 100644 index 0000000..661727f --- /dev/null +++ b/src/utils/hooks/use-posts-list/use-posts-list.ts @@ -0,0 +1,66 @@ +import { useCallback, useState } from 'react'; +import type { PostData } from '../../../components'; +import type { Maybe, RawArticle } from '../../../types'; +import { getPostsList } from '../../helpers'; +import { + type UsePaginationConfig, + usePagination, + type UsePaginationReturn, +} from '../use-pagination'; + +export type usePostsListReturn = Omit< + UsePaginationReturn<RawArticle>, + 'data' +> & { + /** + * The index of the first new result when loading more posts. + */ + firstNewResultIndex: Maybe<number>; + /** + * The posts list. + */ + posts: Maybe<PostData[]>; +}; + +export const usePostsList = ( + config: UsePaginationConfig<RawArticle> +): usePostsListReturn => { + const { + data, + error, + hasNextPage, + isEmpty, + isError, + isLoading, + isLoadingMore, + isRefreshing, + isValidating, + loadMore, + size, + } = usePagination(config); + const [firstNewResultIndex, setFirstNewResultIndex] = + useState<Maybe<number>>(undefined); + + const posts = data ? getPostsList(data) : undefined; + + const handleLoadMore = useCallback(async () => { + setFirstNewResultIndex(size * config.perPage + 1); + + await loadMore(); + }, [config.perPage, loadMore, size]); + + return { + error, + firstNewResultIndex, + hasNextPage, + isEmpty, + isError, + isLoading, + isLoadingMore, + isRefreshing, + isValidating, + loadMore: handleLoadMore, + posts, + size, + }; +}; |
