From e1963fd1eed89176065ee8e420e9509f30aa957c Mon Sep 17 00:00:00 2001 From: sdrejkarz <123745148+sdrejkarz@users.noreply.github.com> Date: Thu, 30 May 2024 16:20:52 +0200 Subject: [PATCH] fix: #443 Fix pagination issues (#577) --- .../__tests__/usePaginatedQuery.hook.spec.tsx | 15 ++++++------ .../usePaginatedQuery.hook.ts | 23 +++++++++++++++---- .../crudDemoItemList.component.spec.tsx | 15 +++++++++++- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/packages/webapp-libs/webapp-api-client/src/hooks/usePaginatedQuery/__tests__/usePaginatedQuery.hook.spec.tsx b/packages/webapp-libs/webapp-api-client/src/hooks/usePaginatedQuery/__tests__/usePaginatedQuery.hook.spec.tsx index ed1490bdf..370ab904c 100644 --- a/packages/webapp-libs/webapp-api-client/src/hooks/usePaginatedQuery/__tests__/usePaginatedQuery.hook.spec.tsx +++ b/packages/webapp-libs/webapp-api-client/src/hooks/usePaginatedQuery/__tests__/usePaginatedQuery.hook.spec.tsx @@ -1,5 +1,6 @@ import { MockedResponse } from '@apollo/client/testing'; -import { act } from '@testing-library/react-hooks'; +import { waitFor } from '@testing-library/react'; +import { act } from 'react'; import { fillPaginationItemListQuery, paginationTestItemFactory } from '../../../tests/factories'; import { renderHook } from '../../../tests/utils/rendering'; @@ -25,10 +26,9 @@ describe('usePaginationQuery: Hook', () => { }, { first: 8 } ); + const useEffectCleanMock = initMockedResponse; - const mocks = [initMockedResponse, mock].filter( - (x): x is MockedResponse, Record> => x !== undefined - ); + const mocks = mock ? [initMockedResponse, mock, useEffectCleanMock] : [initMockedResponse, useEffectCleanMock]; const { result, waitForApolloMocks } = renderHook( () => @@ -61,6 +61,7 @@ describe('usePaginationQuery: Hook', () => { expect(firstItem?.id).toBe('item-1'); expect(data?.allNotifications?.edges.length).toBe(initDataLength); + await waitForApolloMocks(); }); it('should fetch next page', async () => { @@ -87,9 +88,9 @@ describe('usePaginationQuery: Hook', () => { result.current.loadNext(); }); - await waitForApolloMocks(); + await waitForApolloMocks(1); - expect(result.current.data?.allNotifications?.edges.length).toBe(nextDataLength); + await waitFor(() => expect(result.current.data?.allNotifications?.edges.length).toBe(nextDataLength)); }); it('should fetch previous page', async () => { @@ -110,7 +111,7 @@ describe('usePaginationQuery: Hook', () => { result.current.loadPrevious(); }); - await waitForApolloMocks(); + await waitForApolloMocks(1); expect(result.current.data?.allNotifications?.edges.length).toBe(initDataLength); }); diff --git a/packages/webapp-libs/webapp-api-client/src/hooks/usePaginatedQuery/usePaginatedQuery.hook.ts b/packages/webapp-libs/webapp-api-client/src/hooks/usePaginatedQuery/usePaginatedQuery.hook.ts index e48ac49a3..8991368f5 100644 --- a/packages/webapp-libs/webapp-api-client/src/hooks/usePaginatedQuery/usePaginatedQuery.hook.ts +++ b/packages/webapp-libs/webapp-api-client/src/hooks/usePaginatedQuery/usePaginatedQuery.hook.ts @@ -62,9 +62,9 @@ export const usePaginatedQuery = < const { data, loading, fetchMore } = useQuery(query, options.hookOptions); useEffect(() => { - if (cachedCursors.includes(data?.[options.dataKey]?.pageInfo.endCursor)) { - setCachedCursors([]); - } + const currentEndCursor = data?.[options.dataKey]?.pageInfo.endCursor; + const isFirstEndCursor = cachedCursors.indexOf(currentEndCursor) === 0; + if (isFirstEndCursor) setCachedCursors([]); }, [data, cachedCursors, options.dataKey]); useEffect(() => { @@ -72,10 +72,20 @@ export const usePaginatedQuery = < setHasNext(data?.[options.dataKey]?.pageInfo.hasNextPage ?? false); }, [data, cachedCursors.length, options.dataKey]); + useEffect(() => { + const setCacheToFirstPage = () => { + fetchMore({ + updateQuery: (_, { fetchMoreResult }) => fetchMoreResult, + }); + }; + + return setCacheToFirstPage; + }, [fetchMore]); + const loadNext = useCallback(() => { const queryData = data?.[options.dataKey]; const endCursor = queryData?.pageInfo.endCursor; - setCachedCursors((prev) => [...prev, endCursor]); + fetchMore({ variables: { after: endCursor, @@ -83,12 +93,13 @@ export const usePaginatedQuery = < updateQuery: (_, { fetchMoreResult }) => { return fetchMoreResult; }, + }).then(() => { + setCachedCursors((prev) => [...prev, endCursor]); }); }, [data, setCachedCursors, fetchMore, options.dataKey]); const loadPrevious = useCallback(() => { const newCachedCursors = cachedCursors.slice(0, -1); - setCachedCursors(newCachedCursors); const lastEndCursor = newCachedCursors.length > 0 ? newCachedCursors[newCachedCursors.length - 1] : undefined; fetchMore({ @@ -98,6 +109,8 @@ export const usePaginatedQuery = < updateQuery: (_, { fetchMoreResult }) => { return fetchMoreResult; }, + }).then(() => { + setCachedCursors(newCachedCursors); }); }, [cachedCursors, setCachedCursors, fetchMore]); diff --git a/packages/webapp-libs/webapp-crud-demo/src/routes/crudDemoItem/crudDemoItemList/__tests__/crudDemoItemList.component.spec.tsx b/packages/webapp-libs/webapp-crud-demo/src/routes/crudDemoItem/crudDemoItemList/__tests__/crudDemoItemList.component.spec.tsx index dd806de24..593523cf7 100644 --- a/packages/webapp-libs/webapp-crud-demo/src/routes/crudDemoItem/crudDemoItemList/__tests__/crudDemoItemList.component.spec.tsx +++ b/packages/webapp-libs/webapp-crud-demo/src/routes/crudDemoItem/crudDemoItemList/__tests__/crudDemoItemList.component.spec.tsx @@ -41,6 +41,7 @@ describe('CrudDemoItemList: Component', () => { }) ), fillCrudDemoItemPaginationListQuery(allItems, {}, { tenantId, first: 8 }), + fillCrudDemoItemPaginationListQuery(allItems, {}, { tenantId, first: 8 }), ]; render(, { routerProps, apolloMocks }); @@ -50,7 +51,19 @@ describe('CrudDemoItemList: Component', () => { it('should render link to add new item form', async () => { const routerProps = createMockRouterProps(RoutesConfig.crudDemoItem.list); - const apolloMocks = [fillCommonQueryWithUser(), fillCrudDemoItemPaginationListQuery(allItems, {}, { first: 8 })]; + const apolloMocks = [ + fillCommonQueryWithUser( + currentUserFactory({ + tenants: [ + tenantFactory({ + id: tenantId, + }), + ], + }) + ), + fillCrudDemoItemPaginationListQuery(allItems, {}, { tenantId, first: 8 }), + fillCrudDemoItemPaginationListQuery(allItems, {}, { tenantId, first: 8 }), + ]; render(, { routerProps, apolloMocks });