import { useState } from 'react' import { ArrowLeft, Clock, PauseCircle, Target, UserCheck, UserMinus, UserPlus, Users } from 'lucide-react' import { Link, useParams } from 'react-router-dom' import { ToolHeader } from '../../components/ToolHeader' import { Modal, Panel } from '../../components/ui' import { useAuth } from '../../lib/useAuth' import { recruitBrand } from './brand' import { useChangeStatus, useClaimRequisition, useReleaseRequisition, useRequisition, } from './requisitionQueries' import { PRIORITY_LABEL, REQ_TRANSITIONS, STATUS_ACTION, STATUS_LABEL, priorityColor, rateRange, statusColor, targetText, } from './statusUi' const inputCls = 'w-full rounded-lg border border-line/70 bg-navy-900 px-3 py-2 text-sm text-ink outline-none focus:border-recruit' function Stat({ label, value, hint, icon }: { label: string; value: string; hint?: string; icon: React.ReactNode }) { return (

{icon} {label}

{value}

{hint &&

{hint}

}
) } export function RequisitionDetail() { const { reqId } = useParams() const { principal } = useAuth() const q = useRequisition(reqId ?? null) const change = useChangeStatus() const claim = useClaimRequisition() const release = useReleaseRequisition() const [pending, setPending] = useState(null) const [note, setNote] = useState('') if (q.isLoading) return Loading job order… if (q.isError || !q.data) { return ( Could not load this job order. {(q.error as Error)?.message} ) } const r = q.data const mine = !!r.owner_user_id && r.owner_user_id === principal?.user_id const canEdit = mine || !r.owner_user_id const t = targetText(r) const moves = REQ_TRANSITIONS[r.status] ?? [] const confirmMove = () => { if (!pending) return change.mutate( { id: r.id, expected_updated_at: r.updated_at, status: pending, note }, { onSuccess: () => { setPending(null) setNote('') }, }, ) } return (
All job orders Pipeline

{r.title} {STATUS_LABEL[r.status] ?? r.status}

{r.client_id ? ( {r.client_name} ) : ( 'No client' )} {r.hiring_manager_name ? ` · ${r.hiring_manager_name}` : ''} · {r.openings} opening {r.openings === 1 ? '' : 's'} · {r.employment_type.replace(/_/g, ' ')} · {PRIORITY_LABEL[r.priority]} priority

{r.owner_user_id ? ( <> {mine ? 'You are working this' : `Worked by ${r.owner_name}`} {mine && ( )} ) : ( )}
{!canEdit && (

{r.owner_name} is working this job order. Talk to them before changing it, or ask an admin to reassign it.

)} {/* The three clocks. Both the wall clock and the worked time are shown, because both are legitimate and the industry does not agree on which to report. Showing only one invites the question of what it excludes. */}
} /> } /> } /> } />
{(r.bill_rate_min || r.bill_rate_max || r.salary_min || r.salary_max) && (

{rateRange(r.bill_rate_min, r.bill_rate_max) && `Bill ${rateRange(r.bill_rate_min, r.bill_rate_max)}`} {r.pay_rate_min || r.pay_rate_max ? ` · Pay ${rateRange(r.pay_rate_min, r.pay_rate_max)}` : ''} {r.salary_min || r.salary_max ? ` · Salary ${rateRange(r.salary_min, r.salary_max, '')}` : ''}

)} {canEdit && moves.length > 0 && (
Move to {/* Only legal destinations are offered. The server refuses anything else regardless, so this is a convenience rather than the rule, but offering a button that always fails is worse than offering fewer buttons. */} {moves.map((m) => ( ))}
)} {r.description &&

{r.description}

}
{r.events.length === 0 ? (

No history yet.

) : (
    {[...r.events].reverse().map((e) => (
  1. {e.from_status ? `${STATUS_LABEL[e.from_status] ?? e.from_status} to ${STATUS_LABEL[e.to_status] ?? e.to_status}` : `Opened as ${STATUS_LABEL[e.to_status] ?? e.to_status}`} {e.from_status && e.days_in_from > 0 && ( after {e.days_in_from.toFixed(1)}d )}

    {e.note &&

    {e.note}

    }

    {new Date(e.occurred_at).toLocaleString()} {e.actor_user_name ? ` · ${e.actor_user_name}` : ''}

  2. ))}
)}
{ setPending(null) setNote('') }} title={pending ? (STATUS_ACTION[pending] ?? pending) : ''} >

This job order moves from {STATUS_LABEL[r.status] ?? r.status} to{' '} {pending ? (STATUS_LABEL[pending] ?? pending) : ''}.

{pending === 'on_hold' && (

Time on hold is subtracted from how long this order took to fill, so a client freeze does not count against the desk.

)}