feat(review): add enhanced pagination with first/last page buttons and page input

- Add first page (<<) and last page (>>) navigation buttons
- Add direct page number input field for jumping to specific pages
- Update CSS styling for new pagination controls including input field
- Use stacked ChevronLeft/ChevronRight icons for first/last (lucide-react compatibility)
This commit is contained in:
kempersc 2026-01-13 23:27:28 +01:00
parent 9a395f3dbe
commit 17da3a81e9
2 changed files with 97 additions and 7 deletions

View file

@ -432,7 +432,7 @@
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
gap: 0.5rem;
padding: 0.75rem;
border-top: 1px solid var(--border-color, #e0e0e0);
}
@ -441,12 +441,14 @@
border-top-color: var(--border-color, #2a2a4a);
}
.pagination button {
.pagination button,
.pagination-btn {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
min-width: 32px;
height: 32px;
padding: 0 4px;
border: 1px solid var(--border-color, #e0e0e0);
border-radius: 6px;
background: var(--bg-primary, #fff);
@ -455,23 +457,62 @@
transition: all 0.15s;
}
.dark .pagination button {
.dark .pagination button,
.dark .pagination-btn {
border-color: var(--border-color, #2a2a4a);
background: var(--bg-secondary, #1a1a2e);
color: var(--text-primary, #e0e0e0);
}
.pagination button:hover:not(:disabled) {
.pagination button:hover:not(:disabled),
.pagination-btn:hover:not(:disabled) {
background: var(--primary-color, #3b82f6);
color: white;
border-color: var(--primary-color, #3b82f6);
}
.pagination button:disabled {
.pagination button:disabled,
.pagination-btn:disabled {
opacity: 0.4;
cursor: not-allowed;
}
.pagination-input-form {
display: flex;
align-items: center;
gap: 0.25rem;
}
.pagination-input {
width: 40px;
height: 32px;
padding: 0 0.5rem;
border: 1px solid var(--border-color, #e0e0e0);
border-radius: 6px;
background: var(--bg-primary, #fff);
color: var(--text-primary, #1a1a2e);
font-size: 0.875rem;
text-align: center;
}
.dark .pagination-input {
border-color: var(--border-color, #2a2a4a);
background: var(--bg-secondary, #1a1a2e);
color: var(--text-primary, #e0e0e0);
}
.pagination-input:focus {
outline: none;
border-color: var(--primary-color, #3b82f6);
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
}
.pagination-total {
font-size: 0.875rem;
color: var(--text-secondary, #666);
white-space: nowrap;
}
.pagination span {
font-size: 0.875rem;
color: var(--text-secondary, #666);

View file

@ -176,6 +176,7 @@ export default function EntityReviewPage() {
const [error, setError] = useState<string | null>(null);
const [page, setPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [pageInput, setPageInput] = useState('1');
const pageSize = 20;
// Filtering state
@ -339,6 +340,22 @@ export default function EntityReviewPage() {
return () => window.removeEventListener('keydown', handleKeyDown);
}, [saveDecision, savingDecision, selectedCandidate, isAuthenticated]);
// Sync page input with page state
useEffect(() => {
setPageInput(page.toString());
}, [page]);
// Handle page input submission
const handlePageInputSubmit = (e: React.FormEvent | React.KeyboardEvent) => {
e.preventDefault();
const newPage = parseInt(pageInput, 10);
if (!isNaN(newPage) && newPage >= 1 && newPage <= totalPages) {
setPage(newPage);
} else {
setPageInput(page.toString()); // Reset to current page if invalid
}
};
// Handle logout
const handleLogout = () => {
sessionStorage.removeItem('review_token');
@ -542,19 +559,51 @@ export default function EntityReviewPage() {
{/* Pagination */}
<div className="pagination">
<button
onClick={() => setPage(1)}
disabled={page === 1}
title="First page"
className="pagination-btn"
>
<ChevronLeft size={14} />
<ChevronLeft size={14} style={{ marginLeft: -8 }} />
</button>
<button
onClick={() => setPage(p => Math.max(1, p - 1))}
disabled={page === 1}
title="Previous page"
className="pagination-btn"
>
<ChevronLeft size={16} />
</button>
<span>{page} / {totalPages}</span>
<form onSubmit={handlePageInputSubmit} className="pagination-input-form">
<input
type="text"
value={pageInput}
onChange={(e) => setPageInput(e.target.value)}
onBlur={handlePageInputSubmit}
onKeyDown={(e) => e.key === 'Enter' && handlePageInputSubmit(e)}
className="pagination-input"
/>
<span className="pagination-total">/ {totalPages}</span>
</form>
<button
onClick={() => setPage(p => Math.min(totalPages, p + 1))}
disabled={page === totalPages}
title="Next page"
className="pagination-btn"
>
<ChevronRight size={16} />
</button>
<button
onClick={() => setPage(totalPages)}
disabled={page === totalPages}
title="Last page"
className="pagination-btn"
>
<ChevronRight size={14} />
<ChevronRight size={14} style={{ marginLeft: -8 }} />
</button>
</div>
</>
)}