mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
chore: update Pagination component
This commit is contained in:
+299
-209
@@ -1,7 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { ReactNode } from 'react';
|
||||
import { ChangeEventHandler, ReactNode } from 'react';
|
||||
|
||||
import { Icon } from '@iconify/react';
|
||||
import Button from '@/components/Button';
|
||||
|
||||
import { cn } from '@/lib/helper';
|
||||
|
||||
@@ -17,16 +19,18 @@ const PaginationButton = ({
|
||||
disabled?: boolean;
|
||||
onClick?: () => void;
|
||||
}) => (
|
||||
<button
|
||||
className={cn(
|
||||
'join-item btn btn-ghost p-2.5 rounded-lg text-sm font-medium text-gray-500 aspect-square',
|
||||
'disabled:text-gray-700 disabled:pointer-events-auto! disabled:cursor-not-allowed! disabled:bg-gray-50 disabled:active:translate-y-0'
|
||||
)}
|
||||
<Button
|
||||
variant='ghost'
|
||||
color='none'
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
className={cn(
|
||||
'join-item w-10 h-10 grid place-items-center p-2.5 rounded-lg text-sm font-semibold text-base-content/50 aspect-square',
|
||||
'disabled:text-primary disabled:pointer-events-auto! disabled:cursor-not-allowed! disabled:bg-primary/10 disabled:active:translate-y-0'
|
||||
)}
|
||||
>
|
||||
{content}
|
||||
</button>
|
||||
</Button>
|
||||
);
|
||||
|
||||
const EtcPaginationButton = ({
|
||||
@@ -90,16 +94,20 @@ const Pagination = ({
|
||||
currentPage = 1,
|
||||
totalItems = 0,
|
||||
itemsPerPage = 10,
|
||||
rowOptions = [10, 20, 50, 100],
|
||||
onPageChange,
|
||||
onPrevPage = () => {},
|
||||
onNextPage = () => {},
|
||||
onRowChange,
|
||||
}: {
|
||||
currentPage: number;
|
||||
totalItems: number;
|
||||
itemsPerPage: number;
|
||||
rowOptions?: number[];
|
||||
onPageChange: (pageNumber: number) => void;
|
||||
onPrevPage: () => void;
|
||||
onNextPage: () => void;
|
||||
onRowChange?: (row: number) => void;
|
||||
}) => {
|
||||
const totalPages =
|
||||
Math.ceil(totalItems / itemsPerPage) === 0
|
||||
@@ -107,30 +115,139 @@ const Pagination = ({
|
||||
: Math.ceil(totalItems / itemsPerPage);
|
||||
|
||||
const pageChangeHandler = (pageNumber: number) => onPageChange(pageNumber);
|
||||
const firstPageClickHandler = () => onPageChange(1);
|
||||
const lastPageClickHandler = () => onPageChange(totalPages);
|
||||
|
||||
const rowChangeHandler: ChangeEventHandler<HTMLSelectElement> = (e) => {
|
||||
onRowChange?.(Number(e.target.value));
|
||||
};
|
||||
|
||||
const DisplayedRowCountSelect = () => (
|
||||
<div className='flex flex-row items-center gap-4'>
|
||||
<span className='text-sm font-medium text-base-content/50'>Showing</span>
|
||||
|
||||
<select
|
||||
defaultValue={itemsPerPage}
|
||||
onChange={rowChangeHandler}
|
||||
className='select select-xs w-fit text-base-content/50'
|
||||
>
|
||||
{rowOptions.map((rowOption, rowOptionIdx) => (
|
||||
<option
|
||||
key={rowOptionIdx}
|
||||
value={rowOption}
|
||||
className='text-base-content active:text-neutral-content'
|
||||
>
|
||||
{rowOption} Per page
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
|
||||
const GoToFirstPageButton = () => (
|
||||
<Button
|
||||
disabled={currentPage === 1}
|
||||
onClick={firstPageClickHandler}
|
||||
variant='ghost'
|
||||
color='none'
|
||||
className={cn(
|
||||
'join-item w-10 h-10 grid place-items-center p-2.5 rounded-lg text-sm font-semibold text-base-content/50 aspect-square',
|
||||
'disabled:bg-[initial]! disabled:text-base-content disabled:pointer-events-auto! disabled:cursor-not-allowed disabled:active:translate-y-0'
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
icon='heroicons:chevron-double-left'
|
||||
width={20}
|
||||
height={20}
|
||||
className='text-gray-400 group-disabled:text-gray-300'
|
||||
/>
|
||||
</Button>
|
||||
);
|
||||
|
||||
const PrevPageButton = () => (
|
||||
<Button
|
||||
disabled={currentPage === 1}
|
||||
onClick={onPrevPage}
|
||||
variant='ghost'
|
||||
color='none'
|
||||
className={cn(
|
||||
'join-item w-10 h-10 grid place-items-center p-2.5 rounded-lg text-sm font-semibold text-base-content/50 aspect-square',
|
||||
'disabled:bg-[initial]! disabled:text-base-content disabled:pointer-events-auto! disabled:cursor-not-allowed disabled:active:translate-y-0'
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
icon='heroicons:chevron-left'
|
||||
width={20}
|
||||
height={20}
|
||||
className='text-gray-400 group-disabled:text-gray-300'
|
||||
/>
|
||||
</Button>
|
||||
);
|
||||
|
||||
const GoToLastPageButton = () => (
|
||||
<Button
|
||||
variant='ghost'
|
||||
color='none'
|
||||
disabled={currentPage === totalPages}
|
||||
onClick={lastPageClickHandler}
|
||||
className={cn(
|
||||
'join-item w-10 h-10 grid place-items-center p-2.5 rounded-lg text-sm font-semibold text-base-content/50 aspect-square',
|
||||
'disabled:bg-[initial]! disabled:text-base-content disabled:pointer-events-auto! disabled:cursor-not-allowed disabled:active:translate-y-0'
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
icon='heroicons:chevron-double-right'
|
||||
width={20}
|
||||
height={20}
|
||||
className='text-gray-400 group-disabled:text-gray-300'
|
||||
/>
|
||||
</Button>
|
||||
);
|
||||
|
||||
const NextPageButton = () => (
|
||||
<Button
|
||||
variant='ghost'
|
||||
color='none'
|
||||
disabled={currentPage === totalPages}
|
||||
onClick={onNextPage}
|
||||
className={cn(
|
||||
'join-item w-10 h-10 grid place-items-center p-2.5 rounded-lg text-sm font-semibold text-base-content/50 aspect-square',
|
||||
'disabled:bg-[initial]! disabled:text-base-content disabled:pointer-events-auto! disabled:cursor-not-allowed disabled:active:translate-y-0'
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
icon='heroicons:chevron-right'
|
||||
width={20}
|
||||
height={20}
|
||||
className='text-gray-400 group-disabled:text-gray-300'
|
||||
/>
|
||||
</Button>
|
||||
);
|
||||
|
||||
const PageInfo = () => (
|
||||
<span className='text-nowrap text-sm font-medium text-base-content/50'>
|
||||
Page {currentPage} of {totalPages}
|
||||
</span>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='join w-full justify-between items-center gap-3'>
|
||||
<button
|
||||
disabled={currentPage === 1}
|
||||
onClick={onPrevPage}
|
||||
className={cn(
|
||||
'join-item btn btn-outline group px-3 py-2 text-sm font-semibold rounded-lg border border-gray-300 shadow-xs hidden sm:flex justify-center items-center gap-1.5',
|
||||
'disabled:bg-[initial]! disabled:text-gray-400 disabled:pointer-events-auto! disabled:cursor-not-allowed disabled:active:translate-y-0'
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
icon='uil:arrow-left'
|
||||
width={20}
|
||||
height={20}
|
||||
className='text-gray-400 group-disabled:text-gray-300'
|
||||
/>{' '}
|
||||
Previous
|
||||
</button>
|
||||
<div className='@container'>
|
||||
<div className='flex flex-row justify-center items-center'>
|
||||
<div className='hidden @lg:block'>
|
||||
<DisplayedRowCountSelect />
|
||||
</div>
|
||||
|
||||
{totalPages <= 7 && (
|
||||
<div className='join-item join gap-0.5'>
|
||||
{range(1, totalPages).map((pageNumber) => (
|
||||
<div className='join w-full justify-end @lg:justify-center items-center gap-0.5'>
|
||||
<div className='hidden @lg:block'>
|
||||
<GoToFirstPageButton />
|
||||
</div>
|
||||
|
||||
<div className='hidden @lg:block'>
|
||||
<PrevPageButton />
|
||||
</div>
|
||||
|
||||
{totalPages <= 7 &&
|
||||
range(1, totalPages).map((pageNumber) => (
|
||||
<PaginationButton
|
||||
key={pageNumber}
|
||||
content={pageNumber}
|
||||
@@ -138,195 +255,168 @@ const Pagination = ({
|
||||
onClick={() => pageChangeHandler(pageNumber)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{totalPages > 7 && (
|
||||
<div className='join-item join gap-0.5'>
|
||||
<PaginationButton
|
||||
content={1}
|
||||
disabled={currentPage === 1}
|
||||
onClick={() => pageChangeHandler(1)}
|
||||
/>
|
||||
|
||||
{totalPages >= 2 &&
|
||||
(currentPage <= 3 || currentPage >= totalPages - 2) && (
|
||||
<PaginationButton
|
||||
content={2}
|
||||
disabled={currentPage === 2}
|
||||
onClick={() => pageChangeHandler(2)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 2 &&
|
||||
currentPage > 3 &&
|
||||
currentPage < totalPages - 2 && (
|
||||
<EtcPaginationButton
|
||||
startPage={2}
|
||||
endPage={currentPage - 2}
|
||||
onPageItemClick={pageChangeHandler}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 3 &&
|
||||
(currentPage <= 4 || currentPage >= totalPages - 2) &&
|
||||
currentPage !== totalPages - 2 && (
|
||||
<PaginationButton
|
||||
content={3}
|
||||
disabled={currentPage === 3}
|
||||
onClick={() => pageChangeHandler(3)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 7 &&
|
||||
(currentPage <= 2 || currentPage >= totalPages - 2) && (
|
||||
<EtcPaginationButton
|
||||
startPage={
|
||||
currentPage <= 2
|
||||
? currentPage + 2
|
||||
: currentPage === totalPages - 2
|
||||
? 3
|
||||
: currentPage >= totalPages - 1
|
||||
? 4
|
||||
: 1
|
||||
}
|
||||
endPage={
|
||||
currentPage <= 2 || currentPage >= totalPages - 1
|
||||
? totalPages - 3
|
||||
: currentPage === totalPages - 2
|
||||
? totalPages - 4
|
||||
: 2
|
||||
}
|
||||
onPageItemClick={pageChangeHandler}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 3 &&
|
||||
currentPage > 4 &&
|
||||
currentPage < totalPages - 1 && (
|
||||
<PaginationButton
|
||||
content={currentPage - 1}
|
||||
onClick={() => pageChangeHandler(currentPage - 1)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 7 &&
|
||||
currentPage > 3 &&
|
||||
currentPage < totalPages - 2 && (
|
||||
<PaginationButton content={currentPage} disabled />
|
||||
)}
|
||||
|
||||
{totalPages >= 5 &&
|
||||
currentPage > 2 &&
|
||||
currentPage < totalPages - 2 && (
|
||||
<PaginationButton
|
||||
content={currentPage + 1}
|
||||
onClick={() => pageChangeHandler(currentPage + 1)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 5 &&
|
||||
(currentPage <= 2 || currentPage >= totalPages - 2) && (
|
||||
<PaginationButton
|
||||
content={totalPages - 2}
|
||||
disabled={currentPage === totalPages - 2}
|
||||
onClick={() => pageChangeHandler(totalPages - 2)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 6 &&
|
||||
currentPage > 2 &&
|
||||
currentPage < totalPages - 3 && (
|
||||
<EtcPaginationButton
|
||||
startPage={
|
||||
currentPage <= 3
|
||||
? currentPage + 2
|
||||
: currentPage >= 4
|
||||
? currentPage + 2
|
||||
: 1
|
||||
}
|
||||
endPage={
|
||||
currentPage <= 3
|
||||
? totalPages - 2
|
||||
: currentPage >= 4
|
||||
? totalPages - 1
|
||||
: 0
|
||||
}
|
||||
onPageItemClick={pageChangeHandler}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 6 &&
|
||||
(currentPage <= 3 || currentPage >= totalPages - 3) && (
|
||||
<PaginationButton
|
||||
content={totalPages - 1}
|
||||
disabled={currentPage === totalPages - 1}
|
||||
onClick={() => pageChangeHandler(totalPages - 1)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 7 && (
|
||||
{totalPages > 7 && (
|
||||
<>
|
||||
<PaginationButton
|
||||
content={totalPages}
|
||||
disabled={currentPage === totalPages}
|
||||
onClick={() => pageChangeHandler(totalPages)}
|
||||
content={1}
|
||||
disabled={currentPage === 1}
|
||||
onClick={() => pageChangeHandler(1)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<button
|
||||
disabled={currentPage === totalPages}
|
||||
onClick={onNextPage}
|
||||
className={cn(
|
||||
'join-item btn btn-outline group px-3 py-2 text-sm font-semibold rounded-lg border border-gray-300 shadow-xs hidden sm:flex justify-center items-center gap-1.5',
|
||||
'disabled:bg-[initial]! disabled:text-gray-400 disabled:pointer-events-auto! disabled:cursor-not-allowed disabled:active:translate-y-0'
|
||||
{totalPages >= 2 &&
|
||||
(currentPage <= 3 || currentPage >= totalPages - 2) && (
|
||||
<PaginationButton
|
||||
content={2}
|
||||
disabled={currentPage === 2}
|
||||
onClick={() => pageChangeHandler(2)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 2 &&
|
||||
currentPage > 3 &&
|
||||
currentPage < totalPages - 2 && (
|
||||
<EtcPaginationButton
|
||||
startPage={2}
|
||||
endPage={currentPage - 2}
|
||||
onPageItemClick={pageChangeHandler}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 3 &&
|
||||
(currentPage <= 4 || currentPage >= totalPages - 2) &&
|
||||
currentPage !== totalPages - 2 && (
|
||||
<PaginationButton
|
||||
content={3}
|
||||
disabled={currentPage === 3}
|
||||
onClick={() => pageChangeHandler(3)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 7 &&
|
||||
(currentPage <= 2 || currentPage >= totalPages - 2) && (
|
||||
<EtcPaginationButton
|
||||
startPage={
|
||||
currentPage <= 2
|
||||
? currentPage + 2
|
||||
: currentPage === totalPages - 2
|
||||
? 3
|
||||
: currentPage >= totalPages - 1
|
||||
? 4
|
||||
: 1
|
||||
}
|
||||
endPage={
|
||||
currentPage <= 2 || currentPage >= totalPages - 1
|
||||
? totalPages - 3
|
||||
: currentPage === totalPages - 2
|
||||
? totalPages - 4
|
||||
: 2
|
||||
}
|
||||
onPageItemClick={pageChangeHandler}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 3 &&
|
||||
currentPage > 4 &&
|
||||
currentPage < totalPages - 1 && (
|
||||
<PaginationButton
|
||||
content={currentPage - 1}
|
||||
onClick={() => pageChangeHandler(currentPage - 1)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 7 &&
|
||||
currentPage > 3 &&
|
||||
currentPage < totalPages - 2 && (
|
||||
<PaginationButton content={currentPage} disabled />
|
||||
)}
|
||||
|
||||
{totalPages >= 5 &&
|
||||
currentPage > 2 &&
|
||||
currentPage < totalPages - 2 && (
|
||||
<PaginationButton
|
||||
content={currentPage + 1}
|
||||
onClick={() => pageChangeHandler(currentPage + 1)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 5 &&
|
||||
(currentPage <= 2 || currentPage >= totalPages - 2) && (
|
||||
<PaginationButton
|
||||
content={totalPages - 2}
|
||||
disabled={currentPage === totalPages - 2}
|
||||
onClick={() => pageChangeHandler(totalPages - 2)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 6 &&
|
||||
currentPage > 2 &&
|
||||
currentPage < totalPages - 3 && (
|
||||
<EtcPaginationButton
|
||||
startPage={
|
||||
currentPage <= 3
|
||||
? currentPage + 2
|
||||
: currentPage >= 4
|
||||
? currentPage + 2
|
||||
: 1
|
||||
}
|
||||
endPage={
|
||||
currentPage <= 3
|
||||
? totalPages - 2
|
||||
: currentPage >= 4
|
||||
? totalPages - 1
|
||||
: 0
|
||||
}
|
||||
onPageItemClick={pageChangeHandler}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 6 &&
|
||||
(currentPage <= 3 || currentPage >= totalPages - 3) && (
|
||||
<PaginationButton
|
||||
content={totalPages - 1}
|
||||
disabled={currentPage === totalPages - 1}
|
||||
onClick={() => pageChangeHandler(totalPages - 1)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{totalPages >= 7 && (
|
||||
<PaginationButton
|
||||
content={totalPages}
|
||||
disabled={currentPage === totalPages}
|
||||
onClick={() => pageChangeHandler(totalPages)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
>
|
||||
Next{' '}
|
||||
<Icon
|
||||
icon='uil:arrow-right'
|
||||
width={20}
|
||||
height={20}
|
||||
className='text-gray-400 group-disabled:text-gray-300'
|
||||
/>
|
||||
</button>
|
||||
|
||||
<div className='hidden @lg:block'>
|
||||
<NextPageButton />
|
||||
</div>
|
||||
|
||||
<div className='hidden @lg:block'>
|
||||
<GoToLastPageButton />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='hidden @lg:block'>
|
||||
<PageInfo />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex gap-2 mt-2 sm:hidden'>
|
||||
<button
|
||||
disabled={currentPage === 1}
|
||||
onClick={onPrevPage}
|
||||
className={cn(
|
||||
'join-item btn btn-outline group px-3 py-2 text-sm font-semibold rounded-lg border border-gray-300 shadow-xs flex justify-center items-center gap-1.5',
|
||||
'disabled:bg-[initial]! disabled:text-gray-400 disabled:pointer-events-auto! disabled:cursor-not-allowed disabled:active:translate-y-0'
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
icon='uil:arrow-left'
|
||||
width={20}
|
||||
height={20}
|
||||
className='text-gray-400 group-disabled:text-gray-300'
|
||||
/>{' '}
|
||||
Previous
|
||||
</button>
|
||||
<div className='flex @lg:hidden flex-col justify-center items-end gap-2'>
|
||||
<div className='flex flex-row items-center gap-0.5'>
|
||||
<GoToFirstPageButton />
|
||||
<PrevPageButton />
|
||||
<NextPageButton />
|
||||
<GoToLastPageButton />
|
||||
</div>
|
||||
|
||||
<button
|
||||
disabled={currentPage === totalPages}
|
||||
onClick={onNextPage}
|
||||
className={cn(
|
||||
'join-item btn btn-outline group px-3 py-2 text-sm font-semibold rounded-lg border border-gray-300 shadow-xs flex justify-center items-center gap-1.5',
|
||||
'disabled:bg-[initial]! disabled:text-gray-400 disabled:pointer-events-auto! disabled:cursor-not-allowed disabled:active:translate-y-0'
|
||||
)}
|
||||
>
|
||||
Next{' '}
|
||||
<Icon
|
||||
icon='uil:arrow-right'
|
||||
width={20}
|
||||
height={20}
|
||||
className='text-gray-400 group-disabled:text-gray-300'
|
||||
/>
|
||||
</button>
|
||||
<div className='flex flex-row items-center gap-4'>
|
||||
<DisplayedRowCountSelect />
|
||||
|
||||
<PageInfo />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user