/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. * * OpenCRVS is also distributed under the terms of the Civil Registration * & Healthcare Disclaimer located at http://opencrvs.org/license. * * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. */ import * as React from 'react' import styled from 'styled-components' import { Button } from '../Button' import { Icon } from '../Icon' export type IPaginationVariant = 'small' | 'large' // small for desktop and large for mobile export interface IPaginationProps { currentPage: number totalPages: number onPageChange: (page: number) => void siblingCount?: number } const PaginationWrapper = styled.div` display: flex; align-items: center; ` const DesktopWrapper = styled.div` display: flex; float: left; @media only screen and (max-width: 1023px) { display: none; } ` const MobileWrapper = styled.div` display: none; @media only screen and (max-width: 1023px) { display: inline-flex; align-items: center; margin-left: auto; margin-right: auto; } ` const PaginationContainer = styled.div` height: 40px; padding: 8px; display: flex; align-items: center; justify-content: center; ` const StyledPagination = styled.div` display: flex; flex-direction: row; align-items: center; gap: 2px; ` const PageNumberButton = styled(Button)` height: 24px; ` const DotsButton = styled(Button)` height: 24px; ` const StyledPageNumber = styled.span<{ isCurrentPage: boolean; size?: string }>` ${({ theme, size }) => size && size === 'large' ? theme.fonts.h4 : theme.fonts.bold12}; color: ${({ theme, isCurrentPage }) => isCurrentPage ? theme.colors.grey600 : theme.colors.grey400}; ` export const Pagination = ({ totalPages, currentPage, onPageChange }: IPaginationProps) => { const handleCurrentPage = () => totalPages > 0 ? (currentPage && currentPage > 0 ? currentPage : 1) : 0 const pageRange = (start: number, end: number) => { const length = end - start + 1 return Array.from({ length }, (_, idx) => idx + start) } const paginationRow = ( currentPage: number, totalPages: number, siblingCount: number ) => { if (totalPages <= 6) { return pageRange(1, totalPages) } const DOTs = '...' const leftRangeIndex = Math.max(currentPage - siblingCount, 1) const rightRangeIndex = Math.min(currentPage + siblingCount, totalPages) const showLeftDots = leftRangeIndex > 3 const showRightDots = rightRangeIndex < totalPages - 2 if (showLeftDots && showRightDots) { const middleRange = pageRange(leftRangeIndex, rightRangeIndex) return [1, DOTs, ...middleRange, DOTs, totalPages] } else if (showLeftDots && !showRightDots) { const rightItemsCount = 3 + 2 * siblingCount const rightRange = pageRange(totalPages - rightItemsCount + 1, totalPages) return [1, DOTs, ...rightRange] } else if (!showLeftDots && showRightDots) { const leftItemsCount = 3 + 2 * siblingCount const leftRange = pageRange(1, leftItemsCount) return [...leftRange, DOTs, totalPages] } return pageRange(1, totalPages) } const currentPageValue = handleCurrentPage() const canGoToPreviousPage = currentPageValue > 1 const canGoToNextPage = currentPageValue + 1 <= totalPages const changePage = (page: number | string) => { if (typeof page === 'number') { onPageChange(page) } } const renderPages = (size: IPaginationVariant) => { const currentPage = handleCurrentPage() if (currentPage > totalPages) { changePage(totalPages) } const pages = paginationRow(currentPage, totalPages, 1) return ( {pages.map((page, id) => { if (page === '...') { return ( {page} ) } return ( changePage(page)} > {page} ) })} ) } return ( {renderPages('small')} {renderPages('large')} ) }