added canddiates listing #37

Merged
ahmed.mujtaba merged 1 commits from Canidates_listong_order into main 2026-08-31 08:21:23 +00:00
3 changed files with 29 additions and 26 deletions

View File

@ -102,7 +102,7 @@ class Users(SQLModel, table=True):
select(cls)
.options(selectinload(cls.role))
.where(cls.is_deleted == False)
.order_by(cls.created_at.desc())
.order_by(cls.created_at.desc(),cls.id.desc())
)
if search:
statement = statement.where(cls._search_filter(search))

View File

@ -14,7 +14,7 @@ import { useLocation, useNavigate } from 'react-router-dom'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import Modal from '../ui/Modal'
import { DataTableHead, DEFAULT_PAGE_SIZE, Pagination, pageAfterSizeChange, pageWindow, useDataTable } from '../ui/DataTable'
import { DataTableHead, DEFAULT_PAGE_SIZE, Pagination, pageWindow, useDataTable } from '../ui/DataTable'
import PageHeader from '../ui/PageHeader'
import { Avatar, Badge, EmptyState, FieldError, Icon, SkeletonRows } from '../ui/primitives'
import { useToast } from '../ui/Toast'
@ -117,13 +117,12 @@ export default function Candidates() {
const [filters, setFilters] = useState(EMPTY_FILTERS)
const [showFilters, setShowFilters] = useState(false)
const [sortMode, setSortMode] = useState('recent')
const [page, setPage] = useState(1)
const [skip, setSkip] = useState(0)
const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE)
const [profileFor, setProfileFor] = useState(null)
const [atsFor, setAtsFor] = useState(null)
const [adding, setAdding] = useState(false)
const skip = (page - 1) * pageSize
const countQuery = useQuery({
queryKey: qk.candidates.count({ roleId: CANDIDATE_ROLE_ID }),
queryFn: async () => {
@ -216,8 +215,7 @@ export default function Candidates() {
return true
})
if (sortMode === 'recent') list = [...list].sort((a, b) => (b.applied ?? 0) - (a.applied ?? 0))
else if (sortMode === 'name') list = [...list].sort((a, b) => a.name.localeCompare(b.name))
if (sortMode === 'name') list = [...list].sort((a, b) => a.name.localeCompare(b.name))
return list
}, [candidates, filters, q, sortMode])
@ -238,11 +236,14 @@ export default function Candidates() {
const t = useDataTable({ columns, rows, pageSize: Math.max(rows.length, 1) })
const total = countQuery.data ?? 0
const pages = Math.max(1, Math.ceil(total / pageSize))
const currentPage = Math.min(page, pages)
const from = total ? skip + 1 : 0
const to = total ? skip + rows.length : 0
const currentPage = Math.min(Math.floor(skip / pageSize) + 1, pages)
useEffect(() => {
if (page > pages) setPage(pages)
}, [page, pages])
if (total <= 0 || skip < total) return
setSkip(Math.max(0, Math.floor((total - 1) / pageSize) * pageSize))
}, [total, pageSize, skip])
const recentChips = recentlyViewed
.slice(0, 6)
@ -426,15 +427,15 @@ export default function Candidates() {
</table>
</div>
<Pagination
from={total ? (currentPage - 1) * pageSize + 1 : 0}
to={total ? (currentPage - 1) * pageSize + rows.length : 0}
from={from}
to={to}
total={total}
page={currentPage}
pages={pages}
setPage={setPage}
setPage={(p) => setSkip((p - 1) * pageSize)}
pageButtons={pageWindow(currentPage, pages)}
pageSize={pageSize}
onPageSizeChange={(n) => { setPageSize(n); setPage((p) => pageAfterSizeChange(p, total, n)) }}
onPageSizeChange={(n) => setPageSize(n)}
pageSizeMax={500}
/>
</div>

View File

@ -14,7 +14,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import OpenResumeButton from '../ui/OpenResumeButton'
import PageHeader from '../ui/PageHeader'
import { Tabs } from '../ui/Tabs'
import { DEFAULT_PAGE_SIZE, Pagination, pageAfterSizeChange, pageWindow } from '../ui/DataTable'
import { DEFAULT_PAGE_SIZE, Pagination, pageWindow } from '../ui/DataTable'
import { Avatar, Badge, EmptyState, Icon } from '../ui/primitives'
import { JobCard, PickRoleModal } from '../ui/SuggestedRoles'
import { useToast } from '../ui/Toast'
@ -109,7 +109,7 @@ export default function Matching() {
const deepLink = searchParams.get('record')
const [tab, setTab] = useState('needs')
const [page, setPage] = useState(1)
const [skip, setSkip] = useState(0)
const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE)
const [selectedId, setSelectedId] = useState(deepLink || null)
const [q, setQ] = useState('')
@ -121,9 +121,9 @@ export default function Matching() {
const listParams = useMemo(() => ({
...tabFilter,
top: pageSize,
skip: (page - 1) * pageSize,
skip,
...(q.trim() ? { search: q.trim() } : {}),
}), [tabFilter, page, pageSize, q])
}), [tabFilter, skip, pageSize, q])
const listQuery = useQuery({
queryKey: qk.candidates.matching({ ...listParams, tab }),
@ -147,11 +147,14 @@ export default function Matching() {
const filtered = rows
const total = listQuery.data?.total ?? 0
const pages = Math.max(1, Math.ceil(total / pageSize))
const currentPage = Math.min(page, pages)
const from = total ? skip + 1 : 0
const to = Math.min(skip + pageSize, total)
const currentPage = Math.min(Math.floor(skip / pageSize) + 1, pages)
useEffect(() => {
if (listQuery.isSuccess && page > pages) setPage(pages)
}, [listQuery.isSuccess, page, pages])
if (!listQuery.isSuccess || total <= 0 || skip < total) return
setSkip(Math.max(0, Math.floor((total - 1) / pageSize) * pageSize))
}, [listQuery.isSuccess, total, pageSize, skip])
useEffect(() => {
if (!deepLink) return undefined
@ -284,7 +287,7 @@ export default function Matching() {
<div style={{ padding: '0 8px', borderBottom: '1px solid var(--border)' }}>
<Tabs
value={tab}
onChange={(t) => { setTab(t); setPage(1); setSelectedId(null) }}
onChange={(t) => { setTab(t); setSkip(0); setSelectedId(null) }}
className="tabs tabs-wrap"
tabs={TABS.map((t) => ({
key: t.key,
@ -301,7 +304,7 @@ export default function Matching() {
<Icon name="search" />
<input
value={q}
onChange={(e) => { setQ(e.target.value); setPage(1) }}
onChange={(e) => { setQ(e.target.value); setSkip(0) }}
placeholder="Search…"
/>
</div>
@ -342,18 +345,17 @@ export default function Matching() {
</div>
{listQuery.isSuccess && total > 0 && (
<Pagination
from={total ? (currentPage - 1) * pageSize + 1 : 0}
to={Math.min(currentPage * pageSize, total)}
from={from}
to={to}
total={total}
page={currentPage}
pages={pages}
setPage={(p) => { setPage(p); setSelectedId(null) }}
setPage={(p) => { setSkip((p - 1) * pageSize); setSelectedId(null) }}
pageButtons={pageWindow(currentPage, pages)}
pageSize={pageSize}
pageSizeMax={PAGE_SIZE_MAX}
onPageSizeChange={(n) => {
setPageSize(n)
setPage((p) => pageAfterSizeChange(p, total, n))
setSelectedId(null)
}}
/>