export interface ValidationRule { required?: boolean minLength?: number maxLength?: number email?: boolean pattern?: RegExp match?: string custom?: (value: string) => string | null } export interface FieldErrors { [key: string]: string } export function useFormValidation() { const errors = ref({}) const validateEmail = (email: string): boolean => { const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ return re.test(email) } const validateField = (value: string, rules: ValidationRule, fieldName: string, formData?: Record, messages?: Record): string | null => { if (rules.required && !value.trim()) { return messages?.required || `กรุณากรอก${fieldName}` } if (rules.minLength && value.length < rules.minLength) { return messages?.minLength || `${fieldName}ต้องมีอย่างน้อย ${rules.minLength} ตัวอักษร` } if (rules.maxLength && value.length > rules.maxLength) { return messages?.maxLength || `${fieldName}ต้องไม่เกิน ${rules.maxLength} ตัวอักษร` } if (rules.email && value && !validateEmail(value)) { return messages?.email || 'รูปแบบอีเมลไม่ถูกต้อง' } if (rules.pattern && value && !rules.pattern.test(value)) { return messages?.pattern || `${fieldName}รูปแบบไม่ถูกต้อง` } if (rules.match && formData && value !== formData[rules.match]) { return messages?.match || 'รหัสผ่านไม่ตรงกัน' } if (rules.custom) { return rules.custom(value) } return null } const validate = ( formData: Record, validationRules: Record }> ): boolean => { const newErrors: FieldErrors = {} let isValid = true for (const [fieldKey, config] of Object.entries(validationRules)) { const error = validateField(formData[fieldKey] || '', config.rules, config.label, formData, config.messages) if (error) { newErrors[fieldKey] = error isValid = false } } errors.value = newErrors return isValid } const clearErrors = () => { errors.value = {} } const clearFieldError = (field: string) => { if (errors.value[field]) { // eslint-disable-next-line @typescript-eslint/no-dynamic-delete delete errors.value[field] } } return { errors, validate, clearErrors, clearFieldError } }