document.head.insertAdjacentHTML('beforeend','')
module.exports =
name: 'FormValidator'
render: (new Function '_ctx', '_cache', renderFns['app/shared/FormValidator/index.pug'])()
props:
fields:
type: Object
default: ->
email: true
phone: true
message: true
file: false
validationRules:
type: Object
default: -> {}
data: ->
formData:
email: ''
phone: ''
message: ''
file: null
errors: {}
isSubmitting: false
isSubmitted: false
fileInfo: ''
debounceTimers: {}
computed:
isFormValid: ->
Object.keys(@errors).length == 0 &&
Object.keys(@formData).some((key) => @formData[key] && @formData[key].toString().trim() != '')
mounted: ->
@initializeValidation()
methods:
initializeValidation: ->
# Установка правил валидации по умолчанию
@defaultRules =
email:
required: true
pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
message: 'Введите корректный email адрес'
phone:
required: true
pattern: /^\+?[0-9\s\-\(\)]{10,}$/
message: 'Введите корректный номер телефона'
message:
required: true
minLength: 10
message: 'Сообщение должно содержать минимум 10 символов'
file:
maxSize: 5 * 1024 * 1024 # 5MB
allowedTypes: ['image/jpeg', 'image/png', 'application/pdf']
message: 'Файл должен быть JPEG, PNG или PDF, не более 5MB'
validateField: (fieldName) ->
rules = @validationRules[fieldName] || @defaultRules[fieldName]
value = @formData[fieldName]
@errors[fieldName] = ''
if rules.required && (!value || value.toString().trim() == '')
@errors[fieldName] = 'Это поле обязательно для заполнения'
return false
if rules.pattern && value && !rules.pattern.test(value)
@errors[fieldName] = rules.message
return false
if rules.minLength && value && value.length < rules.minLength
@errors[fieldName] = rules.message
return false
true
debouncedValidate: (fieldName) ->
clearTimeout @debounceTimers[fieldName] if @debounceTimers[fieldName]
@debounceTimers[fieldName] = setTimeout =>
@validateField fieldName
, 500
handleFileUpload: (event) ->
file = event.target.files[0]
return unless file
rules = @defaultRules.file
@errors.file = ''
# Проверка типа файла :cite[2]:cite[7]
if !rules.allowedTypes.includes(file.type)
@errors.file = 'Разрешены только JPEG, PNG и PDF файлы'
return
if file.size > rules.maxSize
@errors.file = 'Файл слишком большой. Максимальный размер: 5MB'
return
@formData.file = file
@fileInfo = "#{file.name} (#{(file.size / 1024 / 1024).toFixed(2)} MB)"
handleSubmit: (event) ->
event.preventDefault()
# Валидация всех полей
isValid = true
for fieldName of @fields
if @fields[fieldName] && !@validateField(fieldName)
isValid = false
return unless isValid
@isSubmitting = true
# Имитация отправки
setTimeout =>
@isSubmitting = false
@isSubmitted = true
@$emit 'form-submitted', @formData
, 2000
getFieldClasses: (fieldName) ->
baseClasses = 'border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white'
errorClasses = 'border-red-500 dark:border-red-400 ring-1 ring-red-500 dark:ring-red-400'
validClasses = 'border-green-500 dark:border-green-400'
if @errors[fieldName]
return "#{baseClasses} #{errorClasses}"
else if @formData[fieldName] && @formData[fieldName].toString().trim() != ''
return "#{baseClasses} #{validClasses}"
else
return baseClasses
emits: ['form-submitted', 'validation-changed']