/** * useAnalysis — start an analysis + poll status until terminal. * * Contract lives in infinith-api/docs/API_CONTRACT.md §2-3. * Replace `any` with generated types from `src/api-types/schema.d.ts` * once backend `openapi.json` is stable. */ import { useEffect, useRef, useState } from 'react' import { apiClient } from '@/lib/apiClient' type Status = 'pending' | 'discovering' | 'collecting' | 'generating' | 'complete' | 'partial' | 'error' interface StatusResponse { analysis_run_id: string status: Status progress: number current_step: string channel_errors: Record completed_at: string | null } interface ChannelHandles { youtube?: string instagram?: string[] facebook?: string naver_blog?: string gangnam_unni?: string } const TERMINAL: Status[] = ['complete', 'partial', 'error'] export function useAnalysis() { const [status, setStatus] = useState(null) const [error, setError] = useState(null) const pollerRef = useRef(null) useEffect( () => () => { if (pollerRef.current) window.clearInterval(pollerRef.current) }, [], ) async function start(input: { clinic_id?: string; url?: string; channels: ChannelHandles }) { try { const { data } = await apiClient.post('/api/analyses', input) pollStatus(data.analysis_run_id) return data.analysis_run_id as string } catch (err) { setError(err as Error) throw err } } function pollStatus(runId: string) { if (pollerRef.current) window.clearInterval(pollerRef.current) pollerRef.current = window.setInterval(async () => { try { const { data } = await apiClient.get(`/api/analyses/${runId}/status`) setStatus(data) if (TERMINAL.includes(data.status) && pollerRef.current) { window.clearInterval(pollerRef.current) pollerRef.current = null } } catch (err) { setError(err as Error) if (pollerRef.current) { window.clearInterval(pollerRef.current) pollerRef.current = null } } }, 2000) } return { start, pollStatus, status, error } }