2026-06-30 12:37:07 +03:00

556 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useEffect } from 'react';
import {
Box,
Button,
Divider,
MenuItem,
Autocomplete,
Stack,
TextField,
} from '@mui/material';
import Modal from '../../../../components/common/Modal/Modal';
import {
DangerOutlinedButton,
PrimaryButton,
} from '../../../../components/common/Buttons/Buttons';
import { useAuth } from '../../../../app/context/AuthProvider';
import { ROLES_NAME_ID } from '../../../../constants';
import {
ModalContainer,
FieldContainer,
FieldLabel,
StyledTextField,
StyledMultilineTextField,
StyledDatePicker,
} from './Modal.style';
const ModalEditAddVsp = ({
open,
onClose,
onSave,
onDelete,
initialData = null,
ssps = [],
loading = false,
}) => {
const { user } = useAuth();
const [formData, setFormData] = useState({
registration_number: '',
ssp_id: null,
vsp_type: '',
address: '',
approved_format: '',
open_date: null,
close_date: null,
notes: '',
location_form: '',
numbers: '',
area: null,
rent_contract_num: '',
rent_end_date: null,
system_code: '',
});
const [errors, setErrors] = useState({});
const isExecutor = user?.role_id !== ROLES_NAME_ID.admin;
const canSelectSsp = !isExecutor;
const readOnlyFields = [
'system_code',
'registration_number',
'ssp_id',
'vsp_type',
'address',
'approved_format',
'open_date',
'close_date',
'notes',
];
// Только эти поля readOnly для executor_rf
const isReadOnlyField = (fieldName) => {
if (!isExecutor) return false;
return readOnlyFields.includes(fieldName);
};
const locationFormOptions = [
{ value: 'аренда', label: 'Аренда' },
{ value: 'субаренда', label: 'Субаренда' },
{ value: 'встроенное помещение', label: 'Встроенное помещение' },
];
useEffect(() => {
if (initialData) {
setFormData({
registration_number: initialData.registration_number || '',
ssp_id: initialData.ssp_id || null,
vsp_type: initialData.vsp_type || '',
address: initialData.address || '',
approved_format: initialData.approved_format || '',
open_date: initialData.open_date
? new Date(initialData.open_date)
: null,
close_date: initialData.close_date
? new Date(initialData.close_date)
: null,
notes: initialData.notes || '',
location_form: initialData.location_form || '',
numbers: initialData.staff_count?.toString() || '',
area: initialData.area || null,
rent_contract_num: initialData.rent_contract_num || '',
rent_end_date: initialData.rent_end_date
? new Date(initialData.rent_end_date)
: null,
system_code: initialData.system_code || '',
});
} else {
setFormData({
registration_number: '',
ssp_id: isExecutor ? user?.ssp_id : null,
address: '',
vsp_type: '',
location: '',
approved_format: '',
open_date: null,
close_date: null,
notes: '',
location_form: '',
numbers: '',
area: null,
rent_contract_num: '',
rent_end_date: null,
system_code: '',
});
}
setErrors({});
}, [initialData, open, user, isExecutor]);
// Валидация только для registration_number и ssp_id
const validateForm = () => {
const newErrors = {};
if (!formData.registration_number || !formData.registration_number.trim()) {
newErrors.registration_number = 'Регистрационный номер ВСП обязателен';
}
if (canSelectSsp && !formData.ssp_id) {
newErrors.ssp_id = 'Региональный филиал обязателен';
}
if (isExecutor && !formData.ssp_id) {
newErrors.ssp_id = 'Региональный филиал не найден';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleChange = (field) => (event) => {
if (isReadOnlyField(field)) return;
setFormData({
...formData,
[field]: event.target.value,
});
if (errors[field]) {
setErrors({
...errors,
[field]: '',
});
}
};
const handleNumberChange = (field) => (event) => {
if (isReadOnlyField(field)) return;
const inputValue = event.target.value;
const isValidInput = /^\d*\.?\d*$/.test(inputValue) || inputValue === '';
if (isValidInput) {
setFormData({
...formData,
[field]: inputValue,
});
if (errors[field]) {
setErrors({
...errors,
[field]: '',
});
}
}
};
const handleSspChange = (event, newValue) => {
if (isReadOnlyField('ssp_id')) return;
setFormData({
...formData,
ssp_id: newValue?.id || null,
});
if (errors.ssp_id) {
setErrors({
...errors,
ssp_id: '',
});
}
};
const handleDateChange = (field) => (date) => {
if (isReadOnlyField(field)) return;
setFormData({
...formData,
[field]: date,
});
if (errors[field]) {
setErrors({
...errors,
[field]: '',
});
}
};
const handleSubmit = async () => {
// Выполняем валидацию перед отправкой
if (!validateForm()) return;
const submitData = {
...formData,
numbers: formData.staff_count ? parseInt(formData.staff_count, 10) : null,
area: formData.area ? parseFloat(formData.area) : null,
open_date: formData.open_date
? formData.open_date.toLocaleDateString('en-CA')
: null,
close_date: formData.close_date
? formData.close_date.toLocaleDateString('en-CA')
: null,
rent_end_date: formData.rent_end_date
? formData.rent_end_date.toLocaleDateString('en-CA')
: null,
};
if (user.role_id !== ROLES_NAME_ID.admin) {
const submitDataForExecutor = Object.fromEntries(
Object.entries(submitData).filter(
([key]) => !readOnlyFields.includes(key),
),
);
await onSave(submitDataForExecutor);
} else {
await onSave(submitData);
}
if (!loading) {
handleClose();
}
};
const handleClose = () => {
if (!loading) {
setFormData({
registration_number: '',
ssp_id: null,
vsp_type: '',
location: '',
approved_format: '',
open_date: null,
close_date: null,
notes: '',
location_form: '',
numbers: '',
area: '',
rent_contract_num: '',
rent_end_date: null,
system_code: '',
});
setErrors({});
onClose();
}
};
const handleDelete = () => {
onDelete?.(initialData.id);
handleClose();
};
const selectedSsp = ssps.find((ssp) => ssp.id === formData.ssp_id) || null;
const showActions = true;
const showDeleteButton = !isExecutor;
return (
<Modal
title={initialData ? 'Редактирование ВСП' : 'Добавление ВСП'}
open={open}
onClose={handleClose}
customSize={'60'}
actions={
showActions && (
<Stack
direction={'row'}
justifyContent={'space-between'}
width={'100%'}
>
{showDeleteButton && (
<DangerOutlinedButton
onClick={handleDelete}
style={{ height: '2.5rem' }}
>
Удалить
</DangerOutlinedButton>
)}
{!showDeleteButton && <Box />} {/* Спейсер для выравнивания */}
<Stack spacing={'.5rem'} direction={'row'}>
<Button
variant="grey"
onClick={handleClose}
style={{ height: '2.5rem' }}
disabled={loading}
>
Отменить
</Button>
<PrimaryButton
variant="contained"
onClick={handleSubmit}
style={{ height: '2.5rem' }}
disabled={loading}
>
{loading
? 'Сохранение...'
: initialData
? 'Сохранить'
: 'Создать'}
</PrimaryButton>
</Stack>
</Stack>
)
}
>
<Divider sx={{ mb: '1.5rem' }} />
<ModalContainer maxHeight="60vh">
<FieldContainer>
<FieldLabel>Код РФ</FieldLabel>
<StyledTextField
value={formData.system_code}
onChange={handleChange('system_code')}
placeholder="Введите код РФ"
error={!!errors.system_code}
helperText={errors.system_code}
disabled={loading || isReadOnlyField('system_code')}
/>
</FieldContainer>
<FieldContainer>
<FieldLabel>
Регистрационный номер ВСП <span style={{ color: 'red' }}>*</span>
</FieldLabel>
<StyledTextField
value={formData.registration_number}
onChange={handleChange('registration_number')}
placeholder="Введите регистрационный номер ВСП"
error={!!errors.registration_number}
helperText={errors.registration_number}
disabled={loading || isReadOnlyField('registration_number')}
/>
</FieldContainer>
{canSelectSsp && (
<FieldContainer>
<FieldLabel>
Региональный филиал <span style={{ color: 'red' }}>*</span>
</FieldLabel>
<Autocomplete
options={ssps}
getOptionLabel={(option) => option.title || option.name || ''}
value={selectedSsp}
onChange={handleSspChange}
disabled={loading || isReadOnlyField('ssp_id')}
getOptionKey={(option) =>
option.id || option.name || option.title
}
renderInput={(params) => (
<TextField
{...params}
placeholder="Выберите региональный филиал"
size="small"
error={!!errors.ssp_id}
helperText={errors.ssp_id}
disabled={loading || isReadOnlyField('ssp_id')}
sx={{
'& .MuiInputBase-root': {
height: '2.69rem',
},
}}
/>
)}
noOptionsText="Не найдено"
sx={{ width: '100%' }}
/>
</FieldContainer>
)}
<FieldContainer>
<FieldLabel>Вид ВСП</FieldLabel>
<StyledTextField
value={formData.vsp_type}
onChange={handleChange('vsp_type')}
placeholder="Введите вид ВСП"
disabled={loading || isReadOnlyField('vsp_type')}
/>
</FieldContainer>
<FieldContainer>
<FieldLabel>Адрес ВСП</FieldLabel>
<StyledMultilineTextField
value={formData.address}
onChange={handleChange('address')}
placeholder="Введите адрес ВСП"
error={!!errors.address}
helperText={errors.address}
disabled={loading || isReadOnlyField('address')}
/>
</FieldContainer>
<FieldContainer>
<FieldLabel>Утвержденный формат</FieldLabel>
<StyledTextField
value={formData.approved_format}
onChange={handleChange('approved_format')}
placeholder="Введите утвержденный формат"
error={!!errors.approved_format}
helperText={errors.approved_format}
disabled={loading || isReadOnlyField('approved_format')}
/>
</FieldContainer>
<FieldContainer>
<FieldLabel>Дата открытия ВСП</FieldLabel>
<StyledDatePicker
value={formData.open_date}
onChange={handleDateChange('open_date')}
disabled={loading || isReadOnlyField('open_date')}
error={!!errors.open_date}
helperText={errors.open_date}
/>
</FieldContainer>
<FieldContainer>
<FieldLabel>Дата закрытия ВСП</FieldLabel>
<StyledDatePicker
value={formData.close_date}
onChange={handleDateChange('close_date')}
disabled={loading || isReadOnlyField('close_date')}
error={!!errors.close_date}
helperText={errors.close_date}
/>
</FieldContainer>
<FieldContainer>
<FieldLabel>Примечания</FieldLabel>
<StyledMultilineTextField
value={formData.notes}
onChange={handleChange('notes')}
placeholder="Введите примечания"
error={!!errors.notes}
helperText={errors.notes}
disabled={loading || isReadOnlyField('notes')}
/>
</FieldContainer>
<FieldContainer>
<FieldLabel>Форма расположения ВСП</FieldLabel>
<StyledTextField
select
value={formData.location_form}
onChange={handleChange('location_form')}
placeholder="Выберите форму расположения"
error={!!errors.location_form}
helperText={errors.location_form}
disabled={loading}
slotProps={{
select: {
MenuProps: {
sx: { zIndex: 1301 },
style: { zIndex: 1301 },
PaperProps: {
sx: {
zIndex: 1301,
backgroundColor: '#fff',
color: '#171a1c',
},
},
},
},
}}
>
{locationFormOptions.map((option) => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</StyledTextField>
</FieldContainer>
<FieldContainer>
<FieldLabel>Штатная численность ВСП</FieldLabel>
<StyledTextField
type="text"
value={formData.staff_count}
onChange={handleNumberChange('numbers')}
placeholder="Введите численность"
error={!!errors.staff_count}
helperText={errors.staff_count}
disabled={loading}
slotProps={{
htmlInput: { min: 1, step: 1 },
}}
/>
</FieldContainer>
<FieldContainer>
<FieldLabel>Площадь помещений ВСП</FieldLabel>
<StyledTextField
type="text"
value={formData.area?.toString() || ''}
onChange={handleNumberChange('area')}
placeholder="Введите площадь помещений"
error={!!errors.area}
helperText={errors.area}
disabled={loading}
slotProps={{
htmlInput: { min: 1, step: 1 },
}}
/>
</FieldContainer>
<FieldContainer>
<FieldLabel>Номер договора аренды</FieldLabel>
<StyledTextField
value={formData.rent_contract_num}
onChange={handleChange('rent_contract_num')}
placeholder="Введите номер договора аренды"
error={!!errors.rent_contract_num}
helperText={errors.rent_contract_num}
disabled={loading}
/>
</FieldContainer>
<FieldContainer>
<FieldLabel>Срок окончания договора аренды</FieldLabel>
<StyledDatePicker
value={formData.rent_end_date}
onChange={handleDateChange('rent_end_date')}
disabled={loading}
error={!!errors.rent_end_date}
helperText={errors.rent_end_date}
/>
</FieldContainer>
</ModalContainer>
<Divider sx={{ mt: '1.5rem' }} />
</Modal>
);
};
export default ModalEditAddVsp;