import React, { useEffect, useMemo, useRef, useState } from "react"; import { Button, ButtonGroup, Dropdown, Form, InputGroup, Overlay, Popover, } from "react-bootstrap"; import { FormattedMessage, FormattedNumber, useIntl } from "react-intl"; import useFocus from "src/utils/focus"; import { Icon } from "../Shared/Icon"; import { faCheck, faChevronDown } from "@fortawesome/free-solid-svg-icons"; import { useStopWheelScroll } from "src/utils/form"; const PageCount: React.FC<{ totalPages: number; currentPage: number; onChangePage: (page: number) => void; }> = ({ totalPages, currentPage, onChangePage }) => { const intl = useIntl(); const currentPageCtrl = useRef(null); const [pageInput, pageFocus] = useFocus(); const [showSelectPage, setShowSelectPage] = useState(false); useEffect(() => { if (showSelectPage) { // delaying the focus to the next execution loop so that rendering takes place first and stops the page from resetting. setTimeout(() => { pageFocus(); }, 0); } }, [showSelectPage, pageFocus]); useStopWheelScroll(pageInput); const pageOptions = useMemo(() => { const maxPagesToShow = 10; const min = Math.max(1, currentPage - maxPagesToShow / 2); const max = Math.min(min + maxPagesToShow, totalPages); const pages = []; for (let i = min; i <= max; i++) { pages.push(i); } return pages; }, [totalPages, currentPage]); function onCustomChangePage() { const newPage = Number.parseInt(pageInput.current?.value ?? "0"); if (newPage) { onChangePage(newPage); } setShowSelectPage(false); } return (
{pageOptions.map((s) => ( onChangePage(s)} > {s} ))} setShowSelectPage(false)} >
{/* can't use NumberField because of the ref */} ) => { if (e.key === "Enter") { onCustomChangePage(); e.preventDefault(); } }} onFocus={(e: React.FocusEvent) => e.target.select() } />
); }; interface IPaginationProps { itemsPerPage: number; currentPage: number; totalItems: number; metadataByline?: React.ReactNode; onChangePage: (page: number) => void; } interface IPaginationIndexProps { itemsPerPage: number; currentPage: number; totalItems: number; metadataByline?: React.ReactNode; } const minPagesForCompact = 4; export const Pagination: React.FC = ({ itemsPerPage, currentPage, totalItems, onChangePage, }) => { const intl = useIntl(); const totalPages = useMemo( () => Math.ceil(totalItems / itemsPerPage), [totalItems, itemsPerPage] ); const pageButtons = useMemo(() => { if (totalPages >= minPagesForCompact) return ( ); const pages = [...Array(totalPages).keys()].map((i) => i + 1); return pages.map((page: number) => ( )); }, [totalPages, currentPage, onChangePage]); if (totalPages <= 1) return
; return ( {pageButtons} ); }; export const PaginationIndex: React.FC = ({ itemsPerPage, currentPage, totalItems, metadataByline, }) => { const intl = useIntl(); // Build the pagination index string const firstItemCount: number = Math.min( (currentPage - 1) * itemsPerPage + 1, totalItems ); const lastItemCount: number = Math.min( firstItemCount + (itemsPerPage - 1), totalItems ); const indexText: string = `${intl.formatNumber( firstItemCount )}-${intl.formatNumber(lastItemCount)} of ${intl.formatNumber(totalItems)}`; return ( {indexText}
{metadataByline}
); };