From 462b6d6d40d90526ec2a8fd53e09a07a11f345b4 Mon Sep 17 00:00:00 2001 From: Tola Leng Date: Fri, 23 May 2025 20:37:36 +0800 Subject: [PATCH] Build Incident and maintenance service --- application/src/services/incidentService.ts | 4 + .../src/services/maintenanceService.ts | 182 ++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 application/src/services/incidentService.ts create mode 100644 application/src/services/maintenanceService.ts diff --git a/application/src/services/incidentService.ts b/application/src/services/incidentService.ts new file mode 100644 index 0000000..d8e3f46 --- /dev/null +++ b/application/src/services/incidentService.ts @@ -0,0 +1,4 @@ + +// Re-export incident service from the new modular structure +export * from './incident'; +export { incidentService as default } from './incident'; diff --git a/application/src/services/maintenanceService.ts b/application/src/services/maintenanceService.ts new file mode 100644 index 0000000..feccc2a --- /dev/null +++ b/application/src/services/maintenanceService.ts @@ -0,0 +1,182 @@ + +import { pb, getCurrentEndpoint } from '@/lib/pocketbase'; +import { MaintenanceItem, CreateMaintenanceInput } from './types/maintenance.types'; + +// Helper function to get the API URL +const getApiUrl = (): string => { + return getCurrentEndpoint(); +}; + +// Helper function to normalize maintenance items +const normalizeMaintenanceItem = (item: any): MaintenanceItem => { + return { + ...item, + id: item.id || '', + title: item.title || '', + description: item.description || '', + status: item.status || 'Scheduled', + affected: item.affected || '', + priority: item.priority || 'Medium', + field: item.field || 'Minor', + } as MaintenanceItem; +}; + +const getMaintenanceRecords = async (): Promise => { + try { + // Use a unique requestKey to prevent caching issues + const timestamp = new Date().getTime(); + + console.log("Fetching maintenance records from API..."); + + // Increase items per page to ensure we get all records + const result = await pb.collection('maintenance').getList(1, 200, { + sort: '-created', + requestKey: `maintenance-${timestamp}`, + }); + + console.log("Maintenance API response:", result); + + if (!result || !result.items || result.items.length === 0) { + console.log("No maintenance records found"); + return []; + } + + return result.items.map(normalizeMaintenanceItem); + } catch (error) { + // Handle abort errors gracefully without console errors + if ((error as any)?.isAbort) { + console.log("Request aborted:", error); + return []; + } + + console.error('Error fetching maintenance records:', error); + // Return empty array instead of throwing to prevent UI crashes + return []; + } +}; + +const getUpcomingMaintenance = async (): Promise => { + try { + const allRecords = await getMaintenanceRecords(); + const currentDate = new Date(); + + // Filter for upcoming maintenance + const upcomingItems = allRecords.filter(item => { + const status = item.status?.toLowerCase() || ''; + const startTime = new Date(item.start_time); + + return (status === 'scheduled' && startTime > currentDate); + }); + + return upcomingItems; + } catch (error) { + console.error('Error fetching upcoming maintenance:', error); + return []; + } +}; + +const getOngoingMaintenance = async (): Promise => { + try { + const allRecords = await getMaintenanceRecords(); + const currentDate = new Date(); + + // Filter for ongoing maintenance + const ongoingItems = allRecords.filter(item => { + const status = item.status?.toLowerCase() || ''; + const startTime = new Date(item.start_time); + const endTime = new Date(item.end_time); + + return status === 'in_progress' || + (status === 'scheduled' && startTime <= currentDate && endTime >= currentDate); + }); + + return ongoingItems; + } catch (error) { + console.error('Error fetching ongoing maintenance:', error); + return []; + } +}; + +const getCompletedMaintenance = async (): Promise => { + try { + const allRecords = await getMaintenanceRecords(); + + // Filter for completed maintenance + const completedItems = allRecords.filter(item => { + const status = item.status?.toLowerCase() || ''; + return status === 'completed' || status === 'cancelled'; + }); + + return completedItems; + } catch (error) { + console.error('Error fetching completed maintenance:', error); + return []; + } +}; + +const updateMaintenanceStatus = async (id: string, status: string): Promise => { + try { + // Ensure proper case for the status value + const formattedStatus = status.charAt(0).toUpperCase() + status.slice(1); + await pb.collection('maintenance').update(id, { status: formattedStatus }); + } catch (error) { + console.error('Error updating maintenance status:', error); + throw error; + } +}; + +const deleteMaintenance = async (id: string): Promise => { + try { + await pb.collection('maintenance').delete(id); + } catch (error) { + console.error('Error deleting maintenance:', error); + throw error; + } +}; + +const createMaintenance = async (data: CreateMaintenanceInput): Promise => { + try { + // Validate that all required fields are present + if (!data.title || !data.description || !data.start_time || !data.end_time || + !data.affected || !data.priority || !data.status || !data.field) { + throw new Error("Missing required fields for maintenance creation"); + } + + // Format the payload according to API requirements + const payload = { + title: data.title, + description: data.description, + start_time: data.start_time, + end_time: data.end_time, + affected: data.affected, + priority: data.priority.charAt(0).toUpperCase() + data.priority.slice(1), + status: data.status.charAt(0).toUpperCase() + data.status.slice(1), + field: data.field.charAt(0).toUpperCase() + data.field.slice(1), + created_by: data.created_by, + notify_subscribers: data.notify_subscribers, + assigned_users: data.assigned_users || "", + notification_channel_id: data.notification_channel_id || "", + }; + + await pb.collection('maintenance').create(payload); + } catch (error) { + console.error('Error creating maintenance:', error); + if (error instanceof Error) { + console.error('Error details:', error.message); + } + throw error; + } +}; + +export const maintenanceService = { + getApiUrl, + getMaintenanceRecords, + getUpcomingMaintenance, + getOngoingMaintenance, + getCompletedMaintenance, + updateMaintenanceStatus, + deleteMaintenance, + createMaintenance, +}; + +// No need to re-export types here as they are now imported from maintenance.types.ts