Files
GestionIntegralWeb/Frontend/src/components/Modals/PlantaFormModal.tsx

144 lines
4.8 KiB
TypeScript
Raw Normal View History

feat: Implementación módulos Empresas, Plantas, Tipos y Estados Bobina Backend API: - Implementado CRUD completo para Empresas (DE001-DE004): - EmpresaRepository, EmpresaService, EmpresasController. - Lógica de creación/eliminación de saldos iniciales en EmpresaService. - Transacciones y registro en tablas _H. - Verificación de permisos específicos. - Implementado CRUD completo para Plantas de Impresión (IP001-IP004): - PlantaRepository, PlantaService, PlantasController. - Transacciones y registro en tablas _H. - Verificación de permisos. - Implementado CRUD completo para Tipos de Bobina (IB006-IB009): - TipoBobinaRepository, TipoBobinaService, TiposBobinaController. - Transacciones y registro en tablas _H. - Verificación de permisos. - Implementado CRUD completo para Estados de Bobina (IB010-IB013): - EstadoBobinaRepository, EstadoBobinaService, EstadosBobinaController. - Transacciones y registro en tablas _H. - Verificación de permisos. Frontend React: - Módulo Empresas: - empresaService.ts para interactuar con la API. - EmpresaFormModal.tsx para crear/editar empresas. - GestionarEmpresasPage.tsx con tabla, filtro, paginación y menú de acciones. - Integración con el hook usePermissions para control de acceso. - Módulo Plantas de Impresión: - plantaService.ts. - PlantaFormModal.tsx. - GestionarPlantasPage.tsx con tabla, filtro, paginación y acciones. - Integración con usePermissions. - Módulo Tipos de Bobina: - tipoBobinaService.ts. - TipoBobinaFormModal.tsx. - GestionarTiposBobinaPage.tsx con tabla, filtro, paginación y acciones. - Integración con usePermissions. - Módulo Estados de Bobina: - estadoBobinaService.ts. - EstadoBobinaFormModal.tsx. - GestionarEstadosBobinaPage.tsx con tabla, filtro, paginación y acciones. - Integración con usePermissions. - Navegación: - Añadidas sub-pestañas y rutas para los nuevos módulos dentro de "Distribución" (Empresas) e "Impresión" (Plantas, Tipos Bobina, Estados Bobina). - Creado ImpresionIndexPage.tsx para la navegación interna del módulo de Impresión. Correcciones: - Corregido el uso de CommitAsync/RollbackAsync a Commit/Rollback síncronos en PlantaService.cs debido a que IDbTransaction no los soporta asíncronamente.
2025-05-09 10:08:53 -03:00
import React, { useState, useEffect } from 'react';
import { Modal, Box, Typography, TextField, Button, CircularProgress, Alert } from '@mui/material';
import type { PlantaDto } from '../../models/dtos/Impresion/PlantaDto';
import type { CreatePlantaDto } from '../../models/dtos/Impresion/CreatePlantaDto';
import type { UpdatePlantaDto } from '../../models/dtos/Impresion/UpdatePlantaDto';
const modalStyle = { /* ... (mismo estilo que otros modales) ... */
position: 'absolute' as 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 400,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
p: 4,
};
interface PlantaFormModalProps {
open: boolean;
onClose: () => void;
onSubmit: (data: CreatePlantaDto | (UpdatePlantaDto & { idPlanta: number })) => Promise<void>;
initialData?: PlantaDto | null;
errorMessage?: string | null;
clearErrorMessage: () => void;
}
const PlantaFormModal: React.FC<PlantaFormModalProps> = ({
open,
onClose,
onSubmit,
initialData,
errorMessage,
clearErrorMessage
}) => {
const [nombre, setNombre] = useState('');
const [detalle, setDetalle] = useState(''); // Detalle es string, no opcional según la BD
const [loading, setLoading] = useState(false);
const [localErrorNombre, setLocalErrorNombre] = useState<string | null>(null);
const [localErrorDetalle, setLocalErrorDetalle] = useState<string | null>(null);
const isEditing = Boolean(initialData);
useEffect(() => {
if (open) {
setNombre(initialData?.nombre || '');
setDetalle(initialData?.detalle || ''); // Inicializar detalle
setLocalErrorNombre(null);
setLocalErrorDetalle(null);
clearErrorMessage();
}
}, [open, initialData, clearErrorMessage]);
const handleInputChange = (field: 'nombre' | 'detalle') => {
if (field === 'nombre' && localErrorNombre) setLocalErrorNombre(null);
if (field === 'detalle' && localErrorDetalle) setLocalErrorDetalle(null);
if (errorMessage) clearErrorMessage();
};
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
setLocalErrorNombre(null);
setLocalErrorDetalle(null);
clearErrorMessage();
let hasError = false;
if (!nombre.trim()) {
setLocalErrorNombre('El nombre es obligatorio.');
hasError = true;
}
if (!detalle.trim()) { // Detalle también es requerido según la BD
setLocalErrorDetalle('El detalle es obligatorio.');
hasError = true;
}
if (hasError) return;
setLoading(true);
try {
const dataToSubmit = { nombre, detalle }; // Detalle siempre se envía
if (isEditing && initialData) {
await onSubmit({ ...dataToSubmit, idPlanta: initialData.idPlanta });
} else {
await onSubmit(dataToSubmit as CreatePlantaDto);
}
onClose();
} catch (error: any) {
console.error("Error en submit de PlantaFormModal:", error);
// El error API se muestra vía 'errorMessage'
} finally {
setLoading(false);
}
};
return (
<Modal open={open} onClose={onClose}>
<Box sx={modalStyle}>
<Typography variant="h6" component="h2">
{isEditing ? 'Editar Planta de Impresión' : 'Agregar Nueva Planta de Impresión'}
</Typography>
<Box component="form" onSubmit={handleSubmit} sx={{ mt: 2 }}>
<TextField
label="Nombre"
fullWidth
required
value={nombre}
onChange={(e) => { setNombre(e.target.value); handleInputChange('nombre'); }}
margin="normal"
error={!!localErrorNombre}
helperText={localErrorNombre || ''}
disabled={loading}
autoFocus
/>
<TextField
label="Detalle" // Ya no es opcional
fullWidth
required // Marcar como requerido
value={detalle}
onChange={(e) => { setDetalle(e.target.value); handleInputChange('detalle'); }}
margin="normal"
multiline
rows={3}
error={!!localErrorDetalle} // Añadir manejo de error para detalle
helperText={localErrorDetalle || ''} // Mostrar error de detalle
disabled={loading}
/>
{errorMessage && <Alert severity="error" sx={{ mt: 1 }}>{errorMessage}</Alert>}
<Box sx={{ mt: 3, display: 'flex', justifyContent: 'flex-end', gap: 1 }}>
<Button onClick={onClose} color="secondary" disabled={loading}>
Cancelar
</Button>
<Button type="submit" variant="contained" disabled={loading}>
{loading ? <CircularProgress size={24} /> : (isEditing ? 'Guardar Cambios' : 'Agregar')}
</Button>
</Box>
</Box>
</Box>
</Modal>
);
};
export default PlantaFormModal;