import React, { useState, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { Plus, AlertTriangle, Settings, CheckCircle, Eye, Wrench, Thermometer, Activity, Search, Filter, Bell, History, Calendar, Edit, Trash2 } from 'lucide-react'; import { Button, StatsGrid, StatusCard, getStatusColor, SearchAndFilter, type FilterConfig, EmptyState } from '../../../../components/ui'; import { Badge } from '../../../../components/ui/Badge'; import { LoadingSpinner } from '../../../../components/ui'; import { PageHeader } from '../../../../components/layout'; import { useCurrentTenant } from '../../../../stores/tenant.store'; import { Equipment } from '../../../../api/types/equipment'; import { EquipmentModal } from '../../../../components/domain/equipment/EquipmentModal'; import { DeleteEquipmentModal } from '../../../../components/domain/equipment/DeleteEquipmentModal'; import { MaintenanceHistoryModal } from '../../../../components/domain/equipment/MaintenanceHistoryModal'; import { ScheduleMaintenanceModal, type MaintenanceScheduleData } from '../../../../components/domain/equipment/ScheduleMaintenanceModal'; import { ReportFailureModal } from '../../../../components/domain/equipment/ReportFailureModal'; import { MarkAsRepairedModal } from '../../../../components/domain/equipment/MarkAsRepairedModal'; import { useEquipment, useCreateEquipment, useUpdateEquipment, useDeleteEquipment, useHardDeleteEquipment } from '../../../../api/hooks/equipment'; import { equipmentService } from '../../../../api/services/equipment'; import { useQueryClient } from '@tanstack/react-query'; const MaquinariaPage: React.FC = () => { const queryClient = useQueryClient(); const { t } = useTranslation(['equipment', 'common']); const [searchTerm, setSearchTerm] = useState(''); const [statusFilter, setStatusFilter] = useState(''); const [typeFilter, setTypeFilter] = useState(''); const [showEquipmentModal, setShowEquipmentModal] = useState(false); const [equipmentModalMode, setEquipmentModalMode] = useState<'view' | 'edit' | 'create'>('create'); const [selectedEquipment, setSelectedEquipment] = useState(null); // New modal states const [showDeleteModal, setShowDeleteModal] = useState(false); const [showHistoryModal, setShowHistoryModal] = useState(false); const [showScheduleModal, setShowScheduleModal] = useState(false); const [showReportFailureModal, setShowReportFailureModal] = useState(false); const [showMarkRepairedModal, setShowMarkRepairedModal] = useState(false); const [equipmentForAction, setEquipmentForAction] = useState(null); const currentTenant = useCurrentTenant(); const tenantId = currentTenant?.id || ''; // Fetch equipment data from API const { data: equipment = [], isLoading, error } = useEquipment(tenantId, { is_active: true }); // Mutations for create, update, and delete const createEquipmentMutation = useCreateEquipment(tenantId); const updateEquipmentMutation = useUpdateEquipment(tenantId); const deleteEquipmentMutation = useDeleteEquipment(tenantId); const hardDeleteEquipmentMutation = useHardDeleteEquipment(tenantId); const handleCreateEquipment = () => { setSelectedEquipment({ id: '', name: '', type: 'other', model: '', serialNumber: '', location: '', status: 'operational', installDate: new Date().toISOString().split('T')[0], lastMaintenance: new Date().toISOString().split('T')[0], nextMaintenance: new Date().toISOString().split('T')[0], maintenanceInterval: 30, efficiency: 100, uptime: 100, energyUsage: 0, utilizationToday: 0, alerts: [], maintenanceHistory: [], specifications: { power: 0, capacity: 0, dimensions: { width: 0, height: 0, depth: 0 }, weight: 0 } } as Equipment); setEquipmentModalMode('create'); setShowEquipmentModal(true); }; const handleEditEquipment = (equipmentId: string) => { // Find the equipment to edit from real data const equipmentToEdit = equipment.find(eq => eq.id === equipmentId); if (equipmentToEdit) { setSelectedEquipment(equipmentToEdit); setEquipmentModalMode('edit'); setShowEquipmentModal(true); } }; const handleReportFailure = (equipment: Equipment) => { setEquipmentForAction(equipment); setShowReportFailureModal(true); }; const handleMarkAsRepaired = (equipment: Equipment) => { setEquipmentForAction(equipment); setShowMarkRepairedModal(true); }; const handleScheduleMaintenance = (equipment: Equipment) => { setEquipmentForAction(equipment); setShowScheduleModal(true); }; const handleReportFailureSubmit = async (equipmentId: string, failureData: { failureType: string; severity: string; description: string; photos?: File[]; estimatedImpact: boolean; }) => { try { // Use the new API endpoint await equipmentService.reportEquipmentFailure( tenantId, equipmentId, failureData ); // Refresh equipment data await queryClient.invalidateQueries({ queryKey: ['equipment', tenantId] }); setShowReportFailureModal(false); setEquipmentForAction(null); } catch (error) { console.error('Error reporting failure:', error); throw error; } }; const handleMarkAsRepairedSubmit = async (equipmentId: string, repairData: { repairDate: string; technicianName: string; repairDescription: string; partsReplaced: string[]; cost: number; photos?: File[]; testResults: boolean; }) => { try { // Use the new API endpoint await equipmentService.markEquipmentAsRepaired( tenantId, equipmentId, repairData ); // Refresh equipment data await queryClient.invalidateQueries({ queryKey: ['equipment', tenantId] }); setShowMarkRepairedModal(false); setEquipmentForAction(null); } catch (error) { console.error('Error marking as repaired:', error); throw error; } }; const handleScheduleMaintenanceSubmit = async (equipmentId: string, maintenanceData: MaintenanceScheduleData) => { try { // Update next maintenance date based on scheduled date await updateEquipmentMutation.mutateAsync({ equipmentId: equipmentId, equipmentData: { nextMaintenance: maintenanceData.scheduledDate } as Partial }); setShowScheduleModal(false); setEquipmentForAction(null); } catch (error) { console.error('Error scheduling maintenance:', error); throw error; } }; const handleViewMaintenanceHistory = (equipment: Equipment) => { setEquipmentForAction(equipment); setShowHistoryModal(true); }; const handleDeleteEquipment = (equipment: Equipment) => { setEquipmentForAction(equipment); setShowDeleteModal(true); }; const handleSoftDelete = async (equipmentId: string) => { try { await deleteEquipmentMutation.mutateAsync(equipmentId); setShowDeleteModal(false); setEquipmentForAction(null); } catch (error) { console.error('Error deleting equipment:', error); throw error; } }; const handleHardDelete = async (equipmentId: string) => { try { await hardDeleteEquipmentMutation.mutateAsync(equipmentId); setShowDeleteModal(false); setEquipmentForAction(null); } catch (error) { console.error('Error hard deleting equipment:', error); throw error; } }; const handleSaveEquipment = async (equipmentData: Equipment) => { try { if (equipmentModalMode === 'create') { await createEquipmentMutation.mutateAsync(equipmentData); } else if (equipmentModalMode === 'edit' && equipmentData.id) { await updateEquipmentMutation.mutateAsync({ equipmentId: equipmentData.id, equipmentData: equipmentData }); } setShowEquipmentModal(false); setSelectedEquipment(null); } catch (error) { console.error('Error saving equipment:', error); // Error is already handled by mutation with toast } }; const filteredEquipment = useMemo(() => { return equipment.filter(eq => { const matchesSearch = !searchTerm || eq.name.toLowerCase().includes(searchTerm.toLowerCase()) || eq.location.toLowerCase().includes(searchTerm.toLowerCase()) || eq.type.toLowerCase().includes(searchTerm.toLowerCase()); const matchesStatus = !statusFilter || eq.status === statusFilter; const matchesType = !typeFilter || eq.type === typeFilter; return matchesSearch && matchesStatus && matchesType; }); }, [equipment, searchTerm, statusFilter, typeFilter]); const equipmentStats = useMemo(() => { const total = equipment.length; const operational = equipment.filter(e => e.status === 'operational').length; const warning = equipment.filter(e => e.status === 'warning').length; const maintenance = equipment.filter(e => e.status === 'maintenance').length; const down = equipment.filter(e => e.status === 'down').length; const totalAlerts = equipment.reduce((sum, e) => sum + e.alerts.filter(a => !a.acknowledged).length, 0); return { total, operational, warning, maintenance, down, totalAlerts }; }, [equipment]); const getStatusConfig = (status: Equipment['status']) => { const configs = { operational: { color: getStatusColor('completed'), text: t('equipment_status.operational'), icon: CheckCircle }, warning: { color: getStatusColor('warning'), text: t('equipment_status.warning'), icon: AlertTriangle }, maintenance: { color: getStatusColor('info'), text: t('equipment_status.maintenance'), icon: Wrench }, down: { color: getStatusColor('error'), text: t('equipment_status.down'), icon: AlertTriangle } }; return configs[status] || { color: getStatusColor('other'), text: status, icon: Settings }; }; const getTypeIcon = (type: Equipment['type']) => { const icons = { oven: Thermometer, mixer: Activity, proofer: Settings, freezer: Settings, packaging: Settings, other: Settings }; return icons[type]; }; const stats = [ { title: t('labels.total_equipment'), value: equipmentStats.total, variant: 'default' as const, icon: Settings, }, { title: t('labels.operational'), value: equipmentStats.operational, variant: 'success' as const, icon: CheckCircle, }, { title: t('labels.warning'), value: equipmentStats.warning, variant: 'warning' as const, icon: AlertTriangle, }, { title: t('labels.maintenance_required'), value: equipmentStats.maintenance, variant: 'info' as const, icon: Wrench, }, { title: t('labels.down'), value: equipmentStats.down, variant: 'error' as const, icon: AlertTriangle, }, { title: t('labels.active_alerts'), value: equipmentStats.totalAlerts, variant: equipmentStats.totalAlerts === 0 ? 'success' as const : 'error' as const, icon: Bell, }, ]; const handleShowMaintenanceDetails = (equipment: Equipment) => { setSelectedEquipment(equipment); setEquipmentModalMode('view'); setShowEquipmentModal(true); }; // Loading state if (!tenantId) { return (
); } if (isLoading) { return (
); } if (error) { return (

{t('common:errors.load_error')}

{t('common:errors.try_again')}

); } return (
{/* Stats Grid */} {/* Search and Filter Controls */} setStatusFilter(value as string), placeholder: t('common:forms.select_option'), options: [ { value: 'operational', label: t('equipment_status.operational') }, { value: 'warning', label: t('equipment_status.warning') }, { value: 'maintenance', label: t('equipment_status.maintenance') }, { value: 'down', label: t('equipment_status.down') } ] }, { key: 'type', label: 'Tipo', type: 'dropdown', value: typeFilter, onChange: (value) => setTypeFilter(value as string), placeholder: 'Todos los tipos', options: [ { value: 'oven', label: 'Horno' }, { value: 'mixer', label: 'Batidora' }, { value: 'proofer', label: 'Fermentadora' }, { value: 'freezer', label: 'Congelador' }, { value: 'packaging', label: 'Empaquetado' }, { value: 'other', label: 'Otro' } ] } ] as FilterConfig[]} /> {/* Equipment Grid */}
{filteredEquipment.map((equipment) => { const statusConfig = getStatusConfig(equipment.status); const TypeIcon = getTypeIcon(equipment.type); // Calculate maintenance status const nextMaintenanceDate = new Date(equipment.nextMaintenance); const daysUntilMaintenance = Math.ceil((nextMaintenanceDate.getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24)); const isOverdue = daysUntilMaintenance < 0; return ( handleShowMaintenanceDetails(equipment)} actions={[ { label: t('actions.view_details'), icon: Eye, variant: 'primary', priority: 'primary', onClick: () => handleShowMaintenanceDetails(equipment) }, // Context-aware actions based on equipment status ...(equipment.status === 'operational' || equipment.status === 'warning' ? [ { label: t('actions.report_failure'), icon: AlertTriangle, variant: 'outline' as const, priority: 'secondary' as const, highlighted: true, destructive: true, onClick: () => handleReportFailure(equipment) } ] : []), ...(equipment.status === 'down' ? [ { label: t('actions.mark_repaired'), icon: CheckCircle, variant: 'primary' as const, priority: 'secondary' as const, highlighted: true, onClick: () => handleMarkAsRepaired(equipment) } ] : []), { label: t('actions.view_history'), icon: History, priority: 'secondary', onClick: () => handleViewMaintenanceHistory(equipment) }, { label: t('actions.schedule_maintenance'), icon: Wrench, priority: 'secondary', highlighted: true, onClick: () => handleScheduleMaintenance(equipment) }, { label: t('actions.delete'), icon: Trash2, priority: 'secondary', destructive: true, onClick: () => handleDeleteEquipment(equipment) } ]} /> ); })}
{/* Empty State */} {filteredEquipment.length === 0 && ( )} {/* Equipment Modal - Used for View Details, Edit, and Create */} {showEquipmentModal && ( { setShowEquipmentModal(false); setSelectedEquipment(null); }} equipment={selectedEquipment} onSave={handleSaveEquipment} mode={equipmentModalMode} /> )} {/* Delete Equipment Modal */} {showDeleteModal && equipmentForAction && ( { setShowDeleteModal(false); setEquipmentForAction(null); }} equipment={equipmentForAction} onSoftDelete={handleSoftDelete} onHardDelete={handleHardDelete} isLoading={deleteEquipmentMutation.isPending || hardDeleteEquipmentMutation.isPending} /> )} {/* Maintenance History Modal */} {showHistoryModal && equipmentForAction && ( { setShowHistoryModal(false); setEquipmentForAction(null); }} equipment={equipmentForAction} /> )} {/* Report Failure Modal */} {showReportFailureModal && equipmentForAction && ( { setShowReportFailureModal(false); setEquipmentForAction(null); }} equipment={equipmentForAction} onReportFailure={(failureData) => handleReportFailureSubmit(equipmentForAction.id, failureData)} isLoading={updateEquipmentMutation.isPending} /> )} {/* Mark as Repaired Modal */} {showMarkRepairedModal && equipmentForAction && ( { setShowMarkRepairedModal(false); setEquipmentForAction(null); }} equipment={equipmentForAction} onMarkAsRepaired={(repairData) => handleMarkAsRepairedSubmit(equipmentForAction.id, repairData)} isLoading={updateEquipmentMutation.isPending} /> )} {/* Schedule Maintenance Modal */} {showScheduleModal && equipmentForAction && ( { setShowScheduleModal(false); setEquipmentForAction(null); }} equipment={equipmentForAction} onSchedule={handleScheduleMaintenanceSubmit} isLoading={updateEquipmentMutation.isPending} /> )}
); }; export default MaquinariaPage;