import React, { useState, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { Plus, AlertTriangle, Settings, CheckCircle, Eye, Clock, Zap, Wrench, Thermometer, Activity, Search, Filter, Download, TrendingUp, Bell, History, Calendar, Edit, Trash2 } from 'lucide-react'; import { Button, Input, Card, StatsGrid, StatusCard, getStatusColor } from '../../../../components/ui'; import { LoadingSpinner } from '../../../../components/shared'; import { PageHeader } from '../../../../components/layout'; import { useCurrentTenant } from '../../../../stores/tenant.store'; import { Equipment } from '../../../../types/equipment'; 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 currentTenant = useCurrentTenant(); const tenantId = currentTenant?.id || ''; // Mock functions for equipment actions - these would be replaced with actual API calls const handleCreateEquipment = () => { console.log('Create new equipment'); // Implementation would go here }; const handleEditEquipment = (equipmentId: string) => { console.log('Edit equipment:', equipmentId); // Implementation would go here }; 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 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 avgEfficiency = MOCK_EQUIPMENT.reduce((sum, e) => sum + e.efficiency, 0) / total; const avgUptime = MOCK_EQUIPMENT.reduce((sum, e) => sum + e.uptime, 0) / total; const totalAlerts = MOCK_EQUIPMENT.reduce((sum, e) => sum + e.alerts.filter(a => !a.acknowledged).length, 0); return { total, operational, warning, maintenance, down, avgEfficiency, avgUptime, 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: Zap, packaging: Settings, other: Settings }; return icons[type]; }; const getStatusColor = (status: string): string => { const statusColors: { [key: string]: string } = { operational: '#10B981', // green-500 warning: '#F59E0B', // amber-500 maintenance: '#3B82F6', // blue-500 down: '#EF4444' // red-500 }; return statusColors[status] || '#6B7280'; // gray-500 as default }; 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.avg_efficiency'), value: `${equipmentStats.avgEfficiency.toFixed(1)}%`, icon: TrendingUp, variant: equipmentStats.avgEfficiency >= 90 ? 'success' as const : 'warning' as const }, { 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.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} ))}
)}
))}
)}
); }; export default MaquinariaPage;