142 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			142 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
|  | import React, { useState, useEffect } from 'react'; | ||
|  | import { Modal, Box, Typography, TextField, Button, CircularProgress, Alert } from '@mui/material'; | ||
|  | import type { EmpresaDto } from '../../models/dtos/Empresas/EmpresaDto'; | ||
|  | import type { CreateEmpresaDto } from '../../models/dtos/Empresas/CreateEmpresaDto'; | ||
|  | import type { UpdateEmpresaDto } from '../../models/dtos/Empresas/UpdateEmpresaDto'; // Necesitamos Update DTO también
 | ||
|  | 
 | ||
|  | const modalStyle = { | ||
|  |   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 EmpresaFormModalProps { | ||
|  |   open: boolean; | ||
|  |   onClose: () => void; | ||
|  |   // El tipo de dato enviado depende si es creación o edición
 | ||
|  |   onSubmit: (data: CreateEmpresaDto | (UpdateEmpresaDto & { idEmpresa: number })) => Promise<void>; | ||
|  |   initialData?: EmpresaDto | null; // Para editar
 | ||
|  |   errorMessage?: string | null;    // Error de la API pasado desde el padre
 | ||
|  |   clearErrorMessage: () => void;    // Función para limpiar el error en el padre
 | ||
|  | } | ||
|  | 
 | ||
|  | const EmpresaFormModal: React.FC<EmpresaFormModalProps> = ({ | ||
|  |   open, | ||
|  |   onClose, | ||
|  |   onSubmit, | ||
|  |   initialData, | ||
|  |   errorMessage, | ||
|  |   clearErrorMessage | ||
|  | }) => { | ||
|  |   const [nombre, setNombre] = useState(''); | ||
|  |   const [detalle, setDetalle] = useState(''); | ||
|  |   const [loading, setLoading] = useState(false); | ||
|  |   const [localError, setLocalError] = useState<string | null>(null); // Para validaciones locales (ej: campo requerido)
 | ||
|  | 
 | ||
|  |   const isEditing = Boolean(initialData); | ||
|  | 
 | ||
|  |   useEffect(() => { | ||
|  |     if (open) { | ||
|  |         // Poblar formulario si es edición, limpiar si es creación
 | ||
|  |         setNombre(initialData?.nombre || ''); | ||
|  |         setDetalle(initialData?.detalle || ''); | ||
|  |         setLocalError(null); // Limpiar error local al abrir/cambiar
 | ||
|  |         clearErrorMessage(); // Limpiar error API del padre
 | ||
|  |     } | ||
|  |     // No necesitamos limpiar al cerrar, ya que el useEffect se ejecuta al abrir `open = true`
 | ||
|  |   }, [open, initialData, clearErrorMessage]); | ||
|  | 
 | ||
|  |    // Limpia errores cuando el usuario empieza a escribir
 | ||
|  |    const handleInputChange = () => { | ||
|  |       if (localError) setLocalError(null); | ||
|  |       if (errorMessage) clearErrorMessage(); | ||
|  |   }; | ||
|  | 
 | ||
|  |   const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => { | ||
|  |     event.preventDefault(); | ||
|  |     setLocalError(null); | ||
|  |     clearErrorMessage(); // Limpiar errores antes de enviar
 | ||
|  | 
 | ||
|  |     // Validación local simple
 | ||
|  |     if (!nombre.trim()) { | ||
|  |         setLocalError('El nombre es obligatorio.'); | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     setLoading(true); | ||
|  |     try { | ||
|  |       // Preparar datos según sea creación o edición
 | ||
|  |       const dataToSubmit = { nombre, detalle: detalle || undefined }; // Usa undefined si detalle está vacío
 | ||
|  | 
 | ||
|  |       if (isEditing && initialData) { | ||
|  |         // Si es edición, combina los datos del formulario con el ID existente
 | ||
|  |         await onSubmit({ ...dataToSubmit, idEmpresa: initialData.idEmpresa }); | ||
|  |       } else { | ||
|  |         // Si es creación, envía solo los datos del formulario
 | ||
|  |         await onSubmit(dataToSubmit as CreateEmpresaDto); | ||
|  |       } | ||
|  |       onClose(); // Cierra el modal SOLO si onSubmit fue exitoso
 | ||
|  |     } catch (error: any) { | ||
|  |       // El error de la API será manejado por el componente padre y mostrado vía 'errorMessage'
 | ||
|  |       // No necesitamos setear localError aquí a menos que sea un error específico del submit no cubierto por la API
 | ||
|  |       console.error("Error en submit de EmpresaFormModal:", error); | ||
|  |       // El componente padre es responsable de poner setLoading(false) si onSubmit falla
 | ||
|  |     } finally { | ||
|  |       // Asegúrate de que el loading se detenga incluso si hay un error no capturado por el padre
 | ||
|  |        setLoading(false); | ||
|  |     } | ||
|  |   }; | ||
|  | 
 | ||
|  |   return ( | ||
|  |     <Modal open={open} onClose={onClose}> | ||
|  |       <Box sx={modalStyle}> | ||
|  |         <Typography variant="h6" component="h2"> | ||
|  |           {isEditing ? 'Editar Empresa' : 'Agregar Nueva Empresa'} | ||
|  |         </Typography> | ||
|  |         <Box component="form" onSubmit={handleSubmit} sx={{ mt: 2 }}> | ||
|  |           <TextField | ||
|  |             label="Nombre" | ||
|  |             fullWidth | ||
|  |             required // HTML5 required
 | ||
|  |             value={nombre} | ||
|  |             onChange={(e) => {setNombre(e.target.value); handleInputChange();} } | ||
|  |             margin="normal" | ||
|  |             error={!!localError} // Mostrar error si localError tiene un mensaje
 | ||
|  |             helperText={localError ? localError : ''} // Mostrar el mensaje de error local
 | ||
|  |             disabled={loading} | ||
|  |             autoFocus // Poner el foco en el primer campo
 | ||
|  |           /> | ||
|  |           <TextField | ||
|  |             label="Detalle (Opcional)" | ||
|  |             fullWidth | ||
|  |             value={detalle} | ||
|  |             onChange={(e) => {setDetalle(e.target.value); handleInputChange();}} | ||
|  |             margin="normal" | ||
|  |             multiline | ||
|  |             rows={3} | ||
|  |             disabled={loading} | ||
|  |           /> | ||
|  |           {/* Mostrar error de la API si existe */} | ||
|  |           {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 EmpresaFormModal; |