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:
parent
9a395f3dbe
commit
17da3a81e9
2 changed files with 97 additions and 7 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
</>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Reference in a new issue