Files
Tracearr/apps/web/src/hooks/queries/useViolations.ts
Rephl3x 3015f48118
Some checks failed
CI / Lint & Typecheck (push) Has been cancelled
CI / Test (routes) (push) Has been cancelled
CI / Test (security) (push) Has been cancelled
CI / Test (services) (push) Has been cancelled
CI / Test (unit) (push) Has been cancelled
CI / Test (integration) (push) Has been cancelled
CI / Test Coverage (push) Has been cancelled
CI / Build (push) Has been cancelled
Initial Upload
2025-12-17 12:32:50 +13:00

84 lines
2.7 KiB
TypeScript

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import type { ViolationWithDetails, PaginatedResponse, ViolationSeverity } from '@tracearr/shared';
import { toast } from 'sonner';
import { api } from '@/lib/api';
interface ViolationsParams {
page?: number;
pageSize?: number;
userId?: string;
severity?: ViolationSeverity;
acknowledged?: boolean;
serverId?: string;
}
export function useViolations(params: ViolationsParams = {}) {
return useQuery({
queryKey: ['violations', 'list', params],
queryFn: () => api.violations.list(params),
staleTime: 1000 * 30, // 30 seconds
});
}
export function useAcknowledgeViolation() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => api.violations.acknowledge(id),
onMutate: async (id) => {
// Optimistic update
await queryClient.cancelQueries({ queryKey: ['violations', 'list'] });
const previousData = queryClient.getQueriesData<PaginatedResponse<ViolationWithDetails>>({
queryKey: ['violations', 'list'],
});
// Update all matching queries
queryClient.setQueriesData<PaginatedResponse<ViolationWithDetails>>(
{ queryKey: ['violations', 'list'] },
(old) => {
if (!old) return old;
return {
...old,
data: old.data.map((v) =>
v.id === id ? { ...v, acknowledgedAt: new Date() } : v
),
};
}
);
return { previousData };
},
onError: (err, id, context) => {
// Rollback on error
if (context?.previousData) {
for (const [queryKey, data] of context.previousData) {
queryClient.setQueryData(queryKey, data);
}
}
toast.error('Failed to Acknowledge', { description: (err).message });
},
onSuccess: () => {
void queryClient.invalidateQueries({ queryKey: ['violations'] });
void queryClient.invalidateQueries({ queryKey: ['stats', 'dashboard'] });
toast.success('Violation Acknowledged', { description: 'The violation has been marked as acknowledged.' });
},
});
}
export function useDismissViolation() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => api.violations.dismiss(id),
onSuccess: () => {
void queryClient.invalidateQueries({ queryKey: ['violations'] });
void queryClient.invalidateQueries({ queryKey: ['stats', 'dashboard'] });
toast.success('Violation Dismissed', { description: 'The violation has been dismissed.' });
},
onError: (error: Error) => {
toast.error('Failed to Dismiss', { description: error.message });
},
});
}