import { useRef, useState } from 'react' import { Link, useParams } from 'react-router-dom' import { ArrowLeft, Clock, Download, FileUp, Hand, Mail, Paperclip, Send, ShieldCheck, Users, } from 'lucide-react' import { Badge, Modal, Panel } from '../components/ui' import { Empty, Labeled, Note, Select, btnGhost, btnPrimary, fieldCls } from '../components/form' import { CAP, can } from '../lib/can' import { useAuth } from '../lib/useAuth' import { useCandidate } from '../lib/queries' import { useOrgPolicy } from '../lib/settingsQueries' import { useAddToList, useCandidateDocuments, useCandidateMessages, useClaim, useLists, useListsForCandidate, useRelease, useRemoveFromList, useSendMessage, useSupersedeDocument, useTemplates, useWorkActivity, } from '../lib/workflowQueries' import { CLAIM_ACTIVITIES, uploadCandidateDocument, workflowApi } from '../lib/workflow' import { AEDT_DATA_CATEGORIES, useNoticeStatus, useRecordNotice, useSetAccess } from '../lib/governance' import { accessColor } from '../lib/workflow' // THE CANDIDATE RECORD. // // Everything the recruiter surfaces built this session hang off one person: who is working them, what has // been sent to them, what documents are held, and which lists they are on. Four screens would have meant four // places to look before making one phone call. // // OPENING THIS PAGE RECORDS THE VISIT. That is deliberate and it is the whole basis of the collision warning: // presence only means anything if arriving is what registers it. Asking somebody to press a button to say // they are looking at a record is asking them to do the thing the feature exists to avoid. const DOCUMENT_TYPES = [ { value: 'resume', label: 'Resume' }, { value: 'certification', label: 'Certification' }, { value: 'clearance', label: 'Clearance paperwork' }, { value: 'reference', label: 'Reference' }, { value: 'other', label: 'Other' }, ] export function CandidateRecord() { const { candidateId = '' } = useParams() const { principal } = useAuth() const candidate = useCandidate(candidateId || null) const mayWrite = can(principal, CAP.candidateWrite) if (candidate.isError) { return ( This record could not be opened. {(candidate.error as Error)?.message} {' '}It may have been merged into another record, or it may be outside what you can see. ) } const c = candidate.data return (
Back to find people

{c?.full_name ?? 'Loading'}

{c ? `${c.clearance_level} · ${c.clearance_status} · ${c.years_experience} years` : ''} {c?.location ? ` · ${c.location}` : ''}

{c?.available && ( available )}
{/* Stated once, where clearance appears, per the product rule. It is not a footnote: a customer FSO is the only thing that verifies a clearance and this product never claims to. */}

Clearance here is a self reported indicator, never a verified status. The real check is the hiring client FSO through DISS at onboarding.

) } // THE BREAK IN ACCESS CLOCK, which is the fact that decides whether a cleared person is placeable. // // Continuous vetting replaced periodic reinvestigation in October 2021, so the reinvestigation date this // product has always stored describes a world that no longer exists. What matters now is the break: separation // pulls somebody out of their sponsor's enrollment, and inside twenty four months a new sponsor can usually // reinstate on paperwork. Outside it, a new investigation is months of lead time. // // The dates come from a phone call. There is no import for them, which is why the write is here rather than // somewhere administrative. function AccessPanel({ candidateId, mayWrite }: { candidateId: string; mayWrite: boolean }) { const set = useSetAccess(candidateId) const [ended, setEnded] = useState('') const [adj, setAdj] = useState('') const intel = set.data return ( {intel ? (
{intel.label} {intel.detail}
) : ( Record when this person was last in access and when their adjudication closed, and their reinstatement position is worked out from there. Without those dates it cannot be known, which is a gap in the record rather than a problem with the candidate. )} {mayWrite && (
setEnded(e.target.value)} className={fieldCls} /> setAdj(e.target.value)} className={fieldCls} />
)} {set.isError && (
{(set.error as Error).message}
)}

An indicator worked out from dates you entered, never an eligibility determination. The real check is the hiring client FSO through DISS.

) } // THE AUTOMATED DECISION NOTICE. // // This product scores people with an automated employment decision tool. Several jurisdictions require the // person to be told BEFORE that happens, to be told what is assessed, and require the employer to be able to // prove it: New York City Local Law 144 puts a ten business day floor on the notice, and the EU AI Act treats // hiring as high risk from August 2026. // // THE ROUTE TO RECORD ONE HAS EXISTED SINCE THE GOVERNANCE MODULE SHIPPED AND NOTHING CALLED IT. Production // carried three scored candidates and zero notices. This panel is the missing half: it asks whether a notice // exists, says so plainly when one does not, and records one in a click. function NoticePanel({ candidateId, mayWrite }: { candidateId: string; mayWrite: boolean }) { const status = useNoticeStatus(candidateId) const record = useRecordNotice(candidateId) const policy = useOrgPolicy() const s = status.data if (!s) return null const required = policy.data?.aedt_notice_required ?? false return ( {s.on_file ? ( <> Disclosed {s.disclosed_at ? new Date(s.disclosed_at).toLocaleDateString() : ''} {s.notice_version ? `, version ${s.notice_version}` : ''} {s.count > 1 ? `. ${s.count} notices on file, the newest is shown.` : '.'} {s.data_categories && s.data_categories.length > 0 && (

