/* ============================================================ jobStats.js — per-job pipeline stage counts (GET /job/stats/fetch). Live aggregation over inbox + manual upload + unpromoted sheet rows, deduped by email. Needs jobs.view or pipeline.view. ============================================================ */ import { request } from '../lib/apiClient' import { toDate } from '../lib/format' import { REQUISITION_STATUSES } from './jobs' const REQ_STATUS_LABEL = Object.fromEntries(REQUISITION_STATUSES.map((s) => [s.value, s.label])) /** * List or single-job stage counts. * Omit jobPostId for a paged list; pass jobPostId for one object. */ export function list({ jobPostId, search, ids, top, skip, activeOnly } = {}) { return request('/job/stats/fetch', { params: { job_post_id: jobPostId, search, ids: Array.isArray(ids) ? ids.join(',') : ids, top, skip, active_only: activeOnly, }, }) } /** Whole days from created_at to the browser clock. Null if timestamp missing. */ export function daysOpen(createdAt, now = Date.now()) { if (!createdAt) return null const start = toDate(createdAt)?.getTime() if (!Number.isFinite(start)) return null return Math.max(0, Math.floor((now - start) / 86_400_000)) } /** API row -> what Progress cards and the table render. */ export function toJobStatsView(row) { const createdAt = row.created_at || null return { id: row.job_post_id, title: row.title || 'Untitled role', department: row.department || null, location: row.location || null, status: REQ_STATUS_LABEL[row.requisition_status] ?? row.requisition_status ?? '—', requisitionStatus: row.requisition_status, recruiterId: row.current_recruiter_id || null, recruiterName: row.recruiter_name || null, createdAt, daysOpen: daysOpen(createdAt), total: Number(row.total_applicants) || 0, shortlist: Number(row.shortlisting) || 0, screened: Number(row.screened) || 0, assessment: Number(row.assessment) || 0, interviewed: Number(row.interviewed) || 0, offered: Number(row.offered) || 0, onHold: Number(row.on_hold) || 0, rejected: Number(row.rejected) || 0, approved: Number(row.approved) || 0, hired: Number(row.hired) || 0, reapplied: Number(row.reapplied) || 0, } }