import { useState, useEffect, useRef } from 'react' import { IconCheck, IconX, IconAlertCircle } from '@tabler/icons-react' /** * ValidatedInput - input с real-time валидацией * @param {function} validate - функция валидации, возвращает { valid: boolean, message: string } * @param {number} debounce - задержка перед валидацией в ms */ function ValidatedInput({ value, onChange, validate, debounce = 300, label, placeholder, hint, required = false, type = 'text', className = '', showValidIcon = true, validateOnChange = true, ...props }) { const [validationState, setValidationState] = useState({ valid: null, message: '', isValidating: false }) const [isTouched, setIsTouched] = useState(false) const timeoutRef = useRef(null) useEffect(() => { // Не валидируем, пока пользователь не начал вводить if (!isTouched || !validateOnChange) return if (!validate) { setValidationState({ valid: null, message: '', isValidating: false }) return } // Очищаем предыдущий таймер if (timeoutRef.current) { clearTimeout(timeoutRef.current) } // Показываем индикатор валидации setValidationState(prev => ({ ...prev, isValidating: true })) // Запускаем валидацию с debounce timeoutRef.current = setTimeout(async () => { try { const result = validate(value) // Поддержка как синхронной, так и асинхронной валидации const validationResult = result instanceof Promise ? await result : result setValidationState({ valid: validationResult.valid, message: validationResult.message || '', isValidating: false }) } catch (error) { setValidationState({ valid: false, message: 'Ошибка валидации', isValidating: false }) } }, debounce) return () => { if (timeoutRef.current) { clearTimeout(timeoutRef.current) } } }, [value, validate, debounce, isTouched, validateOnChange]) const handleChange = (e) => { if (!isTouched) setIsTouched(true) onChange(e) } const handleBlur = () => { setIsTouched(true) // Запускаем валидацию сразу при потере фокуса if (validate && !validateOnChange) { const result = validate(value) const validationResult = result instanceof Promise ? result.then(r => { setValidationState({ valid: r.valid, message: r.message || '', isValidating: false }) }) : setValidationState({ valid: result.valid, message: result.message || '', isValidating: false }) } } const getInputClass = () => { const classes = ['form-control'] if (isTouched && validationState.valid === true) { classes.push('is-valid') } else if (isTouched && validationState.valid === false) { classes.push('is-invalid') } return classes.join(' ') } return (