From e0bd255d1f4c60692102f9f80fed642db9a1c86c Mon Sep 17 00:00:00 2001 From: Claudia Malzer Date: Tue, 30 Apr 2024 14:48:18 +0200 Subject: [PATCH 1/9] ERM-3220 Update pagination mechanisms for MCLs to work without stats * add pageCount property --- lib/hooks/usePrevNextPagination.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/hooks/usePrevNextPagination.js b/lib/hooks/usePrevNextPagination.js index 7b7ddf49..e7f2b704 100644 --- a/lib/hooks/usePrevNextPagination.js +++ b/lib/hooks/usePrevNextPagination.js @@ -17,7 +17,8 @@ const usePrevNextPagination = ({ defaultToPageOne = true, // A prop to allow the implementor to turn off the defaulting to page=1 pageSize = DEFAULT_PAGINATION_SIZE, // Only needed for reading back MCL props id = DEFAULT_PAGE_KEY, // This id is ONLY used for syncToLocation: false cases, as a key to the zustand store - syncToLocation = true // Used to turn on/off location syncing, so can be used as standalone state if required + syncToLocation = true, // Used to turn on/off location syncing, so can be used as standalone state if required, + pageCount = 0 } = {}) => { /* ------ ZUSTAND STORE ------ */ // For NON-SYNC-TO-LOCATION use cases, store the currentPage in a keyed store @@ -146,7 +147,7 @@ const usePrevNextPagination = ({ ]); // Set up MCL specific props based on page - const pagingCanGoNext = currentPage && currentPage < Number(count) / pageSize; + const pagingCanGoNext = currentPage && (currentPage < Number(count) / pageSize || pageCount === pageSize); const pagingCanGoPrevious = currentPage && Number(currentPage) > 1; const pagingOffset = currentPage ? (currentPage - 1) * pageSize : 0; const onNeedMoreData = (...args) => { From 078d8a9b5ec0ad4f79a7ce9423b0f57888d6052e Mon Sep 17 00:00:00 2001 From: Claudia Malzer Date: Wed, 8 May 2024 21:23:52 +0200 Subject: [PATCH 2/9] ERM-3220 Update pagination mechanisms for MCLs to work without stats * create new hook for fetch with no stats * add hasNextPage prop to usePrevNextPagination --- lib/hooks/index.js | 1 + lib/hooks/useFetchWithNoStats.js | 54 ++++++++++++++++++++++++++++++ lib/hooks/usePrevNextPagination.js | 4 +-- 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 lib/hooks/useFetchWithNoStats.js diff --git a/lib/hooks/index.js b/lib/hooks/index.js index de52ae13..2795a6d2 100644 --- a/lib/hooks/index.js +++ b/lib/hooks/index.js @@ -11,6 +11,7 @@ export { default as useInterfaceCredentials } from './useInterfaceCredentials'; export { default as useSingleFetchInterfaceCredentials } from './useSingleFetchInterfaceCredentials'; export { default as useChunkedCQLFetch } from './useChunkedCQLFetch'; export { default as useChunkedUsers } from './useChunkedUsers'; +export { default as useFetchWithNoStats } from './useFetchWithNoStats'; export { default as useParallelBatchFetch } from './useParallelBatchFetch'; export { default as usePrevNextPagination } from './usePrevNextPagination'; export { default as usePrevious } from './usePrevious'; diff --git a/lib/hooks/useFetchWithNoStats.js b/lib/hooks/useFetchWithNoStats.js new file mode 100644 index 00000000..463ab1c4 --- /dev/null +++ b/lib/hooks/useFetchWithNoStats.js @@ -0,0 +1,54 @@ +import { useMemo } from 'react'; +import { useQueries } from 'react-query'; +import { useOkapiKy } from '@folio/stripes/core'; +import { generateKiwtQueryParams } from '@k-int/stripes-kint-components'; + +const usePrevNextPagination = ({ + id, // for future use / local zustand store + params = {}, + path = '', + keyArray = [], +} = {}) => { + const ky = useOkapiKy(); + const queryArray = []; + const currentPageParams = useMemo(() => ( + generateKiwtQueryParams( + { ...params, stats: false }, + {} + ) + ), [params]); + const currentPageParamsSpread = [...currentPageParams]; + queryArray.push({ + queryKey: [ + path, + currentPageParams, + ...keyArray + ], + queryFn: () => ky.get(`${path}?${currentPageParamsSpread?.join('&')}`).json(), + }); + + const nextPageParams = useMemo(() => ( + generateKiwtQueryParams( + { ...params, page: params.page + 1, stats: false }, + {} + ) + ), [params]); + const nextPageParamsSpread = [...nextPageParams]; + queryArray.push({ + queryKey: [ + path, + nextPageParams, + ...keyArray + ], + queryFn: () => ky.get(`${path}?${nextPageParamsSpread?.join('&')}`).json(), + }); + + const queries = useQueries(queryArray); + + return ({ + currentPage: queries[0], + nextPage: queries[1], + }); +}; + +export default usePrevNextPagination; diff --git a/lib/hooks/usePrevNextPagination.js b/lib/hooks/usePrevNextPagination.js index e7f2b704..6d5ea4d7 100644 --- a/lib/hooks/usePrevNextPagination.js +++ b/lib/hooks/usePrevNextPagination.js @@ -18,7 +18,7 @@ const usePrevNextPagination = ({ pageSize = DEFAULT_PAGINATION_SIZE, // Only needed for reading back MCL props id = DEFAULT_PAGE_KEY, // This id is ONLY used for syncToLocation: false cases, as a key to the zustand store syncToLocation = true, // Used to turn on/off location syncing, so can be used as standalone state if required, - pageCount = 0 + hasNextPage = false } = {}) => { /* ------ ZUSTAND STORE ------ */ // For NON-SYNC-TO-LOCATION use cases, store the currentPage in a keyed store @@ -147,7 +147,7 @@ const usePrevNextPagination = ({ ]); // Set up MCL specific props based on page - const pagingCanGoNext = currentPage && (currentPage < Number(count) / pageSize || pageCount === pageSize); + const pagingCanGoNext = currentPage && (currentPage < Number(count) / pageSize || hasNextPage); const pagingCanGoPrevious = currentPage && Number(currentPage) > 1; const pagingOffset = currentPage ? (currentPage - 1) * pageSize : 0; const onNeedMoreData = (...args) => { From 47d5c718fe8284398f23d3ca3896b58fef2b42b8 Mon Sep 17 00:00:00 2001 From: Claudia Malzer Date: Wed, 8 May 2024 21:25:49 +0200 Subject: [PATCH 3/9] ERM-3220 Update pagination mechanisms for MCLs to work without stats * create new hook for fetch with no stats * add hasNextPage prop to usePrevNextPagination --- lib/hooks/useFetchWithNoStats.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/hooks/useFetchWithNoStats.js b/lib/hooks/useFetchWithNoStats.js index 463ab1c4..ddc7d017 100644 --- a/lib/hooks/useFetchWithNoStats.js +++ b/lib/hooks/useFetchWithNoStats.js @@ -3,7 +3,7 @@ import { useQueries } from 'react-query'; import { useOkapiKy } from '@folio/stripes/core'; import { generateKiwtQueryParams } from '@k-int/stripes-kint-components'; -const usePrevNextPagination = ({ +const useFetchWithNoStats = ({ id, // for future use / local zustand store params = {}, path = '', @@ -51,4 +51,4 @@ const usePrevNextPagination = ({ }); }; -export default usePrevNextPagination; +export default useFetchWithNoStats; From f480712223f0bafbeb051a0f167c8fa7301ca8b8 Mon Sep 17 00:00:00 2001 From: Jack Golding Date: Mon, 13 May 2024 10:57:17 +0100 Subject: [PATCH 4/9] refactor: Changed hasNextPage functionality Now the hasNextPage overwrites the canGoNext calculation if it is provided --- lib/hooks/usePrevNextPagination.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/hooks/usePrevNextPagination.js b/lib/hooks/usePrevNextPagination.js index 6d5ea4d7..cd8cea0b 100644 --- a/lib/hooks/usePrevNextPagination.js +++ b/lib/hooks/usePrevNextPagination.js @@ -12,13 +12,16 @@ import { import useLocalPageStore from './useLocalPageStore'; +// Currently there are several places in which this hook is used twice within the same component +// Once in order to get the current page, and again in order to handle changes to paginations +// This hook should be refactored in order to resolve these issue - @EthanFreestone const usePrevNextPagination = ({ count = 0, // Only needed for reading back MCL props defaultToPageOne = true, // A prop to allow the implementor to turn off the defaulting to page=1 pageSize = DEFAULT_PAGINATION_SIZE, // Only needed for reading back MCL props id = DEFAULT_PAGE_KEY, // This id is ONLY used for syncToLocation: false cases, as a key to the zustand store syncToLocation = true, // Used to turn on/off location syncing, so can be used as standalone state if required, - hasNextPage = false + hasNextPage = null // Override for canGoNext, used in the case in which resources are fetched with no stats } = {}) => { /* ------ ZUSTAND STORE ------ */ // For NON-SYNC-TO-LOCATION use cases, store the currentPage in a keyed store @@ -147,7 +150,7 @@ const usePrevNextPagination = ({ ]); // Set up MCL specific props based on page - const pagingCanGoNext = currentPage && (currentPage < Number(count) / pageSize || hasNextPage); + const pagingCanGoNext = hasNextPage ?? (currentPage && (currentPage < Number(count) / pageSize)); const pagingCanGoPrevious = currentPage && Number(currentPage) > 1; const pagingOffset = currentPage ? (currentPage - 1) * pageSize : 0; const onNeedMoreData = (...args) => { From 550eb93eaf630fff2b3259c7c1ada81a171a576f Mon Sep 17 00:00:00 2001 From: Jack Golding Date: Mon, 13 May 2024 11:42:14 +0100 Subject: [PATCH 5/9] refactor: Spread params tidy up --- lib/hooks/useFetchWithNoStats.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/hooks/useFetchWithNoStats.js b/lib/hooks/useFetchWithNoStats.js index ddc7d017..90c2278a 100644 --- a/lib/hooks/useFetchWithNoStats.js +++ b/lib/hooks/useFetchWithNoStats.js @@ -5,7 +5,7 @@ import { generateKiwtQueryParams } from '@k-int/stripes-kint-components'; const useFetchWithNoStats = ({ id, // for future use / local zustand store - params = {}, + params, // Need an initial value for page as to not cause issues when generating params path = '', keyArray = [], } = {}) => { @@ -17,14 +17,13 @@ const useFetchWithNoStats = ({ {} ) ), [params]); - const currentPageParamsSpread = [...currentPageParams]; queryArray.push({ queryKey: [ path, - currentPageParams, + ...currentPageParams, ...keyArray ], - queryFn: () => ky.get(`${path}?${currentPageParamsSpread?.join('&')}`).json(), + queryFn: () => ky.get(`${path}?${currentPageParams?.join('&')}`).json(), }); const nextPageParams = useMemo(() => ( @@ -33,14 +32,13 @@ const useFetchWithNoStats = ({ {} ) ), [params]); - const nextPageParamsSpread = [...nextPageParams]; queryArray.push({ queryKey: [ path, - nextPageParams, + ...nextPageParams, ...keyArray ], - queryFn: () => ky.get(`${path}?${nextPageParamsSpread?.join('&')}`).json(), + queryFn: () => ky.get(`${path}?${nextPageParams?.join('&')}`).json(), }); const queries = useQueries(queryArray); From 48d4dbca6946214314e067b252041350ccd1f8be Mon Sep 17 00:00:00 2001 From: Claudia Malzer Date: Mon, 13 May 2024 16:35:57 +0200 Subject: [PATCH 6/9] ERM-3220 Update pagination mechanisms for MCLs to work without stats * rename hook * set defaukt page --- lib/hooks/index.js | 2 +- ...thNoStats.js => useFetchCurrentAndNext.js} | 22 ++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) rename lib/hooks/{useFetchWithNoStats.js => useFetchCurrentAndNext.js} (66%) diff --git a/lib/hooks/index.js b/lib/hooks/index.js index 2795a6d2..8a18117f 100644 --- a/lib/hooks/index.js +++ b/lib/hooks/index.js @@ -11,7 +11,7 @@ export { default as useInterfaceCredentials } from './useInterfaceCredentials'; export { default as useSingleFetchInterfaceCredentials } from './useSingleFetchInterfaceCredentials'; export { default as useChunkedCQLFetch } from './useChunkedCQLFetch'; export { default as useChunkedUsers } from './useChunkedUsers'; -export { default as useFetchWithNoStats } from './useFetchWithNoStats'; +export { default as useFetchCurrentAndNext } from './useFetchCurrentAndNext'; export { default as useParallelBatchFetch } from './useParallelBatchFetch'; export { default as usePrevNextPagination } from './usePrevNextPagination'; export { default as usePrevious } from './usePrevious'; diff --git a/lib/hooks/useFetchWithNoStats.js b/lib/hooks/useFetchCurrentAndNext.js similarity index 66% rename from lib/hooks/useFetchWithNoStats.js rename to lib/hooks/useFetchCurrentAndNext.js index 90c2278a..5e6ac913 100644 --- a/lib/hooks/useFetchWithNoStats.js +++ b/lib/hooks/useFetchCurrentAndNext.js @@ -3,20 +3,26 @@ import { useQueries } from 'react-query'; import { useOkapiKy } from '@folio/stripes/core'; import { generateKiwtQueryParams } from '@k-int/stripes-kint-components'; -const useFetchWithNoStats = ({ - id, // for future use / local zustand store - params, // Need an initial value for page as to not cause issues when generating params +const defaultParams = { page: 1 }; + +const useFetchCurrentAndNext = ({ + // id, // for future use / local zustand store + params = {}, path = '', keyArray = [], } = {}) => { const ky = useOkapiKy(); const queryArray = []; + + // Apply defaultParams ensuring that 'page' is defaulted properly + const effectiveParams = useMemo(() => ({ ...defaultParams, ...params }), [params]); + const currentPageParams = useMemo(() => ( generateKiwtQueryParams( - { ...params, stats: false }, + { ...effectiveParams }, {} ) - ), [params]); + ), [effectiveParams]); queryArray.push({ queryKey: [ path, @@ -28,10 +34,10 @@ const useFetchWithNoStats = ({ const nextPageParams = useMemo(() => ( generateKiwtQueryParams( - { ...params, page: params.page + 1, stats: false }, + { ...effectiveParams, page: effectiveParams.page + 1 }, {} ) - ), [params]); + ), [effectiveParams]); queryArray.push({ queryKey: [ path, @@ -49,4 +55,4 @@ const useFetchWithNoStats = ({ }); }; -export default useFetchWithNoStats; +export default useFetchCurrentAndNext; From a2f788e617ce49cba3565e664b883e84e9e89f38 Mon Sep 17 00:00:00 2001 From: Claudia Malzer Date: Tue, 14 May 2024 11:22:04 +0200 Subject: [PATCH 7/9] ERM-3220 Update pagination mechanisms for MCLs to work without stats * remove comments * add resetPageStore function --- lib/hooks/index.js | 1 + lib/hooks/useFetchCurrentAndNext.js | 1 - lib/hooks/useLocalPageStore.js | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/hooks/index.js b/lib/hooks/index.js index 8a18117f..e21d6a18 100644 --- a/lib/hooks/index.js +++ b/lib/hooks/index.js @@ -12,6 +12,7 @@ export { default as useSingleFetchInterfaceCredentials } from './useSingleFetchI export { default as useChunkedCQLFetch } from './useChunkedCQLFetch'; export { default as useChunkedUsers } from './useChunkedUsers'; export { default as useFetchCurrentAndNext } from './useFetchCurrentAndNext'; +export { default as useLocalPageStore } from './useLocalPageStore'; export { default as useParallelBatchFetch } from './useParallelBatchFetch'; export { default as usePrevNextPagination } from './usePrevNextPagination'; export { default as usePrevious } from './usePrevious'; diff --git a/lib/hooks/useFetchCurrentAndNext.js b/lib/hooks/useFetchCurrentAndNext.js index 5e6ac913..7d21b769 100644 --- a/lib/hooks/useFetchCurrentAndNext.js +++ b/lib/hooks/useFetchCurrentAndNext.js @@ -6,7 +6,6 @@ import { generateKiwtQueryParams } from '@k-int/stripes-kint-components'; const defaultParams = { page: 1 }; const useFetchCurrentAndNext = ({ - // id, // for future use / local zustand store params = {}, path = '', keyArray = [], diff --git a/lib/hooks/useLocalPageStore.js b/lib/hooks/useLocalPageStore.js index 8a2c3bc4..58896985 100644 --- a/lib/hooks/useLocalPageStore.js +++ b/lib/hooks/useLocalPageStore.js @@ -12,6 +12,7 @@ const useLocalPageStore = create( return { ...state, pageStore: { ...state.pageStore, [key]: page } }; }), + resetPageStore: () => set({ pageStore: {} }), }), ); From 4d22ea0ce1af61e1bfae6199b42389ea32f01f04 Mon Sep 17 00:00:00 2001 From: Claudia Malzer Date: Wed, 15 May 2024 15:11:28 +0200 Subject: [PATCH 8/9] ERM-3220 Update pagination mechanisms for MCLs to work without stats * remove resetPageStore function --- lib/hooks/index.js | 1 - lib/hooks/useLocalPageStore.js | 1 - 2 files changed, 2 deletions(-) diff --git a/lib/hooks/index.js b/lib/hooks/index.js index e21d6a18..8a18117f 100644 --- a/lib/hooks/index.js +++ b/lib/hooks/index.js @@ -12,7 +12,6 @@ export { default as useSingleFetchInterfaceCredentials } from './useSingleFetchI export { default as useChunkedCQLFetch } from './useChunkedCQLFetch'; export { default as useChunkedUsers } from './useChunkedUsers'; export { default as useFetchCurrentAndNext } from './useFetchCurrentAndNext'; -export { default as useLocalPageStore } from './useLocalPageStore'; export { default as useParallelBatchFetch } from './useParallelBatchFetch'; export { default as usePrevNextPagination } from './usePrevNextPagination'; export { default as usePrevious } from './usePrevious'; diff --git a/lib/hooks/useLocalPageStore.js b/lib/hooks/useLocalPageStore.js index 58896985..8a2c3bc4 100644 --- a/lib/hooks/useLocalPageStore.js +++ b/lib/hooks/useLocalPageStore.js @@ -12,7 +12,6 @@ const useLocalPageStore = create( return { ...state, pageStore: { ...state.pageStore, [key]: page } }; }), - resetPageStore: () => set({ pageStore: {} }), }), ); From 84d87035db4e569eef79827877c1a8eb9d9dc3d3 Mon Sep 17 00:00:00 2001 From: Ethan Freestone Date: Fri, 17 May 2024 16:33:43 +0100 Subject: [PATCH 9/9] feat: useFetchMultiplePages Renamed hook to "useFetchMultiplePages", so it will be primed for any future logic to expand past just two pages. For now it will make use of the page passed in the params object Also changed out keyArray for getQueryKey which allows finer control over the queryKey for the implementing code refs ERM-3220 --- lib/hooks/index.js | 2 +- ...entAndNext.js => useFetchMultiplePages.js} | 33 ++++++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) rename lib/hooks/{useFetchCurrentAndNext.js => useFetchMultiplePages.js} (54%) diff --git a/lib/hooks/index.js b/lib/hooks/index.js index 8a18117f..b8fb65aa 100644 --- a/lib/hooks/index.js +++ b/lib/hooks/index.js @@ -11,7 +11,7 @@ export { default as useInterfaceCredentials } from './useInterfaceCredentials'; export { default as useSingleFetchInterfaceCredentials } from './useSingleFetchInterfaceCredentials'; export { default as useChunkedCQLFetch } from './useChunkedCQLFetch'; export { default as useChunkedUsers } from './useChunkedUsers'; -export { default as useFetchCurrentAndNext } from './useFetchCurrentAndNext'; +export { default as useFetchMultiplePages } from './useFetchMultiplePages'; export { default as useParallelBatchFetch } from './useParallelBatchFetch'; export { default as usePrevNextPagination } from './usePrevNextPagination'; export { default as usePrevious } from './usePrevious'; diff --git a/lib/hooks/useFetchCurrentAndNext.js b/lib/hooks/useFetchMultiplePages.js similarity index 54% rename from lib/hooks/useFetchCurrentAndNext.js rename to lib/hooks/useFetchMultiplePages.js index 7d21b769..aadc3c01 100644 --- a/lib/hooks/useFetchCurrentAndNext.js +++ b/lib/hooks/useFetchMultiplePages.js @@ -5,10 +5,11 @@ import { generateKiwtQueryParams } from '@k-int/stripes-kint-components'; const defaultParams = { page: 1 }; -const useFetchCurrentAndNext = ({ - params = {}, +const useFetchMultiplePages = ({ + getQueryKey = ({ params, pathStr, pageNum }) => [pathStr, pageNum, params], + params = {}, // Accepts an object of the shape expected by the first parameter of generateKiwtQueryParams path = '', - keyArray = [], + // At some point in the future I'd like this to be able to accept a list of pages, and run those all in parallel (possibly with some chunking logic) } = {}) => { const ky = useOkapiKy(); const queryArray = []; @@ -23,11 +24,11 @@ const useFetchCurrentAndNext = ({ ) ), [effectiveParams]); queryArray.push({ - queryKey: [ - path, - ...currentPageParams, - ...keyArray - ], + queryKey: getQueryKey({ + params: currentPageParams, + pageNum: effectiveParams.page, + pathStr: path + }), queryFn: () => ky.get(`${path}?${currentPageParams?.join('&')}`).json(), }); @@ -38,20 +39,20 @@ const useFetchCurrentAndNext = ({ ) ), [effectiveParams]); queryArray.push({ - queryKey: [ - path, - ...nextPageParams, - ...keyArray - ], + queryKey: getQueryKey({ + params: nextPageParams, + pageNum: effectiveParams.page + 1, + pathStr: path + }), queryFn: () => ky.get(`${path}?${nextPageParams?.join('&')}`).json(), }); const queries = useQueries(queryArray); return ({ - currentPage: queries[0], - nextPage: queries[1], + [effectiveParams.page]: queries[0], + [effectiveParams.page + 1]: queries[1], // For now this is just "current" and "next", but longer term this could be expanded to n pages from a list for prefetching etc }); }; -export default useFetchCurrentAndNext; +export default useFetchMultiplePages;