All files / src/contexts AIStatusContext.tsx

80% Statements 24/30
50% Branches 3/6
71.42% Functions 5/7
77.77% Lines 21/27

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110                          5x                   5x       6x               9x             9x   9x                                               9x 5x 5x 5x 5x 3x 3x                 1x 1x 1x                 4x     5x   5x 5x     9x            
import { createContext, useContext, useState, useEffect, useCallback, ReactNode } from 'react'
import { api, AIStatus } from '../api/client'
 
interface AIStatusContextType {
  available: boolean
  configured: boolean
  valid: boolean
  error: string | null
  errorCode: string | null
  loading: boolean
  refresh: () => Promise<void>
}
 
const defaultStatus: AIStatusContextType = {
  available: false,
  configured: false,
  valid: false,
  error: null,
  errorCode: null,
  loading: true,
  refresh: async () => {},
}
 
const AIStatusContext = createContext<AIStatusContextType>(defaultStatus)
 
// eslint-disable-next-line react-refresh/only-export-components -- Hook is tightly coupled to provider
export function useAIStatus() {
  return useContext(AIStatusContext)
}
 
interface AIStatusProviderProps {
  children: ReactNode
}
 
export function AIStatusProvider({ children }: AIStatusProviderProps) {
  const [status, setStatus] = useState<Omit<AIStatusContextType, 'refresh' | 'loading'>>({
    available: false,
    configured: false,
    valid: false,
    error: null,
    errorCode: null,
  })
  const [loading, setLoading] = useState(true)
 
  const refresh = useCallback(async () => {
    try {
      const data: AIStatus = await api.ai.status()
      setStatus({
        available: data.available,
        configured: data.configured,
        valid: data.valid,
        error: data.error,
        errorCode: data.error_code,
      })
    } catch (error) {
      console.error('Failed to fetch AI status:', error)
      setStatus({
        available: false,
        configured: false,
        valid: false,
        error: 'Failed to check AI availability',
        errorCode: 'connection_error',
      })
    } finally {
      setLoading(false)
    }
  }, [])
 
  useEffect(() => {
    let cancelled = false
    const doRefresh = async () => {
      try {
        const data: AIStatus = await api.ai.status()
        Eif (!cancelled) {
          setStatus({
            available: data.available,
            configured: data.configured,
            valid: data.valid,
            error: data.error,
            errorCode: data.error_code,
          })
        }
      } catch (error) {
        Eif (!cancelled) {
          console.error('Failed to fetch AI status:', error)
          setStatus({
            available: false,
            configured: false,
            valid: false,
            error: 'Failed to check AI availability',
            errorCode: 'connection_error',
          })
        }
      } finally {
        Eif (!cancelled) setLoading(false)
      }
    }
    doRefresh()
    // Refresh every 5 minutes
    const interval = setInterval(doRefresh, 5 * 60 * 1000)
    return () => { cancelled = true; clearInterval(interval) }
  }, [])
 
  return (
    <AIStatusContext.Provider value={{ ...status, loading, refresh }}>
      {children}
    </AIStatusContext.Provider>
  )
}
 
← Back to Dashboard