import React, { useState, useEffect, useCallback } from 'react'; import { useParams, useNavigate, useSearchParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { useMaintenanceLogDetails, useMaintenanceMutations } from '../hooks/useAssetMaintenance'; import { FaArrowLeft, FaSave, FaEdit, FaClock, FaList, FaPlus, FaTrash, FaCheck, FaTimes, FaExclamationTriangle } from 'react-icons/fa'; import apiService from '../services/apiService'; import WorkflowActions from '../components/WorkflowActions'; import useDefaultHospital from '../hooks/useDefaultHospital'; // Cast apiService to any to bypass strict typing const api = apiService as any; // PPM Table Row Interface interface PPMTableRow { name?: string; idx?: number; maintenance_name: string; working: number | boolean; defect_found: number | boolean; not_working: number | boolean; } // Updated Interface with all fields from JSON interface MaintenanceLogData { name?: string; owner?: string; creation?: string; modified?: string; modified_by?: string; docstatus?: number; idx?: number; workflow_state?: string; asset_maintenance?: string; naming_series?: string; asset_name: string; custom_asset_type?: string; item_code?: string; item_name?: string; custom_asset_names?: string; custom_hospital_name?: string; task?: string; task_name?: string; maintenance_type: string; periodicity?: string; has_certificate?: number | boolean; custom_early_completion?: string; maintenance_status: string; custom_accepted_by_moh?: number | boolean; assign_to_name?: string; due_date?: string; completion_date?: string; custom_early_completion_reason?: string; custom_accepted_by_moh_?: number | boolean; custom_template?: string; custom_table?: PPMTableRow[]; description?: string; } // Toast notification component const Toast: React.FC<{ message: string; type: 'warning' | 'success' | 'error'; onClose: () => void }> = ({ message, type, onClose }) => { useEffect(() => { const timer = setTimeout(onClose, 10000); return () => clearTimeout(timer); }, [onClose]); const bgColor = type === 'warning' ? 'bg-yellow-500' : type === 'success' ? 'bg-green-500' : 'bg-red-500'; return (

{message}

); }; const AssetMaintenanceDetail: React.FC = () => { const { t } = useTranslation(); const { logName } = useParams<{ logName: string }>(); const navigate = useNavigate(); const [searchParams] = useSearchParams(); const duplicateFromLog = searchParams.get('duplicate'); const isNewLog = logName === 'new'; const isDuplicating = isNewLog && !!duplicateFromLog; const { log, loading, error } = useMaintenanceLogDetails( isDuplicating ? duplicateFromLog : (isNewLog ? null : logName || null) ); const { createLog, updateLog, loading: saving } = useMaintenanceMutations(); // Check if document is approved (not editable) const isApproved = log?.workflow_state === 'Approved'; const [isEditing, setIsEditing] = useState(isNewLog); const [ppmTableRows, setPpmTableRows] = useState([]); const [toast, setToast] = useState<{ message: string; type: 'warning' | 'success' | 'error' } | null>(null); const [templateLoading, setTemplateLoading] = useState(false); const [formData, setFormData] = useState({ asset_name: '', custom_asset_type: '', item_code: '', item_name: '', custom_asset_names: '', custom_hospital_name: '', task: '', task_name: '', maintenance_type: 'Preventive Maintenance', periodicity: '', has_certificate: 0, custom_early_completion: '', maintenance_status: 'Planned', custom_accepted_by_moh: 0, assign_to_name: '', due_date: '', completion_date: '', custom_early_completion_reason: '', custom_accepted_by_moh_: 0, custom_template: '', custom_table: [], description: '', }); useDefaultHospital(setFormData, { enabled: isNewLog && !isDuplicating, fields: ['custom_hospital_name'], }); // Check early completion logic const checkEarlyCompletion = useCallback((dueDate: string, completionDate: string, maintenanceStatus: string) => { if (maintenanceStatus !== 'Completed') { setFormData(prev => ({ ...prev, custom_early_completion: '' })); return; } if (!dueDate || !completionDate) { return; } const dueDateObj = new Date(dueDate); const completionDateObj = new Date(completionDate); const dueMonthStart = new Date(dueDateObj.getFullYear(), dueDateObj.getMonth(), 1); if (completionDateObj < dueMonthStart) { setFormData(prev => ({ ...prev, custom_early_completion: 'Yes' })); const formattedCompletionDate = completionDateObj.toLocaleDateString(); const formattedDueDate = dueDateObj.toLocaleDateString(); setToast({ message: `⚠️ Warning: Completion Date (${formattedCompletionDate}) is before the Due Date Month (${formattedDueDate}). Please verify.`, type: 'warning' }); } }, []); // Load PPM Template const loadPPMTemplate = useCallback(async (templateName: string) => { if (!templateName) return; setTemplateLoading(true); try { const response = await api.apiCall( `/api/resource/PPM Templates/${encodeURIComponent(templateName)}`, 'GET' ); if (response?.data?.ppm_template_table && Array.isArray(response.data.ppm_template_table)) { const templateRows: PPMTableRow[] = response.data.ppm_template_table.map((row: any, index: number) => ({ idx: index + 1, maintenance_name: row.maintenance_name || '', working: 0, defect_found: 0, not_working: 0, })); setPpmTableRows(templateRows); } } catch (err) { console.error('Error loading PPM template:', err); setToast({ message: 'Failed to load PPM template. Please add items manually.', type: 'error' }); } finally { setTemplateLoading(false); } }, []); // Load data when log is loaded useEffect(() => { if (log) { // If document is approved, ensure editing is disabled if (log.workflow_state === 'Approved') { setIsEditing(false); } setFormData({ asset_name: log.asset_name || '', custom_asset_type: log.custom_asset_type || '', item_code: log.item_code || '', item_name: log.item_name || '', custom_asset_names: log.custom_asset_names || '', custom_hospital_name: log.custom_hospital_name || '', task: log.task || '', task_name: log.task_name || '', maintenance_type: log.maintenance_type || 'Preventive Maintenance', periodicity: log.periodicity || '', has_certificate: log.has_certificate || 0, custom_early_completion: isDuplicating ? '' : (log.custom_early_completion || ''), maintenance_status: isDuplicating ? 'Planned' : (log.maintenance_status || 'Planned'), custom_accepted_by_moh: log.custom_accepted_by_moh || 0, assign_to_name: log.assign_to_name || '', due_date: log.due_date || '', completion_date: isDuplicating ? '' : (log.completion_date || ''), custom_early_completion_reason: isDuplicating ? '' : (log.custom_early_completion_reason || ''), custom_accepted_by_moh_: log.custom_accepted_by_moh_ || 0, custom_template: log.custom_template || '', custom_table: log.custom_table || [], description: log.description || '', }); if (log.custom_table && Array.isArray(log.custom_table) && log.custom_table.length > 0) { setPpmTableRows(log.custom_table.map((row: any, index: number) => ({ name: row.name, idx: row.idx || index + 1, maintenance_name: row.maintenance_name || '', working: row.working || 0, defect_found: row.defect_found || 0, not_working: row.not_working || 0, }))); } else if (log.custom_template && (!log.custom_table || log.custom_table.length === 0)) { loadPPMTemplate(log.custom_template); } } }, [log, isDuplicating, loadPPMTemplate]); // Handle completion_date change - trigger early completion check useEffect(() => { if (formData.completion_date && formData.due_date) { checkEarlyCompletion(formData.due_date, formData.completion_date, formData.maintenance_status); } }, [formData.completion_date, formData.due_date, formData.maintenance_status, checkEarlyCompletion]); const handleChange = (e: React.ChangeEvent) => { const { name, value, type } = e.target; const checked = (e.target as HTMLInputElement).checked; setFormData(prev => ({ ...prev, [name]: type === 'checkbox' ? (checked ? 1 : 0) : value })); }; const handleStatusChange = (e: React.ChangeEvent) => { const newStatus = e.target.value; setFormData(prev => ({ ...prev, maintenance_status: newStatus })); if (newStatus === 'Completed') { checkEarlyCompletion(formData.due_date || '', formData.completion_date || '', newStatus); } else { setFormData(prev => ({ ...prev, custom_early_completion: '' })); } }; const handleCompletionDateChange = (e: React.ChangeEvent) => { const newDate = e.target.value; setFormData(prev => ({ ...prev, completion_date: newDate })); if (formData.maintenance_status === 'Completed') { checkEarlyCompletion(formData.due_date || '', newDate, formData.maintenance_status); } }; const handleTemplateChange = async (e: React.ChangeEvent) => { const newTemplate = e.target.value; setFormData(prev => ({ ...prev, custom_template: newTemplate })); if (newTemplate && ppmTableRows.length === 0) { loadPPMTemplate(newTemplate); } else if (newTemplate && ppmTableRows.length > 0) { if (window.confirm('Loading a template will replace existing checklist items. Continue?')) { loadPPMTemplate(newTemplate); } } }; // PPM Table handlers const addPpmRow = () => { const newRow: PPMTableRow = { idx: ppmTableRows.length + 1, maintenance_name: '', working: 0, defect_found: 0, not_working: 0, }; setPpmTableRows([...ppmTableRows, newRow]); }; const removePpmRow = (index: number) => { const updated = ppmTableRows.filter((_, i) => i !== index).map((row, i) => ({ ...row, idx: i + 1 })); setPpmTableRows(updated); }; const updatePpmRow = (index: number, field: keyof PPMTableRow, value: any) => { const updated = [...ppmTableRows]; updated[index] = { ...updated[index], [field]: value }; setPpmTableRows(updated); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!formData.asset_name) { alert('Please enter Asset Name'); return; } if (!formData.maintenance_type) { alert('Please select Maintenance Type'); return; } // Clean PPM table rows - ensure name is either a valid string or removed const cleanedPpmRows = ppmTableRows.map((row, index) => { const cleanedRow: any = { idx: row.idx || index + 1, maintenance_name: row.maintenance_name || '', working: row.working ? 1 : 0, defect_found: row.defect_found ? 1 : 0, not_working: row.not_working ? 1 : 0, }; // Only include name if it's a valid non-empty string (existing row from DB) if (row.name && typeof row.name === 'string' && row.name.trim() !== '') { cleanedRow.name = row.name; } return cleanedRow; }); const submitData = { ...formData, custom_table: cleanedPpmRows, }; console.log('Submitting maintenance log data:', submitData); try { if (isNewLog || isDuplicating) { const newLog = await createLog(submitData as any); const successMessage = isDuplicating ? 'Maintenance log duplicated successfully!' : 'Maintenance log created successfully!'; alert(successMessage); navigate(`/maintenance/${newLog.name}`); } else if (logName) { await updateLog(logName, submitData as any); alert('Maintenance log updated successfully!'); setIsEditing(false); } } catch (err) { console.error('Maintenance log save error:', err); alert('Failed to save: ' + (err instanceof Error ? err.message : 'Unknown error')); } }; const getWorkflowStateBadge = (state: string) => { const stateColors: Record = { 'Draft': 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300', 'Applied': 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200', 'Pending': 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200', 'Approved': 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200', 'Rejected': 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200', 'Completed': 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200', }; return stateColors[state] || 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300'; }; const getStatusBadge = (status: string) => { const statusColors: Record = { 'Planned': 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200', 'Completed': 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200', 'Overdue': 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200', 'Cancelled': 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300', }; return statusColors[status] || 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300'; }; if (loading) { return (

Loading maintenance log...

); } if (error && !isNewLog && !isDuplicating) { return (

Error: {error}

); } return (
{/* Toast Notification */} {toast && ( setToast(null)} /> )} {/* Header */}
{!isNewLog && log?.workflow_state && ( {log.workflow_state} )} {/* {isApproved && ( 🔒 Locked )} */}
{!isNewLog && !isEditing && !isApproved && ( )} {isEditing && ( <> )}
{/* Standard View Form */}
{/* Left Column - Main Content */}
{/* Basic Information */}

