import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { api } from './api' import type { OpportunityFilters, SaveCandidateRequest } from './types' export function useCandidates() { return useQuery({ queryKey: ['candidates'], queryFn: api.candidates }) } export function useRequirements() { return useQuery({ queryKey: ['requirements'], queryFn: api.requirements }) } // Single candidate or requirement by id, so a deep linked evaluation resolves the row directly instead // of scanning the first list page (which silently rendered blank when the row was paged out). export function useCandidate(id: string | null) { return useQuery({ queryKey: ['candidate', id], queryFn: () => api.candidate(id as string), enabled: !!id, }) } export function useRequirement(id: string | null) { return useQuery({ queryKey: ['requirement', id], queryFn: () => api.requirement(id as string), enabled: !!id, }) } export function useOpportunities(candidateId: string | null) { return useQuery({ queryKey: ['opportunities', candidateId], queryFn: () => api.opportunities(candidateId as string), enabled: !!candidateId, }) } export function useRankedCandidates(requirementId: string | null) { return useQuery({ queryKey: ['ranked', requirementId], queryFn: () => api.rankCandidates(requirementId as string), enabled: !!requirementId, }) } // The Command Center, candidate intelligence, and adopt forecast moved to the missionMATCH tool module // (tools/missionmatch), which calls its own /api/missionmatch namespace client. export function useSamOpportunities(filters: OpportunityFilters) { return useQuery({ queryKey: ['sam-opportunities', filters], queryFn: () => api.samOpportunities(filters), }) } export function useIncumbents(naics: string | null) { return useQuery({ queryKey: ['incumbents', naics], queryFn: () => api.incumbents(naics as string), enabled: !!naics, }) } export function useGalapagosAwards() { return useQuery({ queryKey: ['galapagos-awards'], queryFn: api.galapagosAwards }) } export function useWages() { return useQuery({ queryKey: ['wages'], queryFn: api.wages }) } export function useExternalCandidates() { return useQuery({ queryKey: ['external-candidates'], queryFn: api.externalCandidates }) } export function useDeleteExternalCandidate() { const qc = useQueryClient() return useMutation({ mutationFn: (id: string) => api.deleteExternalCandidate(id), onSuccess: () => { qc.invalidateQueries({ queryKey: ['external-candidates'] }) qc.invalidateQueries({ queryKey: ['candidate-intelligence'] }) }, }) } export function useScreen() { return useMutation({ mutationFn: (v: { candidateId: string; requirementId: string }) => api.screen(v.candidateId, v.requirementId), }) } // Mission Check (W1) mutations. Nothing is cached on the scoring paths because nothing is stored; the // resume text is passed in and the result is shown once. Save Candidate invalidates the candidate lists. export function useMissionCheckOpportunities() { return useMutation({ mutationFn: (v: { text: string; limit?: number }) => api.missionCheckOpportunities(v.text, v.limit), }) } export function useMissionCheckJD() { return useMutation({ mutationFn: (v: { resume: string; jd: string }) => api.missionCheckJD(v.resume, v.jd), }) } export function useSaveCandidate() { const qc = useQueryClient() return useMutation({ mutationFn: (v: SaveCandidateRequest) => api.saveCandidate(v), onSuccess: () => { qc.invalidateQueries({ queryKey: ['candidates'] }) qc.invalidateQueries({ queryKey: ['candidate-intelligence'] }) }, }) } // Slate generation and the human in the loop decision moved to the slateMATCH tool module // (tools/slatematch), which calls its own /api/slatematch namespace client and sends the reviewer note. // useAdverseImpact loads the four fifths adverse impact report (compliance role only). export function useAdverseImpact() { return useQuery({ queryKey: ['adverse-impact'], queryFn: api.adverseImpact, retry: false }) }