feat: implement pagination for extractions and playlists with updated API responses

This commit is contained in:
JSC
2025-08-17 11:22:02 +02:00
parent 04401092bb
commit 75ecd26e06
5 changed files with 277 additions and 25 deletions

View File

@@ -0,0 +1,147 @@
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from '@/components/ui/pagination'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
interface AppPaginationProps {
currentPage: number
totalPages: number
totalCount: number
pageSize: number
pageSizeOptions?: number[]
onPageChange: (page: number) => void
onPageSizeChange: (size: number) => void
itemName?: string // e.g., "items", "extractions", "playlists"
}
export function AppPagination({
currentPage,
totalPages,
totalCount,
pageSize,
pageSizeOptions = [10, 20, 50, 100],
onPageChange,
onPageSizeChange,
itemName = 'items',
}: AppPaginationProps) {
// Don't render if there are no items
if (totalCount === 0) return null
const getVisiblePages = () => {
const delta = 2
const range = []
const rangeWithDots = []
for (
let i = Math.max(2, currentPage - delta);
i <= Math.min(totalPages - 1, currentPage + delta);
i++
) {
range.push(i)
}
if (currentPage - delta > 2) {
rangeWithDots.push(1, '...')
} else {
rangeWithDots.push(1)
}
rangeWithDots.push(...range)
if (currentPage + delta < totalPages - 1) {
rangeWithDots.push('...', totalPages)
} else if (totalPages > 1) {
rangeWithDots.push(totalPages)
}
return rangeWithDots
}
const startItem = Math.min((currentPage - 1) * pageSize + 1, totalCount)
const endItem = Math.min(currentPage * pageSize, totalCount)
return (
<div className="flex items-center justify-between">
<p className="text-sm text-muted-foreground whitespace-nowrap">
Showing {startItem} to {endItem} of {totalCount} {itemName}
</p>
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious
href="#"
onClick={(e) => {
e.preventDefault()
if (currentPage > 1) onPageChange(currentPage - 1)
}}
className={currentPage <= 1 ? 'pointer-events-none opacity-50' : ''}
/>
</PaginationItem>
{getVisiblePages().map((page, index) => (
<PaginationItem key={index}>
{page === '...' ? (
<PaginationEllipsis />
) : (
<PaginationLink
href="#"
onClick={(e) => {
e.preventDefault()
onPageChange(page as number)
}}
isActive={currentPage === page}
>
{page}
</PaginationLink>
)}
</PaginationItem>
))}
<PaginationItem>
<PaginationNext
href="#"
onClick={(e) => {
e.preventDefault()
if (currentPage < totalPages) onPageChange(currentPage + 1)
}}
className={currentPage >= totalPages ? 'pointer-events-none opacity-50' : ''}
/>
</PaginationItem>
</PaginationContent>
</Pagination>
<div className="flex items-center gap-2 whitespace-nowrap">
<span className="text-sm text-muted-foreground">Show</span>
<Select
value={pageSize.toString()}
onValueChange={value => onPageSizeChange(parseInt(value, 10))}
>
<SelectTrigger className="w-[75px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
{pageSizeOptions.map(size => (
<SelectItem key={size} value={size.toString()}>
{size}
</SelectItem>
))}
</SelectContent>
</Select>
<span className="text-sm text-muted-foreground">rows</span>
</div>
</div>
)
}