Basic Information

{isDuplicating && (

💡 Duplicating from: {duplicateFromLog}

)}
{/*
*/}
{/* Maintenance Details */}

Maintenance Details

Enter template name to auto-load checklist items

{/* Early Completion & MOH Section */}

Completion & Approval

Auto-set based on completion date vs due date

{formData.custom_early_completion === 'Yes' && (
)}
{/* PPM Table (Checklist) */}

PPM Checklist Table {templateLoading && (Loading template...)}

{isEditing && ( )}
{isEditing && } {ppmTableRows.length === 0 ? ( ) : ( ppmTableRows.map((row, index) => ( {isEditing && ( )} )) )}
# Maintenance Task
Working
Defect
Not Working
Action
No checklist items. {isEditing && 'Enter a template name above or click "Add Row" to add items.'}
{row.idx || index + 1} {isEditing ? ( updatePpmRow(index, 'maintenance_name', e.target.value)} placeholder="Enter maintenance task" className="w-full px-2 py-1 text-sm border border-gray-300 dark:border-gray-600 rounded focus:outline-none focus:ring-1 focus:ring-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-white" /> ) : ( {row.maintenance_name} )} updatePpmRow(index, 'working', e.target.checked ? 1 : 0)} disabled={!isEditing} className="w-5 h-5 text-green-600 rounded focus:ring-2 focus:ring-green-500 cursor-pointer disabled:cursor-default" /> updatePpmRow(index, 'defect_found', e.target.checked ? 1 : 0)} disabled={!isEditing} className="w-5 h-5 text-yellow-600 rounded focus:ring-2 focus:ring-yellow-500 cursor-pointer disabled:cursor-default" /> updatePpmRow(index, 'not_working', e.target.checked ? 1 : 0)} disabled={!isEditing} className="w-5 h-5 text-red-600 rounded focus:ring-2 focus:ring-red-500 cursor-pointer disabled:cursor-default" />
{/* Right Column - Status Summary */}
{/* Workflow Actions */} {!isNewLog && log && (

Workflow Actions

{ if (success) { console.log(`Action "${action}" completed successfully`); } }} onStateChange={() => { // Reload page to reflect new state window.location.reload(); }} />
)} {/* Status Card */}

Status Summary

{!isNewLog && log ? (

Current Status

{formData.maintenance_status || 'Planned'}

Workflow State

{log.workflow_state || 'Draft'}
{formData.custom_early_completion === 'Yes' && (

⚠️ Early Completion

Completion date is before the due month

)}

Due Date

{formData.due_date ? new Date(formData.due_date).toLocaleDateString() : 'Not set'}

{formData.due_date && new Date(formData.due_date) < new Date() && formData.maintenance_status !== 'Completed' && (

⚠️ Overdue

)}

Completion Date

{formData.completion_date ? new Date(formData.completion_date).toLocaleDateString() : 'Not completed'}

Assigned To

{formData.assign_to_name || 'Unassigned'}

PPM Checklist

{ppmTableRows.length} item(s)

{ppmTableRows.length > 0 && (

✓ Working: {ppmTableRows.filter(r => r.working).length}

⚠ Defects: {ppmTableRows.filter(r => r.defect_found).length}

✗ Not Working: {ppmTableRows.filter(r => r.not_working).length}

)}
) : (

Status information will appear after creation

)}
{/* Audit Information */} {!isNewLog && log && (

Audit Information

Created By

{log.owner || '-'}

Created On

{log.creation ? new Date(log.creation).toLocaleString() : '-'}

Modified By

{log.modified_by || '-'}

Modified On

{log.modified ? new Date(log.modified).toLocaleString() : '-'}

)}
); }; export default AssetMaintenanceDetail;