e74bf35264
The console was generating excessive messages after schedule maintenance updates.
181 lines
5.7 KiB
TypeScript
181 lines
5.7 KiB
TypeScript
|
|
import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
|
|
import { maintenanceService, MaintenanceItem } from '@/services/maintenance';
|
|
import { useToast } from '@/hooks/use-toast';
|
|
import { useLanguage } from '@/contexts/LanguageContext';
|
|
|
|
interface UseMaintenanceDataProps {
|
|
refreshTrigger?: number;
|
|
}
|
|
|
|
export const useMaintenanceData = ({ refreshTrigger = 0 }: UseMaintenanceDataProps) => {
|
|
const { t } = useLanguage();
|
|
const { toast } = useToast();
|
|
const [loading, setLoading] = useState(true);
|
|
const [allMaintenanceData, setAllMaintenanceData] = useState<MaintenanceItem[]>([]);
|
|
const [filter, setFilter] = useState("upcoming");
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [initialized, setInitialized] = useState(false);
|
|
|
|
// Refs for cleanup and request management
|
|
const mountedRef = useRef(true);
|
|
const currentRequestRef = useRef<Promise<void> | null>(null);
|
|
|
|
// Memoize categorized data to prevent unnecessary recalculations
|
|
const categorizedData = useMemo(() => {
|
|
if (!allMaintenanceData.length) return { upcoming: [], ongoing: [], completed: [] };
|
|
|
|
const currentDate = new Date();
|
|
const upcoming: MaintenanceItem[] = [];
|
|
const ongoing: MaintenanceItem[] = [];
|
|
const completed: MaintenanceItem[] = [];
|
|
|
|
allMaintenanceData.forEach(item => {
|
|
const status = item.status?.toLowerCase() || '';
|
|
const startTime = new Date(item.start_time);
|
|
const endTime = new Date(item.end_time);
|
|
|
|
if (status === 'completed' || status === 'cancelled') {
|
|
completed.push(item);
|
|
} else if (status === 'in_progress' ||
|
|
(status === 'scheduled' && startTime <= currentDate && endTime >= currentDate)) {
|
|
ongoing.push(item);
|
|
} else if (status === 'scheduled' && startTime > currentDate) {
|
|
upcoming.push(item);
|
|
} else {
|
|
// Default case: treat as upcoming if we can't determine
|
|
upcoming.push(item);
|
|
}
|
|
});
|
|
|
|
return { upcoming, ongoing, completed };
|
|
}, [allMaintenanceData]);
|
|
|
|
// Simple fetch function - only called when explicitly requested
|
|
const fetchMaintenanceData = useCallback(async (force = false) => {
|
|
// Check if component is still mounted
|
|
if (!mountedRef.current) return;
|
|
|
|
// Prevent duplicate requests
|
|
if (currentRequestRef.current) {
|
|
await currentRequestRef.current;
|
|
return;
|
|
}
|
|
|
|
// Only show loading state for initial load or forced refresh
|
|
if (!initialized || force) {
|
|
setLoading(true);
|
|
}
|
|
|
|
setError(null);
|
|
|
|
const requestPromise = (async () => {
|
|
try {
|
|
const data = await maintenanceService.getMaintenanceRecords();
|
|
|
|
// Check if component is still mounted before updating state
|
|
if (!mountedRef.current) return;
|
|
|
|
// Update state with fetched data
|
|
setAllMaintenanceData(data);
|
|
setInitialized(true);
|
|
|
|
// Clear any previous error
|
|
if (error) {
|
|
setError(null);
|
|
}
|
|
|
|
} catch (err) {
|
|
console.error('Error fetching maintenance data:', err);
|
|
|
|
// Only update error state if component is still mounted
|
|
if (!mountedRef.current) return;
|
|
|
|
const errorMessage = 'Failed to load maintenance data. Please try again.';
|
|
setError(errorMessage);
|
|
|
|
// Show toast for errors
|
|
toast({
|
|
title: t('error'),
|
|
description: t('errorFetchingMaintenanceData'),
|
|
variant: 'destructive',
|
|
});
|
|
} finally {
|
|
// Only update loading state if component is still mounted
|
|
if (mountedRef.current) {
|
|
setLoading(false);
|
|
}
|
|
currentRequestRef.current = null;
|
|
}
|
|
})();
|
|
|
|
currentRequestRef.current = requestPromise;
|
|
await requestPromise;
|
|
}, [t, toast, error, initialized]);
|
|
|
|
// Initial fetch on mount - NO AUTOMATIC POLLING
|
|
useEffect(() => {
|
|
mountedRef.current = true;
|
|
|
|
// Only fetch initial data, no polling
|
|
fetchMaintenanceData(true);
|
|
|
|
return () => {
|
|
mountedRef.current = false;
|
|
currentRequestRef.current = null;
|
|
};
|
|
}, []); // Remove fetchMaintenanceData from dependencies to prevent re-runs
|
|
|
|
// Handle refresh trigger changes - ONLY when explicitly triggered
|
|
useEffect(() => {
|
|
if (refreshTrigger > 0) {
|
|
fetchMaintenanceData(true); // Force refresh to bypass cache
|
|
}
|
|
}, [refreshTrigger, fetchMaintenanceData]);
|
|
|
|
// Get filtered data based on current tab
|
|
const maintenanceData = useMemo(() => {
|
|
if (!initialized) return [];
|
|
return categorizedData[filter as keyof typeof categorizedData] || [];
|
|
}, [filter, categorizedData, initialized]);
|
|
|
|
// Calculate overview stats with memoization
|
|
const overviewStats = useMemo(() => {
|
|
const { upcoming, ongoing, completed } = categorizedData;
|
|
|
|
// Calculate total hours more efficiently
|
|
const calculateTotalHours = (items: MaintenanceItem[]) => {
|
|
return items.reduce((total, item) => {
|
|
try {
|
|
const start = new Date(item.start_time).getTime();
|
|
const end = new Date(item.end_time).getTime();
|
|
const durationHours = (end - start) / (1000 * 60 * 60);
|
|
return total + (isNaN(durationHours) ? 0 : durationHours);
|
|
} catch (e) {
|
|
return total;
|
|
}
|
|
}, 0).toFixed(1);
|
|
};
|
|
|
|
return {
|
|
upcoming: upcoming.length,
|
|
ongoing: ongoing.length,
|
|
completed: completed.length,
|
|
totalDuration: calculateTotalHours([...upcoming, ...ongoing]),
|
|
};
|
|
}, [categorizedData]);
|
|
|
|
const isEmpty = !loading && maintenanceData.length === 0 && initialized;
|
|
|
|
return {
|
|
loading,
|
|
filter,
|
|
setFilter,
|
|
maintenanceData,
|
|
overviewStats,
|
|
fetchMaintenanceData,
|
|
isEmpty,
|
|
error,
|
|
initialized,
|
|
};
|
|
}; |