From ce92e0508c21df00a09dc1791d5fe3d148df3cd7 Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Fri, 9 Jun 2023 12:46:20 +0200 Subject: [PATCH 1/2] Pagination with router params (#4698) Co-authored-by: bipoza Co-authored-by: ionlizarazu Co-authored-by: Unai --- cypress/support/commands.js | 20 + cypress/tests/core/blocks/blocks-listing.js | 384 ++++++++++++++++++ news/4159.bugfix | 1 + .../Blocks/Listing/ListingBody.test.jsx | 20 + .../__snapshots__/ListingBody.test.jsx.snap | 2 +- .../Blocks/Listing/withQuerystringResults.jsx | 12 +- .../manage/Blocks/Search/hocs/withSearch.jsx | 12 +- src/helpers/Utils/usePagination.js | 86 +++- src/helpers/Utils/usePagination.test.js | 115 ++++++ 9 files changed, 629 insertions(+), 23 deletions(-) create mode 100644 news/4159.bugfix create mode 100644 src/helpers/Utils/usePagination.test.js diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 8c91883fc6..d271d9c0e9 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -849,3 +849,23 @@ Cypress.Commands.add('getTableSlate', (header = false) => { ); return slate; }); + +Cypress.Commands.add('configureListingWith', (contentType) => { + cy.get('.sidebar-container .tabs-wrapper .menu .item') + .contains('Block') + .click(); + cy.get('.querystring-widget .fields').contains('Add criteria').click(); + cy.get( + '.querystring-widget .fields:first-of-type .field:first-of-type .react-select__menu .react-select__option', + ) + .contains('Type') + .click(); + + //insert Page + cy.get('.querystring-widget .fields:first-of-type > .field').click(); + cy.get( + '.querystring-widget .fields:first-of-type > .field .react-select__menu .react-select__option', + ) + .contains(contentType) + .click(); +}); diff --git a/cypress/tests/core/blocks/blocks-listing.js b/cypress/tests/core/blocks/blocks-listing.js index c6de188ce0..260aef04c5 100644 --- a/cypress/tests/core/blocks/blocks-listing.js +++ b/cypress/tests/core/blocks/blocks-listing.js @@ -21,6 +21,42 @@ describe('Listing Block Tests', () => { cy.waitForResourceToLoad(''); }); + it('Add Listing block with no results', () => { + cy.intercept('PATCH', '/**/my-page').as('save'); + cy.intercept('GET', '/**/my-page').as('content'); + cy.intercept('GET', '/**/@types/Document').as('schema'); + + cy.createContent({ + contentType: 'Document', + contentId: 'my-page-test', + contentTitle: 'My Page Test', + path: 'my-page', + }); + + cy.navigate('/my-page'); + cy.wait('@content'); + + cy.navigate('/my-page/edit'); + cy.wait('@schema'); + + cy.clearSlateTitle().type('My title'); + + //add listing block + cy.addNewBlock('listing'); + + cy.configureListingWith('News Item'); + + //save + cy.get('#toolbar-save').click(); + cy.wait('@save'); + cy.wait('@content'); + + //test after save + cy.get('#page-document .block.listing.default .emptyListing').contains( + 'No results found.', + ); + }); + it('Add Listing block', () => { cy.intercept('PATCH', '/**/my-page').as('save'); cy.intercept('GET', '/**/my-page').as('content'); @@ -874,6 +910,354 @@ describe('Listing Block Tests', () => { cy.get('.listing-item h4').first().contains('My Folder 3'); }); + it('Navigates in listing block pagination and url clears on logo click', () => { + cy.intercept('PATCH', '/**/my-page').as('save'); + cy.intercept('GET', '/**/my-page').as('content'); + cy.intercept('GET', '/**/@types/Document').as('schema'); + + cy.createContent({ + contentType: 'Document', + contentId: 'my-folder', + contentTitle: 'My Folder', + path: 'my-page', + }); + cy.createContent({ + contentType: 'Document', + contentId: 'my-folder2', + contentTitle: 'My Folder 2', + path: 'my-page', + }); + cy.createContent({ + contentType: 'Document', + contentId: 'my-folder3', + contentTitle: 'My Folder 3', + path: 'my-page', + }); + + cy.navigate('/my-page'); + cy.wait('@content'); + + cy.navigate('/my-page/edit'); + cy.wait('@schema'); + + cy.clearSlateTitle().type('Listing block - navigate to second page'); + + //add listing block + cy.addNewBlock('listing'); + + //verify before save + cy.get(`.block.listing .listing-body:first-of-type`).contains('My Folder'); + + cy.get('.sidebar-container .tabs-wrapper .menu .item') + .contains('Block') + .click(); + cy.get('.querystring-widget .fields').contains('Add criteria').click(); + cy.get( + '.querystring-widget .fields:first-of-type .field:first-of-type .react-select__menu .react-select__option', + ) + .contains('Type') + .click(); + + //insert Page + cy.get('.querystring-widget .fields:first-of-type > .field').click(); + cy.get( + '.querystring-widget .fields:first-of-type > .field .react-select__menu .react-select__option', + ) + .contains('Page') + .click(); + + cy.get('#field-limit-3-querystring').click().type('2'); + + cy.get('#field-limit-3-querystring').click().clear().type('0'); + cy.get('#field-b_size-4-querystring').click().type('2'); + cy.get('.ui.pagination.menu a[value="2"]').first().click(); + cy.get('#toolbar-save').click(); + cy.wait('@save'); + cy.wait('@content'); + //test second pagination click + cy.get('.ui.pagination.menu a[value="2"]').first().click({ force: true }); + cy.url().should('include', '?page=2'); + //on logo click go to home page and remove ?page=2 from path + cy.get('.logo').first().click(); + cy.url().should('not.include', '?page=2'); + }); + + // reload url when ?page=2 + it('Reload path when listing page = 2', () => { + cy.intercept('PATCH', '/**/my-page').as('save'); + cy.intercept('GET', '/**/my-page').as('content'); + cy.intercept('GET', '/**/@types/Document').as('schema'); + + cy.createContent({ + contentType: 'Document', + contentId: 'my-folder', + contentTitle: 'My Folder', + path: 'my-page', + }); + cy.createContent({ + contentType: 'Document', + contentId: 'my-folder2', + contentTitle: 'My Folder 2', + path: 'my-page', + }); + cy.createContent({ + contentType: 'Document', + contentId: 'my-folder3', + contentTitle: 'My Folder 3', + path: 'my-page', + }); + + cy.navigate('/my-page'); + cy.wait('@content'); + + cy.navigate('/my-page/edit'); + cy.wait('@schema'); + + cy.clearSlateTitle().type( + 'Listing block - navigate to second page and reload path', + ); + + //add listing block + cy.addNewBlock('listing'); + + //verify before save + cy.get(`.block.listing .listing-body:first-of-type`).contains('My Folder'); + + cy.get('.sidebar-container .tabs-wrapper .menu .item') + .contains('Block') + .click(); + cy.get('.querystring-widget .fields').contains('Add criteria').click(); + cy.get( + '.querystring-widget .fields:first-of-type .field:first-of-type .react-select__menu .react-select__option', + ) + .contains('Type') + .click(); + + //insert Page + cy.get('.querystring-widget .fields:first-of-type > .field').click(); + cy.get( + '.querystring-widget .fields:first-of-type > .field .react-select__menu .react-select__option', + ) + .contains('Page') + .click(); + + cy.get('#field-limit-3-querystring').click().type('2'); + + //save + cy.get('#toolbar-save').click(); + cy.wait('@save'); + cy.wait('@content'); + + //test after save + cy.get('#page-document .listing-item:first-of-type a').should( + 'have.attr', + 'href', + '/my-page/my-folder', + ); + cy.get('.listing-item').should(($els) => { + expect($els).to.have.length(2); + }); + + cy.navigate('/my-page/edit'); + cy.wait('@schema'); + + cy.get('.block-editor-listing').click(); + cy.get('.sidebar-container .tabs-wrapper .menu .item') + .contains('Block') + .click(); + + cy.get('#field-limit-3-querystring').click().clear().type('0'); + cy.get('#field-b_size-4-querystring').click().type('2'); + cy.get('.ui.pagination.menu a[value="2"]').first().click(); + + cy.get('.listing-item h4').first().contains('My Folder 3'); + cy.get('#toolbar-save').click(); + cy.wait('@save'); + cy.wait('@content'); + //test second pagination click + cy.get('.ui.pagination.menu a[value="2"]').first().click(); + + //test f5 + cy.reload(); + cy.url().should('include', '?page=2'); + }); + + // different page in two listings on the same page + it('Navigate to different pages on two different listings', () => { + cy.intercept('PATCH', '/**/my-page').as('save'); + cy.intercept('GET', '/**/my-page').as('content'); + cy.intercept('GET', '/**/@types/Document').as('schema'); + + cy.createContent({ + contentType: 'Document', + contentId: 'my-folder', + contentTitle: 'My Folder', + path: 'my-page', + }); + cy.createContent({ + contentType: 'Document', + contentId: 'my-folder2', + contentTitle: 'My Folder 2', + path: 'my-page', + }); + cy.createContent({ + contentType: 'Document', + contentId: 'my-folder3', + contentTitle: 'My Folder 3', + path: 'my-page', + }); + + cy.navigate('/my-page'); + cy.wait('@content'); + + cy.navigate('/my-page/edit'); + cy.wait('@schema'); + + cy.clearSlateTitle().type( + 'Listing block - navigate to different pages on two different listings', + ); + + //add listing block + cy.addNewBlock('listing'); + + //verify before save + cy.get(`.block.listing .listing-body:first-of-type`).contains('My Folder'); + + cy.get('.sidebar-container .tabs-wrapper .menu .item') + .contains('Block') + .click(); + cy.get('.querystring-widget .fields').contains('Add criteria').click(); + cy.get( + '.querystring-widget .fields:first-of-type .field:first-of-type .react-select__menu .react-select__option', + ) + .contains('Type') + .click(); + + //insert Page + cy.get('.querystring-widget .fields:first-of-type > .field').click(); + cy.get( + '.querystring-widget .fields:first-of-type > .field .react-select__menu .react-select__option', + ) + .contains('Page') + .click(); + + cy.get('#field-limit-3-querystring').click().type('0'); + cy.get('#field-b_size-4-querystring').click().type('2'); + + cy.addNewBlock('listing'); + + //verify before save + cy.get(`.block.listing .listing-body:first-of-type`).contains('My Folder'); + + cy.get('.sidebar-container .tabs-wrapper .menu .item') + .contains('Block') + .click(); + cy.get('.querystring-widget .fields').contains('Add criteria').click(); + cy.get( + '.querystring-widget .fields:first-of-type .field:first-of-type .react-select__menu .react-select__option', + ) + .contains('Type') + .click(); + + //insert Page + cy.get('.querystring-widget .fields:first-of-type > .field').click(); + cy.get( + '.querystring-widget .fields:first-of-type > .field .react-select__menu .react-select__option', + ) + .contains('Page') + .click(); + + cy.get('#field-limit-3-querystring').click().type('0'); + cy.get('#field-b_size-4-querystring').click().type('1'); + cy.get('#toolbar-save').click(); + cy.wait('@save'); + cy.wait('@content'); + + // const listing1 = cy.get('.ui.pagination.menu').first(); + // cy.log('listing1', listing1); + //test second pagination click + cy.get('.ui.pagination.menu a[value="2"]').first().click(); + //test f5 + cy.reload(); + cy.url().should('include', '=2'); + // const listing2 = cy.get('.ui.pagination.menu').last(); + //test third pagination click on second listing + cy.get('.ui.pagination.menu a[value="3"]').first().click(); + //test f5 + cy.reload(); + cy.url().should('include', '=2'); + cy.url().should('include', '=3'); + //on logo click go to home page and remove ?page=2 from path + cy.get('.logo').first().click(); + cy.url().should('not.include', '=2'); + cy.url().should('not.include', '=3'); + //test back button + cy.navigate('/my-page'); + cy.wait('@content'); + cy.get('.ui.pagination.menu a[value="2"]').first().click({ force: true }); + cy.get('.ui.pagination.menu a[value="3"]').first().click({ force: true }); + cy.go(-1); + cy.url().should('not.include', '=3'); + cy.go(-1); + cy.url().should('not.include', '=2'); + cy.url().should('not.include', '=3'); + }); + + it('Add Listing block with no results, navigate to home, add a News Item, go to the listing', () => { + cy.intercept('PATCH', '/**/my-page').as('save'); + cy.intercept('GET', '/**/my-page').as('content'); + cy.intercept('GET', '/**/@types/Document').as('schema'); + + cy.createContent({ + contentType: 'Document', + contentId: 'my-page-test', + contentTitle: 'My Page Test', + path: 'my-page', + }); + + cy.navigate('/my-page'); + cy.wait('@content'); + + cy.navigate('/my-page/edit'); + cy.wait('@schema'); + + cy.clearSlateTitle().type('My title'); + + //add listing block + cy.addNewBlock('listing'); + + cy.configureListingWith('News Item'); + + //save + cy.get('#toolbar-save').click(); + cy.wait('@save'); + cy.wait('@content'); + + //test after save + cy.get('#page-document .block.listing.default .emptyListing').contains( + 'No results found.', + ); + + cy.get('.logo').first().click(); + + cy.createContent({ + contentType: 'News Item', + contentId: 'my-news-item-test', + contentTitle: 'My News Item', + path: 'my-page', + }); + cy.navigate('/my-page'); + + cy.get('#page-document .listing-body:first-of-type').contains( + 'My News Item', + ); + cy.get('#page-document .listing-item:first-of-type a').should( + 'have.attr', + 'href', + '/my-page/my-news-item-test', + ); + }); + // it('Listing block - Test Criteria: Location Navigation', () => { // /*not implemented because Navigation ui is not yet developed in Listing Block sidebar*/ // }); diff --git a/news/4159.bugfix b/news/4159.bugfix new file mode 100644 index 0000000000..d9b9f18dfa --- /dev/null +++ b/news/4159.bugfix @@ -0,0 +1 @@ +Added current page parameter to route in listing and search block pagination - Fix: #3868 @bipoza \ No newline at end of file diff --git a/src/components/manage/Blocks/Listing/ListingBody.test.jsx b/src/components/manage/Blocks/Listing/ListingBody.test.jsx index d52c7df814..8a5c359972 100644 --- a/src/components/manage/Blocks/Listing/ListingBody.test.jsx +++ b/src/components/manage/Blocks/Listing/ListingBody.test.jsx @@ -36,6 +36,26 @@ test('renders a ListingBody component', () => { content: { data: { is_folderish: true, + blocks: { + '839ee00b-013b-4f4a-9b10-8867938fdac3': { + '@type': 'listing', + block: '839ee00b-013b-4f4a-9b10-8867938fdac3', + headlineTag: 'h2', + query: [], + querystring: { + b_size: '2', + query: [ + { + i: 'path', + o: 'plone.app.querystring.operation.string.absolutePath', + v: '/', + }, + ], + sort_order: 'ascending', + }, + variation: 'default', + }, + }, }, }, intl: { diff --git a/src/components/manage/Blocks/Listing/__snapshots__/ListingBody.test.jsx.snap b/src/components/manage/Blocks/Listing/__snapshots__/ListingBody.test.jsx.snap index e81db3c83f..5fa1511b42 100644 --- a/src/components/manage/Blocks/Listing/__snapshots__/ListingBody.test.jsx.snap +++ b/src/components/manage/Blocks/Listing/__snapshots__/ListingBody.test.jsx.snap @@ -5,7 +5,7 @@ exports[`renders a ListingBody component 1`] = ` className="emptyListing" >
state.querystringsearch.subrequests, ); @@ -45,7 +47,7 @@ export default function withQuerystringResults(WrappedComponent) { const folderItems = content?.is_folderish ? content.items : []; const hasQuery = querystring?.query?.length > 0; - const hasLoaded = hasQuery ? !querystringResults?.[block]?.loading : true; + const hasLoaded = hasQuery ? querystringResults?.[block]?.loaded : true; const listingItems = querystring?.query?.length > 0 && querystringResults?.[block] @@ -104,6 +106,8 @@ export default function withQuerystringResults(WrappedComponent) { } else { dispatch(getContent(initialPath, null, null, currentPage)); } + adaptedQueryRef.current = adaptedQuery; + currentPageRef.current = currentPage; }, [ block, isImageGallery, diff --git a/src/components/manage/Blocks/Search/hocs/withSearch.jsx b/src/components/manage/Blocks/Search/hocs/withSearch.jsx index 332d6feb4f..b810cc282f 100644 --- a/src/components/manage/Blocks/Search/hocs/withSearch.jsx +++ b/src/components/manage/Blocks/Search/hocs/withSearch.jsx @@ -148,12 +148,16 @@ const getSearchFields = (searchData) => { }; /** - * A HOC that will mirror the search block state to a hash location + * A hook that will mirror the search block state to a hash location */ const useHashState = () => { const location = useLocation(); const history = useHistory(); + /** + * Required to maintain parameter compatibility. + With this we will maintain support for receiving hash (#) and search (?) type parameters. + */ const oldState = React.useMemo(() => { return { ...qs.parse(location.search), @@ -169,7 +173,7 @@ const useHashState = () => { const setSearchData = React.useCallback( (searchData) => { - const newParams = qs.parse(location.hash); + const newParams = qs.parse(location.search); let changed = false; @@ -186,11 +190,11 @@ const useHashState = () => { if (changed) { history.push({ - hash: qs.stringify(newParams), + search: qs.stringify(newParams), }); } }, - [history, oldState, location.hash], + [history, oldState, location.search], ); return [current, setSearchData]; diff --git a/src/helpers/Utils/usePagination.js b/src/helpers/Utils/usePagination.js index acb12d2ac5..083ec48682 100644 --- a/src/helpers/Utils/usePagination.js +++ b/src/helpers/Utils/usePagination.js @@ -1,25 +1,83 @@ -import React from 'react'; -import { isEqual } from 'lodash'; -import { usePrevious } from './usePrevious'; -import useDeepCompareEffect from 'use-deep-compare-effect'; +import React, { useRef, useEffect } from 'react'; +import { useHistory, useLocation } from 'react-router-dom'; +import qs from 'query-string'; +import { useSelector } from 'react-redux'; +import { slugify } from '@plone/volto/helpers/Utils/Utils'; + +/** + * @function useCreatePageQueryStringKey + * @description A hook that creates a key with an id if there are multiple blocks with pagination. + * @returns {string} Example: page || page_012345678 + */ +const useCreatePageQueryStringKey = (id) => { + const blockTypesWithPagination = ['search', 'listing']; + const blocks = useSelector((state) => state?.content?.data?.blocks) || []; + const blocksLayout = + useSelector((state) => state?.content?.data?.blocks_layout?.items) || []; + const displayedBlocks = blocksLayout?.map((item) => blocks[item]); + const hasMultiplePaginations = + displayedBlocks.filter((item) => + blockTypesWithPagination.includes(item['@type']), + ).length > 1 || false; + + return hasMultiplePaginations ? slugify(`page-${id}`) : 'page'; +}; + +const useGetBlockType = (id) => { + const blocks = useSelector((state) => state?.content?.data?.blocks) || []; + const block = blocks[id]; + return block ? block?.['@type'] : null; +}; /** * A pagination helper that tracks the query and resets pagination in case the * query changes. */ -export const usePagination = (query, defaultPage = 1) => { - const previousQuery = usePrevious(query); - const [currentPage, setCurrentPage] = React.useState(defaultPage); +export const usePagination = (id = null, defaultPage = 1) => { + const location = useLocation(); + const history = useHistory(); + const pageQueryStringKey = useCreatePageQueryStringKey(id); + const block_type = useGetBlockType(id); + const pageQueryParam = + qs.parse(location.search)[pageQueryStringKey] || defaultPage; + const [currentPage, setCurrentPageState] = React.useState( + parseInt(pageQueryParam), + ); + const setCurrentPage = (page) => { + setCurrentPageState(page); + const newParams = { + ...qs.parse(location.search), + [pageQueryStringKey]: page, + }; + history.push({ search: qs.stringify(newParams) }); + }; - useDeepCompareEffect(() => { - setCurrentPage(defaultPage); - }, [query, previousQuery, defaultPage]); + const queryRef = useRef(qs.parse(location.search)?.query); + useEffect(() => { + if ( + queryRef.current !== qs.parse(location.search)?.query && + block_type === 'search' + ) { + setCurrentPageState(defaultPage); + const newParams = { + ...qs.parse(location.search), + [pageQueryStringKey]: defaultPage, + }; + delete newParams[pageQueryStringKey]; + history.replace({ search: qs.stringify(newParams) }); + queryRef.current = qs.parse(location.search)?.query; + } else { + setCurrentPageState( + parseInt( + qs.parse(location.search)?.[pageQueryStringKey] || defaultPage, + ), + ); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [location.search, block_type]); return { - currentPage: - previousQuery && !isEqual(previousQuery, query) - ? defaultPage - : currentPage, + currentPage, setCurrentPage, }; }; diff --git a/src/helpers/Utils/usePagination.test.js b/src/helpers/Utils/usePagination.test.js new file mode 100644 index 0000000000..26924d78a0 --- /dev/null +++ b/src/helpers/Utils/usePagination.test.js @@ -0,0 +1,115 @@ +import { renderHook } from '@testing-library/react-hooks'; +import { usePagination } from './usePagination'; +import * as redux from 'react-redux'; +import routeData from 'react-router'; +import { slugify } from '@plone/volto/helpers/Utils/Utils'; + +const searchBlockId = '545b33de-92cf-4747-969d-68851837b317'; +const searchBlockId2 = '454b33de-92cf-4747-969d-68851837b713'; +const searchBlock = { + '@type': 'search', + query: { + b_size: '4', + query: [ + { + i: 'path', + o: 'plone.app.querystring.operation.string.relativePath', + v: '', + }, + ], + sort_order: 'ascending', + }, + showSearchInput: true, + showTotalResults: true, +}; +let state = { + content: { + data: { + blocks: { + [searchBlockId]: searchBlock, + }, + blocks_layout: { + items: [searchBlockId], + }, + }, + }, +}; + +let mockUseLocationValue = { + pathname: '/testroute', + search: '', +}; + +const setUp = (searchParam, numberOfSearches) => { + mockUseLocationValue.search = searchParam; + if (numberOfSearches > 1) { + state.content.data.blocks[searchBlockId2] = searchBlock; + state.content.data.blocks_layout.items.push(searchBlockId2); + } + return renderHook(({ id, defaultPage }) => usePagination(id, defaultPage), { + initialProps: { + id: searchBlockId, + defaultPage: 1, + }, + }); +}; + +describe(`Tests for usePagination, for the block ${searchBlockId}`, () => { + const useLocation = jest.spyOn(routeData, 'useLocation'); + const useHistory = jest.spyOn(routeData, 'useHistory'); + const useSelector = jest.spyOn(redux, 'useSelector'); + beforeEach(() => { + useLocation.mockReturnValue(mockUseLocationValue); + useHistory.mockReturnValue({ replace: jest.fn() }); + useSelector.mockImplementation((cb) => cb(state)); + }); + + it('1 paginated block with id and defaultPage 1 - shoud be 1', () => { + const { result } = setUp(); + expect(result.current.currentPage).toBe(1); + }); + + it('1 paginated block without params - shoud be 1', () => { + const { result } = setUp(); + expect(result.current.currentPage).toBe(1); + }); + + const param1 = '?page=2'; + it(`1 paginated block with params: ${param1} - shoud be 2`, () => { + const { result } = setUp(param1); + expect(result.current.currentPage).toBe(2); + }); + + const param2 = `?${slugify(`page-${searchBlockId}`)}=2`; + it(`2 paginated blocks with current block in the params: ${param2} - shoud be 2`, () => { + const { result } = setUp(param2, 2); + expect(result.current.currentPage).toBe(2); + }); + + const param3 = `?${slugify(`page-${searchBlockId2}`)}=2`; + it(`2 paginated blocks with the other block in the params: ${param3} - shoud be 1`, () => { + const { result } = setUp(param3, 2); + expect(result.current.currentPage).toBe(1); + }); + + const param4 = `?${slugify(`page-${searchBlockId}`)}=2&${slugify( + `page-${searchBlockId2}`, + )}=1`; + it(`2 paginated blocks with both blocks in the params, current 2: ${param4} - shoud be 2`, () => { + const { result } = setUp(param4, 2); + expect(result.current.currentPage).toBe(2); + }); + + const param5 = `?${slugify(`page-${searchBlockId}`)}=1&${slugify( + `page-${searchBlockId2}`, + )}=2`; + it(`2 paginated blocks with both blocks in the params, current 1: ${param5} - shoud be 1`, () => { + const { result } = setUp(param5, 2); + expect(result.current.currentPage).toBe(1); + }); + + it(`2 paginated blocks with wrong page param: ${param1} - shoud be 1`, () => { + const { result } = setUp(param1, 2); + expect(result.current.currentPage).toBe(1); + }); +}); From afeaac9c33570b41a44d7db33a1d2aa778705ce2 Mon Sep 17 00:00:00 2001 From: Victor Fernandez de Alba Date: Fri, 23 Jun 2023 11:56:01 +0200 Subject: [PATCH 2/2] Backport changes in `withQuerystringResults.jsx` to maintain both in sync (change not backported initially because the PR containing it was "breaking" --- .../Blocks/Listing/withQuerystringResults.jsx | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/components/manage/Blocks/Listing/withQuerystringResults.jsx b/src/components/manage/Blocks/Listing/withQuerystringResults.jsx index c2e0e717ae..b61736c3c9 100644 --- a/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +++ b/src/components/manage/Blocks/Listing/withQuerystringResults.jsx @@ -14,18 +14,23 @@ function getDisplayName(WrappedComponent) { export default function withQuerystringResults(WrappedComponent) { function WithQuerystringResults(props) { - const { data = {}, properties: content, path, variation } = props; + const { + data = {}, + id = data.block, + properties: content, + path, + variation, + } = props; const { settings } = config; const querystring = data.querystring || data; // For backwards compat with data saved before Blocks schema. Note, this is also how the Search block passes data to ListingBody - const { block } = data; const { b_size = settings.defaultPageSize } = querystring; // batchsize // save the path so it won't trigger dispatch on eager router location change const [initialPath] = React.useState(getBaseUrl(path)); const copyFields = ['limit', 'query', 'sort_on', 'sort_order', 'depth']; - const { currentPage, setCurrentPage } = usePagination(block, 1); + const { currentPage, setCurrentPage } = usePagination(id, 1); const adaptedQuery = Object.assign( variation?.fullobjects ? { fullobjects: 1 } : { metadata_fields: '_all' }, { @@ -47,32 +52,32 @@ export default function withQuerystringResults(WrappedComponent) { const folderItems = content?.is_folderish ? content.items : []; const hasQuery = querystring?.query?.length > 0; - const hasLoaded = hasQuery ? querystringResults?.[block]?.loaded : true; + const hasLoaded = hasQuery ? querystringResults?.[id]?.loaded : true; const listingItems = - querystring?.query?.length > 0 && querystringResults?.[block] - ? querystringResults?.[block]?.items || [] + querystring?.query?.length > 0 && querystringResults?.[id] + ? querystringResults?.[id]?.items || [] : folderItems; const showAsFolderListing = !hasQuery && content?.items_total > b_size; const showAsQueryListing = - hasQuery && querystringResults?.[block]?.total > b_size; + hasQuery && querystringResults?.[id]?.total > b_size; const totalPages = showAsFolderListing ? Math.ceil(content.items_total / b_size) : showAsQueryListing - ? Math.ceil(querystringResults[block].total / b_size) + ? Math.ceil(querystringResults[id].total / b_size) : 0; const prevBatch = showAsFolderListing ? content.batching?.prev : showAsQueryListing - ? querystringResults[block].batching?.prev + ? querystringResults[id].batching?.prev : null; const nextBatch = showAsFolderListing ? content.batching?.next : showAsQueryListing - ? querystringResults[block].batching?.next + ? querystringResults[id].batching?.next : null; const isImageGallery = @@ -82,7 +87,7 @@ export default function withQuerystringResults(WrappedComponent) { useDeepCompareEffect(() => { if (hasQuery) { dispatch( - getQueryStringResults(initialPath, adaptedQuery, block, currentPage), + getQueryStringResults(initialPath, adaptedQuery, id, currentPage), ); } else if (isImageGallery && !hasQuery) { // when used as image gallery, it doesn't need a query to list children @@ -100,7 +105,7 @@ export default function withQuerystringResults(WrappedComponent) { }, ], }, - block, + id, ), ); } else { @@ -109,7 +114,7 @@ export default function withQuerystringResults(WrappedComponent) { adaptedQueryRef.current = adaptedQuery; currentPageRef.current = currentPage; }, [ - block, + id, isImageGallery, adaptedQuery, hasQuery, @@ -122,7 +127,7 @@ export default function withQuerystringResults(WrappedComponent) { setCurrentPage(activePage)} - total={querystringResults?.[block]?.total} + total={querystringResults?.[id]?.total} batch_size={b_size} currentPage={currentPage} totalPages={totalPages}