They were told this tool assesses: {s.data_categories.join(', ')}.

)} ) : ( No notice has been given to this person.{' '} {required ? 'Your organization requires one before scoring, so this candidate cannot be scored until it is recorded.' : 'Several jurisdictions require a candidate to be told before an automated tool assesses them, and to be able to prove it.'} )} {mayWrite && (
{/* The categories are named ON the button's own screen rather than hidden behind it, because what is being attested to is that the person was told THESE things. */}

Records that this person was told the tool assesses {AEDT_DATA_CATEGORIES.join(', ')}. It does not send anything: delivering the notice is yours, this is the evidence that you did.

{record.isError && (
{(record.error as Error).message}
)}
)}
) } // WorkPanel is the double work warning: who has this record claimed, and who else has been looking at it. function WorkPanel({ candidateId, mayWrite }: { candidateId: string; mayWrite: boolean }) { const activity = useWorkActivity('candidate', candidateId) const claim = useClaim() const release = useRelease() const { principal } = useAuth() const [why, setWhy] = useState('working') const [note, setNote] = useState('') const a = activity.data if (!a) return null // A record the caller is not allowed to see the activity on says so rather than rendering an empty panel // that reads as nobody working it, which is the one wrong answer this feature must never give. if (!a.visible_to_you) { return ( Your organization does not show recruiters each other's work. Your manager can see whether somebody else is on this record. ) } const held = a.claim const mine = held?.mine ?? false const others = a.touches.filter((t) => !t.mine) return ( {held ? (
{mine ? 'You have this record' : `${held.user_name} has this record`} {held.activity ? `, ${held.activity}` : ''} {held.note && {held.note}} until {new Date(held.expires_at).toLocaleString()} {mayWrite && mine && ( )} {/* TAKING A RECORD OFF A COLLEAGUE IS POSSIBLE AND IS NEVER QUIET. A desk has to be able to move on a deadline day, so this is not a block; it is a deliberate act with the other person named. */} {mayWrite && !mine && ( )}
) : ( mayWrite && (
{ e.preventDefault() claim.mutate({ type: 'candidate', id: candidateId, activity: why, note: note.trim() }) }} > setNote(e.target.value)} className={`${fieldCls} max-w-xs`} /> ) )} {a.desk_owner_name && (

{a.desk_owner_user_id === principal?.user_id ? 'This record is on your desk.' : `${a.desk_owner_name} owns this record.`}

)} {others.length > 0 && (

Recently opened by {others.map((t) => t.user_name).join(', ')}.

)} {claim.isError && (
{(claim.error as Error).message}
)}
) } function DocumentsPanel({ candidateId, mayWrite }: { candidateId: string; mayWrite: boolean }) { const docs = useCandidateDocuments(candidateId) const supersede = useSupersedeDocument(candidateId) const fileRef = useRef(null) const [kind, setKind] = useState('resume') const [pct, setPct] = useState(null) const [err, setErr] = useState('') const list = docs.data?.documents ?? [] const current = list.filter((d) => d.is_current) const superseded = list.filter((d) => !d.is_current) const upload = async (file: File) => { setErr('') setPct(0) try { await uploadCandidateDocument(candidateId, file, kind, setPct) await docs.refetch() } catch (e) { setErr((e as Error).message) } finally { setPct(null) if (fileRef.current) fileRef.current.value = '' } } return ( {list.length === 0 ? ( ) : (
    {current.map((d) => (
  • {d.file_name} {d.document_type} · {formatBytes(d.size_bytes)} ·{' '} {new Date(d.created_at).toLocaleDateString()} {d.uploaded_by_name ? ` · ${d.uploaded_by_name}` : ''} {mayWrite && ( )}
  • ))}
)} {/* Superseded documents are KEPT and shown folded away rather than deleted. A resume from two years ago is the evidence of what was true when a past decision was made, which an automated employment decision tool has to be able to reconstruct. */} {superseded.length > 0 && (
{superseded.length === 1 ? '1 older version' : `${superseded.length} older versions`}
    {superseded.map((d) => (
  • {d.file_name} {new Date(d.created_at).toLocaleDateString()}
  • ))}
)} {mayWrite && (
{ const f = e.target.files?.[0] if (f) void upload(f) }} /> {pct !== null && ( {pct}% )}
)} {err && (
{err}
)}
) } function formatBytes(n: number): string { if (n < 1024) return `${n} B` if (n < 1024 * 1024) return `${Math.round(n / 1024)} KB` return `${(n / (1024 * 1024)).toFixed(1)} MB` } function ListsPanel({ candidateId, mayWrite }: { candidateId: string; mayWrite: boolean }) { const on = useListsForCandidate(candidateId) const all = useLists() const add = useAddToList() const remove = useRemoveFromList() const memberOf = on.data?.lists ?? [] const memberIDs = new Set(memberOf.map((l) => l.id)) const addable = (all.data?.lists ?? []).filter((l) => l.status === 'active' && !memberIDs.has(l.id)) return ( {memberOf.length === 0 ? ( ) : (
    {memberOf.map((l) => (
  • {l.purpose === 'do_not_contact' && ( do not contact )} {l.name} {mayWrite && ( )}
  • ))}
)} {mayWrite && addable.length > 0 && (
({ value: t.id, label: t.name })), ]} onChange={(v) => { setTemplateID(v) const t = candidateTemplates.find((x) => x.id === v) if (t) { setSubject(t.subject) setBody(t.body) } }} /> )} setSubject(e.target.value)} className={fieldCls} />