import { useState, useEffect, useCallback } from 'react'; import apiService from '../services/apiService'; // Types for PM Schedule Generator export interface PMEntryLine { name?: string; asset: string; asset_name: string; start_date: string; end_date: string; manufacturer?: string; model?: string; idx?: number; } export interface PMSchedule { name: string; owner?: string; creation?: string; modified?: string; modified_by?: string; docstatus?: number; hospital?: string; modality?: string; device_status?: string; start_date?: string; end_date?: string; maintenance_team?: string; maintenance_manager?: string; periodicity?: string; assign_to?: string; due_date?: string; pm_for?: string; // PM Name field maintenance_entries?: PMEntryLine[]; doctype?: string; [key: string]: any; // Allow additional fields } export interface CreatePMScheduleData { hospital: string; modality?: string; device_status?: string; start_date: string; end_date: string; maintenance_team?: string; maintenance_manager?: string; periodicity: string; assign_to?: string; due_date?: string; maintenance_entries?: PMEntryLine[]; } // Hook for fetching PM Schedules list export function usePMSchedules( filters: Record = {}, limit: number = 20, offset: number = 0, orderBy: string = 'creation desc', permissionFilters: Record = {} ) { const [pmSchedules, setPMSchedules] = useState([]); const [totalCount, setTotalCount] = useState(0); const [hasMore, setHasMore] = useState(false); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [refetchTrigger, setRefetchTrigger] = useState(0); // Stringify filters to prevent object reference changes from causing re-renders const filtersJson = JSON.stringify(filters); const permissionFiltersJson = JSON.stringify(permissionFilters); useEffect(() => { let isCancelled = false; // Capture values at effect execution time const currentFiltersJson = filtersJson; const currentPermissionFiltersJson = permissionFiltersJson; const currentLimit = limit; const currentOffset = offset; const currentOrderBy = orderBy; const fetchPMSchedules = async () => { try { setLoading(true); setError(null); // Parse filters from JSON strings to avoid closure issues let currentFilters: Record = {}; let currentPermissionFilters: Record = {}; try { currentFilters = currentFiltersJson ? JSON.parse(currentFiltersJson) : {}; } catch (e) { currentFilters = {}; } try { currentPermissionFilters = currentPermissionFiltersJson ? JSON.parse(currentPermissionFiltersJson) : {}; } catch (e) { currentPermissionFilters = {}; } // Merge filters with permission filters const combinedFilters = { ...currentFilters, ...currentPermissionFilters }; const response = await apiService.apiCall( '/api/method/asset_lite.api.ppm_generator_api.get_pm_schedules', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ filters: JSON.stringify(combinedFilters), limit: currentLimit, offset: currentOffset, order_by: currentOrderBy, include_child_tables: true, fields: JSON.stringify(['name', 'pm_for', 'hospital', 'modality', 'periodicity', 'start_date', 'end_date', 'due_date']) // Explicitly request pm_for }) } ); if (!isCancelled) { // Handle both response formats: {message: {...}} or direct {...} const data = response?.message || response; if (data && data.pm_schedules) { const schedules = data.pm_schedules || []; console.log('[usePMSchedules] Loaded', schedules.length, 'PM Schedules'); // Debug: Log first schedule to see available fields - ALWAYS log in dev if (schedules.length > 0) { const firstSchedule = schedules[0]; console.log('[usePMSchedules] 🔍 FIRST SCHEDULE FIELDS:', { name: firstSchedule.name, pm_for: firstSchedule.pm_for, 'pm_for (bracket)': firstSchedule['pm_for'], allKeys: Object.keys(firstSchedule), allKeysList: Object.keys(firstSchedule).join(', '), fullObject: firstSchedule }); } setPMSchedules(schedules); setTotalCount(data.total_count || 0); setHasMore(data.has_more || false); } else { console.warn('[usePMSchedules] No pm_schedules in response:', response); setPMSchedules([]); setTotalCount(0); setHasMore(false); } } } catch (err) { if (!isCancelled) { console.error('Error fetching PM Schedules:', err); setError(err instanceof Error ? err.message : 'Failed to fetch PM Schedules'); setPMSchedules([]); setTotalCount(0); } } finally { if (!isCancelled) { setLoading(false); } } }; fetchPMSchedules(); return () => { isCancelled = true; }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [filtersJson, permissionFiltersJson, limit, offset, orderBy, refetchTrigger]); const refetch = useCallback(() => { setRefetchTrigger(prev => prev + 1); }, []); return { pmSchedules, totalCount, hasMore, loading, error, refetch }; } // Hook for fetching single PM Schedule details export function usePMScheduleDetails(pmScheduleName: string | null) { const [pmSchedule, setPMSchedule] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const fetchPMSchedule = useCallback(async () => { if (!pmScheduleName) { setPMSchedule(null); setLoading(false); return; } setLoading(true); setError(null); try { const response = await apiService.apiCall( '/api/method/asset_lite.api.ppm_generator_api.get_pm_schedule_details', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ pm_schedule_name: pmScheduleName }) } ); console.log('[usePMScheduleDetails] API Response:', response); // apiService.apiCall already unwraps the 'message' property // So response is directly the PM Schedule data OR an error object if (response && response.name && !response.error) { console.log('[usePMScheduleDetails] Setting PM Schedule:', response); setPMSchedule(response); } else { const errorMsg = response?.error || 'PM Schedule not found'; console.warn('[usePMScheduleDetails] Error or not found:', errorMsg); setError(errorMsg); setPMSchedule(null); } } catch (err) { console.error('Error fetching PM Schedule details:', err); setError(err instanceof Error ? err.message : 'Failed to fetch PM Schedule'); setPMSchedule(null); } finally { setLoading(false); } }, [pmScheduleName]); useEffect(() => { fetchPMSchedule(); }, [fetchPMSchedule]); return { pmSchedule, loading, error, refetch: fetchPMSchedule }; } // Hook for PM Schedule mutations (create, update, delete, submit, cancel) export function usePMScheduleMutations() { const [loading, setLoading] = useState(false); const createPMSchedule = async (data: CreatePMScheduleData): Promise => { setLoading(true); try { const response = await apiService.apiCall( '/api/method/asset_lite.api.ppm_generator_api.create_pm_schedule', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ pm_schedule_data: JSON.stringify(data) }) } ); // apiService.apiCall already unwraps the 'message' property if (response?.success) { return response.pm_schedule; } else { throw new Error(response?.error || 'Failed to create PM Schedule'); } } finally { setLoading(false); } }; const updatePMSchedule = async (name: string, data: Partial): Promise => { setLoading(true); try { const response = await apiService.apiCall( '/api/method/asset_lite.api.ppm_generator_api.update_pm_schedule', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ pm_schedule_name: name, pm_schedule_data: JSON.stringify(data) }) } ); if (response?.success) { return response.pm_schedule; } else { throw new Error(response?.error || 'Failed to update PM Schedule'); } } finally { setLoading(false); } }; const deletePMSchedule = async (name: string): Promise => { setLoading(true); try { const response = await apiService.apiCall( '/api/method/asset_lite.api.ppm_generator_api.delete_pm_schedule', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ pm_schedule_name: name }) } ); if (!response?.success) { throw new Error(response?.error || 'Failed to delete PM Schedule'); } } finally { setLoading(false); } }; const submitPMSchedule = async (name: string): Promise => { setLoading(true); try { const response = await apiService.apiCall( '/api/method/asset_lite.api.ppm_generator_api.submit_pm_schedule', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ pm_schedule_name: name }) } ); if (response?.success) { return response.pm_schedule; } else { throw new Error(response?.error || 'Failed to submit PM Schedule'); } } finally { setLoading(false); } }; const cancelPMSchedule = async (name: string): Promise => { setLoading(true); try { const response = await apiService.apiCall( '/api/method/asset_lite.api.ppm_generator_api.cancel_pm_schedule', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ pm_schedule_name: name }) } ); if (response?.success) { return response.pm_schedule; } else { throw new Error(response?.error || 'Failed to cancel PM Schedule'); } } finally { setLoading(false); } }; const addMaintenanceEntry = async (pmScheduleName: string, entryData: Partial): Promise => { setLoading(true); try { const response = await apiService.apiCall( '/api/method/asset_lite.api.ppm_generator_api.add_maintenance_entry', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ pm_schedule_name: pmScheduleName, entry_data: JSON.stringify(entryData) }) } ); if (response?.success) { return response.maintenance_entries; } else { throw new Error(response?.error || 'Failed to add maintenance entry'); } } finally { setLoading(false); } }; const removeMaintenanceEntry = async (pmScheduleName: string, entryName: string): Promise => { setLoading(true); try { const response = await apiService.apiCall( '/api/method/asset_lite.api.ppm_generator_api.remove_maintenance_entry', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ pm_schedule_name: pmScheduleName, entry_name: entryName }) } ); if (response?.success) { return response.maintenance_entries; } else { throw new Error(response?.error || 'Failed to remove maintenance entry'); } } finally { setLoading(false); } }; const updateMaintenanceEntry = async ( pmScheduleName: string, entryName: string, entryData: Partial ): Promise => { setLoading(true); try { const response = await apiService.apiCall( '/api/method/asset_lite.api.ppm_generator_api.update_maintenance_entry', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ pm_schedule_name: pmScheduleName, entry_name: entryName, entry_data: JSON.stringify(entryData) }) } ); if (response?.success) { return response.maintenance_entries; } else { throw new Error(response?.error || 'Failed to update maintenance entry'); } } finally { setLoading(false); } }; return { createPMSchedule, updatePMSchedule, deletePMSchedule, submitPMSchedule, cancelPMSchedule, addMaintenanceEntry, removeMaintenanceEntry, updateMaintenanceEntry, loading }; } export default { usePMSchedules, usePMScheduleDetails, usePMScheduleMutations };