import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { api } from './api' import type { AdoptForecastInput, OpportunityFilters, SaveCandidateRequest } from './types' export function useCandidates() { return useQuery({ queryKey: ['candidates'], queryFn: api.candidates }) } export function useCandidateIntelligence() { return useQuery({ queryKey: ['candidate-intelligence'], queryFn: () => api.candidateIntelligence() }) } 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, }) } export function useCommandCenter() { return useQuery({ queryKey: ['command-center'], queryFn: api.commandCenter }) } // useAdoptForecast turns a forecast into a requirement, then refreshes the dashboard so the new // requirement flows through the shared engine into coverage and readiness. export function useAdoptForecast() { const qc = useQueryClient() return useMutation({ mutationFn: ({ recordID, input }: { recordID: string; input: AdoptForecastInput }) => api.adoptForecast(recordID, input), onSuccess: () => qc.invalidateQueries({ queryKey: ['command-center'] }), }) } 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'] }) }, }) } export function useGenerateSlate() { return useMutation({ mutationFn: (v: { requirementId: string; name: string }) => api.generateSlate(v.requirementId, v.name), }) } // useDecideSlateMember records the human in the loop approve or reject on a slate member. export function useDecideSlateMember() { return useMutation({ mutationFn: (v: { slateId: string; candidateId: string; decision: 'approved' | 'rejected' }) => api.decideSlateMember(v.slateId, v.candidateId, v.decision), }) } // useAdverseImpact loads the four fifths adverse impact report (compliance role only). export function useAdverseImpact() { return useQuery({ queryKey: ['adverse-impact'], queryFn: api.adverseImpact, retry: false }) }