import React, { useState, useEffect, useRef } from 'react'; import { useNavigate } from 'react-router-dom'; import { useWorkOrders, useWorkOrderMutations } from '../hooks/useWorkOrder'; import { FaPlus, FaSearch, FaEdit, FaEye, FaTrash, FaCopy, FaEllipsisV, FaDownload, FaPrint, FaFileExport, FaCheckCircle, FaClock, FaExclamationTriangle } from 'react-icons/fa'; const WorkOrderList: React.FC = () => { const navigate = useNavigate(); const [page, setPage] = useState(0); const [searchTerm, setSearchTerm] = useState(''); const [statusFilter, setStatusFilter] = useState(''); const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(null); const [actionMenuOpen, setActionMenuOpen] = useState(null); const dropdownRef = useRef(null); const limit = 20; const filters = statusFilter ? { repair_status: statusFilter } : {}; const { workOrders, totalCount, hasMore, loading, error, refetch } = useWorkOrders( filters, limit, page * limit, 'creation desc' ); const { deleteWorkOrder, loading: mutationLoading } = useWorkOrderMutations(); // Close dropdown when clicking outside useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { setActionMenuOpen(null); } }; if (actionMenuOpen) { document.addEventListener('mousedown', handleClickOutside); } return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, [actionMenuOpen]); const handleCreateNew = () => { navigate('/work-orders/new'); }; const handleView = (workOrderName: string) => { navigate(`/work-orders/${workOrderName}`); }; const handleEdit = (workOrderName: string) => { navigate(`/work-orders/${workOrderName}`); }; const handleDelete = async (workOrderName: string) => { try { await deleteWorkOrder(workOrderName); setDeleteConfirmOpen(null); refetch(); alert('Work order deleted successfully!'); } catch (err) { alert(`Failed to delete work order: ${err instanceof Error ? err.message : 'Unknown error'}`); } }; const handleDuplicate = (workOrderName: string) => { navigate(`/work-orders/new?duplicate=${workOrderName}`); }; const handleExport = (workOrder: any) => { const dataStr = JSON.stringify(workOrder, null, 2); const dataBlob = new Blob([dataStr], { type: 'application/json' }); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = `work_order_${workOrder.name}.json`; link.click(); URL.revokeObjectURL(url); }; const handlePrint = (workOrderName: string) => { window.open(`/work-orders/${workOrderName}?print=true`, '_blank'); }; const handleExportAll = () => { const headers = ['Work Order ID', 'Asset', 'Type', 'Status', 'Department', 'Priority', 'Created']; const csvContent = [ headers.join(','), ...workOrders.map(wo => [ wo.name, wo.asset_name || wo.asset || '', wo.work_order_type || '', wo.repair_status || '', wo.department || '', wo.custom_priority_ || '', wo.creation ? new Date(wo.creation).toLocaleDateString() : '' ].join(',')) ].join('\n'); const dataBlob = new Blob([csvContent], { type: 'text/csv' }); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = `work_orders_export_${new Date().toISOString().split('T')[0]}.csv`; link.click(); URL.revokeObjectURL(url); }; const getStatusIcon = (status: string) => { switch (status?.toLowerCase()) { case 'completed': return ; case 'in progress': return ; case 'pending': return ; default: return ; } }; const getStatusColor = (status: string) => { switch (status?.toLowerCase()) { case 'completed': return 'bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-300'; case 'in progress': return 'bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-300'; case 'pending': case 'open': return 'bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-300'; case 'cancelled': return 'bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-300'; default: return 'bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-300'; } }; const getPriorityColor = (priority: string) => { switch (priority?.toLowerCase()) { case 'high': case 'urgent': return 'bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-300'; case 'medium': return 'bg-orange-100 dark:bg-orange-900/30 text-orange-800 dark:text-orange-300'; case 'low': return 'bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-300'; default: return 'bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-300'; } }; if (loading && page === 0) { return (

Loading work orders...

); } if (error) { return (

⚠️ Work Order API Not Available

The Work Order API endpoint is not deployed yet.

To fix this, deploy the work_order_api.py file to your Frappe server.

Technical Error: {error}

); } // Filter work orders by search term const filteredWorkOrders = workOrders.filter(wo => wo.name?.toLowerCase().includes(searchTerm.toLowerCase()) || wo.asset_name?.toLowerCase().includes(searchTerm.toLowerCase()) || wo.description?.toLowerCase().includes(searchTerm.toLowerCase()) || wo.asset?.toLowerCase().includes(searchTerm.toLowerCase()) ); return (
{/* Header */}

Work Orders

Total: {totalCount} work order{totalCount !== 1 ? 's' : ''}

{/* Filters Bar */}
{/* Search Bar */}
setSearchTerm(e.target.value)} className="flex-1 outline-none text-gray-700 dark:text-gray-200 bg-transparent" />
{/* Status Filter */}
{/* Work Orders Table */}
{filteredWorkOrders.length === 0 ? ( ) : ( filteredWorkOrders.map((workOrder) => ( handleView(workOrder.name)} > )) )}
Work Order ID Asset Type Department Status Priority Actions

No work orders found

{workOrder.name}
{workOrder.creation ? new Date(workOrder.creation).toLocaleDateString() : ''}
{workOrder.asset_name || '-'}
{workOrder.asset || ''}
{workOrder.work_order_type || '-'} {workOrder.department || '-'}
{getStatusIcon(workOrder.repair_status || '')} {workOrder.repair_status || 'Unknown'}
{workOrder.custom_priority_ || 'Normal'}
e.stopPropagation()}> {/* More Actions Dropdown */}
{actionMenuOpen === workOrder.name && (
)}
{/* Pagination */} {filteredWorkOrders.length > 0 && (
Showing {page * limit + 1} to{' '} {Math.min((page + 1) * limit, totalCount)} {' '} of {totalCount} results
)}
{/* Delete Confirmation Modal */} {deleteConfirmOpen && (

Delete Work Order

Are you sure you want to delete this work order? This action cannot be undone.

Work Order ID: {deleteConfirmOpen}

)}
); }; export default WorkOrderList;