Add modal to add equipment

This commit is contained in:
Urtzi Alfaro
2025-09-24 15:58:18 +02:00
parent c17efb001c
commit 474d7176bf
5 changed files with 502 additions and 11 deletions

View File

@@ -0,0 +1,359 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Building2, Settings, Wrench, Thermometer, Activity, CheckCircle, AlertTriangle, Eye, Edit } from 'lucide-react';
import { StatusModal, StatusModalSection } from '../../ui/StatusModal/StatusModal';
import { Equipment } from '../../../types/equipment';
interface EquipmentModalProps {
isOpen: boolean;
onClose: () => void;
equipment?: Equipment | null;
onSave: (equipment: Equipment) => void;
mode: 'view' | 'edit' | 'create';
}
export const EquipmentModal: React.FC<EquipmentModalProps> = ({
isOpen,
onClose,
equipment: initialEquipment,
onSave,
mode
}) => {
const { t } = useTranslation(['equipment', 'common']);
const [currentMode, setCurrentMode] = useState<'view' | 'edit'>(mode === 'create' ? 'edit' : 'view');
const [isCreating, setIsCreating] = useState(mode === 'create');
const [equipment, setEquipment] = useState<Equipment | null>(
initialEquipment || {
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
);
const handleSave = async () => {
if (equipment) {
await onSave(equipment);
setCurrentMode('view');
}
};
const handleFieldChange = (sectionIndex: number, fieldIndex: number, value: string | number) => {
if (!equipment) return;
const newEquipment = { ...equipment };
const sections = getSections();
const section = sections[sectionIndex];
const field = section.fields[fieldIndex];
// Map field labels to equipment properties using translation keys
// This will work regardless of the current language
const fieldLabelKeyMap: { [key: string]: string } = {
[t('fields.name')]: 'name',
[t('fields.type')]: 'type',
[t('fields.model')]: 'model',
[t('fields.serial_number')]: 'serialNumber',
[t('fields.location')]: 'location',
[t('fields.status')]: 'status',
[t('fields.install_date')]: 'installDate',
[t('fields.last_maintenance')]: 'lastMaintenance',
[t('fields.next_maintenance')]: 'nextMaintenance',
[t('fields.maintenance_interval')]: 'maintenanceInterval',
[t('fields.efficiency')]: 'efficiency',
[t('fields.uptime')]: 'uptime',
[t('fields.energy_usage')]: 'energyUsage',
[t('fields.utilization_today')]: 'utilizationToday',
[t('fields.specifications.capacity')]: 'capacity',
[t('fields.specifications.power')]: 'power',
[t('fields.specifications.weight')]: 'weight',
[t('fields.specifications.width')]: 'width',
[t('fields.specifications.height')]: 'height',
[t('fields.specifications.depth')]: 'depth'
};
const propertyName = fieldLabelKeyMap[field.label];
if (propertyName) {
// Handle nested specifications
if (propertyName === 'width' || propertyName === 'height' || propertyName === 'depth') {
newEquipment.specifications = {
...newEquipment.specifications,
dimensions: {
...newEquipment.specifications.dimensions,
[propertyName]: value
}
};
} else if (propertyName in newEquipment.specifications && propertyName !== 'dimensions') {
newEquipment.specifications = {
...newEquipment.specifications,
[propertyName]: value
};
} else {
(newEquipment as any)[propertyName] = value;
}
setEquipment(newEquipment);
}
};
const getSections = (): StatusModalSection[] => {
if (!equipment) return [];
const equipmentTypes = [
{ label: t('equipment_types.oven'), value: 'oven' },
{ label: t('equipment_types.mixer'), value: 'mixer' },
{ label: t('equipment_types.proofer'), value: 'proofer' },
{ label: t('equipment_types.freezer'), value: 'freezer' },
{ label: t('equipment_types.packaging'), value: 'packaging' },
{ label: t('equipment_types.other'), value: 'other' }
];
const equipmentStatuses = [
{ label: t('equipment_status.operational'), value: 'operational' },
{ label: t('equipment_status.warning'), value: 'warning' },
{ label: t('equipment_status.maintenance'), value: 'maintenance' },
{ label: t('equipment_status.down'), value: 'down' }
];
return [
{
title: t('sections.equipment_info'),
icon: Settings,
fields: [
{
label: t('fields.name'),
value: equipment.name || '',
type: 'text',
highlight: true,
editable: true,
required: true,
placeholder: t('placeholders.name')
},
{
label: t('fields.type'),
value: equipment.type || 'other',
type: 'select',
editable: true,
options: equipmentTypes
},
{
label: t('fields.model'),
value: equipment.model || '',
type: 'text',
editable: true,
placeholder: t('placeholders.model')
},
{
label: t('fields.serial_number'),
value: equipment.serialNumber || '',
type: 'text',
editable: true,
placeholder: t('placeholders.serial_number')
},
{
label: t('fields.location'),
value: equipment.location || '',
type: 'text',
editable: true,
placeholder: t('placeholders.location')
},
{
label: t('fields.status'),
value: equipment.status || 'operational',
type: 'select',
editable: true,
options: equipmentStatuses
}
]
},
{
title: t('sections.performance'),
icon: CheckCircle,
fields: [
{
label: t('fields.efficiency'),
value: equipment.efficiency || 0,
type: 'number',
editable: true,
placeholder: '100'
},
{
label: t('fields.uptime'),
value: equipment.uptime || 0,
type: 'number',
editable: true,
placeholder: '100'
},
{
label: t('fields.energy_usage'),
value: equipment.energyUsage || 0,
type: 'number',
editable: true,
placeholder: '0'
},
{
label: t('fields.utilization_today'),
value: equipment.utilizationToday || 0,
type: 'number',
editable: true,
placeholder: '0'
}
]
},
{
title: t('sections.maintenance'),
icon: Wrench,
fields: [
{
label: t('fields.install_date'),
value: equipment.installDate || new Date().toISOString().split('T')[0],
type: 'date',
editable: true
},
{
label: t('fields.last_maintenance'),
value: equipment.lastMaintenance || new Date().toISOString().split('T')[0],
type: 'date',
editable: true
},
{
label: t('fields.next_maintenance'),
value: equipment.nextMaintenance || new Date().toISOString().split('T')[0],
type: 'date',
editable: true
},
{
label: t('fields.maintenance_interval'),
value: equipment.maintenanceInterval || 30,
type: 'number',
editable: true,
placeholder: '30'
}
]
},
{
title: t('sections.specifications'),
icon: Building2,
fields: [
{
label: t('fields.specifications.power'),
value: equipment.specifications.power || 0,
type: 'number',
editable: true,
placeholder: '0'
},
{
label: t('fields.specifications.capacity'),
value: equipment.specifications.capacity || 0,
type: 'number',
editable: true,
placeholder: '0'
},
{
label: t('fields.specifications.width'),
value: equipment.specifications.dimensions.width || 0,
type: 'number',
editable: true,
placeholder: '0'
},
{
label: t('fields.specifications.height'),
value: equipment.specifications.dimensions.height || 0,
type: 'number',
editable: true,
placeholder: '0'
},
{
label: t('fields.specifications.depth'),
value: equipment.specifications.dimensions.depth || 0,
type: 'number',
editable: true,
placeholder: '0'
},
{
label: t('fields.specifications.weight'),
value: equipment.specifications.weight || 0,
type: 'number',
editable: true,
placeholder: '0'
}
]
}
];
};
const getEquipmentStatusConfig = () => {
if (!equipment) return undefined;
const configs = {
operational: {
color: '#10B981',
text: t('equipment_status.operational'),
icon: CheckCircle,
isCritical: false,
isHighlight: false
},
warning: {
color: '#F59E0B',
text: t('equipment_status.warning'),
icon: AlertTriangle,
isCritical: false,
isHighlight: false
},
maintenance: {
color: '#3B82F6',
text: t('equipment_status.maintenance'),
icon: Wrench,
isCritical: false,
isHighlight: false
},
down: {
color: '#EF4444',
text: t('equipment_status.down'),
icon: AlertTriangle,
isCritical: true,
isHighlight: false
}
};
return configs[equipment.status];
};
return (
<StatusModal
isOpen={isOpen}
onClose={() => {
onClose();
setCurrentMode('view');
setIsCreating(false);
}}
mode={currentMode}
onModeChange={setCurrentMode}
title={isCreating ? t('actions.add_equipment') : equipment?.name || t('common:forms.untitled')}
subtitle={isCreating ? t('sections.create_equipment_subtitle') : `${equipment?.model || ''} - ${equipment?.serialNumber || ''}`}
statusIndicator={getEquipmentStatusConfig()}
size="lg"
sections={getSections()}
showDefaultActions={true}
onSave={handleSave}
onFieldChange={handleFieldChange}
/>
);
};