/** * React Hooks for AI Insights * * Provides React Query hooks for AI Insights API integration. * * Usage: * ```tsx * const { data: insights, isLoading } = useAIInsights(tenantId, { priority: 'high' }); * const { data: stats } = useAIInsightStats(tenantId); * const applyMutation = useApplyInsight(); * ``` * * Last Updated: 2025-11-03 * Status: ✅ Complete - React Query Integration */ import { useQuery, useMutation, useQueryClient, UseQueryOptions, UseMutationOptions } from '@tanstack/react-query'; import { useState } from 'react'; import { aiInsightsService, AIInsight, AIInsightFilters, AIInsightListResponse, AIInsightStatsResponse, FeedbackRequest, OrchestrationReadyInsightsRequest, OrchestrationReadyInsightsResponse, } from '../services/aiInsights'; // Query Keys export const aiInsightsKeys = { all: ['aiInsights'] as const, lists: () => [...aiInsightsKeys.all, 'list'] as const, list: (tenantId: string, filters?: AIInsightFilters) => [...aiInsightsKeys.lists(), tenantId, filters] as const, details: () => [...aiInsightsKeys.all, 'detail'] as const, detail: (tenantId: string, insightId: string) => [...aiInsightsKeys.details(), tenantId, insightId] as const, stats: (tenantId: string, filters?: any) => [...aiInsightsKeys.all, 'stats', tenantId, filters] as const, orchestration: (tenantId: string, targetDate: string) => [...aiInsightsKeys.all, 'orchestration', tenantId, targetDate] as const, dashboard: (tenantId: string) => [...aiInsightsKeys.all, 'dashboard', tenantId] as const, }; /** * Hook to get AI insights with filters */ export function useAIInsights( tenantId: string, filters?: AIInsightFilters, options?: Omit, 'queryKey' | 'queryFn'> ) { return useQuery({ queryKey: aiInsightsKeys.list(tenantId, filters), queryFn: () => aiInsightsService.getInsights(tenantId, filters), staleTime: 1000 * 60 * 2, // 2 minutes ...options, }); } /** * Hook to get a single AI insight */ export function useAIInsight( tenantId: string, insightId: string, options?: Omit, 'queryKey' | 'queryFn'> ) { return useQuery({ queryKey: aiInsightsKeys.detail(tenantId, insightId), queryFn: () => aiInsightsService.getInsight(tenantId, insightId), enabled: !!insightId, staleTime: 1000 * 60 * 5, // 5 minutes ...options, }); } /** * Hook to get AI insight statistics */ export function useAIInsightStats( tenantId: string, filters?: { start_date?: string; end_date?: string }, options?: Omit, 'queryKey' | 'queryFn'> ) { return useQuery({ queryKey: aiInsightsKeys.stats(tenantId, filters), queryFn: () => aiInsightsService.getInsightStats(tenantId, filters), staleTime: 1000 * 60 * 5, // 5 minutes ...options, }); } /** * Hook to get orchestration-ready insights */ export function useOrchestrationReadyInsights( tenantId: string, request: OrchestrationReadyInsightsRequest, options?: Omit, 'queryKey' | 'queryFn'> ) { return useQuery({ queryKey: aiInsightsKeys.orchestration(tenantId, request.target_date), queryFn: () => aiInsightsService.getOrchestrationReadyInsights(tenantId, request), enabled: !!request.target_date, staleTime: 1000 * 60 * 10, // 10 minutes ...options, }); } /** * Hook to get dashboard summary */ export function useAIInsightsDashboard( tenantId: string, options?: Omit, 'queryKey' | 'queryFn'> ) { return useQuery({ queryKey: aiInsightsKeys.dashboard(tenantId), queryFn: () => aiInsightsService.getDashboardSummary(tenantId), staleTime: 1000 * 60 * 2, // 2 minutes ...options, }); } /** * Hook to get high priority insights */ export function useHighPriorityInsights( tenantId: string, limit: number = 10, options?: Omit, 'queryKey' | 'queryFn'> ) { return useQuery({ queryKey: [...aiInsightsKeys.lists(), tenantId, 'highPriority', limit], queryFn: () => aiInsightsService.getHighPriorityInsights(tenantId, limit), staleTime: 1000 * 60 * 2, // 2 minutes ...options, }); } /** * Hook to get actionable insights */ export function useActionableInsights( tenantId: string, limit: number = 20, options?: Omit, 'queryKey' | 'queryFn'> ) { return useQuery({ queryKey: [...aiInsightsKeys.lists(), tenantId, 'actionable', limit], queryFn: () => aiInsightsService.getActionableInsights(tenantId, limit), staleTime: 1000 * 60 * 2, // 2 minutes ...options, }); } /** * Hook to get insights by category */ export function useInsightsByCategory( tenantId: string, category: string, limit: number = 20, options?: Omit, 'queryKey' | 'queryFn'> ) { return useQuery({ queryKey: [...aiInsightsKeys.lists(), tenantId, 'category', category, limit], queryFn: () => aiInsightsService.getInsightsByCategory(tenantId, category, limit), enabled: !!category, staleTime: 1000 * 60 * 2, // 2 minutes ...options, }); } /** * Hook to search insights */ export function useSearchInsights( tenantId: string, query: string, filters?: Partial, options?: Omit, 'queryKey' | 'queryFn'> ) { return useQuery({ queryKey: [...aiInsightsKeys.lists(), tenantId, 'search', query, filters], queryFn: () => aiInsightsService.searchInsights(tenantId, query, filters), enabled: query.length > 0, staleTime: 1000 * 30, // 30 seconds ...options, }); } /** * Mutation hook to apply an insight */ export function useApplyInsight( options?: UseMutationOptions ) { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ tenantId, insightId }: { tenantId: string; insightId: string }) => aiInsightsService.applyInsight(tenantId, insightId), onSuccess: (_, variables) => { // Invalidate all insight queries for this tenant queryClient.invalidateQueries({ queryKey: aiInsightsKeys.lists() }); queryClient.invalidateQueries({ queryKey: aiInsightsKeys.detail(variables.tenantId, variables.insightId) }); queryClient.invalidateQueries({ queryKey: aiInsightsKeys.stats(variables.tenantId) }); queryClient.invalidateQueries({ queryKey: aiInsightsKeys.dashboard(variables.tenantId) }); }, ...options, }); } /** * Mutation hook to dismiss an insight */ export function useDismissInsight( options?: UseMutationOptions ) { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ tenantId, insightId }) => aiInsightsService.dismissInsight(tenantId, insightId), onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: aiInsightsKeys.lists() }); queryClient.invalidateQueries({ queryKey: aiInsightsKeys.detail(variables.tenantId, variables.insightId) }); queryClient.invalidateQueries({ queryKey: aiInsightsKeys.stats(variables.tenantId) }); queryClient.invalidateQueries({ queryKey: aiInsightsKeys.dashboard(variables.tenantId) }); }, ...options, }); } /** * Mutation hook to update insight status */ export function useUpdateInsightStatus( options?: UseMutationOptions ) { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ tenantId, insightId, status }) => aiInsightsService.updateInsightStatus(tenantId, insightId, status), onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: aiInsightsKeys.lists() }); queryClient.invalidateQueries({ queryKey: aiInsightsKeys.detail(variables.tenantId, variables.insightId) }); queryClient.invalidateQueries({ queryKey: aiInsightsKeys.stats(variables.tenantId) }); queryClient.invalidateQueries({ queryKey: aiInsightsKeys.dashboard(variables.tenantId) }); }, ...options, }); } /** * Mutation hook to record feedback for an insight */ export function useRecordFeedback( options?: UseMutationOptions ) { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ tenantId, insightId, feedback }) => aiInsightsService.recordFeedback(tenantId, insightId, feedback), onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: aiInsightsKeys.detail(variables.tenantId, variables.insightId) }); queryClient.invalidateQueries({ queryKey: aiInsightsKeys.stats(variables.tenantId) }); }, ...options, }); } /** * Utility hook to manage insight selection */ export function useInsightSelection() { const [selectedInsights, setSelectedInsights] = useState([]); const toggleInsight = (insightId: string) => { setSelectedInsights((prev) => prev.includes(insightId) ? prev.filter((id) => id !== insightId) : [...prev, insightId] ); }; const selectAll = (insightIds: string[]) => { setSelectedInsights(insightIds); }; const clearSelection = () => { setSelectedInsights([]); }; return { selectedInsights, toggleInsight, selectAll, clearSelection, isSelected: (insightId: string) => selectedInsights.includes(insightId), }; }