mirror of
https://github.com/soconnor0919/beenvoice.git
synced 2025-12-13 09:34:44 -05:00
component - Create custom NumberInput component with increment/decrement buttons - Add 0.25 step increments for hours and rates in invoice forms - Implement emerald-themed styling with hover states and accessibility - Add keyboard navigation (arrow keys) and proper ARIA support - Condense invoice editor tax/totals section into efficient grid layout - Update client dropdown to single-line format (name + email) - Add fixed footer with floating action bar pattern matching business forms - Redesign invoice viewer with better space utilization and visual hierarchy - Maintain professional appearance and consistent design system - Fix Next.js 15 params Promise handling across all invoice pages - Resolve TypeScript compilation errors and type-only imports
7.8 KiB
7.8 KiB
Forms Improvement Guide
Overview
The business and client creation/editing forms have been significantly improved with better organization, shared components, enhanced validation, and improved user experience.
Key Improvements
1. Shared Components & Utilities
Address Form Component (src/components/ui/address-form.tsx)
A reusable address form component that handles:
- Country-aware formatting (US ZIP codes, Canadian postal codes)
- State dropdown for US addresses, text input for other countries
- Popular countries listed first in country dropdown
- Automatic field adjustments based on country selection
<AddressForm
addressLine1={formData.addressLine1}
addressLine2={formData.addressLine2}
city={formData.city}
state={formData.state}
postalCode={formData.postalCode}
country={formData.country}
onChange={handleInputChange}
errors={errors}
required={false}
/>
Form Constants & Utilities (src/lib/form-constants.ts)
Centralized location for:
- US states list with proper formatting
- All countries with ISO codes
- Popular countries for quick selection
- Format functions for phone, postal codes, tax IDs, and URLs
- Validation utilities and messages
2. Enhanced Form Validation
Real-time Validation
- Errors clear as soon as user starts typing
- Field-specific validation messages
- Visual feedback with red borders on invalid fields
Smart Validation Rules
- Email: Proper email format checking
- Phone: US phone number format validation
- Address: Required fields only if any address field is filled
- URL: Automatic https:// prefix addition
// Example validation
if (formData.email && !isValidEmail(formData.email)) {
newErrors.email = VALIDATION_MESSAGES.email;
}
3. Better Form Organization
Card-based Sections
Forms are now organized into logical sections using cards:
- Basic Information: Core fields like name, tax ID
- Contact Information: Email, phone, website
- Address: Complete address form with smart country handling
- Settings: Business-specific settings like default business flag
Consistent Layout
- Maximum width container for better readability
- Responsive grid layouts that stack on mobile
- Proper spacing between sections
- Clear visual hierarchy
4. Improved User Experience
Loading States
- Skeleton loader while fetching data in edit mode
- Disabled form fields during submission
- Loading spinner in submit button
Unsaved Changes Warning
const handleCancel = () => {
if (isDirty) {
const confirmed = window.confirm(
"You have unsaved changes. Are you sure you want to leave?"
);
if (!confirmed) return;
}
router.push("/dashboard/businesses");
};
Smart Field Formatting
- Phone numbers: Auto-format as (555) 123-4567
- Tax ID: Auto-format as 12-3456789
- Postal codes: Format based on country (US vs Canadian)
- Website URLs: Auto-add https:// if missing
5. Responsive Design
Mobile Optimizations
- Form sections stack vertically on small screens
- Touch-friendly input sizes
- Proper button positioning
- Readable font sizes
Desktop Enhancements
- Two-column layouts for related fields
- Optimal reading width
- Side-by-side form actions
6. Code Reusability
Shared Between Business & Client Forms
- Address form component
- Validation logic
- Format functions
- Constants (states, countries)
- Error handling patterns
TypeScript Interfaces
interface FormData {
name: string;
email: string;
phone: string;
// ... other fields
}
interface FormErrors {
name?: string;
email?: string;
// ... validation errors
}
Usage Examples
Basic Form Implementation
export function BusinessForm({ businessId, mode }: BusinessFormProps) {
const [formData, setFormData] = useState<FormData>(initialFormData);
const [errors, setErrors] = useState<FormErrors>({});
const [isSubmitting, setIsSubmitting] = useState(false);
const [isDirty, setIsDirty] = useState(false);
// Handle input changes
const handleInputChange = (field: string, value: string | boolean) => {
setFormData((prev) => ({ ...prev, [field]: value }));
setIsDirty(true);
// Clear error when user types
if (errors[field as keyof FormErrors]) {
setErrors((prev) => ({ ...prev, [field]: undefined }));
}
};
// Validate and submit
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!validateForm()) {
toast.error("Please correct the errors in the form");
return;
}
// Submit logic...
};
}
Field with Icon and Validation
<div className="space-y-2">
<Label htmlFor="email">
Email
<span className="text-muted-foreground ml-1 text-xs">(Optional)</span>
</Label>
<div className="relative">
<Mail className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
<Input
id="email"
type="email"
value={formData.email}
onChange={(e) => handleInputChange("email", e.target.value)}
placeholder={PLACEHOLDERS.email}
className={`pl-10 ${errors.email ? "border-destructive" : ""}`}
disabled={isSubmitting}
/>
</div>
{errors.email && (
<p className="text-sm text-destructive">{errors.email}</p>
)}
</div>
Best Practices
1. Form State Management
- Use controlled components for all inputs
- Track dirty state for unsaved changes warnings
- Clear errors when user corrects them
- Disable form during submission
2. Validation Strategy
- Validate on submit, not on blur (less annoying)
- Clear errors immediately when user starts fixing them
- Show field-level errors below each input
- Use consistent error message format
3. Accessibility
- Proper label associations with htmlFor
- Required field indicators
- Error messages linked to fields
- Keyboard navigation support
- Focus management
4. Performance
- Memoize expensive computations
- Use debouncing for format functions if needed
- Lazy load country lists
- Optimize re-renders with proper state management
Migration Guide
From Old Forms
- Replace inline state/country arrays with imported constants
- Use
AddressFormcomponent instead of individual address fields - Apply format functions from
form-constants.ts - Update validation to use shared utilities
- Wrap sections in Card components
- Add loading and dirty state tracking
Example Migration
// Before
const US_STATES = [
{ value: "AL", label: "Alabama" },
// ... duplicated in each form
];
// After
import { US_STATES, formatPhoneNumber } from "~/lib/form-constants";
import { AddressForm } from "~/components/ui/address-form";
Future Enhancements
Planned Improvements
- Field-level permissions: Disable fields based on user role
- Auto-save: Save draft as user types
- Multi-step forms: Break long forms into steps
- Conditional fields: Show/hide fields based on other values
- Bulk operations: Create multiple records at once
- Import from templates: Pre-fill common business types
Extensibility
The form system is designed to be easily extended:
- Add new format functions to
form-constants.ts - Create additional shared form components
- Extend validation rules as needed
- Add new field types with consistent patterns
Troubleshooting
Common Issues
- Validation not working: Ensure field names match FormErrors interface
- Format function not applying: Check that onChange uses the format function
- Country dropdown not searching: Verify SearchableSelect has search enabled
- Address validation failing: Check if country field affects validation rules
Debug Tips
- Use React DevTools to inspect form state
- Check console for validation errors
- Verify API responses match expected format
- Test with different country selections