175 lines
4.9 KiB
TypeScript
175 lines
4.9 KiB
TypeScript
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
import ppmService from '../services/ppmService';
|
|
import type { AssetMaintenance, PPMFilters, CreatePPMData } from '../services/ppmService';
|
|
|
|
/**
|
|
* Hook to fetch list of asset maintenances (PPM schedules) with filters and pagination
|
|
*/
|
|
export function usePPMs(
|
|
filters?: PPMFilters,
|
|
limit: number = 20,
|
|
offset: number = 0,
|
|
orderBy?: string
|
|
) {
|
|
const [ppms, setPPMs] = useState<AssetMaintenance[]>([]);
|
|
const [totalCount, setTotalCount] = useState(0);
|
|
const [hasMore, setHasMore] = useState(false);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [refetchTrigger, setRefetchTrigger] = useState(0);
|
|
const hasAttemptedRef = useRef(false);
|
|
|
|
const filtersJson = JSON.stringify(filters);
|
|
|
|
useEffect(() => {
|
|
if (hasAttemptedRef.current && error) {
|
|
return;
|
|
}
|
|
|
|
let isCancelled = false;
|
|
hasAttemptedRef.current = true;
|
|
|
|
const fetchPPMs = async () => {
|
|
try {
|
|
setLoading(true);
|
|
|
|
const response = await ppmService.getAssetMaintenances(filters, undefined, limit, offset, orderBy);
|
|
|
|
if (!isCancelled) {
|
|
setPPMs(response.asset_maintenances);
|
|
setTotalCount(response.total_count);
|
|
setHasMore(response.has_more);
|
|
setError(null);
|
|
}
|
|
} catch (err) {
|
|
if (!isCancelled) {
|
|
const errorMessage = err instanceof Error ? err.message : 'Failed to fetch PPM schedules';
|
|
|
|
if (errorMessage.includes('417') || errorMessage.includes('Expectation Failed') || errorMessage.includes('has no attribute')) {
|
|
setError('API endpoint not deployed. Please deploy ppm_api.py to your Frappe server.');
|
|
} else {
|
|
setError(errorMessage);
|
|
}
|
|
|
|
setPPMs([]);
|
|
setTotalCount(0);
|
|
setHasMore(false);
|
|
}
|
|
} finally {
|
|
if (!isCancelled) {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
};
|
|
|
|
fetchPPMs();
|
|
|
|
return () => {
|
|
isCancelled = true;
|
|
};
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [filtersJson, limit, offset, orderBy, refetchTrigger]);
|
|
|
|
const refetch = useCallback(() => {
|
|
hasAttemptedRef.current = false;
|
|
setRefetchTrigger(prev => prev + 1);
|
|
}, []);
|
|
|
|
return { ppms, totalCount, hasMore, loading, error, refetch };
|
|
}
|
|
|
|
/**
|
|
* Hook to fetch a single PPM schedule by name
|
|
*/
|
|
export function usePPMDetails(ppmName: string | null) {
|
|
const [ppm, setPPM] = useState<AssetMaintenance | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const fetchPPM = useCallback(async () => {
|
|
if (!ppmName) {
|
|
setPPM(null);
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
const data = await ppmService.getAssetMaintenanceDetails(ppmName);
|
|
setPPM(data);
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'Failed to fetch PPM details');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [ppmName]);
|
|
|
|
useEffect(() => {
|
|
fetchPPM();
|
|
}, [fetchPPM]);
|
|
|
|
const refetch = useCallback(() => {
|
|
fetchPPM();
|
|
}, [fetchPPM]);
|
|
|
|
return { ppm, loading, error, refetch };
|
|
}
|
|
|
|
/**
|
|
* Hook to manage PPM operations (create, update, delete)
|
|
*/
|
|
export function usePPMMutations() {
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const createPPM = useCallback(async (data: CreatePPMData) => {
|
|
try {
|
|
setLoading(true);
|
|
setError(null);
|
|
const result = await ppmService.createAssetMaintenance(data);
|
|
return result;
|
|
} catch (err) {
|
|
const errorMessage = err instanceof Error ? err.message : 'Failed to create PPM schedule';
|
|
setError(errorMessage);
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
const updatePPM = useCallback(async (ppmName: string, data: Partial<CreatePPMData>) => {
|
|
try {
|
|
setLoading(true);
|
|
setError(null);
|
|
const result = await ppmService.updateAssetMaintenance(ppmName, data);
|
|
return result;
|
|
} catch (err) {
|
|
const errorMessage = err instanceof Error ? err.message : 'Failed to update PPM schedule';
|
|
setError(errorMessage);
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
const deletePPM = useCallback(async (ppmName: string) => {
|
|
try {
|
|
setLoading(true);
|
|
setError(null);
|
|
const result = await ppmService.deleteAssetMaintenance(ppmName);
|
|
return result;
|
|
} catch (err) {
|
|
const errorMessage = err instanceof Error ? err.message : 'Failed to delete PPM schedule';
|
|
setError(errorMessage);
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
return { createPPM, updatePPM, deletePPM, loading, error };
|
|
}
|
|
|