feat(pagination): implement windowed pagination for improved navigation
- Introduced windowed pagination logic in the TendersTable component to enhance user experience by allowing for a more manageable view of pages. - Updated the pagination component to accept new props for page range and margin pages, enabling customizable pagination display. - Refactored the useTenderListPresenter to utilize the new windowed pagination functionality, improving clarity and maintainability of pagination handling.
This commit is contained in:
@@ -42,6 +42,7 @@ const TendersTable = () => {
|
|||||||
navigateToTenderDetails,
|
navigateToTenderDetails,
|
||||||
navigateToTenderFeedback,
|
navigateToTenderFeedback,
|
||||||
handlePaginationChange,
|
handlePaginationChange,
|
||||||
|
buildWindowedPageLabel,
|
||||||
getRowNumber,
|
getRowNumber,
|
||||||
formatDateTimeCell,
|
formatDateTimeCell,
|
||||||
pagination,
|
pagination,
|
||||||
@@ -157,6 +158,9 @@ const TendersTable = () => {
|
|||||||
currentPage={pagination.currentPage}
|
currentPage={pagination.currentPage}
|
||||||
totalPages={pagination.totalPages}
|
totalPages={pagination.totalPages}
|
||||||
onPageChange={handlePaginationChange}
|
onPageChange={handlePaginationChange}
|
||||||
|
pageRangeDisplayed={3}
|
||||||
|
marginPagesDisplayed={1}
|
||||||
|
pageLabelBuilder={buildWindowedPageLabel}
|
||||||
/>
|
/>
|
||||||
</IsVisible>
|
</IsVisible>
|
||||||
</ListWrapper>
|
</ListWrapper>
|
||||||
|
|||||||
@@ -346,6 +346,42 @@ const useTenderListPresenter = () => {
|
|||||||
error,
|
error,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const MAX_PAGE_JUMP = 10;
|
||||||
|
const paginationWindow = useMemo(() => {
|
||||||
|
const windowStart = Math.max(0, pagination.currentPage - MAX_PAGE_JUMP);
|
||||||
|
const windowEnd = Math.min(
|
||||||
|
Math.max(pagination.totalPages - 1, 0),
|
||||||
|
pagination.currentPage + MAX_PAGE_JUMP,
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
windowStart,
|
||||||
|
virtualCurrent: pagination.currentPage - windowStart,
|
||||||
|
virtualTotal: Math.max(windowEnd - windowStart + 1, 1),
|
||||||
|
};
|
||||||
|
}, [pagination.currentPage, pagination.totalPages]);
|
||||||
|
|
||||||
|
const handleWindowedPaginationChange = useCallback(
|
||||||
|
(e: { selected: number }) => {
|
||||||
|
handlePaginationChange({
|
||||||
|
selected: e.selected + paginationWindow.windowStart,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[handlePaginationChange, paginationWindow.windowStart],
|
||||||
|
);
|
||||||
|
|
||||||
|
const buildWindowedPageLabel = useCallback(
|
||||||
|
(virtualPage: number) => String(virtualPage + paginationWindow.windowStart),
|
||||||
|
[paginationWindow.windowStart],
|
||||||
|
);
|
||||||
|
|
||||||
|
const windowedPagination = useMemo(
|
||||||
|
() => ({
|
||||||
|
currentPage: paginationWindow.virtualCurrent,
|
||||||
|
totalPages: paginationWindow.virtualTotal,
|
||||||
|
}),
|
||||||
|
[paginationWindow.virtualCurrent, paginationWindow.virtualTotal],
|
||||||
|
);
|
||||||
|
|
||||||
const shouldShowPagination =
|
const shouldShowPagination =
|
||||||
!isPending && (data?.meta?.pages ?? 1) * (data?.meta?.limit ?? 10) > 10;
|
!isPending && (data?.meta?.pages ?? 1) * (data?.meta?.limit ?? 10) > 10;
|
||||||
|
|
||||||
@@ -498,10 +534,11 @@ const useTenderListPresenter = () => {
|
|||||||
tendersList,
|
tendersList,
|
||||||
navigateToTenderDetails,
|
navigateToTenderDetails,
|
||||||
navigateToTenderFeedback,
|
navigateToTenderFeedback,
|
||||||
handlePaginationChange,
|
handlePaginationChange: handleWindowedPaginationChange,
|
||||||
|
buildWindowedPageLabel,
|
||||||
getRowNumber,
|
getRowNumber,
|
||||||
formatDateTimeCell,
|
formatDateTimeCell,
|
||||||
pagination,
|
pagination: windowedPagination,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,23 @@ interface IProps {
|
|||||||
currentPage: number;
|
currentPage: number;
|
||||||
totalPages: number;
|
totalPages: number;
|
||||||
onPageChange: ReactPaginateProps["onPageChange"];
|
onPageChange: ReactPaginateProps["onPageChange"];
|
||||||
|
pageRangeDisplayed?: number;
|
||||||
|
marginPagesDisplayed?: number;
|
||||||
|
pageLabelBuilder?: ReactPaginateProps["pageLabelBuilder"];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Full-cell hit target: styles live on <li>, but react-paginate puts clicks on the inner <a>. */
|
/** Full-cell hit target: styles live on <li>, but react-paginate puts clicks on the inner <a>. */
|
||||||
const pageLinkClassName =
|
const pageLinkClassName =
|
||||||
"absolute inset-0 z-[1] flex cursor-pointer items-center justify-center select-none";
|
"absolute inset-0 z-[1] flex cursor-pointer items-center justify-center select-none";
|
||||||
|
|
||||||
const Pagination: FC<IProps> = ({ totalPages, currentPage, onPageChange }) => {
|
const Pagination: FC<IProps> = ({
|
||||||
|
totalPages,
|
||||||
|
currentPage,
|
||||||
|
onPageChange,
|
||||||
|
pageRangeDisplayed = 5,
|
||||||
|
marginPagesDisplayed = 3,
|
||||||
|
pageLabelBuilder,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<ReactPaginate
|
<ReactPaginate
|
||||||
@@ -19,7 +29,9 @@ const Pagination: FC<IProps> = ({ totalPages, currentPage, onPageChange }) => {
|
|||||||
forcePage={currentPage}
|
forcePage={currentPage}
|
||||||
nextLabel="›"
|
nextLabel="›"
|
||||||
previousLabel="‹"
|
previousLabel="‹"
|
||||||
pageRangeDisplayed={5}
|
pageRangeDisplayed={pageRangeDisplayed}
|
||||||
|
marginPagesDisplayed={marginPagesDisplayed}
|
||||||
|
pageLabelBuilder={pageLabelBuilder}
|
||||||
activeClassName="flex h-9 min-w-9 items-center justify-center rounded-xl border border-white/35 bg-gradient-to-br from-primary/85 via-primary/75 to-primary/65 px-3 text-sm font-semibold !text-white shadow-theme-xs shadow-primary/20 backdrop-blur-md transition-all duration-300 before:pointer-events-none before:absolute before:inset-x-0 before:top-0 before:h-1/2 before:rounded-t-xl before:bg-gradient-to-b before:from-white/30 before:to-transparent dark:border-white/20 dark:before:from-white/20"
|
activeClassName="flex h-9 min-w-9 items-center justify-center rounded-xl border border-white/35 bg-gradient-to-br from-primary/85 via-primary/75 to-primary/65 px-3 text-sm font-semibold !text-white shadow-theme-xs shadow-primary/20 backdrop-blur-md transition-all duration-300 before:pointer-events-none before:absolute before:inset-x-0 before:top-0 before:h-1/2 before:rounded-t-xl before:bg-gradient-to-b before:from-white/30 before:to-transparent dark:border-white/20 dark:before:from-white/20"
|
||||||
onPageChange={(e) => {
|
onPageChange={(e) => {
|
||||||
if (!onPageChange) return;
|
if (!onPageChange) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user