feat(frontend): Agregar hooks React Query para módulo HSE
Implementación completa de 16 hooks personalizados de React Query para gestión del módulo HSE (Health, Safety & Environment): **Incidentes (7 hooks):** - useIncidentes, useIncidente, useIncidenteStats - useCreateIncidente, useUpdateIncidente - useInvestigateIncidente, useCloseIncidente **Capacitaciones (6 hooks):** - useCapacitaciones, useCapacitacion - useCreateCapacitacion, useUpdateCapacitacion - useToggleCapacitacion, useDeleteCapacitacion **Inspecciones (7 hooks):** - useTiposInspeccion (con staleTime 30min) - useInspecciones, useInspeccion, useInspeccionesStats - useCreateInspeccion, useUpdateEstadoInspeccion - useAddHallazgo **Características:** - Query Keys jerárquicos type-safe - Manejo centralizado de errores con toast - Invalidación inteligente de queries relacionadas - Patrón consistente con useConstruccion.ts - TypeScript completamente tipado - 291 líneas de código **Validaciones:** ✓ npm run type-check (sin errores) ✓ npm run lint (sin warnings) Archivos: - web/src/hooks/useHSE.ts (nuevo, 291 líneas) - web/src/hooks/index.ts (export agregado) Relacionado: MAA-017 (Módulo HSE Backend) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
cbb4f265c5
commit
dac9ae6f19
@ -2,3 +2,4 @@ export * from './useConstruccion';
|
||||
export * from './usePresupuestos';
|
||||
export * from './useReports';
|
||||
export * from './useBidding';
|
||||
export * from './useHSE';
|
||||
|
||||
291
web/src/hooks/useHSE.ts
Normal file
291
web/src/hooks/useHSE.ts
Normal file
@ -0,0 +1,291 @@
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { AxiosError } from 'axios';
|
||||
import toast from 'react-hot-toast';
|
||||
import { ApiError } from '../services/api';
|
||||
import {
|
||||
incidentesApi,
|
||||
IncidenteFilters,
|
||||
CreateIncidenteDto,
|
||||
UpdateIncidenteDto,
|
||||
} from '../services/hse/incidentes.api';
|
||||
import {
|
||||
capacitacionesApi,
|
||||
CapacitacionFilters,
|
||||
CreateCapacitacionDto,
|
||||
UpdateCapacitacionDto,
|
||||
} from '../services/hse/capacitaciones.api';
|
||||
import {
|
||||
inspeccionesApi,
|
||||
InspeccionFilters,
|
||||
CreateInspeccionDto,
|
||||
CreateHallazgoDto,
|
||||
} from '../services/hse/inspecciones.api';
|
||||
|
||||
// Query Keys
|
||||
export const hseKeys = {
|
||||
incidentes: {
|
||||
all: ['hse', 'incidentes'] as const,
|
||||
list: (filters?: IncidenteFilters) => [...hseKeys.incidentes.all, 'list', filters] as const,
|
||||
detail: (id: string) => [...hseKeys.incidentes.all, 'detail', id] as const,
|
||||
stats: () => [...hseKeys.incidentes.all, 'stats'] as const,
|
||||
},
|
||||
capacitaciones: {
|
||||
all: ['hse', 'capacitaciones'] as const,
|
||||
list: (filters?: CapacitacionFilters) =>
|
||||
[...hseKeys.capacitaciones.all, 'list', filters] as const,
|
||||
detail: (id: string) => [...hseKeys.capacitaciones.all, 'detail', id] as const,
|
||||
},
|
||||
inspecciones: {
|
||||
all: ['hse', 'inspecciones'] as const,
|
||||
list: (filters?: InspeccionFilters) =>
|
||||
[...hseKeys.inspecciones.all, 'list', filters] as const,
|
||||
detail: (id: string) => [...hseKeys.inspecciones.all, 'detail', id] as const,
|
||||
stats: () => [...hseKeys.inspecciones.all, 'stats'] as const,
|
||||
tipos: () => [...hseKeys.inspecciones.all, 'tipos'] as const,
|
||||
},
|
||||
};
|
||||
|
||||
// Error handler
|
||||
const handleError = (error: AxiosError<ApiError>) => {
|
||||
const message = error.response?.data?.message || 'Ha ocurrido un error';
|
||||
toast.error(message);
|
||||
};
|
||||
|
||||
// ==================== INCIDENTES ====================
|
||||
|
||||
export function useIncidentes(filters?: IncidenteFilters) {
|
||||
return useQuery({
|
||||
queryKey: hseKeys.incidentes.list(filters),
|
||||
queryFn: () => incidentesApi.list(filters),
|
||||
});
|
||||
}
|
||||
|
||||
export function useIncidente(id: string) {
|
||||
return useQuery({
|
||||
queryKey: hseKeys.incidentes.detail(id),
|
||||
queryFn: () => incidentesApi.get(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
}
|
||||
|
||||
export function useIncidenteStats() {
|
||||
return useQuery({
|
||||
queryKey: hseKeys.incidentes.stats(),
|
||||
queryFn: () => incidentesApi.getStats(),
|
||||
});
|
||||
}
|
||||
|
||||
export function useCreateIncidente() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (data: CreateIncidenteDto) => incidentesApi.create(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.incidentes.all });
|
||||
toast.success('Incidente registrado exitosamente');
|
||||
},
|
||||
onError: handleError,
|
||||
});
|
||||
}
|
||||
|
||||
export function useUpdateIncidente() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({ id, data }: { id: string; data: UpdateIncidenteDto }) =>
|
||||
incidentesApi.update(id, data),
|
||||
onSuccess: (_, { id }) => {
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.incidentes.all });
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.incidentes.detail(id) });
|
||||
toast.success('Incidente actualizado');
|
||||
},
|
||||
onError: handleError,
|
||||
});
|
||||
}
|
||||
|
||||
export function useInvestigateIncidente() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({
|
||||
id,
|
||||
investigadorId,
|
||||
fechaInvestigacion,
|
||||
}: {
|
||||
id: string;
|
||||
investigadorId: string;
|
||||
fechaInvestigacion?: string;
|
||||
}) => incidentesApi.investigate(id, { investigadorId, fechaInvestigacion }),
|
||||
onSuccess: (_, { id }) => {
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.incidentes.all });
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.incidentes.detail(id) });
|
||||
toast.success('Investigación iniciada');
|
||||
},
|
||||
onError: handleError,
|
||||
});
|
||||
}
|
||||
|
||||
export function useCloseIncidente() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({
|
||||
id,
|
||||
fechaCierre,
|
||||
observaciones,
|
||||
}: {
|
||||
id: string;
|
||||
fechaCierre?: string;
|
||||
observaciones?: string;
|
||||
}) => incidentesApi.close(id, { fechaCierre, observaciones }),
|
||||
onSuccess: (_, { id }) => {
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.incidentes.all });
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.incidentes.detail(id) });
|
||||
toast.success('Incidente cerrado');
|
||||
},
|
||||
onError: handleError,
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== CAPACITACIONES ====================
|
||||
|
||||
export function useCapacitaciones(filters?: CapacitacionFilters) {
|
||||
return useQuery({
|
||||
queryKey: hseKeys.capacitaciones.list(filters),
|
||||
queryFn: () => capacitacionesApi.list(filters),
|
||||
});
|
||||
}
|
||||
|
||||
export function useCapacitacion(id: string) {
|
||||
return useQuery({
|
||||
queryKey: hseKeys.capacitaciones.detail(id),
|
||||
queryFn: () => capacitacionesApi.get(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
}
|
||||
|
||||
export function useCreateCapacitacion() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (data: CreateCapacitacionDto) => capacitacionesApi.create(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.capacitaciones.all });
|
||||
toast.success('Capacitacion creada exitosamente');
|
||||
},
|
||||
onError: handleError,
|
||||
});
|
||||
}
|
||||
|
||||
export function useUpdateCapacitacion() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({ id, data }: { id: string; data: UpdateCapacitacionDto }) =>
|
||||
capacitacionesApi.update(id, data),
|
||||
onSuccess: (_, { id }) => {
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.capacitaciones.all });
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.capacitaciones.detail(id) });
|
||||
toast.success('Capacitacion actualizada');
|
||||
},
|
||||
onError: handleError,
|
||||
});
|
||||
}
|
||||
|
||||
export function useToggleCapacitacion() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (id: string) => capacitacionesApi.toggleActive(id),
|
||||
onSuccess: (_, id) => {
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.capacitaciones.all });
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.capacitaciones.detail(id) });
|
||||
toast.success('Estado actualizado');
|
||||
},
|
||||
onError: handleError,
|
||||
});
|
||||
}
|
||||
|
||||
export function useDeleteCapacitacion() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (id: string) => capacitacionesApi.delete(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.capacitaciones.all });
|
||||
toast.success('Capacitacion eliminada');
|
||||
},
|
||||
onError: handleError,
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== INSPECCIONES ====================
|
||||
|
||||
export function useTiposInspeccion() {
|
||||
return useQuery({
|
||||
queryKey: hseKeys.inspecciones.tipos(),
|
||||
queryFn: () => inspeccionesApi.listTipos(),
|
||||
staleTime: 1000 * 60 * 30, // 30 minutos - datos relativamente estáticos
|
||||
});
|
||||
}
|
||||
|
||||
export function useInspecciones(filters?: InspeccionFilters) {
|
||||
return useQuery({
|
||||
queryKey: hseKeys.inspecciones.list(filters),
|
||||
queryFn: () => inspeccionesApi.list(filters),
|
||||
});
|
||||
}
|
||||
|
||||
export function useInspeccion(id: string) {
|
||||
return useQuery({
|
||||
queryKey: hseKeys.inspecciones.detail(id),
|
||||
queryFn: () => inspeccionesApi.get(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
}
|
||||
|
||||
export function useInspeccionesStats() {
|
||||
return useQuery({
|
||||
queryKey: hseKeys.inspecciones.stats(),
|
||||
queryFn: () => inspeccionesApi.getStats(),
|
||||
});
|
||||
}
|
||||
|
||||
export function useCreateInspeccion() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (data: CreateInspeccionDto) => inspeccionesApi.create(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.inspecciones.all });
|
||||
toast.success('Inspección creada exitosamente');
|
||||
},
|
||||
onError: handleError,
|
||||
});
|
||||
}
|
||||
|
||||
export function useUpdateEstadoInspeccion() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({
|
||||
id,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
data: { estado: string; observaciones?: string };
|
||||
}) => inspeccionesApi.updateEstado(id, data),
|
||||
onSuccess: (_, { id }) => {
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.inspecciones.all });
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.inspecciones.detail(id) });
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.inspecciones.stats() });
|
||||
toast.success('Estado de inspección actualizado');
|
||||
},
|
||||
onError: handleError,
|
||||
});
|
||||
}
|
||||
|
||||
export function useAddHallazgo() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({ id, data }: { id: string; data: CreateHallazgoDto }) =>
|
||||
inspeccionesApi.addHallazgo(id, data),
|
||||
onSuccess: (_, { id }) => {
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.inspecciones.all });
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.inspecciones.detail(id) });
|
||||
queryClient.invalidateQueries({ queryKey: hseKeys.inspecciones.stats() });
|
||||
toast.success('Hallazgo agregado');
|
||||
},
|
||||
onError: handleError,
|
||||
});
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user