Files
textbee/web/components/shared/numbered-pagination.tsx
isra el 2623118df3 refactor: decompose 578-line webhooks-history into focused modules
Split app/(app)/dashboard/(components)/webhooks-history.tsx into a
webhooks-history/ folder (import path unchanged via index.tsx):

- use-filters.ts: filter state hook (device, webhook, event, status, preset
  and custom date ranges) with page reset handled in one place
- filters.tsx: the five filter selects + custom-range popover, deduplicated
  via a FilterField wrapper and option tables
- index.tsx: slim container on new useWebhooks / useWebhookNotifications
  hooks in lib/api
- promote the numbered pagination (previously duplicated verbatim between
  message-history and webhooks-history) to
  components/shared/numbered-pagination.tsx
- drop dead code: empty useEffect, never-set isLoading state, ~10 unused
  imports; replace the off-palette sky gradient with card tokens
- add a webhooks history e2e guard

Build, 25 unit tests, and 6 e2e green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 06:45:22 +03:00

111 lines
2.6 KiB
TypeScript

'use client'
import { Button } from '@/components/ui/button'
type PaginationProps = {
page: number
totalPages: number
onPageChange: (page: number) => void
}
function PageButton({
page,
isActive,
onClick,
}: {
page: number
isActive: boolean
onClick: () => void
}) {
return (
<Button
onClick={onClick}
variant={isActive ? 'default' : 'ghost'}
size='icon'
className={`h-8 w-8 rounded-full ${
isActive
? 'bg-primary text-brand-foreground hover:bg-primary/90'
: 'hover:bg-secondary'
}`}
>
{page}
</Button>
)
}
// Numbered pagination with first/last anchors and ellipsis for long ranges.
export default function Pagination({
page,
totalPages,
onPageChange,
}: PaginationProps) {
if (totalPages <= 1) return null
// Middle window: up to 6 pages between the pinned first and last buttons.
const middlePages: number[] = []
for (let i = 0; i < Math.min(6, totalPages - 2); i++) {
let pageToShow: number
if (totalPages <= 8) {
pageToShow = i + 2
} else if (page <= 4) {
pageToShow = i + 2
} else if (page >= totalPages - 3) {
pageToShow = totalPages - 7 + i
} else {
pageToShow = page - 2 + i
}
if (pageToShow > 1 && pageToShow < totalPages) {
middlePages.push(pageToShow)
}
}
return (
<div className='flex justify-center mt-6 space-x-2'>
<Button
onClick={() => onPageChange(Math.max(1, page - 1))}
disabled={page === 1}
variant={page === 1 ? 'ghost' : 'default'}
>
Previous
</Button>
<div className='flex flex-wrap items-center gap-2 justify-center sm:justify-start'>
<PageButton
page={1}
isActive={page === 1}
onClick={() => onPageChange(1)}
/>
{page > 4 && totalPages > 7 && <span className='px-1'>...</span>}
{middlePages.map((p) => (
<PageButton
key={p}
page={p}
isActive={page === p}
onClick={() => onPageChange(p)}
/>
))}
{page < totalPages - 3 && totalPages > 7 && (
<span className='px-1'>...</span>
)}
<PageButton
page={totalPages}
isActive={page === totalPages}
onClick={() => onPageChange(totalPages)}
/>
</div>
<Button
onClick={() => onPageChange(Math.min(totalPages, page + 1))}
disabled={page === totalPages}
variant={page === totalPages ? 'ghost' : 'default'}
>
Next
</Button>
</div>
)
}