"use client"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useEffect } from "react"; import toast from "react-hot-toast"; import { get, post } from "../../lib/api"; import ApiHealth from "./ApiHealth"; export default function StatsSection() { const queryClient = useQueryClient(); const { data: tasks, isLoading: _tasksLoading } = useQuery({ queryKey: ["tasks"], queryFn: () => get("/tasks"), }); const { data: filesSuccessful, isLoading: filesSuccessfulLoading } = useQuery( { queryKey: ["files-stats-successful"], queryFn: () => get("/files/stats/successful"), } ); const { data: filesProcessedTotal, isLoading: filesProcessedLoading } = useQuery({ queryKey: ["files-stats-processed"], queryFn: () => get("/files/stats/processed"), }); const { data: _datasets, isLoading: _datasetsLoading } = useQuery({ queryKey: ["datasets"], queryFn: () => get("/files"), }); const { data: settings, isLoading: settingsLoading } = useQuery({ queryKey: ["settings", "datasets"], queryFn: () => get("/config/settings/datasets"), }); const { data: watcherStatus, isLoading: watcherLoading } = useQuery({ queryKey: ["watcher", "status"], queryFn: () => get("/watcher/status"), }); const { data: taskProcessingStatus, isLoading: taskProcessingLoading } = useQuery({ queryKey: ["tasks", "processing-status"], queryFn: () => get("/tasks/processing-status"), }); const { data: queueStatus, isLoading: _queueLoading } = useQuery({ queryKey: ["tasks", "queue", "status"], queryFn: () => get("/tasks/queue/status"), }); const { data: apiHealth, isLoading: apiHealthLoading } = useQuery({ queryKey: ["api", "health"], queryFn: () => get("/health"), refetchInterval: 30000, }); // Mutations for controlling services const startWatcherMutation = useMutation({ mutationFn: () => post("/watcher/start"), onSuccess: () => { toast.success("File watcher started"); // Invalidate and refetch to ensure status updates immediately queryClient.invalidateQueries({ queryKey: ["watcher", "status"] }); setTimeout(() => { queryClient.refetchQueries({ queryKey: ["watcher", "status"] }); }, 100); }, onError: () => { toast.error("Failed to start file watcher"); }, }); const stopWatcherMutation = useMutation({ mutationFn: () => post("/watcher/stop"), onSuccess: () => { toast.success("File watcher stopped"); // Invalidate and refetch to ensure status updates immediately queryClient.invalidateQueries({ queryKey: ["watcher", "status"] }); setTimeout(() => { queryClient.refetchQueries({ queryKey: ["watcher", "status"] }); }, 100); }, onError: () => { toast.error("Failed to stop file watcher"); }, }); const startTaskProcessingMutation = useMutation({ mutationFn: () => post("/tasks/start-processing"), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["tasks", "processing-status"], }); queryClient.invalidateQueries({ queryKey: ["tasks", "queue", "status"] }); toast.success("Task processing started"); }, onError: () => { toast.error("Failed to start task processing"); }, }); const stopTaskProcessingMutation = useMutation({ mutationFn: () => post("/tasks/stop-processing"), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["tasks", "processing-status"], }); queryClient.invalidateQueries({ queryKey: ["tasks", "queue", "status"] }); toast.success("Task processing stopped"); }, onError: () => { toast.error("Failed to stop task processing"); }, }); const _tasksRunning = tasks?.length || 0; const filesProcessed = filesSuccessful || 0; const totalProcessed = filesProcessedTotal || 0; const successRate = totalProcessed > 0 ? Math.round((filesProcessed / totalProcessed) * 100) : 0; const activeWatchers = settings ? Object.values(settings).filter((dataset: any) => dataset.enabled === true) .length : 0; const isApiHealthy = apiHealth?.status === "healthy"; const isWatcherActive = watcherStatus?.isWatching; const isTaskProcessingActive = taskProcessingStatus?.isProcessing; // Listen for WebSocket updates to refresh stats useEffect(() => { const handleTaskUpdate = (event: CustomEvent) => { const taskData = event.detail; // Refresh task-related queries when tasks are updated if ( taskData.type === "progress" || taskData.type === "completed" || taskData.type === "failed" ) { queryClient.invalidateQueries({ queryKey: ["tasks"] }); queryClient.invalidateQueries({ queryKey: ["tasks", "processing-status"], }); queryClient.invalidateQueries({ queryKey: ["tasks", "queue", "status"], }); } }; const handleFileUpdate = (event: CustomEvent) => { const fileData = event.detail; // Refresh file stats when files are processed if (fileData.type === "processed" || fileData.type === "success") { queryClient.invalidateQueries({ queryKey: ["files-stats-successful"] }); queryClient.invalidateQueries({ queryKey: ["files-stats-processed"] }); } }; window.addEventListener("taskUpdate", handleTaskUpdate as EventListener); window.addEventListener("fileUpdate", handleFileUpdate as EventListener); return () => { window.removeEventListener( "taskUpdate", handleTaskUpdate as EventListener ); window.removeEventListener( "fileUpdate", handleFileUpdate as EventListener ); }; }, [queryClient]); return (