import { useEffect, useState } from 'react' import { CheckCircle2, Compass, FileUp, Loader2, ScanSearch, UploadCloud } from 'lucide-react' import { Badge, Bar, Modal, Panel } from './ui' import { ScreeningResults } from './ScreeningResults' import { useMissionCheckJD, useMissionCheckOpportunities, useSaveCandidate } from '../lib/queries' import { bandColor, missionRecColor, num } from '../lib/format' import type { CandidateListView, ParsedCandidate, ParsedRequirement, RequirementListView, SaveCandidateRequest, } from '../lib/types' type Mode = 'opportunities' | 'jd' // MissionCheckModal is the W1 surface. It parses a resume to text in the browser (nothing is uploaded), // then scores it server side: Mode A against every open opportunity, Mode B against a pasted job // description. The result is advisory and a human decides; the optional Save Candidate persists a // reviewed, audited record. export function MissionCheckModal({ open, onClose }: { open: boolean; onClose: () => void }) { const [mode, setMode] = useState('opportunities') const [resumeText, setResumeText] = useState('') const [jdText, setJdText] = useState('') const [fileNote, setFileNote] = useState('') const [parseError, setParseError] = useState('') const [parsing, setParsing] = useState(false) const modeA = useMissionCheckOpportunities() const modeB = useMissionCheckJD() function close() { modeA.reset() modeB.reset() setResumeText('') setJdText('') setFileNote('') setParseError('') onClose() } async function onFile(file: File | undefined) { if (!file) return setParseError('') setFileNote('') setParsing(true) try { // Lazy load the PDF and DOCX parsers (about 1 MB) only when a file is actually parsed, so they // never weigh down the initial page load. const { extractResumeText } = await import('../lib/resume') const r = await extractResumeText(file) if (r.lowConfidence || r.text.trim() === '') { setParseError('That file had little or no selectable text. It may be a scan, so paste the resume text instead.') } else { setResumeText(r.text) setFileNote(`Parsed ${file.name} in memory as ${r.source.toUpperCase()}. The file was not uploaded or stored.`) } } catch (e) { setParseError(e instanceof Error && e.message ? e.message : 'Could not read that file. Paste the text instead.') } finally { setParsing(false) } } function run() { setParseError('') if (mode === 'opportunities') modeA.mutate({ text: resumeText }) else modeB.mutate({ resume: resumeText, jd: jdText }) } const pending = modeA.isPending || modeB.isPending const runError = (mode === 'opportunities' ? modeA.error : modeB.error) as Error | null const canRun = resumeText.trim() !== '' && (mode === 'jd' ? jdText.trim() !== '' : true) && !pending && !parsing return (

Score a resume against the mission. Parsed in your browser, nothing is uploaded or stored.

Parsed in memory, not stored
{/* mode tabs */}
setMode('opportunities')} label="Match all opportunities" /> setMode('jd')} label="Match a job description" />
{/* resume input */}