Improve teh securty of teh DB

This commit is contained in:
Urtzi Alfaro
2025-10-19 19:22:37 +02:00
parent 62971c07d7
commit 05da20357d
87 changed files with 7998 additions and 932 deletions

View File

@@ -8,144 +8,7 @@ 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
}
}
];
import { useEquipment, useCreateEquipment, useUpdateEquipment } from '../../../../api/hooks/equipment';
const MaquinariaPage: React.FC = () => {
const { t } = useTranslation(['equipment', 'common']);
@@ -157,11 +20,19 @@ const MaquinariaPage: React.FC = () => {
const [showEquipmentModal, setShowEquipmentModal] = useState(false);
const [equipmentModalMode, setEquipmentModalMode] = useState<'view' | 'edit' | 'create'>('create');
const [selectedEquipment, setSelectedEquipment] = useState<Equipment | null>(null);
const currentTenant = useCurrentTenant();
const tenantId = currentTenant?.id || '';
// Mock functions for equipment actions - these would be replaced with actual API calls
// Fetch equipment data from API
const { data: equipment = [], isLoading, error } = useEquipment(tenantId, {
is_active: true
});
// Mutations for create and update
const createEquipmentMutation = useCreateEquipment(tenantId);
const updateEquipmentMutation = useUpdateEquipment(tenantId);
const handleCreateEquipment = () => {
setSelectedEquipment({
id: '',
@@ -193,8 +64,8 @@ const MaquinariaPage: React.FC = () => {
};
const handleEditEquipment = (equipmentId: string) => {
// Find the equipment to edit
const equipmentToEdit = MOCK_EQUIPMENT.find(eq => eq.id === equipmentId);
// Find the equipment to edit from real data
const equipmentToEdit = equipment.find(eq => eq.id === equipmentId);
if (equipmentToEdit) {
setSelectedEquipment(equipmentToEdit);
setEquipmentModalMode('edit');
@@ -217,16 +88,26 @@ const MaquinariaPage: React.FC = () => {
// 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 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 MOCK_EQUIPMENT.filter(eq => {
return equipment.filter(eq => {
const matchesSearch = !searchTerm ||
eq.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
eq.location.toLowerCase().includes(searchTerm.toLowerCase()) ||
@@ -237,15 +118,15 @@ const MaquinariaPage: React.FC = () => {
return matchesSearch && matchesStatus && matchesType;
});
}, [MOCK_EQUIPMENT, searchTerm, statusFilter, typeFilter]);
}, [equipment, searchTerm, statusFilter, typeFilter]);
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);
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,
@@ -255,7 +136,7 @@ const MaquinariaPage: React.FC = () => {
down,
totalAlerts
};
}, [MOCK_EQUIPMENT]);
}, [equipment]);
const getStatusConfig = (status: Equipment['status']) => {
const configs = {
@@ -320,6 +201,28 @@ const MaquinariaPage: React.FC = () => {
);
}
if (isLoading) {
return (
<div className="flex items-center justify-center min-h-64">
<LoadingSpinner text={t('common:loading')} />
</div>
);
}
if (error) {
return (
<div className="flex flex-col items-center justify-center min-h-64">
<AlertTriangle className="w-12 h-12 text-red-500 mb-4" />
<h3 className="text-lg font-medium text-[var(--text-primary)] mb-2">
{t('common:errors.load_error')}
</h3>
<p className="text-[var(--text-secondary)]">
{t('common:errors.try_again')}
</p>
</div>
);
}
return (
<div className="space-y-6">
<PageHeader