Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / frontend/src/tools/screenmatch/ScreeningQueue.tsx |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 720d47fae476b0d38477ae4401697d372b1ea2bc |
| Branch | feature/opportunity-to-outcome |
| Path or archive member | frontend/src/tools/screenmatch/ScreeningQueue.tsx |
| Original SHA-256 | ddb38f35da3a254a2d62ca15269fbdb117e7195c81b5d293f7adfdac120e5517 |
| Git blob SHA | 4d17f96d60fd2acecab11235419d17dd1727a52b |
| Reading-copy SHA-256 | ddb38f35da3a254a2d62ca15269fbdb117e7195c81b5d293f7adfdac120e5517 |
Every recorded occurrence
These 2 records contain identical original source bytes. Their paths and revisions remain part of the archive.
| Original record | Branch or archive | Revision / identifier | Original location |
|---|---|---|---|
| Janady13/missionmatch / frontend/src/tools/screenmatch/ScreeningQueue.tsx | feature/opportunity-to-outcome | 720d47fae476b0d38477ae4401697d372b1ea2bc | Open original |
| Janady13/missionmatch / frontend/src/tools/screenmatch/ScreeningQueue.tsx | feature/aioe-upgrade | 2178e7298d0e5d9af83afa12402fd587f0ba6ed8 | Open original |
Recovered source transcript
Download complete source text ↓228 lines · 9.8 KB
import { useEffect, useMemo, useState } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import { BookOpenText, ChevronRight, Columns3, ExternalLink, Info } from 'lucide-react'
import { useSamOpportunities } from '../../lib/queries'
import { useScreenRanked, useScreenRequirements } from './queries'
import { screenBrand } from './brand'
import type { OpportunityFilters, RequirementListView, SamOpportunity } from '../../lib/types'
import { Badge, Panel } from '../../components/ui'
import { ToolHeader } from '../../components/ToolHeader'
import { bandColor, clearanceLabel, fmtDate, GALAPAGOS, num } from '../../lib/format'
const selectCls =
'rounded-lg border border-line/70 bg-navy-900 px-3 py-2 text-sm text-ink outline-none focus:border-blue min-w-[24rem]'
// The screen flow opens on the relevant, non empty Galapagos slice: their NAICS with Air Force and
// Space Force as the customers. (The strict 8A plus HI, NM intersection is often empty in real data.)
const pickerFilters: OpportunityFilters = {
naics: [...GALAPAGOS.naics],
sub_agency: ['AIR FORCE', 'SPACE FORCE'],
active_only: true,
limit: 100,
}
// Map an opportunity to a representative demo requirement so the engine can score synthetic candidates
// with real, structured criteria. SAM notices don't carry structured clearance/skill specs, so this
// is an explicit, labeled demo bridge, not derived clearance.
const KEYWORDS: string[][] = [
['cyber', 'security', 'defensive', 'soc'],
['intel', 'sigint', 'analyst', 'intelligence'],
['data', 'machine learning', ' ai ', 'scientist'],
['cloud', 'devops', 'aws', 'azure'],
['software', 'developer', 'engineer', 'programming'],
['network', 'systems', 'infrastructure', 'architect'],
]
function pickRequirement(opp: SamOpportunity | undefined, reqs: RequirementListView[]): RequirementListView | null {
if (!reqs.length) return null
const t = (opp?.title ?? '').toLowerCase()
for (const words of KEYWORDS) {
if (words.some((w) => t.includes(w.trim()))) {
const match = reqs.find((r) => words.some((w) => r.title.toLowerCase().includes(w.trim())))
if (match) return match
}
}
return reqs[0]
}
function MiniRing({ value, color }: { value: number; color: string }) {
const r = 22
const c = 2 * Math.PI * r
return (
<div className="relative grid size-[58px] place-items-center">
<svg width="58" height="58" className="-rotate-90">
<circle cx="29" cy="29" r={r} fill="none" stroke="#13314f" strokeWidth="6" />
<circle
cx="29"
cy="29"
r={r}
fill="none"
stroke={color}
strokeWidth="6"
strokeLinecap="round"
strokeDasharray={c}
strokeDashoffset={c * (1 - value / 100)}
/>
</svg>
<span className="absolute text-[13px] font-bold tabular-nums">{value.toFixed(0)}</span>
</div>
)
}
export function ScreeningQueue() {
const opportunities = useSamOpportunities(pickerFilters)
const requirements = useScreenRequirements()
const [noticeId, setNoticeId] = useState('')
const [compareIds, setCompareIds] = useState<string[]>([])
const nav = useNavigate()
const toggleCompare = (id: string) => {
setCompareIds((prev) =>
prev.includes(id) ? prev.filter((x) => x !== id) : prev.length >= 3 ? prev : [...prev, id],
)
}
const opps = useMemo(() => opportunities.data ?? [], [opportunities.data])
useEffect(() => {
// Re-anchor to the first opportunity on initial load OR when a refetch drops the selected notice
// (otherwise the picker shows a blank selection) [review FE-2].
if (opps.length && (!noticeId || !opps.some((o) => o.notice_id === noticeId))) {
setNoticeId(opps[0].notice_id)
}
}, [opps, noticeId])
const selectedOpp = opps.find((o) => o.notice_id === noticeId)
const repReq = pickRequirement(selectedOpp, requirements.data ?? [])
const ranked = useScreenRanked(repReq?.id ?? null)
return (
<div className="space-y-4">
<ToolHeader name={screenBrand.name} tagline={screenBrand.tagline} accent={screenBrand.accent} />
<Panel className="space-y-3 p-4">
<label className="flex flex-col gap-1.5">
<span className="text-[11px] font-bold uppercase tracking-wider text-muted">
Screen against a live SAM.gov opportunity
</span>
<select className={selectCls} value={noticeId} onChange={(e) => setNoticeId(e.target.value)}>
{opps.length === 0 && <option value="">No cached opportunities, run the SAM sync</option>}
{opps.map((o) => (
<option key={o.notice_id} value={o.notice_id}>
{o.title || o.solicitation_number || o.notice_id}
{o.sub_agency ? ` · ${o.sub_agency}` : ''}
</option>
))}
</select>
</label>
{selectedOpp && (
<div className="flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-faint">
<span>
<span className="text-muted">Sol#</span> {selectedOpp.solicitation_number || 'n/a'}
</span>
<span>
<span className="text-muted">NAICS</span> {selectedOpp.naics_code || 'n/a'}
</span>
{selectedOpp.set_aside_code && (
<Badge color="var(--color-gold)" subtle>
{selectedOpp.set_aside_code}
</Badge>
)}
<span>
<span className="text-muted">Response due</span> {fmtDate(selectedOpp.response_deadline)}
</span>
{selectedOpp.ui_link && (
<a
href={selectedOpp.ui_link}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1 text-blue-soft hover:underline"
>
View on SAM.gov <ExternalLink size={11} />
</a>
)}
</div>
)}
{repReq && (
<p className="flex items-start gap-1.5 rounded-lg bg-navy-950/50 px-3 py-2 text-[11px] leading-relaxed text-faint">
<Info size={13} className="mt-0.5 shrink-0 text-blue-soft" />
<span>
Candidate scoring runs against a representative cleared role, <span className="text-muted">{repReq.title}</span>{' '}
(demo requirement). Clearance shown is a self reported or detected indicator, <span className="text-muted">not verified</span>.
Candidates are <span className="text-muted">Demo data</span>; opportunities are live from SAM.gov.
</span>
</p>
)}
</Panel>
<Panel
title="Candidate Screening Queue"
hint={`${ranked.data?.length ?? 0} candidates · ranked by Mission Readiness`}
>
<div className="mb-3 flex flex-wrap items-center gap-2">
<button
disabled={compareIds.length < 2 || !repReq}
onClick={() => repReq && nav(`/screen/compare?req=${repReq.id}&c=${compareIds.join(',')}`)}
className="flex items-center gap-1.5 rounded-lg border border-line/70 px-3 py-1.5 text-sm font-semibold text-muted hover:text-ink disabled:opacity-40"
>
<Columns3 size={14} /> Compare selected ({compareIds.length}/3)
</button>
<Link
to="/screen/aliases"
className="ml-auto flex items-center gap-1.5 rounded-lg border border-line/70 px-3 py-1.5 text-sm font-semibold text-muted hover:text-ink"
>
<BookOpenText size={14} /> Acronyms and terms
</Link>
</div>
{opps.length === 0 ? (
<p className="py-6 text-center text-muted">
No cached opportunities to screen against. Run the SAM sync to populate the feed.
</p>
) : ranked.isLoading ? (
<p className="py-6 text-center text-muted">Scoring candidates…</p>
) : (
<ul className="space-y-2">
{ranked.data?.map((c) => {
const color = bandColor(c.band)
return (
<li
key={c.candidate_id}
onClick={() => repReq && nav(`/screen/evaluate/${c.candidate_id}/${repReq.id}`)}
className="flex cursor-pointer items-center gap-4 rounded-xl border border-line/60 bg-surface/70 px-4 py-3 transition hover:border-screen/60 hover:bg-navy-800/50"
>
<input
type="checkbox"
checked={compareIds.includes(c.candidate_id)}
onChange={() => toggleCompare(c.candidate_id)}
onClick={(e) => e.stopPropagation()}
className="size-4 shrink-0 accent-[var(--color-blue)]"
aria-label={`Select ${c.full_name} for comparison`}
/>
<div className="grid size-11 shrink-0 place-items-center rounded-xl bg-screen/20 text-sm font-bold text-screen-soft">
{c.full_name
.split(' ')
.map((p) => p[0])
.slice(0, 2)
.join('')}
</div>
<div className="min-w-0 flex-1">
<div className="font-semibold">{c.full_name}</div>
<div className="text-xs text-muted">
{clearanceLabel[c.clearance_level] ?? c.clearance_level} (self reported) · {c.years_experience} yrs
{c.location ? ` · ${c.location}` : ''}
</div>
</div>
<Badge color={color} subtle>
{c.status}
</Badge>
<MiniRing value={num(c.score)} color={color} />
<ChevronRight size={18} className="text-faint" />
</li>
)
})}
</ul>
)}
</Panel>
</div>
)
}