Backend: - Extract shared hard-delete authorization utility (#9) - Extract Prisma include constants per entity (#11) - Fix N+1 query pattern in events findAll (#12) - Extract shared date utility functions (#13) - Move vehicle utilization filtering to DB query (#15) - Add ParseBooleanPipe for query params - Add CurrentDriver decorator + ResolveDriverInterceptor (#20) Frontend: - Extract shared form utilities (toDatetimeLocal) and enum labels (#17) - Replace browser confirm() with styled ConfirmModal (#18) - Add centralized query-keys.ts constants (#19) - Clean up unused imports, add useMemo where needed (#19) - Standardize filter button styling across list pages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
67 lines
2.1 KiB
TypeScript
67 lines
2.1 KiB
TypeScript
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
import { api } from '@/lib/api';
|
|
import { Flight, FlightBudget } from '@/types';
|
|
import toast from 'react-hot-toast';
|
|
import { queryKeys } from '@/lib/query-keys';
|
|
|
|
export function useFlights() {
|
|
return useQuery<Flight[]>({
|
|
queryKey: queryKeys.flights.all,
|
|
queryFn: async () => {
|
|
const { data } = await api.get('/flights');
|
|
return data;
|
|
},
|
|
refetchInterval: 60000, // Refresh from DB every 60s (free, no API cost)
|
|
});
|
|
}
|
|
|
|
export function useFlightBudget() {
|
|
return useQuery<FlightBudget>({
|
|
queryKey: queryKeys.flights.budget,
|
|
queryFn: async () => {
|
|
const { data } = await api.get('/flights/tracking/budget');
|
|
return data;
|
|
},
|
|
refetchInterval: 300000, // Every 5 min
|
|
});
|
|
}
|
|
|
|
export function useRefreshFlight() {
|
|
const queryClient = useQueryClient();
|
|
|
|
return useMutation({
|
|
mutationFn: async (flightId: string) => {
|
|
const { data } = await api.post(`/flights/${flightId}/refresh`);
|
|
return data;
|
|
},
|
|
onSuccess: (data) => {
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.flights.all });
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.flights.budget });
|
|
const status = data.status || 'unknown';
|
|
toast.success(`Flight updated: ${data.flightNumber} (${status})`);
|
|
},
|
|
onError: (error: any) => {
|
|
toast.error(error.response?.data?.message || 'Failed to refresh flight');
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useRefreshActiveFlights() {
|
|
const queryClient = useQueryClient();
|
|
|
|
return useMutation({
|
|
mutationFn: async () => {
|
|
const { data } = await api.post('/flights/refresh-active');
|
|
return data;
|
|
},
|
|
onSuccess: (data) => {
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.flights.all });
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.flights.budget });
|
|
toast.success(`Refreshed ${data.refreshed} flights (${data.budgetRemaining} API calls remaining)`);
|
|
},
|
|
onError: (error: any) => {
|
|
toast.error(error.response?.data?.message || 'Failed to refresh flights');
|
|
},
|
|
});
|
|
}
|