import { useMemo } from 'react'; import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react'; export interface PaginationProps { currentPage: number; totalPages: number; onPageChange: (page: number) => void; maxVisiblePages?: number; showFirstLast?: boolean; className?: string; // FE-COMP-006: Additional props for item info totalItems?: number; itemsPerPage?: number; showItemsInfo?: boolean; } /** * FE-COMP-006: Composant Pagination pour navigation entre pages de résultats. * Amélioré avec informations sur les items affichés. */ export function Pagination({ currentPage, totalPages, onPageChange, maxVisiblePages = 5, showFirstLast = false, className, totalItems, itemsPerPage, showItemsInfo = false, }: PaginationProps) { const visiblePages = useMemo(() => { if (totalPages <= maxVisiblePages) { return Array.from({ length: totalPages }, (_, i) => i + 1); } const pages: (number | 'ellipsis-start' | 'ellipsis-end')[] = []; const half = Math.floor(maxVisiblePages / 2); let start = Math.max(1, currentPage - half); const end = Math.min(totalPages, start + maxVisiblePages - 1); // Ajuster si on est proche de la fin if (end === totalPages) { start = Math.max(1, totalPages - maxVisiblePages + 1); } // Première page if (showFirstLast && start > 1) { pages.push(1); if (start > 2) { pages.push('ellipsis-start'); } } else if (start > 1) { pages.push(1); if (start > 2) { pages.push('ellipsis-start'); } } // Pages visibles for (let i = start; i <= end; i++) { pages.push(i); } // Dernière page if (end < totalPages) { if (end < totalPages - 1) { pages.push('ellipsis-end'); } pages.push(totalPages); } return pages; }, [currentPage, totalPages, maxVisiblePages, showFirstLast]); const handlePrevious = () => { if (currentPage > 1) { onPageChange(currentPage - 1); } }; const handleNext = () => { if (currentPage < totalPages) { onPageChange(currentPage + 1); } }; const handleFirst = () => { onPageChange(1); }; const handleLast = () => { onPageChange(totalPages); }; // CRITIQUE FIX #44: Gestion complète du clavier pour l'accessibilité // Gérer les touches de navigation (flèches, Home, End) pour une meilleure accessibilité const handleKeyDown = ( e: React.KeyboardEvent, _action: () => void, _alternativeAction?: () => void, ) => { // Les boutons HTML natifs gèrent déjà Enter et Space automatiquement // On ne doit pas utiliser preventDefault() pour ces touches car cela peut interférer // avec le comportement natif des boutons // Gérer les flèches pour navigation if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') { e.preventDefault(); handlePrevious(); return; } if (e.key === 'ArrowRight' || e.key === 'ArrowDown') { e.preventDefault(); handleNext(); return; } // Gérer Home/End pour aller à la première/dernière page if (e.key === 'Home') { e.preventDefault(); handleFirst(); return; } if (e.key === 'End') { e.preventDefault(); handleLast(); return; } // Pour Enter et Space, laisser le comportement natif du bouton // Ne pas utiliser preventDefault() car les boutons HTML gèrent déjà ces touches }; // FE-COMP-006: Calculate item range for display const startItem = totalItems && itemsPerPage ? (currentPage - 1) * itemsPerPage + 1 : null; const endItem = totalItems && itemsPerPage ? Math.min(currentPage * itemsPerPage, totalItems) : null; if (totalPages <= 1 && !showItemsInfo) { return null; } return (