180 lines
7.4 KiB
TypeScript
180 lines
7.4 KiB
TypeScript
|
|
import React, { useState, useEffect } from 'react';
|
||
|
|
import {
|
||
|
|
Modal, Box, Typography, TextField, Button, CircularProgress, Alert,
|
||
|
|
FormControl, InputLabel, Select, MenuItem, FormControlLabel, Checkbox
|
||
|
|
} from '@mui/material';
|
||
|
|
import type { PublicacionDto } from '../../../models/dtos/Distribucion/PublicacionDto';
|
||
|
|
import type { CreatePublicacionDto } from '../../../models/dtos/Distribucion/CreatePublicacionDto';
|
||
|
|
import type { UpdatePublicacionDto } from '../../../models/dtos/Distribucion/UpdatePublicacionDto';
|
||
|
|
import type { EmpresaDto } from '../../../models/dtos/Distribucion/EmpresaDto';
|
||
|
|
import empresaService from '../../../services/Distribucion/empresaService'; // Para cargar empresas
|
||
|
|
|
||
|
|
const modalStyle = { /* ... (mismo estilo) ... */
|
||
|
|
position: 'absolute' as 'absolute',
|
||
|
|
top: '50%',
|
||
|
|
left: '50%',
|
||
|
|
transform: 'translate(-50%, -50%)',
|
||
|
|
width: { xs: '90%', sm: 500 },
|
||
|
|
bgcolor: 'background.paper',
|
||
|
|
border: '2px solid #000',
|
||
|
|
boxShadow: 24,
|
||
|
|
p: 4,
|
||
|
|
maxHeight: '90vh',
|
||
|
|
overflowY: 'auto'
|
||
|
|
};
|
||
|
|
|
||
|
|
interface PublicacionFormModalProps {
|
||
|
|
open: boolean;
|
||
|
|
onClose: () => void;
|
||
|
|
onSubmit: (data: CreatePublicacionDto | UpdatePublicacionDto, id?: number) => Promise<void>;
|
||
|
|
initialData?: PublicacionDto | null;
|
||
|
|
errorMessage?: string | null;
|
||
|
|
clearErrorMessage: () => void;
|
||
|
|
}
|
||
|
|
|
||
|
|
const PublicacionFormModal: React.FC<PublicacionFormModalProps> = ({
|
||
|
|
open,
|
||
|
|
onClose,
|
||
|
|
onSubmit,
|
||
|
|
initialData,
|
||
|
|
errorMessage,
|
||
|
|
clearErrorMessage
|
||
|
|
}) => {
|
||
|
|
const [nombre, setNombre] = useState('');
|
||
|
|
const [observacion, setObservacion] = useState('');
|
||
|
|
const [idEmpresa, setIdEmpresa] = useState<number | string>('');
|
||
|
|
const [ctrlDevoluciones, setCtrlDevoluciones] = useState(false);
|
||
|
|
const [habilitada, setHabilitada] = useState(true);
|
||
|
|
|
||
|
|
const [empresas, setEmpresas] = useState<EmpresaDto[]>([]);
|
||
|
|
const [loading, setLoading] = useState(false);
|
||
|
|
const [loadingEmpresas, setLoadingEmpresas] = useState(false);
|
||
|
|
const [localErrors, setLocalErrors] = useState<{ [key: string]: string | null }>({});
|
||
|
|
|
||
|
|
const isEditing = Boolean(initialData);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
const fetchEmpresas = async () => {
|
||
|
|
setLoadingEmpresas(true);
|
||
|
|
try {
|
||
|
|
const data = await empresaService.getAllEmpresas();
|
||
|
|
setEmpresas(data);
|
||
|
|
} catch (error) {
|
||
|
|
console.error("Error al cargar empresas", error);
|
||
|
|
setLocalErrors(prev => ({...prev, empresas: 'Error al cargar empresas.'}));
|
||
|
|
} finally {
|
||
|
|
setLoadingEmpresas(false);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
if (open) {
|
||
|
|
fetchEmpresas();
|
||
|
|
setNombre(initialData?.nombre || '');
|
||
|
|
setObservacion(initialData?.observacion || '');
|
||
|
|
setIdEmpresa(initialData?.idEmpresa || '');
|
||
|
|
setCtrlDevoluciones(initialData ? initialData.ctrlDevoluciones : false);
|
||
|
|
setHabilitada(initialData ? initialData.habilitada : true);
|
||
|
|
setLocalErrors({});
|
||
|
|
clearErrorMessage();
|
||
|
|
}
|
||
|
|
}, [open, initialData, clearErrorMessage]);
|
||
|
|
|
||
|
|
const validate = (): boolean => {
|
||
|
|
const errors: { [key: string]: string | null } = {};
|
||
|
|
if (!nombre.trim()) errors.nombre = 'El nombre es obligatorio.';
|
||
|
|
if (!idEmpresa) errors.idEmpresa = 'Debe seleccionar una empresa.';
|
||
|
|
setLocalErrors(errors);
|
||
|
|
return Object.keys(errors).length === 0;
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleInputChange = (fieldName: string) => {
|
||
|
|
if (localErrors[fieldName]) {
|
||
|
|
setLocalErrors(prev => ({ ...prev, [fieldName]: null }));
|
||
|
|
}
|
||
|
|
if (errorMessage) clearErrorMessage();
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||
|
|
event.preventDefault();
|
||
|
|
clearErrorMessage();
|
||
|
|
if (!validate()) return;
|
||
|
|
|
||
|
|
setLoading(true);
|
||
|
|
try {
|
||
|
|
const dataToSubmit = {
|
||
|
|
nombre,
|
||
|
|
observacion: observacion || undefined,
|
||
|
|
idEmpresa: Number(idEmpresa),
|
||
|
|
ctrlDevoluciones,
|
||
|
|
habilitada
|
||
|
|
};
|
||
|
|
|
||
|
|
if (isEditing && initialData) {
|
||
|
|
await onSubmit(dataToSubmit as UpdatePublicacionDto, initialData.idPublicacion);
|
||
|
|
} else {
|
||
|
|
await onSubmit(dataToSubmit as CreatePublicacionDto);
|
||
|
|
}
|
||
|
|
onClose();
|
||
|
|
} catch (error: any) {
|
||
|
|
console.error("Error en submit de PublicacionFormModal:", error);
|
||
|
|
} finally {
|
||
|
|
setLoading(false);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Modal open={open} onClose={onClose}>
|
||
|
|
<Box sx={modalStyle}>
|
||
|
|
<Typography variant="h6" component="h2" gutterBottom>
|
||
|
|
{isEditing ? 'Editar Publicación' : 'Agregar Nueva Publicación'}
|
||
|
|
</Typography>
|
||
|
|
<Box component="form" onSubmit={handleSubmit} sx={{ mt: 1 }}>
|
||
|
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>
|
||
|
|
<TextField label="Nombre Publicación" value={nombre} required
|
||
|
|
onChange={(e) => {setNombre(e.target.value); handleInputChange('nombre');}}
|
||
|
|
margin="dense" fullWidth error={!!localErrors.nombre} helperText={localErrors.nombre || ''}
|
||
|
|
disabled={loading} autoFocus={!isEditing}
|
||
|
|
/>
|
||
|
|
<FormControl fullWidth margin="dense" error={!!localErrors.idEmpresa}>
|
||
|
|
<InputLabel id="empresa-pub-select-label" required>Empresa</InputLabel>
|
||
|
|
<Select labelId="empresa-pub-select-label" label="Empresa" value={idEmpresa}
|
||
|
|
onChange={(e) => {setIdEmpresa(e.target.value as number); handleInputChange('idEmpresa');}}
|
||
|
|
disabled={loading || loadingEmpresas}
|
||
|
|
>
|
||
|
|
<MenuItem value="" disabled><em>Seleccione una empresa</em></MenuItem>
|
||
|
|
{empresas.map((e) => (<MenuItem key={e.idEmpresa} value={e.idEmpresa}>{e.nombre}</MenuItem>))}
|
||
|
|
</Select>
|
||
|
|
{localErrors.idEmpresa && <Typography color="error" variant="caption">{localErrors.idEmpresa}</Typography>}
|
||
|
|
</FormControl>
|
||
|
|
<TextField label="Observación (Opcional)" value={observacion}
|
||
|
|
onChange={(e) => setObservacion(e.target.value)}
|
||
|
|
margin="dense" fullWidth multiline rows={3} disabled={loading}
|
||
|
|
/>
|
||
|
|
<Box sx={{ display: 'flex', justifyContent: 'space-around', mt: 1, flexWrap: 'wrap' }}>
|
||
|
|
<FormControlLabel
|
||
|
|
control={<Checkbox checked={ctrlDevoluciones} onChange={(e) => setCtrlDevoluciones(e.target.checked)} disabled={loading}/>}
|
||
|
|
label="Controla Devoluciones"
|
||
|
|
/>
|
||
|
|
<FormControlLabel
|
||
|
|
control={<Checkbox checked={habilitada} onChange={(e) => setHabilitada(e.target.checked)} disabled={loading}/>}
|
||
|
|
label="Habilitada"
|
||
|
|
/>
|
||
|
|
</Box>
|
||
|
|
</Box>
|
||
|
|
|
||
|
|
{errorMessage && <Alert severity="error" sx={{ mt: 2, width: '100%' }}>{errorMessage}</Alert>}
|
||
|
|
{localErrors.empresas && <Alert severity="warning" sx={{ mt: 1 }}>{localErrors.empresas}</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 || loadingEmpresas}>
|
||
|
|
{loading ? <CircularProgress size={24} /> : (isEditing ? 'Guardar Cambios' : 'Crear Publicación')}
|
||
|
|
</Button>
|
||
|
|
</Box>
|
||
|
|
</Box>
|
||
|
|
</Box>
|
||
|
|
</Modal>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
export default PublicacionFormModal;
|