diff --git a/explorer/src/assets/locales/en/en.json b/explorer/src/assets/locales/en/en.json index 431ff20c..84c29790 100644 --- a/explorer/src/assets/locales/en/en.json +++ b/explorer/src/assets/locales/en/en.json @@ -26,7 +26,8 @@ "noResults": "No Results", "hasntBeenFound": "hasn`t been found", "searchNotFound": "Nothing found on “{{search}}” search request", - "searchFound": "{{count}} results found on “{{search}}” search request" + "searchFound": "{{count}} results found on “{{search}}” search request", + "perPage": "per page" }, "routes": { "issuers": "Issuers", diff --git a/explorer/src/components/Pagination/PerPageSelector/index.tsx b/explorer/src/components/Pagination/PerPageSelector/index.tsx new file mode 100644 index 00000000..dbb634d8 --- /dev/null +++ b/explorer/src/components/Pagination/PerPageSelector/index.tsx @@ -0,0 +1,38 @@ +import { ChevronDown } from "lucide-react"; + +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; + +interface PerPageSelectorProps { + onChange: (val: string | number) => void; + values: string[] | number[]; + value: string | number; +} + +export const PerPageSelector: React.FC = ({ onChange, values, value }) => { + return ( +
+ + + {value} + + + + {values.map((number) => ( + onChange(number)} + > + {number} + + ))} + + +
+ ); +}; diff --git a/explorer/src/components/Pagination/index.tsx b/explorer/src/components/Pagination/index.tsx index ab333b02..0792c70b 100644 --- a/explorer/src/components/Pagination/index.tsx +++ b/explorer/src/components/Pagination/index.tsx @@ -1,6 +1,6 @@ import { t } from "i18next"; import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from "lucide-react"; -import { useEffect, useRef } from "react"; +import { useEffect, useRef, useState } from "react"; import { useSearchParams } from "react-router-dom"; import { ITEMS_PER_PAGE_DEFAULT } from "@/constants"; @@ -9,20 +9,26 @@ import { displayAmountWithComma } from "@/utils/amountUtils"; import { pageBySearchParams } from "@/utils/paginationUtils"; import { IPaginationProps } from "./interface"; +import { PerPageSelector } from "./PerPageSelector"; export const Pagination = ({ itemsCount, handlePage }: IPaginationProps) => { const [searchParams, setSearchParams] = useSearchParams(); - const currentPage = pageBySearchParams(searchParams, itemsCount); + const [itemsPerPage, setItemsPerPage] = useState( + Number(searchParams.get(EQueryParams.ITEMS_PER_PAGE)) || ITEMS_PER_PAGE_DEFAULT, + ); + const currentPage = pageBySearchParams(searchParams, itemsCount, Number(itemsPerPage)); useEffect(() => { handlePage(currentPage); }, [currentPage, handlePage, searchParams]); - const totalPages = Math.ceil(itemsCount / ITEMS_PER_PAGE_DEFAULT); + const totalPages = Math.ceil(itemsCount / Number(itemsPerPage)); const disablePrev = currentPage === 1; const disableNext = currentPage === totalPages; + const itemsPerPageValues = [ITEMS_PER_PAGE_DEFAULT, 20, 50, 100]; + const inputRef = useRef(null); const handlePageChange = (newPage: number) => { @@ -33,6 +39,12 @@ export const Pagination = ({ itemsCount, handlePage }: IPaginationProps) => { } }; + const handleItemsPerPage = (val: number | string) => { + setItemsPerPage(val); + searchParams.set(EQueryParams.ITEMS_PER_PAGE, String(val)); + setSearchParams(searchParams); + }; + const handleFirstPage = () => handlePageChange(1); const handleLastPage = () => handlePageChange(totalPages); const handlePreviousPage = () => handlePageChange(currentPage - 1); @@ -85,6 +97,10 @@ export const Pagination = ({ itemsCount, handlePage }: IPaginationProps) => { className="w-16 h-8 px-2 border text-xs font-semibold dark:bg-transparent text-text-primary dark:text-whiteDefault text-center outline-none border-border-table dark:border-greyDark focus:border-border-inputFocus dark:focus:border-border-inputFocus rounded-lg transition" /> {`of ${displayAmountWithComma(totalPages)}`} + + + {t("common.messages.perPage")} +