diff --git a/src/app/components/PaginationToolbar.js b/src/app/components/PaginationToolbar.js index 61f874e..97ffd5b 100644 --- a/src/app/components/PaginationToolbar.js +++ b/src/app/components/PaginationToolbar.js @@ -9,54 +9,29 @@ function PaginationToolbar({ numPerPage = 30, ...props }) { - const { query, push: pushHistory } = useRouter(); + const { + numTotalPages, + currentPageNumber, + goToPageNumber, + buildPageUrl, + } = useRouterPagination(totalCount, numPerPage); - const currentOffset = parseInt(query.offset) || 0; + const pagesAreLoaded = currentPageNumber != null && numTotalPages != null; + const hasPrevPage = pagesAreLoaded && currentPageNumber > 1; + const hasNextPage = pagesAreLoaded && currentPageNumber < numTotalPages; - const currentPageIndex = Math.floor(currentOffset / numPerPage); - const currentPageNumber = currentPageIndex + 1; - const numTotalPages = totalCount ? Math.ceil(totalCount / numPerPage) : null; - - const prevPageSearchParams = new URLSearchParams(query); - const prevPageOffset = currentOffset - numPerPage; - prevPageSearchParams.set("offset", prevPageOffset); - const prevPageUrl = "?" + prevPageSearchParams.toString(); - - const nextPageSearchParams = new URLSearchParams(query); - const nextPageOffset = currentOffset + numPerPage; - nextPageSearchParams.set("offset", nextPageOffset); - const nextPageUrl = "?" + nextPageSearchParams.toString(); - - // We disable the buttons if we don't know how many total items there are, - // and therefore don't know how far navigation can go. We'll additionally - // show a loading spinner if `isLoading` is true. (But it's possible the - // buttons might be enabled, even if `isLoading` is true, because maybe - // something _else_ is loading. `isLoading` is designed to tell us whether - // waiting _might_ give us the data we need!) - const prevPageIsDisabled = totalCount == null || prevPageOffset < 0; - const nextPageIsDisabled = totalCount == null || nextPageOffset >= totalCount; - - const goToPageNumber = React.useCallback( - (newPageNumber) => { - const newPageIndex = newPageNumber - 1; - const newPageOffset = newPageIndex * numPerPage; - - const newPageSearchParams = new URLSearchParams(query); - newPageSearchParams.set("offset", newPageOffset); - pushHistory("?" + newPageSearchParams.toString()); - }, - [query, pushHistory, numPerPage] - ); + const prevPageUrl = hasPrevPage ? buildPageUrl(currentPageNumber - 1) : null; + const nextPageUrl = hasNextPage ? buildPageUrl(currentPageNumber + 1) : null; return ( ← Prev @@ -75,12 +50,12 @@ function PaginationToolbar({ )} Next → @@ -88,6 +63,41 @@ function PaginationToolbar({ ); } +function useRouterPagination(totalCount, numPerPage) { + const { query, push: pushHistory } = useRouter(); + + const currentOffset = parseInt(query.offset) || 0; + + const currentPageIndex = Math.floor(currentOffset / numPerPage); + const currentPageNumber = currentPageIndex + 1; + const numTotalPages = totalCount ? Math.ceil(totalCount / numPerPage) : null; + + const buildPageUrl = React.useCallback( + (newPageNumber) => { + const newParams = new URLSearchParams(query); + const newPageIndex = newPageNumber - 1; + const newOffset = newPageIndex * numPerPage; + newParams.set("offset", newOffset); + return "?" + newParams.toString(); + }, + [query, numPerPage] + ); + + const goToPageNumber = React.useCallback( + (newPageNumber) => { + pushHistory(buildPageUrl(newPageNumber)); + }, + [buildPageUrl, pushHistory] + ); + + return { + numTotalPages, + currentPageNumber, + goToPageNumber, + buildPageUrl, + }; +} + function LinkOrButton({ href, ...props }) { if (href != null) { return (