/** * Form State Utilities * Utilities for managing form state */ import type { FormState } from '../types/FormTypes'; /** * Check if form is valid (no errors) */ export function isFormValid>( formState: FormState ): boolean { return Object.values(formState.errors).every((error) => error === null); } /** * Check if form is dirty (has changes) */ export function isFormDirty>( formState: FormState, initialValues: T ): boolean { return Object.keys(formState.fields).some((key) => { const fieldKey = key as keyof T; return formState.fields[fieldKey] !== initialValues[fieldKey]; }); } /** * Check if form is touched (any field touched) */ export function isFormTouched>( formState: FormState ): boolean { return Object.values(formState.touched).some((touched) => touched); } /** * Get all errors as array */ export function getFormErrors>( formState: FormState ): string[] { return Object.values(formState.errors).filter((error): error is string => error !== null); } /** * Get first error message */ export function getFirstFormError>( formState: FormState ): string | null { const errors = getFormErrors(formState); return errors.length > 0 ? errors[0] : null; } /** * Count errors */ export function countFormErrors>( formState: FormState ): number { return getFormErrors(formState).length; } /** * Get error for specific field */ export function getFieldError>( formState: FormState, field: keyof T ): string | null { return formState.errors[field] || null; } /** * Check if field has error */ export function fieldHasError>( formState: FormState, field: keyof T ): boolean { return formState.errors[field] !== null; } /** * Check if field is touched */ export function isFieldTouched>( formState: FormState, field: keyof T ): boolean { return formState.touched[field] || false; } /** * Reset form to initial state */ export function resetFormState>( initialValues: T ): FormState { return { fields: initialValues, errors: Object.keys(initialValues).reduce((acc, key) => { acc[key as keyof T] = null; return acc; }, {} as Record), touched: Object.keys(initialValues).reduce((acc, key) => { acc[key as keyof T] = false; return acc; }, {} as Record), }; }