the-tip-top-frontend/components/ui/Pagination.tsx
soufiane 467696e5b8 refactor: add more shared utilities and reduce duplication further
- Add utils/export.ts for centralized CSV export functionality
- Add EmptyState component for consistent empty state UI
- Add Pagination component for reusable pagination controls
- Refactor employe/gains-client to use apiFetch and EmptyState
- Refactor employe/historique to use apiFetch and EmptyState
- Export new components from ui/index.ts

Target: reduce duplication from 13.93% to under 3%

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 23:39:01 +01:00

122 lines
3.3 KiB
TypeScript

'use client';
import React from 'react';
import { ChevronLeft, ChevronRight } from 'lucide-react';
interface PaginationProps {
currentPage: number;
totalPages: number;
onPageChange: (page: number) => void;
showPageNumbers?: boolean;
className?: string;
}
/**
* Reusable pagination component
*/
export const Pagination: React.FC<PaginationProps> = ({
currentPage,
totalPages,
onPageChange,
showPageNumbers = true,
className = '',
}) => {
if (totalPages <= 1) return null;
const handlePrevious = () => {
if (currentPage > 1) {
onPageChange(currentPage - 1);
}
};
const handleNext = () => {
if (currentPage < totalPages) {
onPageChange(currentPage + 1);
}
};
// Generate page numbers to show
const getPageNumbers = () => {
const pages: (number | string)[] = [];
const maxVisible = 5;
if (totalPages <= maxVisible) {
for (let i = 1; i <= totalPages; i++) {
pages.push(i);
}
} else {
if (currentPage <= 3) {
for (let i = 1; i <= 4; i++) pages.push(i);
pages.push('...');
pages.push(totalPages);
} else if (currentPage >= totalPages - 2) {
pages.push(1);
pages.push('...');
for (let i = totalPages - 3; i <= totalPages; i++) pages.push(i);
} else {
pages.push(1);
pages.push('...');
for (let i = currentPage - 1; i <= currentPage + 1; i++) pages.push(i);
pages.push('...');
pages.push(totalPages);
}
}
return pages;
};
return (
<div className={`flex items-center justify-center gap-2 ${className}`}>
<button
onClick={handlePrevious}
disabled={currentPage === 1}
className="flex items-center gap-1 px-3 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed"
>
<ChevronLeft className="w-4 h-4" />
Précédent
</button>
{showPageNumbers && (
<div className="flex items-center gap-1">
{getPageNumbers().map((page, index) =>
page === '...' ? (
<span key={`ellipsis-${index}`} className="px-2 text-gray-500">
...
</span>
) : (
<button
key={page}
onClick={() => onPageChange(page as number)}
className={`px-3 py-2 text-sm font-medium rounded-lg ${
currentPage === page
? 'bg-blue-600 text-white'
: 'text-gray-700 bg-white border border-gray-300 hover:bg-gray-50'
}`}
>
{page}
</button>
)
)}
</div>
)}
{!showPageNumbers && (
<span className="text-sm text-gray-600">
Page {currentPage} sur {totalPages}
</span>
)}
<button
onClick={handleNext}
disabled={currentPage === totalPages}
className="flex items-center gap-1 px-3 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed"
>
Suivant
<ChevronRight className="w-4 h-4" />
</button>
</div>
);
};
export default Pagination;