Files
bakery-ia/frontend/src/api/hooks/aiInsights.ts

304 lines
9.4 KiB
TypeScript
Raw Normal View History

2026-01-21 17:17:16 +01:00
/**
* 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<UseQueryOptions<AIInsightListResponse>, '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<UseQueryOptions<AIInsight>, '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<UseQueryOptions<AIInsightStatsResponse>, '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<UseQueryOptions<OrchestrationReadyInsightsResponse>, '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<UseQueryOptions<any>, '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<UseQueryOptions<AIInsight[]>, '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<UseQueryOptions<AIInsight[]>, '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<UseQueryOptions<AIInsight[]>, '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<AIInsightFilters>,
options?: Omit<UseQueryOptions<AIInsight[]>, '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<AIInsight, Error, { tenantId: string; insightId: string }>
) {
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<void, Error, { tenantId: string; insightId: string }>
) {
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<AIInsight, Error, { tenantId: string; insightId: string; status: 'acknowledged' | 'in_progress' | 'applied' | 'expired' }>
) {
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<any, Error, { tenantId: string; insightId: string; feedback: FeedbackRequest }>
) {
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<string[]>([]);
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),
};
}