/** * useFormValidation Hook * Action 5.2.1.3: Hook for pre-validation of form data */ import { useState, useCallback } from 'react'; import { apiClient } from '@/services/api/client'; import { parseApiError } from '@/utils/apiErrorHandler'; import { logger } from '@/utils/logger'; import type { ApiError } from '@/schemas/apiSchemas'; /** * Validation error from backend */ export interface ValidationError { field: string; message: string; value?: string; } /** * Validation response from backend */ interface ValidateResponse { valid: boolean; errors?: ValidationError[]; message?: string; } /** * Options for useFormValidation hook */ export interface UseFormValidationOptions { /** Validation type (e.g., "RegisterRequest", "LoginRequest") */ type: string; /** Whether to validate automatically on data change */ autoValidate?: boolean; /** Debounce delay in milliseconds (0 = no debounce) */ debounceMs?: number; } /** * Return type for useFormValidation hook */ export interface UseFormValidationReturn { /** Whether validation is in progress */ isValidating: boolean; /** Validation errors from backend */ errors: ValidationError[]; /** Whether the current data is valid */ isValid: boolean | null; /** Last validation error (if any) */ error: ApiError | null; /** Validate the provided data */ validate: (data: unknown) => Promise; /** Clear validation state */ clear: () => void; } /** * Hook for pre-validating form data against backend validation rules * * @param options - Validation options * @returns Validation state and functions * * @example * ```tsx * const { isValidating, errors, validate, isValid } = useFormValidation({ * type: 'RegisterRequest', * }); * * const handleBlur = async () => { * await validate(formData); * }; * ``` */ export function useFormValidation( options: UseFormValidationOptions, ): UseFormValidationReturn { const { type } = options; const [isValidating, setIsValidating] = useState(false); const [errors, setErrors] = useState([]); const [isValid, setIsValid] = useState(null); const [error, setError] = useState(null); const validate = useCallback( async (data: unknown): Promise => { if (!type) { logger.warn('[useFormValidation] Validation type is required'); return false; } setIsValidating(true); setError(null); try { const response = await apiClient.post( '/api/v1/validate', { type, data, }, ); const validationResult = response.data; // Handle both wrapped and direct response formats const result = typeof validationResult === 'object' && 'data' in validationResult ? (validationResult as { data: ValidateResponse }).data : validationResult; if (result.valid) { setErrors([]); setIsValid(true); return true; } else { setErrors(result.errors || []); setIsValid(false); return false; } } catch (err) { const apiError = parseApiError(err); setError(apiError); setErrors([]); setIsValid(false); logger.error('[useFormValidation] Validation request failed', { error: apiError.message, type, }); return false; } finally { setIsValidating(false); } }, [type], ); const clear = useCallback(() => { setErrors([]); setIsValid(null); setError(null); setIsValidating(false); }, []); return { isValidating, errors, isValid, error, validate, clear, }; }