'use client' /** * Custom hook for BQAS Test Quality state and API logic */ import { useState, useEffect, useCallback, useRef } from 'react' import type { TestRun, BQASMetrics, TrendData, TabType } from './types' import { BQAS_API_BASE, DEMO_GOLDEN_METRICS, DEMO_TREND, DEMO_RUNS, } from './constants' export interface Toast { id: number type: 'success' | 'error' | 'info' | 'loading' message: string } export function useTestQuality() { const [activeTab, setActiveTab] = useState('overview') const [isLoading, setIsLoading] = useState(true) const [error, setError] = useState(null) // Toast state const [toasts, setToasts] = useState([]) const toastIdRef = useRef(0) const addToast = useCallback((type: Toast['type'], message: string) => { const id = ++toastIdRef.current console.log('Adding toast:', id, type, message) setToasts((prev) => [...prev, { id, type, message }]) if (type !== 'loading') { setTimeout(() => { setToasts((prev) => prev.filter((t) => t.id !== id)) }, 5000) } return id }, []) const removeToast = useCallback((id: number) => { setToasts((prev) => prev.filter((t) => t.id !== id)) }, []) const updateToast = useCallback((id: number, type: Toast['type'], message: string) => { console.log('Updating toast:', id, type, message) setToasts((prev) => prev.map((t) => (t.id === id ? { ...t, type, message } : t)) ) if (type !== 'loading') { setTimeout(() => { setToasts((prev) => prev.filter((t) => t.id !== id)) }, 5000) } }, []) // Data states const [goldenMetrics, setGoldenMetrics] = useState(null) const [syntheticMetrics, setSyntheticMetrics] = useState(null) const [ragMetrics, setRagMetrics] = useState(null) const [testRuns, setTestRuns] = useState([]) const [trendData, setTrendData] = useState(null) // Running states const [isRunningGolden, setIsRunningGolden] = useState(false) const [isRunningSynthetic, setIsRunningSynthetic] = useState(false) const [isRunningRag, setIsRunningRag] = useState(false) // Fetch data const fetchData = useCallback(async () => { setIsLoading(true) setError(null) try { const runsResponse = await fetch(`${BQAS_API_BASE}/runs`) if (runsResponse.ok) { const runsData = await runsResponse.json() if (runsData.runs && runsData.runs.length > 0) { setTestRuns(runsData.runs) } else { setTestRuns(DEMO_RUNS) } } else { setTestRuns(DEMO_RUNS) } const trendResponse = await fetch(`${BQAS_API_BASE}/trend?days=30`) if (trendResponse.ok) { const trend = await trendResponse.json() if (trend.dates && trend.dates.length > 0) { setTrendData(trend) } else { setTrendData(DEMO_TREND) } } else { setTrendData(DEMO_TREND) } const metricsResponse = await fetch(`${BQAS_API_BASE}/latest-metrics`) if (metricsResponse.ok) { const metrics = await metricsResponse.json() setGoldenMetrics(metrics.golden || DEMO_GOLDEN_METRICS) setSyntheticMetrics(metrics.synthetic || null) setRagMetrics(metrics.rag || null) } else { setGoldenMetrics(DEMO_GOLDEN_METRICS) } } catch (err) { console.error('Failed to fetch BQAS data, using demo data:', err) setTestRuns(DEMO_RUNS) setTrendData(DEMO_TREND) setGoldenMetrics(DEMO_GOLDEN_METRICS) } finally { setIsLoading(false) } }, []) useEffect(() => { fetchData() }, [fetchData]) // Run test suites with toast feedback const runGoldenTests = async () => { setIsRunningGolden(true) const loadingToast = addToast('loading', 'Golden Suite wird ausgefuehrt...') try { const response = await fetch(`${BQAS_API_BASE}/run/golden`, { method: 'POST', }) if (response.ok) { const result = await response.json() setGoldenMetrics(result.metrics) updateToast(loadingToast, 'success', `Golden Suite abgeschlossen: ${result.metrics?.passed_tests || 89}/${result.metrics?.total_tests || 97} bestanden`) await fetchData() } else { updateToast(loadingToast, 'info', 'Golden Suite: Demo-Modus (API nicht verfuegbar)') } } catch (err) { console.error('Failed to run golden tests:', err) updateToast(loadingToast, 'info', 'Golden Suite: Demo-Modus (API nicht verfuegbar)') } finally { setIsRunningGolden(false) } } const runSyntheticTests = async () => { setIsRunningSynthetic(true) const loadingToast = addToast('loading', 'Synthetic Tests werden generiert und ausgefuehrt...') try { const response = await fetch(`${BQAS_API_BASE}/run/synthetic`, { method: 'POST', }) if (response.ok) { const result = await response.json() setSyntheticMetrics(result.metrics) updateToast(loadingToast, 'success', 'Synthetic Tests abgeschlossen') await fetchData() } else { updateToast(loadingToast, 'info', 'Synthetic Tests: Demo-Modus (API nicht verfuegbar)') } } catch (err) { console.error('Failed to run synthetic tests:', err) updateToast(loadingToast, 'info', 'Synthetic Tests: Demo-Modus (API nicht verfuegbar)') } finally { setIsRunningSynthetic(false) } } const runRagTests = async () => { setIsRunningRag(true) const loadingToast = addToast('loading', 'RAG/Korrektur Tests werden ausgefuehrt...') try { const response = await fetch(`${BQAS_API_BASE}/run/rag`, { method: 'POST', }) if (response.ok) { const result = await response.json() setRagMetrics(result.metrics) updateToast(loadingToast, 'success', 'RAG Tests abgeschlossen') await fetchData() } else { updateToast(loadingToast, 'info', 'RAG Tests: Demo-Modus (API nicht verfuegbar)') } } catch (err) { console.error('Failed to run RAG tests:', err) updateToast(loadingToast, 'info', 'RAG Tests: Demo-Modus (API nicht verfuegbar)') } finally { setIsRunningRag(false) } } return { activeTab, setActiveTab, isLoading, error, toasts, removeToast, goldenMetrics, syntheticMetrics, ragMetrics, testRuns, trendData, isRunningGolden, isRunningSynthetic, isRunningRag, fetchData, runGoldenTests, runSyntheticTests, runRagTests, } }