car_mms/app/components/forms/EnhancedVehicleForm.tsx
2025-09-11 14:22:27 +03:00

400 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useEffect } from 'react';
import { Form as RemixForm } from "@remix-run/react";
import { Input } from "~/components/ui/Input";
import { Select } from "~/components/ui/Select";
import { Button } from "~/components/ui/Button";
import { FormField } from "~/components/ui/FormField";
import { Form, FormActions, FormSection, FormGrid } from "~/components/ui/Form";
import { useFormValidation } from "~/hooks/useFormValidation";
import { vehicleSchema } from "~/lib/form-validation";
import { TRANSMISSION_TYPES, FUEL_TYPES, USE_TYPES, BODY_TYPES, MANUFACTURERS, VALIDATION } from "~/lib/constants";
import type { Vehicle } from "~/types/database";
interface EnhancedVehicleFormProps {
vehicle?: Vehicle;
customers: { id: number; name: string; phone?: string | null }[];
onCancel: () => void;
errors?: Record<string, string>;
isLoading: boolean;
onSubmit?: (data: any) => void;
}
export function EnhancedVehicleForm({
vehicle,
customers,
onCancel,
errors = {},
isLoading,
onSubmit,
}: EnhancedVehicleFormProps) {
const {
values,
errors: validationErrors,
touched,
isValid,
setValue,
setTouched,
reset,
validate,
getFieldProps,
} = useFormValidation({
schema: vehicleSchema,
initialValues: {
plateNumber: vehicle?.plateNumber || "",
bodyType: vehicle?.bodyType || "",
manufacturer: vehicle?.manufacturer || "",
model: vehicle?.model || "",
trim: vehicle?.trim || "",
year: vehicle?.year || new Date().getFullYear(),
transmission: vehicle?.transmission || "",
fuel: vehicle?.fuel || "",
cylinders: vehicle?.cylinders || null,
engineDisplacement: vehicle?.engineDisplacement || null,
useType: vehicle?.useType || "",
ownerId: vehicle?.ownerId || 0,
},
validateOnChange: true,
validateOnBlur: true,
});
// Reset form when vehicle changes
useEffect(() => {
if (vehicle) {
reset({
plateNumber: vehicle.plateNumber || "",
bodyType: vehicle.bodyType || "",
manufacturer: vehicle.manufacturer || "",
model: vehicle.model || "",
trim: vehicle.trim || "",
year: vehicle.year || new Date().getFullYear(),
transmission: vehicle.transmission || "",
fuel: vehicle.fuel || "",
cylinders: vehicle.cylinders || null,
engineDisplacement: vehicle.engineDisplacement || null,
useType: vehicle.useType || "",
ownerId: vehicle.ownerId || 0,
});
} else {
reset({
plateNumber: "",
bodyType: "",
manufacturer: "",
model: "",
trim: "",
year: new Date().getFullYear(),
transmission: "",
fuel: "",
cylinders: null,
engineDisplacement: null,
useType: "",
ownerId: 0,
});
}
}, [vehicle, reset]);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const { isValid: formIsValid } = validate();
if (formIsValid && onSubmit) {
onSubmit(values);
}
};
const isEditing = !!vehicle;
const combinedErrors = { ...validationErrors, ...errors };
const currentYear = new Date().getFullYear();
return (
<Form
title={isEditing ? "تعديل بيانات المركبة" : "إضافة مركبة جديدة"}
description={isEditing ? "قم بتعديل بيانات المركبة أدناه" : "أدخل بيانات المركبة الجديدة"}
loading={isLoading}
onSubmit={handleSubmit}
>
<input
type="hidden"
name="_action"
value={isEditing ? "update" : "create"}
/>
{isEditing && (
<input type="hidden" name="id" value={vehicle.id} />
)}
<FormSection
title="المعلومات الأساسية"
description="البيانات الأساسية للمركبة"
>
<FormGrid columns={2}>
{/* Plate Number */}
<FormField
label="رقم اللوحة"
required
error={combinedErrors.plateNumber}
htmlFor="plateNumber"
>
<Input
id="plateNumber"
name="plateNumber"
type="text"
placeholder="أدخل رقم اللوحة"
disabled={isLoading}
dir="ltr"
{...getFieldProps('plateNumber')}
/>
</FormField>
{/* Owner */}
<FormField
label="المالك"
required
error={combinedErrors.ownerId}
htmlFor="ownerId"
>
<Select
id="ownerId"
name="ownerId"
placeholder="اختر المالك"
disabled={isLoading}
options={customers.map(customer => ({
value: customer.id.toString(),
label: `${customer.name}${customer.phone ? ` (${customer.phone})` : ''}`,
}))}
value={values.ownerId?.toString() || ''}
onChange={(e) => setValue('ownerId', parseInt(e.target.value) || 0)}
/>
</FormField>
</FormGrid>
</FormSection>
<FormSection
title="مواصفات المركبة"
description="التفاصيل التقنية للمركبة"
>
<FormGrid columns={3}>
{/* Body Type */}
<FormField
label="نوع الهيكل"
required
error={combinedErrors.bodyType}
htmlFor="bodyType"
>
<Select
id="bodyType"
name="bodyType"
placeholder="اختر نوع الهيكل"
aria-readonly={isLoading}
options={BODY_TYPES.map(type => ({
value: type.value,
label: type.label,
}))}
{...getFieldProps('bodyType')}
/>
</FormField>
{/* Manufacturer */}
<FormField
label="الشركة المصنعة"
required
error={combinedErrors.manufacturer}
htmlFor="manufacturer"
>
<Select
id="manufacturer"
name="manufacturer"
placeholder="اختر الشركة المصنعة"
disabled={isLoading}
options={MANUFACTURERS.map(manufacturer => ({
value: manufacturer.value,
label: manufacturer.label,
}))}
{...getFieldProps('manufacturer')}
/>
</FormField>
{/* Model */}
<FormField
label="الموديل"
required
error={combinedErrors.model}
htmlFor="model"
>
<Input
id="model"
name="model"
type="text"
placeholder="أدخل الموديل"
disabled={isLoading}
{...getFieldProps('model')}
/>
</FormField>
{/* Trim */}
<FormField
label="الفئة"
error={combinedErrors.trim}
htmlFor="trim"
helperText="الفئة اختيارية"
>
<Input
id="trim"
name="trim"
type="text"
placeholder="أدخل الفئة (اختياري)"
disabled={isLoading}
{...getFieldProps('trim')}
/>
</FormField>
{/* Year */}
<FormField
label="سنة الصنع"
required
error={combinedErrors.year}
htmlFor="year"
>
<Input
id="year"
name="year"
type="number"
min={VALIDATION.MIN_YEAR}
max={VALIDATION.MAX_YEAR}
placeholder={`${VALIDATION.MIN_YEAR} - ${currentYear}`}
disabled={isLoading}
value={values.year?.toString() || ''}
onChange={(e) => setValue('year', parseInt(e.target.value) || currentYear)}
/>
</FormField>
{/* Use Type */}
<FormField
label="نوع الاستخدام"
required
error={combinedErrors.useType}
htmlFor="useType"
>
<Select
id="useType"
name="useType"
placeholder="اختر نوع الاستخدام"
disabled={isLoading}
options={USE_TYPES.map(useType => ({
value: useType.value,
label: useType.label,
}))}
{...getFieldProps('useType')}
/>
</FormField>
</FormGrid>
</FormSection>
<FormSection
title="المحرك والناقل"
description="مواصفات المحرك وناقل الحركة"
>
<FormGrid columns={2}>
{/* Transmission */}
<FormField
label="ناقل الحركة"
required
error={combinedErrors.transmission}
htmlFor="transmission"
>
<Select
id="transmission"
name="transmission"
placeholder="اختر ناقل الحركة"
disabled={isLoading}
options={TRANSMISSION_TYPES.map(transmission => ({
value: transmission.value,
label: transmission.label,
}))}
{...getFieldProps('transmission')}
/>
</FormField>
{/* Fuel */}
<FormField
label="نوع الوقود"
required
error={combinedErrors.fuel}
htmlFor="fuel"
>
<Select
id="fuel"
name="fuel"
placeholder="اختر نوع الوقود"
disabled={isLoading}
options={FUEL_TYPES.map(fuel => ({
value: fuel.value,
label: fuel.label,
}))}
{...getFieldProps('fuel')}
/>
</FormField>
{/* Cylinders */}
<FormField
label="عدد الأسطوانات"
error={combinedErrors.cylinders}
htmlFor="cylinders"
helperText="عدد الأسطوانات اختياري"
>
<Input
id="cylinders"
name="cylinders"
type="number"
min="1"
max={VALIDATION.MAX_CYLINDERS}
placeholder="عدد الأسطوانات (اختياري)"
disabled={isLoading}
value={values.cylinders?.toString() || ''}
onChange={(e) => setValue('cylinders', e.target.value ? parseInt(e.target.value) : null)}
/>
</FormField>
{/* Engine Displacement */}
<FormField
label="سعة المحرك (لتر)"
error={combinedErrors.engineDisplacement}
htmlFor="engineDisplacement"
helperText="سعة المحرك اختيارية"
>
<Input
id="engineDisplacement"
name="engineDisplacement"
type="number"
step="0.1"
min="0.1"
max={VALIDATION.MAX_ENGINE_DISPLACEMENT}
placeholder="سعة المحرك (اختياري)"
disabled={isLoading}
value={values.engineDisplacement?.toString() || ''}
onChange={(e) => setValue('engineDisplacement', e.target.value ? parseFloat(e.target.value) : null)}
/>
</FormField>
</FormGrid>
</FormSection>
<FormActions>
<Button
type="button"
variant="outline"
onClick={onCancel}
disabled={isLoading}
>
إلغاء
</Button>
<Button
type="submit"
disabled={isLoading || !isValid || !values.plateNumber?.trim() || !values.ownerId}
loading={isLoading}
>
{isEditing ? "تحديث المركبة" : "إنشاء المركبة"}
</Button>
</FormActions>
</Form>
);
}