363 lines
8.7 KiB
Markdown
363 lines
8.7 KiB
Markdown
# Reusable Form Components and Validation
|
||
|
||
This document describes the enhanced reusable form components and validation utilities implemented for the car maintenance management system.
|
||
|
||
## Overview
|
||
|
||
The system now includes a comprehensive set of reusable form components with RTL support, client-side and server-side validation, and enhanced data table functionality with Arabic text support.
|
||
|
||
## Components
|
||
|
||
### Form Input Components
|
||
|
||
#### Input Component (`app/components/ui/Input.tsx`)
|
||
Enhanced input component with RTL support, validation, and icons.
|
||
|
||
```tsx
|
||
import { Input } from '~/components/ui/Input';
|
||
|
||
<Input
|
||
label="اسم العميل"
|
||
placeholder="أدخل اسم العميل"
|
||
error={errors.name}
|
||
helperText="الاسم مطلوب"
|
||
startIcon={<UserIcon />}
|
||
required
|
||
/>
|
||
```
|
||
|
||
**Props:**
|
||
- `label`: Field label
|
||
- `error`: Error message to display
|
||
- `helperText`: Helper text below input
|
||
- `startIcon`/`endIcon`: Icons for input decoration
|
||
- `fullWidth`: Whether input takes full width (default: true)
|
||
- All standard HTML input props
|
||
|
||
#### Select Component (`app/components/ui/Select.tsx`)
|
||
Dropdown select component with RTL support and validation.
|
||
|
||
```tsx
|
||
import { Select } from '~/components/ui/Select';
|
||
|
||
<Select
|
||
label="نوع الوقود"
|
||
placeholder="اختر نوع الوقود"
|
||
options={[
|
||
{ value: 'gasoline', label: 'بنزين' },
|
||
{ value: 'diesel', label: 'ديزل' },
|
||
]}
|
||
error={errors.fuel}
|
||
/>
|
||
```
|
||
|
||
**Props:**
|
||
- `options`: Array of `{ value, label, disabled? }` objects
|
||
- `placeholder`: Placeholder text
|
||
- Other props same as Input component
|
||
|
||
#### Textarea Component (`app/components/ui/Textarea.tsx`)
|
||
Multi-line text input with RTL support.
|
||
|
||
```tsx
|
||
import { Textarea } from '~/components/ui/Textarea';
|
||
|
||
<Textarea
|
||
label="العنوان"
|
||
placeholder="أدخل العنوان"
|
||
rows={3}
|
||
resize="vertical"
|
||
error={errors.address}
|
||
/>
|
||
```
|
||
|
||
**Props:**
|
||
- `resize`: Resize behavior ('none', 'vertical', 'horizontal', 'both')
|
||
- `rows`: Number of visible rows
|
||
- Other props same as Input component
|
||
|
||
#### FormField Component (`app/components/ui/FormField.tsx`)
|
||
Wrapper component for consistent field styling and validation display.
|
||
|
||
```tsx
|
||
import { FormField } from '~/components/ui/FormField';
|
||
|
||
<FormField
|
||
label="اسم العميل"
|
||
required
|
||
error={errors.name}
|
||
helperText="أدخل الاسم الكامل"
|
||
>
|
||
<input type="text" name="name" />
|
||
</FormField>
|
||
```
|
||
|
||
### Form Layout Components
|
||
|
||
#### Form Component (`app/components/ui/Form.tsx`)
|
||
Main form wrapper with title, description, and error handling.
|
||
|
||
```tsx
|
||
import { Form, FormActions, FormSection, FormGrid } from '~/components/ui/Form';
|
||
|
||
<Form
|
||
title="إضافة عميل جديد"
|
||
description="أدخل بيانات العميل"
|
||
loading={isLoading}
|
||
error={generalError}
|
||
success={successMessage}
|
||
>
|
||
<FormSection title="المعلومات الأساسية">
|
||
<FormGrid columns={2}>
|
||
{/* Form fields */}
|
||
</FormGrid>
|
||
</FormSection>
|
||
|
||
<FormActions>
|
||
<Button variant="outline">إلغاء</Button>
|
||
<Button type="submit">حفظ</Button>
|
||
</FormActions>
|
||
</Form>
|
||
```
|
||
|
||
**Components:**
|
||
- `Form`: Main form wrapper
|
||
- `FormActions`: Action buttons container
|
||
- `FormSection`: Grouped form fields with title
|
||
- `FormGrid`: Responsive grid layout for fields
|
||
|
||
### Enhanced Data Table
|
||
|
||
#### DataTable Component (`app/components/ui/DataTable.tsx`)
|
||
Advanced data table with search, filtering, sorting, and pagination.
|
||
|
||
```tsx
|
||
import { DataTable } from '~/components/ui/DataTable';
|
||
|
||
<DataTable
|
||
data={customers}
|
||
columns={[
|
||
{
|
||
key: 'name',
|
||
header: 'الاسم',
|
||
sortable: true,
|
||
filterable: true,
|
||
render: (customer) => <strong>{customer.name}</strong>
|
||
},
|
||
{
|
||
key: 'phone',
|
||
header: 'الهاتف',
|
||
filterable: true,
|
||
filterType: 'text'
|
||
}
|
||
]}
|
||
searchable
|
||
searchPlaceholder="البحث في العملاء..."
|
||
filterable
|
||
pagination={{
|
||
enabled: true,
|
||
pageSize: 10,
|
||
currentPage: 1,
|
||
onPageChange: handlePageChange
|
||
}}
|
||
actions={{
|
||
label: 'الإجراءات',
|
||
render: (item) => (
|
||
<Button onClick={() => edit(item)}>تعديل</Button>
|
||
)
|
||
}}
|
||
/>
|
||
```
|
||
|
||
**Features:**
|
||
- Search across multiple fields
|
||
- Column-based filtering
|
||
- Sorting with Arabic text support
|
||
- Pagination
|
||
- Custom action buttons
|
||
- RTL layout support
|
||
- Loading and empty states
|
||
|
||
## Validation
|
||
|
||
### Server-Side Validation (`app/lib/form-validation.ts`)
|
||
|
||
Zod-based validation schemas with Arabic error messages.
|
||
|
||
```tsx
|
||
import { validateCustomerData } from '~/lib/form-validation';
|
||
|
||
const result = validateCustomerData(formData);
|
||
if (!result.success) {
|
||
return json({ errors: result.errors });
|
||
}
|
||
```
|
||
|
||
**Available Validators:**
|
||
- `validateUserData(data)`
|
||
- `validateCustomerData(data)`
|
||
- `validateVehicleData(data)`
|
||
- `validateMaintenanceVisitData(data)`
|
||
- `validateExpenseData(data)`
|
||
|
||
### Client-Side Validation Hook (`app/hooks/useFormValidation.ts`)
|
||
|
||
React hook for real-time form validation.
|
||
|
||
```tsx
|
||
import { useFormValidation } from '~/hooks/useFormValidation';
|
||
import { customerSchema } from '~/lib/form-validation';
|
||
|
||
const {
|
||
values,
|
||
errors,
|
||
isValid,
|
||
setValue,
|
||
getFieldProps,
|
||
validate
|
||
} = useFormValidation({
|
||
schema: customerSchema,
|
||
initialValues: { name: '', email: '' },
|
||
validateOnChange: true,
|
||
validateOnBlur: true
|
||
});
|
||
|
||
// Use with form fields
|
||
<Input {...getFieldProps('name')} />
|
||
```
|
||
|
||
### Validation Utilities (`app/lib/validation-utils.ts`)
|
||
|
||
Utility functions for field-level validation.
|
||
|
||
```tsx
|
||
import { validateField, validateEmail, PATTERNS } from '~/lib/validation-utils';
|
||
|
||
// Single field validation
|
||
const result = validateField(value, {
|
||
required: true,
|
||
minLength: 3,
|
||
email: true
|
||
});
|
||
|
||
// Specific validators
|
||
const emailResult = validateEmail('test@example.com');
|
||
const phoneResult = validatePhone('+966501234567');
|
||
|
||
// Pattern matching
|
||
const isValidEmail = PATTERNS.email.test(email);
|
||
```
|
||
|
||
## Table Utilities (`app/lib/table-utils.ts`)
|
||
|
||
Utilities for data processing with Arabic text support.
|
||
|
||
```tsx
|
||
import {
|
||
searchData,
|
||
filterData,
|
||
sortData,
|
||
processTableData
|
||
} from '~/lib/table-utils';
|
||
|
||
// Process table data with search, filter, sort, and pagination
|
||
const result = processTableData(
|
||
data,
|
||
{
|
||
search: 'محمد',
|
||
filters: { status: 'active' },
|
||
sort: { key: 'name', direction: 'asc' },
|
||
pagination: { page: 1, pageSize: 10 }
|
||
},
|
||
['name', 'email'] // searchable fields
|
||
);
|
||
```
|
||
|
||
## Example Forms
|
||
|
||
### Enhanced Customer Form (`app/components/forms/EnhancedCustomerForm.tsx`)
|
||
|
||
Complete example showing all components working together:
|
||
|
||
```tsx
|
||
import { EnhancedCustomerForm } from '~/components/forms/EnhancedCustomerForm';
|
||
|
||
<EnhancedCustomerForm
|
||
customer={customer}
|
||
onCancel={() => setShowForm(false)}
|
||
errors={actionData?.errors}
|
||
isLoading={navigation.state === 'submitting'}
|
||
onSubmit={(data) => submit(data, { method: 'post' })}
|
||
/>
|
||
```
|
||
|
||
### Enhanced Vehicle Form (`app/components/forms/EnhancedVehicleForm.tsx`)
|
||
|
||
Complex form with multiple sections and validation:
|
||
|
||
```tsx
|
||
import { EnhancedVehicleForm } from '~/components/forms/EnhancedVehicleForm';
|
||
|
||
<EnhancedVehicleForm
|
||
vehicle={vehicle}
|
||
customers={customers}
|
||
onCancel={() => setShowForm(false)}
|
||
errors={actionData?.errors}
|
||
isLoading={isSubmitting}
|
||
/>
|
||
```
|
||
|
||
## Features
|
||
|
||
### RTL Support
|
||
- All components support right-to-left layout
|
||
- Arabic text rendering and alignment
|
||
- Proper icon and element positioning
|
||
|
||
### Validation
|
||
- Client-side real-time validation
|
||
- Server-side validation with Zod schemas
|
||
- Arabic error messages
|
||
- Field-level and form-level validation
|
||
|
||
### Accessibility
|
||
- Proper ARIA labels and descriptions
|
||
- Keyboard navigation support
|
||
- Screen reader compatibility
|
||
- Focus management
|
||
|
||
### Performance
|
||
- Memoized components to prevent unnecessary re-renders
|
||
- Debounced search functionality
|
||
- Efficient data processing utilities
|
||
- Lazy loading for large datasets
|
||
|
||
## Usage Guidelines
|
||
|
||
1. **Always use FormField wrapper** for consistent styling and error display
|
||
2. **Implement both client and server validation** for security and UX
|
||
3. **Use the validation hook** for real-time feedback
|
||
4. **Leverage table utilities** for consistent data processing
|
||
5. **Follow RTL design patterns** for Arabic text and layout
|
||
6. **Test with Arabic content** to ensure proper rendering
|
||
|
||
## Migration from Old Components
|
||
|
||
To migrate existing forms to use the new components:
|
||
|
||
1. Replace basic inputs with the new Input/Select/Textarea components
|
||
2. Wrap fields with FormField for consistent styling
|
||
3. Add validation using the useFormValidation hook
|
||
4. Update data tables to use the enhanced DataTable component
|
||
5. Use Form layout components for better structure
|
||
|
||
## Testing
|
||
|
||
All components include comprehensive tests:
|
||
- `app/lib/__tests__/form-validation.test.ts`
|
||
- `app/lib/__tests__/validation-utils.test.ts`
|
||
|
||
Run tests with:
|
||
```bash
|
||
npm run test -- --run app/lib/__tests__/form-validation.test.ts
|
||
``` |