import { useEffect, useMemo, useState } from 'react' import { useLocation, useNavigate } from 'react-router-dom' import { useMutation, useQuery } from '@tanstack/react-query' import Modal from '../ui/Modal' import { DEFAULT_PAGE_SIZE, Pagination, pageAfterSizeChange, pageWindow } from '../ui/DataTable' import PageHeader from '../ui/PageHeader' import { Avatar, Badge, EmptyState, Icon, SkeletonRows } from '../ui/primitives' import { useToast } from '../ui/Toast' import { useAuth } from '../auth/AuthContext' import { qk } from '../lib/queryKeys' import { friendlyAuthError } from '../lib/errors' import * as usersApi from '../api/users' import * as jobsApi from '../api/jobs' import * as inboxApi from '../api/inbox' const PAGE_SIZE_MAX = 500 /** Seeded `hiring_manager` role (backend/role/models.py::EnumRoles). */ const HIRING_MANAGER_ROLE_ID = 4 async function fetchManagers({ top = DEFAULT_PAGE_SIZE, skip = 0 } = {}) { const res = await usersApi.list({ roleId: HIRING_MANAGER_ROLE_ID, top, skip }) const rows = Array.isArray(res?.data) ? res.data : [] return { rows: rows.map(usersApi.toManagerView), total: typeof res?.total === 'number' ? res.total : 0, } } async function fetchJobs() { // Keep within GET /jobs/fetch `top` ceiling (and match Jobs.jsx) so a shared // qk.jobs.list() cache entry is never poisoned by a 422 from top=200. const res = await jobsApi.list({ top: 100 }) const rows = Array.isArray(res?.data) ? res.data : [] return rows.map(jobsApi.toJobView) } export default function Managers() { const { toast } = useToast() const { can } = useAuth() const navigate = useNavigate() const location = useLocation() const [page, setPage] = useState(1) const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE) const [detail, setDetail] = useState(null) const skip = (page - 1) * pageSize const managersQuery = useQuery({ queryKey: qk.managers.list({ roleId: HIRING_MANAGER_ROLE_ID, top: pageSize, skip }), queryFn: () => fetchManagers({ top: pageSize, skip }), }) const jobsQuery = useQuery({ queryKey: qk.jobs.list(), queryFn: fetchJobs }) const managers = managersQuery.data?.rows ?? [] const total = managersQuery.data?.total ?? 0 const jobs = jobsQuery.data ?? [] const openByManager = useMemo(() => { const map = {} for (const j of jobs) { if (j.hiringManagerId && j.status === 'Open') { const key = String(j.hiringManagerId) map[key] = (map[key] || 0) + 1 } } return map }, [jobs]) const totalReqs = jobs.filter((j) => j.status === 'Open').length const pages = Math.max(1, Math.ceil(total / pageSize)) const currentPage = Math.min(page, pages) useEffect(() => { if (page > pages) setPage(pages) }, [page, pages]) useEffect(() => { const id = location.state?.openManager if (id) setDetail(managers.find((m) => m.id === id) ?? null) }, [location.state, managers]) return (
Loading requisitions…
) : openMine.length === 0 ? (No open requisitions for this manager
) : ( openMine.slice(0, 8).map((j) => (