turash/bugulma/frontend/components/ui/Pagination.tsx
Damir Mukimov 673e8d4361
Some checks failed
CI/CD Pipeline / backend-lint (push) Failing after 31s
CI/CD Pipeline / backend-build (push) Has been skipped
CI/CD Pipeline / frontend-lint (push) Failing after 1m37s
CI/CD Pipeline / frontend-build (push) Has been skipped
CI/CD Pipeline / e2e-test (push) Has been skipped
fix: resolve all frontend lint errors (85 issues fixed)
- Replace all 'any' types with proper TypeScript interfaces
- Fix React hooks setState in useEffect issues with lazy initialization
- Remove unused variables and imports across all files
- Fix React Compiler memoization dependency issues
- Add comprehensive i18n translation keys for admin interfaces
- Apply consistent prettier formatting throughout codebase
- Clean up unused bulk editing functionality
- Improve type safety and code quality across frontend

Files changed: 39
- ImpactMetrics.tsx: Fixed any types and interfaces
- AdminVerificationQueuePage.tsx: Added i18n keys, removed unused vars
- LocalizationUIPage.tsx: Fixed memoization, added translations
- LocalizationDataPage.tsx: Added type safety and translations
- And 35+ other files with various lint fixes
2025-12-25 14:14:58 +01:00

165 lines
4.2 KiB
TypeScript

import React from 'react';
import { clsx } from 'clsx';
import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from 'lucide-react';
import { useTranslation } from '@/hooks/useI18n';
import Button from './Button';
export interface PaginationProps {
currentPage: number;
totalPages: number;
onPageChange: (page: number) => void;
pageSize?: number;
totalItems?: number;
showPageNumbers?: boolean;
showFirstLast?: boolean;
className?: string;
}
/**
* Pagination component
*/
export const Pagination = ({
currentPage,
totalPages,
onPageChange,
pageSize,
totalItems,
showPageNumbers = true,
showFirstLast = true,
className,
}: PaginationProps) => {
const { t } = useTranslation();
const getPageNumbers = () => {
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 {
rangeWithDots.push(totalPages);
}
return rangeWithDots;
};
const pageNumbers = getPageNumbers();
if (totalPages <= 1) return null;
return (
<div className={clsx('flex items-center justify-between gap-2', className)}>
{/* Info */}
{totalItems !== undefined && pageSize && (
<div className="text-sm text-muted-foreground hidden sm:block">
{t('pagination.showing', {
start: (currentPage - 1) * pageSize + 1,
end: Math.min(currentPage * pageSize, totalItems),
total: totalItems,
})}
</div>
)}
{/* Pagination Controls */}
<div className="flex items-center gap-1">
{showFirstLast && (
<Button
variant="outline"
size="sm"
onClick={() => onPageChange(1)}
disabled={currentPage === 1}
aria-label="First page"
>
<ChevronsLeft className="h-4 w-4" />
</Button>
)}
<Button
variant="outline"
size="sm"
onClick={() => onPageChange(currentPage - 1)}
disabled={currentPage === 1}
aria-label="Previous page"
>
<ChevronLeft className="h-4 w-4" />
</Button>
{showPageNumbers && (
<div className="flex items-center gap-1">
{pageNumbers.map((page, index) => {
if (page === '...') {
return (
<span
key={`ellipsis-${index}`}
className="px-3 py-2 text-sm text-muted-foreground"
>
...
</span>
);
}
const pageNum = page as number;
const isActive = pageNum === currentPage;
return (
<Button
key={pageNum}
variant={isActive ? 'primary' : 'outline'}
size="sm"
onClick={() => onPageChange(pageNum)}
className={clsx('min-w-[2.5rem]', {
'pointer-events-none': isActive,
})}
aria-label={`Page ${pageNum}`}
aria-current={isActive ? 'page' : undefined}
>
{pageNum}
</Button>
);
})}
</div>
)}
<Button
variant="outline"
size="sm"
onClick={() => onPageChange(currentPage + 1)}
disabled={currentPage === totalPages}
aria-label="Next page"
>
<ChevronRight className="h-4 w-4" />
</Button>
{showFirstLast && (
<Button
variant="outline"
size="sm"
onClick={() => onPageChange(totalPages)}
disabled={currentPage === totalPages}
aria-label="Last page"
>
<ChevronsRight className="h-4 w-4" />
</Button>
)}
</div>
</div>
);
};