import { useMutation, useQueryClient } from '@tanstack/react-query'; import { supabase } from '@/lib/supabaseClient'; import { queryKeys } from '@/lib/queryKeys'; import { toast } from 'sonner'; import { breadcrumb } from '@/lib/errorBreadcrumbs'; import type { GroupedAlert } from './useGroupedAlerts'; export function useResolveAlertGroup() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ alertIds, source }: { alertIds: string[]; source: 'system' | 'rate_limit'; }) => { const table = source === 'system' ? 'system_alerts' : 'rate_limit_alerts'; // Log breadcrumb for debugging breadcrumb.userAction(`resolve-alerts`, 'AlertGroupActions', { alertIds, source, count: alertIds.length, }); const { data, error } = await supabase .from(table) .update({ resolved_at: new Date().toISOString() }) .in('id', alertIds) .select(); if (error) { // Enhanced error handling with specific messages if (error.code === '42501') { throw new Error('Permission denied. You do not have access to resolve these alerts.'); } else if (error.code === 'PGRST116') { throw new Error('No alerts found to resolve. They may have already been resolved.'); } else { console.error('Supabase error details:', error); throw new Error(`Failed to resolve alerts: ${error.message}`); } } return { count: alertIds.length, updatedAlerts: data }; }, onMutate: async ({ alertIds }) => { // Cancel any outgoing refetches await queryClient.cancelQueries({ queryKey: queryKeys.monitoring.groupedAlerts() }); const previousData = queryClient.getQueryData( queryKeys.monitoring.groupedAlerts() ); // Optimistically update to the new value queryClient.setQueryData( queryKeys.monitoring.groupedAlerts(), (old: GroupedAlert[] | undefined) => { if (!old) return old; return old.map(alert => { const hasMatchingIds = alert.alert_ids.some(id => alertIds.includes(id) ); if (hasMatchingIds) { return { ...alert, unresolved_count: 0, has_resolved: true, }; } return alert; }); } ); return { previousData }; }, onSuccess: (data) => { toast.success(`Resolved ${data.count} alert${data.count > 1 ? 's' : ''}`); }, onError: (error: Error, variables, context) => { // Rollback on error if (context?.previousData) { queryClient.setQueryData( queryKeys.monitoring.groupedAlerts(), context.previousData ); } // Show detailed error message toast.error(error.message || 'Failed to resolve alerts', { description: 'Please try again or contact support if the issue persists.', duration: 5000, }); // Log to error tracking system breadcrumb.apiCall('resolve-alerts', 'POST', 500); console.error('Error resolving alert group:', error, { alertIds: variables.alertIds, source: variables.source, }); }, onSettled: () => { queryClient.invalidateQueries({ queryKey: queryKeys.monitoring.groupedAlerts() }); queryClient.invalidateQueries({ queryKey: queryKeys.monitoring.combinedAlerts() }); }, }); } export function useSnoozeAlertGroup() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ groupKey, duration }: { groupKey: string; duration: number; }) => { const snoozedAlerts = JSON.parse( localStorage.getItem('snoozed_alerts') || '{}' ); snoozedAlerts[groupKey] = Date.now() + duration; localStorage.setItem('snoozed_alerts', JSON.stringify(snoozedAlerts)); return { groupKey, until: snoozedAlerts[groupKey] }; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: queryKeys.monitoring.groupedAlerts() }); toast.success('Alert group snoozed'); }, }); }