/** * useErrors - Sentry Error Data Hook * =================================== * Phase 10: Sentry + OpenClaw + UI 整合 (#41-44) * * 提供錯誤數據的 React Hook: * - 統計概覽 * - 問題列表 * - 趨勢數據 * * 建立: 2026-03-26 (台北時區) * 建立者: Claude Code (#44 Error UI) */ import { useState, useEffect, useCallback } from 'react' import { apiClient, type ErrorStatsResponse, type ErrorTrendResponse, type SentryIssue, } from '@/lib/api-client' // ============================================================================= // Types // ============================================================================= interface UseErrorsState { stats: ErrorStatsResponse | null issues: SentryIssue[] trends: ErrorTrendResponse | null loading: boolean error: string | null activePeriod: '24h' | '7d' | '30d' } interface UseErrorsReturn extends UseErrorsState { refetch: () => Promise setPeriod: (period: '24h' | '7d' | '30d') => void } // ============================================================================= // Hook // ============================================================================= export function useErrors(): UseErrorsReturn { const [state, setState] = useState({ stats: null, issues: [], trends: null, loading: true, error: null, activePeriod: '24h', }) const fetchData = useCallback(async (period: '24h' | '7d' | '30d' = '24h') => { setState((prev) => ({ ...prev, loading: true, error: null })) try { const [statsResult, issuesResult, trendsResult] = await Promise.allSettled([ apiClient.getErrorStats(), apiClient.listErrors({ limit: 10 }), apiClient.getErrorTrends(period), ]) setState((prev) => ({ ...prev, stats: statsResult.status === 'fulfilled' ? statsResult.value : null, issues: issuesResult.status === 'fulfilled' ? issuesResult.value.issues : [], trends: trendsResult.status === 'fulfilled' ? trendsResult.value : null, loading: false, error: null, activePeriod: period, })) } catch (err) { setState((prev) => ({ ...prev, loading: false, error: err instanceof Error ? err.message : 'Failed to fetch error data', })) } }, []) const setPeriod = useCallback((period: '24h' | '7d' | '30d') => { fetchData(period) }, [fetchData]) const refetch = useCallback(() => { return fetchData(state.activePeriod) }, [fetchData, state.activePeriod]) // Initial fetch useEffect(() => { fetchData('24h') }, [fetchData]) // Auto-refresh every 60 seconds useEffect(() => { const interval = setInterval(() => { fetchData(state.activePeriod) }, 60000) return () => clearInterval(interval) }, [fetchData, state.activePeriod]) return { ...state, refetch, setPeriod, } }