Successfully implemented centralized form validation across all 11 forms in the application using react-hook-form built-in validation (no external libraries like Zod or Yup).
- ValidationPatterns: Regex patterns for email, phone, zipcode
- ValidationMessages: Standardized error messages
- ValidationRules: 20+ reusable validation rule functions:
email()- Email validation with pattern matchingphone()- Phone number validationname(),firstName(),lastName()- Name field validationpassword(),confirmPassword()- Password validation with matchingtext(),number()- Generic text/number validation with min/maxaddress1(),address2(),city(),state(),country(),zipcode()- Address field validationcompanyName(),select(),extension(),department(),jobTitle()- Specialized validation
- combineValidations(): Utility to merge multiple validation rules
- FormTextField: Wrapper for TextFieldElement with validation
- FormSelectField: Wrapper for SelectElement with validation
- FormCheckboxField: Wrapper for CheckboxElement
- FieldWidths: Standard width constants (FULL, DRAWER: 410px, STANDARD: 31%, HALF: 48%)
- CommonFields: Pre-configured validated components:
Email,Phone,FirstName,LastNameAddress1,Address2,City,State,Country,ZipcodeExtension,Department,JobTitle,Password,Status
-
UserForm.tsx - User profile editing
- Fields: firstName, lastName, email, jobTitle, department, location, phoneNumber, extension
- Uses: CommonFields components with phone validation
-
ProfileChangePassword.tsx - Password change
- Fields: currentPassword, password, confirmPassword
- Features: Password matching validation with
watch()hook
-
AddContact.tsx - New contact creation
- Fields: All contact fields (13 total) including name, email, phone, address
- Uses: CommonFields components with full address validation
-
ContactGeneral.tsx - Contact editing
- Similar to AddContact but with existing data loading
- Handles possibly undefined response
-
AddCompany.tsx - New company creation
- Fields: Company name, address, revenue, employeesCount, etc. (14 fields)
- Features: Number validation for revenue and employee count
-
EditCompany.tsx - Company editing
- Same as AddCompany with data loading
- Fixed: Convert id parameter to number for API call
-
AddInventory.tsx - New inventory creation
- Fields: tracking, dimensions (length/width/height), weight, notes
- Features: Number validation for dimensions
-
InventoryGeneral.tsx - Inventory editing
- Similar to AddInventory with existing data
- Handles possibly undefined response
-
AddQuote.tsx - New quote creation
- Fields: quoteName, serviceTypeId, transportMode, companyId, contactId, expiryDate
- Features: Company → Contacts cascade with useEffect watch
- Date field with InputLabelProps support
-
QuoteEdit.tsx - Quote editing
- Complex form with child components (QuoteCargoDetail, QuoteRoutes, QuoteAccessorials)
- Validation applied to main form container
- EmailForm.tsx - Email composition
- Fields: title, message, isCritical checkbox
- Features: Multiline text validation for message field
// 1. Added imports
import { ValidationRules } from "../../utils/validation.util";
import { CommonFields, FormTextField } from "../../shared/components/FormFields";
// 2. Added mode: "onBlur" to useForm
const formContext = useForm({
defaultValues,
mode: "onBlur" // Validate on blur for better UX
});
// 3. Removed manual validation checks
// BEFORE: if (!data.email || !data.fullName) return;
// AFTER: Validation handled by form rules
// 4. Updated field components
// BEFORE: <TextFieldElement validation={{ maxLength: 100 }} />
// AFTER: <FormTextField rules={ValidationRules.text(undefined, 100, true)} />
// 5. Fixed FormContainer onSuccess
// BEFORE: onSuccess={() => handleSubmit(handleSubmitForm)}
// AFTER: onSuccess={handleSubmitForm} // Receives data directly
// 6. Removed onClick from submit buttons
// BEFORE: <Button onClick={handleSubmitForm} type="submit" />
// AFTER: <Button type="submit" /> // FormContainer handles submission- Circular JSON Error: Removed
onClick={handleSubmitForm}from submit buttons (caused circular DOM reference) - TypeScript Errors:
- Fixed
validationprop →rulesprop throughout - Added type definitions for form data (e.g., AddQuoteFormData)
- Handled possibly undefined responses with null checks
- Converted string id to number where needed (EditCompany)
- Fixed
- Date Field Support: Added "date" type to FormTextField interface and InputLabelProps support
- ✅ ~500+ lines of duplicate validation code eliminated
- ✅ Consistent validation patterns across all forms
- ✅ Type-safe validation rules with TypeScript
- ✅ Zero TypeScript compilation errors
- ✅ Validation on blur (not on every keystroke)
- ✅ Consistent error messages
- ✅ Clear field requirements
- ✅ Proper form submission handling
- ✅ Single source of truth for validation rules
- ✅ Reusable components reduce boilerplate
- ✅ Easy to add new validation rules
- ✅ Easy to update validation messages globally
<CommonFields.Email
name="email"
label="Email"
sx={{ m: 1, minWidth: "90%" }}
/>
// Built-in: required, pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, maxLength: 100<CommonFields.Phone
name="phoneNumber"
label="Phone"
sx={{ m: 1, width: FieldWidths.STANDARD }}
/>
// Built-in: required, pattern: /^\+?1?\d{10,14}$/, maxLength: 15<FormTextField
name="customField"
label="Custom"
rules={combineValidations(
ValidationRules.text(5, 50, true),
{ pattern: { value: /^[A-Z]/, message: "Must start with capital" } }
)}
/>const password = watch("password");
<CommonFields.Password name="confirmPassword" label="Confirm Password" />
<FormTextField
name="confirmPassword"
rules={ValidationRules.confirmPassword(password)}
/>✅ All forms compile successfully ✅ Zero TypeScript errors ✅ Production build: 7.03s
- Add async validation for duplicate checking (emails, company names)
- Add custom validation error styling
- Add field-level validation status indicators
- Add form-level validation summary
- Add validation unit tests