import { useCallback, useEffect, useRef, useState } from 'react'; import { AssessorApiClient } from '../../api/assessor-api-client'; import type { AssessmentProject } from '../../domain/canonical-model'; import type { DatahubReferenceReadiness } from './datahub-processing-readiness'; const api = new AssessorApiClient(); /** Load only status summaries, with bounded concurrency and no background polling. */ export function useReferenceRecognitionStatus(projects: AssessmentProject[], connected: boolean, refreshKey: number) { const [states, setStates] = useState>({}); const pending = useRef(new Map()); const reportStatus = useCallback((projectId: string, state: DatahubReferenceReadiness) => { // A panel result must win over an older overview request for the same client. pending.current.delete(projectId); setStates(current => ({ ...current, [projectId]: state })); }, []); useEffect(() => { let cancelled = false; let next = 0; pending.current.clear(); const queue = connected ? projects.map(project => ({ ...project, token: Symbol() })) : []; for (const project of queue) pending.current.set(project.id, project.token); setStates(Object.fromEntries(queue.map(project => [project.id, { state: 'checking' }]))); const loadNext = async () => { while (!cancelled && next < queue.length) { const { id: projectId, token } = queue[next++]; if (pending.current.get(projectId) !== token) continue; let state: DatahubReferenceReadiness; try { state = { state: 'ready', status: await api.getReferenceRecognitionStatus(projectId) }; } catch { state = { state: 'unavailable' }; } if (!cancelled && pending.current.get(projectId) === token) { pending.current.delete(projectId); setStates(current => ({ ...current, [projectId]: state })); } } }; for (let worker = 0; worker < Math.min(3, queue.length); worker++) void loadNext(); return () => { cancelled = true; }; }, [projects, connected, refreshKey]); return { states, reportStatus }; }