pmtool / src /services /systemDetailsApi.ts
devarshia5's picture
Upload 487 files
d97b8f9 verified
Raw
History Blame Contribute Delete
10.5 kB
import apiClient from '@/lib/api/axios-instance';
import { AxiosError } from 'axios';
import {
SystemDetails,
SystemDetailsCreateRequest,
SystemDetailsUpdateRequest,
validateSystemDetailsApiResponse
} from '@/types/asset-management';
import { assetApi } from './assetApi';
// Helper to create a safe system details object with default values for null/undefined fields
const createSafeSystemDetails = (data: any): SystemDetails => {
return {
systemDetailsID: data.systemDetailsID || 0,
assetID: data.assetID || 0,
systemModel: data.systemModel || '',
processor: data.processor || '',
installedRAM: data.installedRAM || '',
graphics: data.graphics || '',
screenResolution: data.screenResolution || '',
diskModel: data.diskModel || '',
diskSize: data.diskSize || '',
manufacturer: data.manufacturer || '',
};
};
// Helper to handle API errors with user-friendly messages
const handleApiError = (error: unknown, operation: string): never => {
console.error(`SystemDetailsApi: Error during ${operation}:`, error);
if (error instanceof AxiosError) {
const status = error.response?.status;
const message = error.response?.data?.message || error.message;
switch (status) {
case 400:
throw new Error(`Invalid request: ${message}`);
case 401:
throw new Error('You are not authorized to perform this action. Please log in again.');
case 403:
throw new Error('You do not have permission to perform this action.');
case 404:
throw new Error('The requested system details were not found.');
case 409:
throw new Error('System details already exist for this asset or conflict with existing data.');
case 422:
throw new Error(`Validation failed: ${message}`);
case 500:
throw new Error('Server error occurred. Please try again later.');
case 503:
throw new Error('Service is temporarily unavailable. Please try again later.');
default:
throw new Error(`${operation} failed: ${message}`);
}
}
if (error instanceof Error) {
throw new Error(`${operation} failed: ${error.message}`);
}
throw new Error(`${operation} failed: Unknown error occurred`);
};
// Helper for retry logic
const retryOperation = async <T>(
operation: () => Promise<T>,
maxRetries: number = 3,
delay: number = 1000
): Promise<T> => {
let lastError: unknown;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
lastError = error;
// Don't retry on client errors (4xx) except for 408 (timeout) and 429 (rate limit)
if (error instanceof AxiosError) {
const status = error.response?.status;
if (status && status >= 400 && status < 500 && status !== 408 && status !== 429) {
throw error;
}
}
if (attempt === maxRetries) {
throw lastError;
}
// Exponential backoff
const waitTime = delay * Math.pow(2, attempt - 1);
console.log(`SystemDetailsApi: Retry attempt ${attempt}/${maxRetries} in ${waitTime}ms`);
await new Promise(resolve => setTimeout(resolve, waitTime));
}
}
throw lastError;
};
class SystemDetailsApi {
private baseUrl = `/api/SystemsDetails`;
async getAll(): Promise<SystemDetails[]> {
return retryOperation(async () => {
try {
console.log('SystemDetailsApi: Fetching all system details from', this.baseUrl);
const response = await apiClient.get(this.baseUrl);
console.log('SystemDetailsApi: Response status', response.status);
if (!response.data) {
console.warn('SystemDetailsApi: No data in response');
return [];
}
if (!Array.isArray(response.data)) {
console.warn('SystemDetailsApi: Response is not an array', response.data);
return [];
}
console.log(`SystemDetailsApi: Found ${response.data.length} system details`);
// Map each item to ensure it has all required fields and validate
return response.data.map(item => {
try {
return validateSystemDetailsApiResponse(item);
} catch (error) {
console.warn('SystemDetailsApi: Invalid system details data, using safe fallback:', error);
return createSafeSystemDetails(item);
}
});
} catch (error) {
handleApiError(error, 'fetch system details');
}
});
}
async getById(id: number): Promise<SystemDetails | null> {
try {
console.log(`SystemDetailsApi: Fetching system details ${id}`);
const response = await apiClient.get(`${this.baseUrl}/${id}`);
console.log(`SystemDetailsApi: Response status for system details ${id}`, response.status);
if (response.data) {
try {
return validateSystemDetailsApiResponse(response.data);
} catch (error) {
console.warn(`SystemDetailsApi: Invalid system details data for ID ${id}, using safe fallback:`, error);
return createSafeSystemDetails(response.data);
}
}
return null;
} catch (error) {
console.error(`SystemDetailsApi: Error fetching system details ${id}:`, error);
return null;
}
}
async getByAssetId(assetId: number): Promise<SystemDetails | null> {
return retryOperation(async () => {
try {
console.log(`SystemDetailsApi: Fetching system details for asset ${assetId}`);
const response = await apiClient.get(`${this.baseUrl}/by-asset/${assetId}`);
console.log(`SystemDetailsApi: Response status for asset ${assetId} system details`, response.status);
if (!response.data) {
console.warn(`SystemDetailsApi: No system details found for asset ${assetId}`);
return null;
}
// Handle both single object and array responses
let systemDetailsData;
if (Array.isArray(response.data)) {
// If it's an array, take the first item (assuming one system details per asset)
systemDetailsData = response.data.length > 0 ? response.data[0] : null;
console.log(`SystemDetailsApi: Found ${response.data.length} system details for asset ${assetId}, using first one`);
} else {
// If it's a single object, use it directly
systemDetailsData = response.data;
console.log(`SystemDetailsApi: Found system details for asset ${assetId}`);
}
if (!systemDetailsData) {
return null;
}
try {
return validateSystemDetailsApiResponse(systemDetailsData);
} catch (error) {
console.warn(`SystemDetailsApi: Invalid system details data for asset ${assetId}, using safe fallback:`, error);
return createSafeSystemDetails(systemDetailsData);
}
} catch (error) {
if (error instanceof AxiosError && error.response?.status === 404) {
console.log(`SystemDetailsApi: No system details found for asset ${assetId}`);
return null;
}
handleApiError(error, `fetch system details for asset ${assetId}`);
}
});
}
async create(systemDetails: SystemDetailsCreateRequest): Promise<SystemDetails> {
return retryOperation(async () => {
try {
// Validate that the referenced asset exists
const asset = await assetApi.getById(systemDetails.assetID);
if (!asset) {
throw new Error(`Asset with ID ${systemDetails.assetID} does not exist. Please select a valid asset.`);
}
const systemDetailsData = { ...systemDetails };
console.log('SystemDetailsApi: Creating system details with data', systemDetailsData);
const response = await apiClient.post(this.baseUrl, systemDetailsData);
console.log('SystemDetailsApi: Create response status', response.status);
try {
return validateSystemDetailsApiResponse(response.data);
} catch (error) {
console.warn('SystemDetailsApi: Invalid response data from create, using safe fallback:', error);
return createSafeSystemDetails(response.data);
}
} catch (error) {
handleApiError(error, 'create system details');
}
}, 2); // Fewer retries for create operations
}
async update(id: number, systemDetails: SystemDetailsUpdateRequest): Promise<SystemDetails> {
try {
// Validate that the referenced asset exists
const asset = await assetApi.getById(systemDetails.assetID);
if (!asset) {
const errorMessage = `Asset with ID ${systemDetails.assetID} does not exist`;
console.error('SystemDetailsApi:', errorMessage);
throw new Error(errorMessage);
}
const systemDetailsData = { ...systemDetails };
console.log(`SystemDetailsApi: Updating system details ${id} with data`, systemDetailsData);
const response = await apiClient.put(`${this.baseUrl}/${id}`, systemDetailsData);
console.log(`SystemDetailsApi: Update response status for system details ${id}`, response.status);
try {
return validateSystemDetailsApiResponse(response.data);
} catch (error) {
console.warn(`SystemDetailsApi: Invalid response data from update for ID ${id}, using safe fallback:`, error);
return createSafeSystemDetails(response.data);
}
} catch (error) {
console.error(`SystemDetailsApi: Error updating system details ${id}:`, error);
throw error;
}
}
async delete(id: number): Promise<void> {
try {
console.log(`SystemDetailsApi: Deleting system details ${id}`);
await apiClient.delete(`${this.baseUrl}/${id}`);
console.log(`SystemDetailsApi: System details ${id} deleted successfully`);
} catch (error) {
console.error(`SystemDetailsApi: Error deleting system details ${id}:`, error);
throw error;
}
}
}
export const systemDetailsApi = new SystemDetailsApi();