Initial Commit
This commit is contained in:
148
frontend/src/core/query/query-config.ts
Normal file
148
frontend/src/core/query/query-config.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* @ai-summary Enhanced Query Client configuration with mobile optimization
|
||||
*/
|
||||
|
||||
import { QueryClient, QueryCache, MutationCache } from '@tanstack/react-query';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
// Mobile detection utility
|
||||
const isMobileDevice = (): boolean => {
|
||||
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||
|
||||
window.innerWidth <= 768;
|
||||
};
|
||||
|
||||
// Enhanced error handler for mobile devices
|
||||
const handleQueryError = (error: any) => {
|
||||
const isMobile = isMobileDevice();
|
||||
|
||||
if (error?.response?.status === 401) {
|
||||
// Token refresh handled by Auth0Provider
|
||||
if (isMobile) {
|
||||
toast.error('Refreshing session...', {
|
||||
duration: 2000,
|
||||
id: 'mobile-auth-refresh'
|
||||
});
|
||||
}
|
||||
} else if (error?.response?.status >= 500) {
|
||||
toast.error(isMobile ? 'Server issue, retrying...' : 'Server error occurred', {
|
||||
duration: isMobile ? 3000 : 4000,
|
||||
});
|
||||
} else if (error?.code === 'NETWORK_ERROR') {
|
||||
if (isMobile) {
|
||||
toast.error('Check connection and try again', {
|
||||
duration: 4000,
|
||||
id: 'mobile-network-error'
|
||||
});
|
||||
} else {
|
||||
toast.error('Network error occurred');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Create enhanced query client with mobile-optimized settings
|
||||
export const createEnhancedQueryClient = (): QueryClient => {
|
||||
const isMobile = isMobileDevice();
|
||||
|
||||
return new QueryClient({
|
||||
queryCache: new QueryCache({
|
||||
onError: handleQueryError,
|
||||
}),
|
||||
mutationCache: new MutationCache({
|
||||
onError: handleQueryError,
|
||||
}),
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
// Mobile-optimized retry strategy
|
||||
retry: (failureCount, error: any) => {
|
||||
// Don't retry 4xx errors except 401 (auth issues)
|
||||
if (error?.response?.status >= 400 && error?.response?.status < 500) {
|
||||
return error?.response?.status === 401 && failureCount < 2;
|
||||
}
|
||||
|
||||
// Mobile devices get more aggressive retry for network issues
|
||||
if (isMobile) {
|
||||
return failureCount < 3;
|
||||
}
|
||||
|
||||
return failureCount < 2;
|
||||
},
|
||||
|
||||
// Mobile-optimized timing
|
||||
retryDelay: (attemptIndex) => {
|
||||
const baseDelay = isMobile ? 1000 : 500;
|
||||
return Math.min(baseDelay * (2 ** attemptIndex), 30000);
|
||||
},
|
||||
|
||||
// Stale time optimization for mobile
|
||||
staleTime: isMobile ? 1000 * 60 * 2 : 1000 * 60 * 5, // 2 min mobile, 5 min desktop
|
||||
|
||||
// GC time optimization
|
||||
gcTime: isMobile ? 1000 * 60 * 10 : 1000 * 60 * 30, // 10 min mobile, 30 min desktop
|
||||
|
||||
// Refetch behavior
|
||||
refetchOnWindowFocus: !isMobile, // Disable on mobile to save data
|
||||
refetchOnReconnect: true,
|
||||
refetchOnMount: true,
|
||||
|
||||
// Network mode for offline capability
|
||||
networkMode: 'offlineFirst',
|
||||
},
|
||||
mutations: {
|
||||
// Mutation retry strategy
|
||||
retry: (failureCount, error: any) => {
|
||||
if (error?.response?.status >= 400 && error?.response?.status < 500) {
|
||||
return false; // Don't retry 4xx errors for mutations
|
||||
}
|
||||
|
||||
return failureCount < (isMobile ? 2 : 1);
|
||||
},
|
||||
|
||||
retryDelay: (attemptIndex) => {
|
||||
const baseDelay = isMobile ? 2000 : 1000;
|
||||
return Math.min(baseDelay * (2 ** attemptIndex), 30000);
|
||||
},
|
||||
|
||||
networkMode: 'offlineFirst',
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// Query key factories for consistent cache management
|
||||
export const queryKeys = {
|
||||
all: ['motovaultpro'] as const,
|
||||
users: () => [...queryKeys.all, 'users'] as const,
|
||||
user: (id: string) => [...queryKeys.users(), id] as const,
|
||||
vehicles: () => [...queryKeys.all, 'vehicles'] as const,
|
||||
vehicle: (id: string) => [...queryKeys.vehicles(), id] as const,
|
||||
vehiclesByUser: (userId: string) => [...queryKeys.vehicles(), 'user', userId] as const,
|
||||
fuelLogs: () => [...queryKeys.all, 'fuel-logs'] as const,
|
||||
fuelLog: (id: string) => [...queryKeys.fuelLogs(), id] as const,
|
||||
fuelLogsByVehicle: (vehicleId: string) => [...queryKeys.fuelLogs(), 'vehicle', vehicleId] as const,
|
||||
settings: () => [...queryKeys.all, 'settings'] as const,
|
||||
userSettings: (userId: string) => [...queryKeys.settings(), 'user', userId] as const,
|
||||
} as const;
|
||||
|
||||
// Performance monitoring utilities
|
||||
export const queryPerformanceMonitor = {
|
||||
logSlowQuery: (queryKey: readonly unknown[], duration: number) => {
|
||||
if (duration > 5000) { // Log queries taking more than 5 seconds
|
||||
console.warn('Slow query detected:', {
|
||||
queryKey,
|
||||
duration: `${duration}ms`,
|
||||
isMobile: isMobileDevice(),
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
logCacheHit: (queryKey: readonly unknown[], fromCache: boolean) => {
|
||||
if (import.meta.env.MODE === 'development') {
|
||||
console.log('Query cache:', {
|
||||
queryKey,
|
||||
fromCache,
|
||||
isMobile: isMobileDevice(),
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user