// src/components/common/ProjectCardComponent/ModalCreateProject.jsx import { useState, useEffect } from 'react'; import { Box, Button, Divider, TextField, Typography } from '@mui/material'; import SelectWithOptions from '../AdminPanel/components/SelectWithOptions'; import Modal from '../../components/common/Modal/Modal'; import { PrimaryButton } from '../../components/common/Buttons/Buttons'; export const ModalCreateProject = ({ open, onClose, onCreate, config = {}, initialData = null, isEdit = false, projectId = null, }) => { const [projectData, setProjectData] = useState(() => { // Если есть initialData, используем её, иначе создаем из конфига if (initialData) { return { ...initialData }; } const initial = {}; Object.keys(config).forEach((key) => { initial[key] = config[key].defaultValue; }); return initial; }); const [errors, setErrors] = useState({}); // Обновляем данные при изменении initialData useEffect(() => { if (initialData) { setProjectData({ ...initialData }); } else { const initial = {}; Object.keys(config).forEach((key) => { initial[key] = config[key].defaultValue; }); setProjectData(initial); } setErrors({}); }, [initialData, config]); const handleChange = (field, value) => { setProjectData((prev) => ({ ...prev, [field]: value, })); // Очищаем ошибку для поля при изменении if (errors[field]) { setErrors((prev) => ({ ...prev, [field]: undefined, })); } }; const validateField = (fieldName, config) => { if (config.required_field) { const value = projectData[fieldName]; // Проверка для разных типов полей if (config.type === 'multiselect') { if (!value || (Array.isArray(value) && value.length === 0) || value === '') { return `Поле "${fieldName}" обязательно для заполнения`; } } else if (config.type === 'text') { if (!value || value.trim() === '') { return `Поле "${fieldName}" обязательно для заполнения`; } } else if (config.type === 'number') { if (value === null || value === undefined || value === '') { return `Поле "${fieldName}" обязательно для заполнения`; } // Проверка на минимальное значение if (config.min !== undefined && Number(value) < config.min) { return `Значение должно быть не меньше ${config.min}`; } // Проверка на максимальное значение if (config.max !== undefined && Number(value) > config.max) { return `Значение должно быть не больше ${config.max}`; } } } return null; }; const validateAllFields = () => { const newErrors = {}; let hasErrors = false; Object.entries(config).forEach(([fieldName, fieldConfig]) => { const error = validateField(fieldName, fieldConfig); if (error) { newErrors[fieldName] = error; hasErrors = true; } }); setErrors(newErrors); return !hasErrors; }; const handleClickCreate = () => { if (validateAllFields()) { onCreate(projectData); // Не закрываем модалку здесь, пусть это делает родительский компонент } }; const handleClose = () => { const resetData = {}; Object.keys(config).forEach((key) => { resetData[key] = config[key].defaultValue; }); setProjectData(resetData); setErrors({}); onClose(); }; const renderField = (fieldName, config) => { const hasError = !!errors[fieldName]; const errorText = errors[fieldName]; switch (config.type) { case 'multiselect': return ( {fieldName} {config.required_field && ( * )} handleChange(fieldName, value)} width="28.25rem" style={{ borderColor: hasError ? 'var(--error-color, #d32f2f)' : undefined, borderWidth: hasError ? '2px' : undefined, }} /> {hasError && ( {errorText} )} ); case 'text': return ( {fieldName} {config.required_field && ( * )} handleChange(fieldName, e.target.value)} placeholder={config.placeholder} size="small" error={hasError} helperText={hasError ? errorText : ''} FormHelperTextProps={{ sx: { marginLeft: 0, fontSize: '0.75rem', }, }} /> ); case 'number': return ( {fieldName} {config.required_field && ( * )} { const inputValue = e.target.value; //только числа const isValidInput = /^\d*\.?\d*$/.test(inputValue) || inputValue === ''; if (isValidInput) { handleChange(fieldName, inputValue); } }} placeholder={config.placeholder} size="small" error={hasError} helperText={hasError ? errorText : ''} slotProps={{ htmlInput: { min: config.min, max: config.max || null, step: config.step || 1, }, }} FormHelperTextProps={{ sx: { marginLeft: 0, fontSize: '0.75rem', }, }} /> ); default: return null; } }; return ( {isEdit ? 'Сохранить' : 'Создать'} } > {Object.entries(config).map(([fieldName, config]) => renderField(fieldName, config), )} ); };