Add modal to add equipment
This commit is contained in:
359
frontend/src/components/domain/equipment/EquipmentModal.tsx
Normal file
359
frontend/src/components/domain/equipment/EquipmentModal.tsx
Normal 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}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -7,7 +7,7 @@
|
||||
"down": "Out of Service",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"equipment_type": {
|
||||
"equipment_types": {
|
||||
"oven": "Oven",
|
||||
"mixer": "Mixer",
|
||||
"proofer": "Proofing Chamber",
|
||||
@@ -34,7 +34,17 @@
|
||||
"power": "Power",
|
||||
"capacity": "Capacity",
|
||||
"weight": "Weight",
|
||||
"parts": "Parts"
|
||||
"parts": "Parts",
|
||||
"utilization_today": "Utilization Today",
|
||||
"edit": "Edit",
|
||||
"specifications": {
|
||||
"power": "Power",
|
||||
"capacity": "Capacity",
|
||||
"weight": "Weight",
|
||||
"width": "Width",
|
||||
"height": "Height",
|
||||
"depth": "Depth"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"add_equipment": "Add Equipment",
|
||||
@@ -57,6 +67,19 @@
|
||||
"overdue_maintenance": "Overdue Maintenance",
|
||||
"low_efficiency": "Low Efficiency"
|
||||
},
|
||||
"sections": {
|
||||
"equipment_info": "Equipment Information",
|
||||
"performance": "Performance",
|
||||
"maintenance": "Maintenance Information",
|
||||
"specifications": "Specifications",
|
||||
"create_equipment_subtitle": "Fill in the details for the new equipment"
|
||||
},
|
||||
"placeholders": {
|
||||
"name": "Enter equipment name",
|
||||
"model": "Enter equipment model",
|
||||
"serial_number": "Enter serial number",
|
||||
"location": "Enter location"
|
||||
},
|
||||
"descriptions": {
|
||||
"equipment_efficiency": "Current equipment efficiency percentage",
|
||||
"uptime_percentage": "Percentage of uptime",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"down": "Fuera de Servicio",
|
||||
"warning": "Advertencia"
|
||||
},
|
||||
"equipment_type": {
|
||||
"equipment_types": {
|
||||
"oven": "Horno",
|
||||
"mixer": "Batidora",
|
||||
"proofer": "Cámara de Fermentación",
|
||||
@@ -33,7 +33,17 @@
|
||||
"target_temperature": "Temperatura Objetivo",
|
||||
"power": "Potencia",
|
||||
"capacity": "Capacidad",
|
||||
"weight": "Peso"
|
||||
"weight": "Peso",
|
||||
"utilization_today": "Utilización Hoy",
|
||||
"edit": "Editar",
|
||||
"specifications": {
|
||||
"power": "Potencia",
|
||||
"capacity": "Capacidad",
|
||||
"weight": "Peso",
|
||||
"width": "Ancho",
|
||||
"height": "Alto",
|
||||
"depth": "Profundidad"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"add_equipment": "Agregar Equipo",
|
||||
@@ -43,7 +53,9 @@
|
||||
"view_maintenance_history": "Ver Historial de Mantenimiento",
|
||||
"acknowledge_alert": "Reconocer Alerta",
|
||||
"view_details": "Ver Detalles",
|
||||
"view_history": "Ver Historial"
|
||||
"view_history": "Ver Historial",
|
||||
"close": "Cerrar",
|
||||
"cost": "Costo"
|
||||
},
|
||||
"labels": {
|
||||
"total_equipment": "Total de Equipos",
|
||||
@@ -54,6 +66,19 @@
|
||||
"overdue_maintenance": "Mantenimiento Atrasado",
|
||||
"low_efficiency": "Baja Eficiencia"
|
||||
},
|
||||
"sections": {
|
||||
"equipment_info": "Información de Equipo",
|
||||
"performance": "Rendimiento",
|
||||
"maintenance": "Información de Mantenimiento",
|
||||
"specifications": "Especificaciones",
|
||||
"create_equipment_subtitle": "Completa los detalles del nuevo equipo"
|
||||
},
|
||||
"placeholders": {
|
||||
"name": "Introduce el nombre del equipo",
|
||||
"model": "Introduce el modelo del equipo",
|
||||
"serial_number": "Introduce el número de serie",
|
||||
"location": "Introduce la ubicación"
|
||||
},
|
||||
"descriptions": {
|
||||
"equipment_efficiency": "Porcentaje de eficiencia actual de los equipos",
|
||||
"uptime_percentage": "Porcentaje de tiempo de funcionamiento",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"down": "Zerbitzuetik kanpo",
|
||||
"warning": "Abisua"
|
||||
},
|
||||
"equipment_type": {
|
||||
"equipment_types": {
|
||||
"oven": "Labean",
|
||||
"mixer": "Nahaste-makina",
|
||||
"proofer": "Igoera-gela",
|
||||
@@ -34,7 +34,16 @@
|
||||
"power": "Potentzia",
|
||||
"capacity": "Edukiera",
|
||||
"weight": "Pisua",
|
||||
"parts": "Piezak"
|
||||
"utilization_today": "Gaurko erabilera",
|
||||
"edit": "Editatu",
|
||||
"specifications": {
|
||||
"power": "Potentzia",
|
||||
"capacity": "Edukiera",
|
||||
"weight": "Pisua",
|
||||
"width": "Zabalera",
|
||||
"height": "Altuera",
|
||||
"depth": "Sakonera"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"add_equipment": "Gehitu makina",
|
||||
@@ -57,6 +66,19 @@
|
||||
"overdue_maintenance": "Mantentzea atzeratuta",
|
||||
"low_efficiency": "Eraginkortasun baxua"
|
||||
},
|
||||
"sections": {
|
||||
"equipment_info": "Makinaren informazioa",
|
||||
"performance": "Errendimendua",
|
||||
"maintenance": "Mantentze informazioa",
|
||||
"specifications": "Zehaztapenak",
|
||||
"create_equipment_subtitle": "Bete makinaren xehetasunak"
|
||||
},
|
||||
"placeholders": {
|
||||
"name": "Sartu makinaren izena",
|
||||
"model": "Sartu makinaren modeloa",
|
||||
"serial_number": "Sartu serie-zenbakia",
|
||||
"location": "Sartu kokapena"
|
||||
},
|
||||
"descriptions": {
|
||||
"equipment_efficiency": "Uneko makinaren eraginkortasun-ehunekoa",
|
||||
"uptime_percentage": "Funtzionamendu-denboraren ehunekoa",
|
||||
|
||||
@@ -7,6 +7,7 @@ import { LoadingSpinner } from '../../../../components/shared';
|
||||
import { PageHeader } from '../../../../components/layout';
|
||||
import { useCurrentTenant } from '../../../../stores/tenant.store';
|
||||
import { Equipment } from '../../../../types/equipment';
|
||||
import { EquipmentModal } from '../../../../components/domain/equipment/EquipmentModal';
|
||||
|
||||
const MOCK_EQUIPMENT: Equipment[] = [
|
||||
{
|
||||
@@ -152,19 +153,52 @@ const MaquinariaPage: React.FC = () => {
|
||||
const [statusFilter, setStatusFilter] = useState<Equipment['status'] | 'all'>('all');
|
||||
const [selectedItem, setSelectedItem] = useState<Equipment | null>(null);
|
||||
const [showMaintenanceModal, setShowMaintenanceModal] = useState(false);
|
||||
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
|
||||
const handleCreateEquipment = () => {
|
||||
console.log('Create new equipment');
|
||||
// Implementation would go here
|
||||
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) => {
|
||||
console.log('Edit equipment:', equipmentId);
|
||||
// Implementation would go here
|
||||
// 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) => {
|
||||
@@ -182,6 +216,14 @@ 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 filteredEquipment = useMemo(() => {
|
||||
return MOCK_EQUIPMENT.filter(eq => {
|
||||
const matchesSearch = !searchTerm ||
|
||||
@@ -363,6 +405,12 @@ const MaquinariaPage: React.FC = () => {
|
||||
priority: 'primary',
|
||||
onClick: () => handleShowMaintenanceDetails(equipment)
|
||||
},
|
||||
{
|
||||
label: t('actions.edit'),
|
||||
icon: Edit,
|
||||
priority: 'secondary',
|
||||
onClick: () => handleEditEquipment(equipment.id)
|
||||
},
|
||||
{
|
||||
label: t('actions.view_history'),
|
||||
icon: History,
|
||||
@@ -578,6 +626,20 @@ const MaquinariaPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Equipment Modal */}
|
||||
{showEquipmentModal && (
|
||||
<EquipmentModal
|
||||
isOpen={showEquipmentModal}
|
||||
onClose={() => {
|
||||
setShowEquipmentModal(false);
|
||||
setSelectedEquipment(null);
|
||||
}}
|
||||
equipment={selectedEquipment}
|
||||
onSave={handleSaveEquipment}
|
||||
mode={equipmentModalMode}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user