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, Input, Card, StatsGrid, StatusCard, getStatusColor } 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'; const MOCK_EQUIPMENT: Equipment[] = [ { id: '1', name: 'Horno Principal #1', type: 'oven', model: 'Miwe Condo CO 4.1212', serialNumber: 'MCO-2021-001', location: 'Área de Horneado - Zona A', status: 'operational', installDate: '2021-03-15', lastMaintenance: '2024-01-15', nextMaintenance: '2024-04-15', maintenanceInterval: 90, temperature: 220, targetTemperature: 220, efficiency: 92, uptime: 98.5, energyUsage: 45.2, utilizationToday: 87, alerts: [], maintenanceHistory: [ { id: '1', date: '2024-01-15', type: 'preventive', description: 'Limpieza general y calibración de termostatos', technician: 'Juan Pérez', cost: 150, downtime: 2, partsUsed: ['Filtros de aire', 'Sellos de puerta'] } ], specifications: { power: 45, capacity: 24, dimensions: { width: 200, height: 180, depth: 120 }, weight: 850 } }, { id: '2', name: 'Batidora Industrial #2', type: 'mixer', model: 'Hobart HL800', serialNumber: 'HHL-2020-002', location: 'Área de Preparación - Zona B', status: 'warning', installDate: '2020-08-10', lastMaintenance: '2024-01-20', nextMaintenance: '2024-02-20', maintenanceInterval: 30, efficiency: 88, uptime: 94.2, energyUsage: 12.8, utilizationToday: 76, alerts: [ { id: '1', type: 'warning', message: 'Vibración inusual detectada en el motor', timestamp: '2024-01-23T10:30:00Z', acknowledged: false }, { id: '2', type: 'info', message: 'Mantenimiento programado en 5 días', timestamp: '2024-01-23T08:00:00Z', acknowledged: true } ], maintenanceHistory: [ { id: '1', date: '2024-01-20', type: 'corrective', description: 'Reemplazo de correas de transmisión', technician: 'María González', cost: 85, downtime: 4, partsUsed: ['Correa tipo V', 'Rodamientos'] } ], specifications: { power: 15, capacity: 80, dimensions: { width: 120, height: 150, depth: 80 }, weight: 320 } }, { id: '3', name: 'Cámara de Fermentación #1', type: 'proofer', model: 'Bongard EUROPA 16.18', serialNumber: 'BEU-2022-001', location: 'Área de Fermentación', status: 'maintenance', installDate: '2022-06-20', lastMaintenance: '2024-01-23', nextMaintenance: '2024-01-24', maintenanceInterval: 60, temperature: 32, targetTemperature: 35, efficiency: 0, uptime: 85.1, energyUsage: 0, utilizationToday: 0, alerts: [ { id: '1', type: 'info', message: 'En mantenimiento programado', timestamp: '2024-01-23T06:00:00Z', acknowledged: true } ], maintenanceHistory: [ { id: '1', date: '2024-01-23', type: 'preventive', description: 'Mantenimiento programado - sistema de humidificación', technician: 'Carlos Rodríguez', cost: 200, downtime: 8, partsUsed: ['Sensor de humedad', 'Válvulas'] } ], specifications: { power: 8, capacity: 16, dimensions: { width: 180, height: 200, depth: 100 }, weight: 450 } } ]; const MaquinariaPage: React.FC = () => { const { t } = useTranslation(['equipment', 'common']); const [searchTerm, setSearchTerm] = useState(''); const [statusFilter, setStatusFilter] = useState('all'); const [selectedItem, setSelectedItem] = useState(null); const [showMaintenanceModal, setShowMaintenanceModal] = useState(false); const [showEquipmentModal, setShowEquipmentModal] = useState(false); const [equipmentModalMode, setEquipmentModalMode] = useState<'view' | 'edit' | 'create'>('create'); const [selectedEquipment, setSelectedEquipment] = useState(null); const currentTenant = useCurrentTenant(); const tenantId = currentTenant?.id || ''; // Mock functions for equipment actions - these would be replaced with actual API calls 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 const equipmentToEdit = MOCK_EQUIPMENT.find(eq => eq.id === equipmentId); if (equipmentToEdit) { setSelectedEquipment(equipmentToEdit); setEquipmentModalMode('edit'); setShowEquipmentModal(true); } }; const handleScheduleMaintenance = (equipmentId: string) => { console.log('Schedule maintenance for equipment:', equipmentId); // Implementation would go here }; const handleAcknowledgeAlert = (equipmentId: string, alertId: string) => { console.log('Acknowledge alert:', alertId, 'for equipment:', equipmentId); // Implementation would go here }; const handleViewMaintenanceHistory = (equipmentId: string) => { console.log('View maintenance history for equipment:', equipmentId); // Implementation would go here }; const handleSaveEquipment = (equipment: Equipment) => { console.log('Saving equipment:', equipment); // In a real implementation, you would save to the API // For now, just close the modal setShowEquipmentModal(false); // Refresh equipment list if needed }; const filteredEquipment = useMemo(() => { return MOCK_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 === 'all' || eq.status === statusFilter; return matchesSearch && matchesStatus; }); }, [MOCK_EQUIPMENT, searchTerm, statusFilter]); const equipmentStats = useMemo(() => { const total = MOCK_EQUIPMENT.length; const operational = MOCK_EQUIPMENT.filter(e => e.status === 'operational').length; const warning = MOCK_EQUIPMENT.filter(e => e.status === 'warning').length; const maintenance = MOCK_EQUIPMENT.filter(e => e.status === 'maintenance').length; const down = MOCK_EQUIPMENT.filter(e => e.status === 'down').length; const totalAlerts = MOCK_EQUIPMENT.reduce((sum, e) => sum + e.alerts.filter(a => !a.acknowledged).length, 0); return { total, operational, warning, maintenance, down, totalAlerts }; }, [MOCK_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]; }; 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, icon: Settings, variant: 'default' as const }, { title: t('labels.operational'), value: equipmentStats.operational, icon: CheckCircle, variant: 'success' as const, subtitle: `${((equipmentStats.operational / equipmentStats.total) * 100).toFixed(1)}%` }, { title: t('labels.active_alerts'), value: equipmentStats.totalAlerts, icon: Bell, variant: equipmentStats.totalAlerts === 0 ? 'success' as const : 'error' as const } ]; const handleShowMaintenanceDetails = (equipment: Equipment) => { setSelectedItem(equipment); setShowMaintenanceModal(true); }; const handleCloseMaintenanceModal = () => { setShowMaintenanceModal(false); setSelectedItem(null); }; // Loading state if (!tenantId) { return (
); } return (
{/* Stats Grid */} {/* Controls */}
setSearchTerm(e.target.value)} className="pl-10" />
{/* 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) }, { label: t('actions.edit'), icon: Edit, priority: 'secondary', onClick: () => handleEditEquipment(equipment.id) }, { label: t('actions.view_history'), icon: History, priority: 'secondary', onClick: () => handleViewMaintenanceHistory(equipment.id) }, { label: t('actions.schedule_maintenance'), icon: Wrench, priority: 'secondary', onClick: () => handleScheduleMaintenance(equipment.id) } ]} /> ); })}
{/* Empty State */} {filteredEquipment.length === 0 && (

{t('common:forms.no_results')}

{t('common:forms.empty_state')}

)} {/* Maintenance Details Modal */} {selectedItem && showMaintenanceModal && (

{selectedItem.name}

{selectedItem.model} - {selectedItem.serialNumber}

{/* Equipment Status */}

{t('fields.status')}

{t(`equipment_status.${selectedItem.status}`)}

{t('fields.efficiency')}

{selectedItem.efficiency}%
{/* Maintenance Information */}

{t('maintenance.title')}

{t('maintenance.last')}

{new Date(selectedItem.lastMaintenance).toLocaleDateString('es-ES')}

{t('maintenance.next')}

{new Date(selectedItem.nextMaintenance).toLocaleDateString('es-ES')}

{t('maintenance.interval')}

{selectedItem.maintenanceInterval} {t('common:units.days')}

{new Date(selectedItem.nextMaintenance).getTime() < new Date().getTime() && (
{t('maintenance.overdue')}
)}
{/* Active Alerts */} {selectedItem.alerts.filter(a => !a.acknowledged).length > 0 && (

{t('alerts.title')}

{selectedItem.alerts.filter(a => !a.acknowledged).map((alert) => (
{alert.message}
{new Date(alert.timestamp).toLocaleString('es-ES')}
))}
)} {/* Maintenance History */}

{t('maintenance.history')}

{selectedItem.maintenanceHistory.map((history) => (

{history.description}

{new Date(history.date).toLocaleDateString('es-ES')} - {history.technician}

{t(`maintenance.type.${history.type}`)}
{t('common:actions.cost')}: €{history.cost} {t('fields.uptime')}: {history.downtime}h
{history.partsUsed.length > 0 && (
{t('fields.parts')}:
{history.partsUsed.map((part, index) => ( {part} ))}
)}
))}
)} {/* Equipment Modal */} {showEquipmentModal && ( { setShowEquipmentModal(false); setSelectedEquipment(null); }} equipment={selectedEquipment} onSave={handleSaveEquipment} mode={equipmentModalMode} /> )}
); }; export default MaquinariaPage;