update page to using same tamplet in all project not using inline code
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import { Alert, Spinner } from "../UI";
|
||||
import { Alert, Button, Input, Modal, Select } from "../UI";
|
||||
import { getStoredToken } from "@/src/lib/auth";
|
||||
import {
|
||||
createCarSchema,
|
||||
@@ -18,35 +18,9 @@ import type {
|
||||
import type { Branch } from "@/src/types/branch";
|
||||
import { branchService } from "@/src/services/branch.service";
|
||||
|
||||
// ── Shared input style ────────────────────────────────────────────────────────
|
||||
|
||||
const inputBase: React.CSSProperties = {
|
||||
width: "100%",
|
||||
height: 40,
|
||||
padding: "0 0.75rem",
|
||||
borderRadius: "var(--radius-md)",
|
||||
border: "1px solid var(--color-border)",
|
||||
background: "var(--color-surface)",
|
||||
fontSize: 13,
|
||||
color: "var(--color-text-primary)",
|
||||
outline: "none",
|
||||
fontFamily: "var(--font-sans)",
|
||||
};
|
||||
|
||||
const labelStyle: React.CSSProperties = {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 6,
|
||||
fontSize: 12,
|
||||
fontWeight: 600,
|
||||
color: "var(--color-text-secondary)",
|
||||
};
|
||||
|
||||
const errorTextStyle: React.CSSProperties = {
|
||||
fontSize: 11,
|
||||
color: "var(--color-danger)",
|
||||
fontWeight: 500,
|
||||
};
|
||||
// ── Shared styles ─────────────────────────────────────────────────────────────
|
||||
// Only section-heading styling is left here — every input/select/label/error
|
||||
// visual is now owned by the shared <Input /> / <Select /> components.
|
||||
|
||||
const sectionHeadingStyle: React.CSSProperties = {
|
||||
fontSize: 11,
|
||||
@@ -57,6 +31,8 @@ const sectionHeadingStyle: React.CSSProperties = {
|
||||
margin: "0.5rem 0 0",
|
||||
};
|
||||
|
||||
const FORM_ID = "car-form";
|
||||
|
||||
// ── Date helper ───────────────────────────────────────────────────────────────
|
||||
// <input type="date"> gives "YYYY-MM-DD"; backend expects full ISO-8601.
|
||||
|
||||
@@ -140,9 +116,13 @@ export function CarFormModal({
|
||||
register,
|
||||
handleSubmit,
|
||||
setError,
|
||||
setFocus,
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm<CarFormValues>({
|
||||
resolver: yupResolver(isNew ? createCarSchema : updateCarSchema) as never,
|
||||
// The create/update schemas have structurally different required fields,
|
||||
// so yup's inferred types don't unify — cast the schema itself (not the
|
||||
// yupResolver() call) to sidestep the mismatch.
|
||||
resolver: yupResolver<CarFormValues>((isNew ? createCarSchema : updateCarSchema) as any),
|
||||
defaultValues: {
|
||||
manufacturer: editCar?.manufacturer ?? "",
|
||||
model: editCar?.model ?? "",
|
||||
@@ -169,18 +149,14 @@ export function CarFormModal({
|
||||
});
|
||||
|
||||
const [apiError, setApiError] = useState("");
|
||||
const firstRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
// register("manufacturer") already provides a ref for this input, so we
|
||||
// focus it via RHF's setFocus instead of a separate useRef — assigning
|
||||
// both `ref={firstRef}` and `{...register(...)}` on the same element
|
||||
// causes the second ref to silently overwrite the first.
|
||||
useEffect(() => {
|
||||
firstRef.current?.focus();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
const h = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape") onClose();
|
||||
};
|
||||
window.addEventListener("keydown", h);
|
||||
return () => window.removeEventListener("keydown", h);
|
||||
}, [onClose]);
|
||||
setFocus("manufacturer");
|
||||
}, [setFocus]);
|
||||
|
||||
// Numeric fields: empty string -> undefined (never NaN), matching the
|
||||
// behavior of the old parseNum() helper.
|
||||
@@ -191,11 +167,6 @@ export function CarFormModal({
|
||||
setValueAs: (v) => (v === "" || v === null ? undefined : Number(v)),
|
||||
});
|
||||
|
||||
const withError = (hasError: boolean): React.CSSProperties => ({
|
||||
...inputBase,
|
||||
...(hasError ? { borderColor: "var(--color-danger)", background: "#FEF2F2" } : {}),
|
||||
});
|
||||
|
||||
// ── Submit ────────────────────────────────────────────────────────────────
|
||||
|
||||
const submitHandler = async (data: CarFormValues) => {
|
||||
@@ -244,351 +215,173 @@ export function CarFormModal({
|
||||
// ── Render ────────────────────────────────────────────────────────────────
|
||||
|
||||
return (
|
||||
<div
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="car-modal-title"
|
||||
onClick={(e) => {
|
||||
if (e.target === e.currentTarget) onClose();
|
||||
}}
|
||||
style={{
|
||||
position: "fixed",
|
||||
inset: 0,
|
||||
zIndex: 50,
|
||||
background: "rgba(15,23,42,0.55)",
|
||||
backdropFilter: "blur(4px)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
padding: "1rem",
|
||||
overflowY: "auto",
|
||||
}}
|
||||
<Modal
|
||||
open
|
||||
title={isNew ? "مركبة جديدة" : `${editCar?.manufacturer} ${editCar?.model}`}
|
||||
subtitle={isNew ? "إضافة مركبة" : "تعديل مركبة"}
|
||||
onClose={onClose}
|
||||
size="lg"
|
||||
footer={
|
||||
<>
|
||||
<Button variant="secondary" onClick={onClose} disabled={isSubmitting}>
|
||||
إلغاء
|
||||
</Button>
|
||||
<Button type="submit" form={FORM_ID} loading={isSubmitting}>
|
||||
{isNew ? "إضافة المركبة" : "حفظ التغييرات"}
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
style={{
|
||||
width: "100%",
|
||||
maxWidth: 620,
|
||||
background: "var(--color-surface)",
|
||||
borderRadius: "var(--radius-2xl)",
|
||||
border: "1px solid var(--color-border)",
|
||||
boxShadow: "0 24px 64px rgba(0,0,0,.18)",
|
||||
overflow: "hidden",
|
||||
margin: "auto",
|
||||
}}
|
||||
<form
|
||||
id={FORM_ID}
|
||||
onSubmit={handleSubmit(submitHandler)}
|
||||
noValidate
|
||||
style={{ display: "flex", flexDirection: "column", gap: "1rem" }}
|
||||
dir="rtl"
|
||||
>
|
||||
{/* Header */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
padding: "1.25rem 1.5rem",
|
||||
borderBottom: "1px solid var(--color-border)",
|
||||
background: "var(--color-surface-muted)",
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<p
|
||||
style={{
|
||||
fontSize: 11,
|
||||
letterSpacing: "0.3em",
|
||||
textTransform: "uppercase",
|
||||
color: "#2563EB",
|
||||
fontWeight: 600,
|
||||
margin: 0,
|
||||
}}
|
||||
>
|
||||
{isNew ? "إضافة مركبة" : "تعديل مركبة"}
|
||||
</p>
|
||||
<h2
|
||||
id="car-modal-title"
|
||||
style={{
|
||||
fontSize: 17,
|
||||
fontWeight: 700,
|
||||
color: "var(--color-text-primary)",
|
||||
margin: "4px 0 0",
|
||||
}}
|
||||
>
|
||||
{isNew ? "مركبة جديدة" : `${editCar?.manufacturer} ${editCar?.model}`}
|
||||
</h2>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
aria-label="إغلاق"
|
||||
style={{
|
||||
width: 34,
|
||||
height: 34,
|
||||
borderRadius: "var(--radius-md)",
|
||||
border: "1px solid var(--color-border)",
|
||||
background: "var(--color-surface)",
|
||||
cursor: "pointer",
|
||||
fontSize: 18,
|
||||
color: "var(--color-text-muted)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
{errors.manufacturer?.type === "manual" && (
|
||||
<Alert
|
||||
type="error"
|
||||
message={errors.manufacturer.message ?? ""}
|
||||
onClose={() => setApiError("")}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* ── Section: Basic Info ── */}
|
||||
<p style={sectionHeadingStyle}>بيانات أساسية</p>
|
||||
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.75rem" }}>
|
||||
<Input
|
||||
label="الشركة المصنعة *"
|
||||
{...register("manufacturer")}
|
||||
error={
|
||||
errors.manufacturer && errors.manufacturer.type !== "manual"
|
||||
? errors.manufacturer.message
|
||||
: undefined
|
||||
}
|
||||
placeholder="تويوتا"
|
||||
dir="rtl"
|
||||
autoComplete="off"
|
||||
/>
|
||||
<Input
|
||||
label="الموديل *"
|
||||
{...register("model")}
|
||||
error={errors.model?.message}
|
||||
placeholder="لاند كروزر"
|
||||
dir="rtl"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Form */}
|
||||
<form
|
||||
onSubmit={handleSubmit(submitHandler)}
|
||||
noValidate
|
||||
style={{
|
||||
padding: "1.5rem",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "1rem",
|
||||
maxHeight: "75vh",
|
||||
overflowY: "auto",
|
||||
}}
|
||||
dir="rtl"
|
||||
>
|
||||
{errors.manufacturer?.type === "manual" && (
|
||||
<Alert
|
||||
type="error"
|
||||
message={errors.manufacturer.message ?? ""}
|
||||
onClose={() => setApiError("")}
|
||||
/>
|
||||
)}
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: "0.75rem" }}>
|
||||
<Input
|
||||
label="سنة الصنع *"
|
||||
type="number"
|
||||
min={1900}
|
||||
max={new Date().getFullYear() + 1}
|
||||
{...numberField("year")}
|
||||
error={errors.year?.message}
|
||||
dir="ltr"
|
||||
/>
|
||||
<Input label="اللون" {...register("color")} placeholder="أبيض" dir="rtl" />
|
||||
<Input label="نوع اللوحة" {...register("plateType")} placeholder="خاص" dir="rtl" />
|
||||
</div>
|
||||
|
||||
{/* ── Section: Basic Info ── */}
|
||||
<p style={sectionHeadingStyle}>بيانات أساسية</p>
|
||||
{/* ── Section: Plate ── */}
|
||||
<p style={sectionHeadingStyle}>بيانات اللوحة</p>
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.75rem" }}>
|
||||
<Input
|
||||
label="رقم اللوحة *"
|
||||
{...register("plateNumber")}
|
||||
error={errors.plateNumber?.message}
|
||||
placeholder="1234"
|
||||
dir="ltr"
|
||||
/>
|
||||
<Input
|
||||
label="حروف اللوحة *"
|
||||
{...register("plateLetters")}
|
||||
error={errors.plateLetters?.message}
|
||||
placeholder="أ ب ج"
|
||||
dir="rtl"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.75rem" }}>
|
||||
<label style={labelStyle}>
|
||||
الشركة المصنعة *
|
||||
<input
|
||||
ref={firstRef}
|
||||
style={withError(!!errors.manufacturer && errors.manufacturer.type !== "manual")}
|
||||
{...register("manufacturer")}
|
||||
placeholder="تويوتا"
|
||||
dir="rtl"
|
||||
autoComplete="off"
|
||||
/>
|
||||
{errors.manufacturer && errors.manufacturer.type !== "manual" && (
|
||||
<span style={errorTextStyle}>{errors.manufacturer.message}</span>
|
||||
)}
|
||||
</label>
|
||||
<label style={labelStyle}>
|
||||
الموديل *
|
||||
<input
|
||||
style={withError(!!errors.model)}
|
||||
{...register("model")}
|
||||
placeholder="لاند كروزر"
|
||||
dir="rtl"
|
||||
/>
|
||||
{errors.model && <span style={errorTextStyle}>{errors.model.message}</span>}
|
||||
</label>
|
||||
</div>
|
||||
{/* ── Section: Registration & Legal ── */}
|
||||
<p style={sectionHeadingStyle}>الترخيص والتأمين</p>
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.75rem" }}>
|
||||
<Input
|
||||
label="رقم الاستمارة *"
|
||||
{...register("registrationNumber")}
|
||||
error={errors.registrationNumber?.message}
|
||||
placeholder="SA-001234"
|
||||
dir="ltr"
|
||||
/>
|
||||
<Input
|
||||
label="رقم الهيكل (VIN)"
|
||||
{...register("vinNumber")}
|
||||
error={errors.vinNumber?.message}
|
||||
placeholder="1HGBH41JXMN109186"
|
||||
dir="ltr"
|
||||
/>
|
||||
<Input
|
||||
label="انتهاء الاستمارة"
|
||||
type="date"
|
||||
{...register("registrationExpiryDate")}
|
||||
/>
|
||||
<Select label="حالة التأمين" {...register("insuranceStatus")} dir="rtl">
|
||||
<option value="Valid">سارٍ</option>
|
||||
<option value="Expired">منتهي</option>
|
||||
<option value="NotInsured">غير مؤمَّن</option>
|
||||
</Select>
|
||||
<Input
|
||||
label="انتهاء التأمين"
|
||||
type="date"
|
||||
{...register("insuranceExpiryDate")}
|
||||
/>
|
||||
<Input
|
||||
label="انتهاء الفحص الدوري"
|
||||
type="date"
|
||||
{...register("inspectionExpiryDate")}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: "0.75rem" }}>
|
||||
<label style={labelStyle}>
|
||||
سنة الصنع *
|
||||
<input
|
||||
style={withError(!!errors.year)}
|
||||
type="number"
|
||||
min={1900}
|
||||
max={new Date().getFullYear() + 1}
|
||||
{...numberField("year")}
|
||||
dir="ltr"
|
||||
/>
|
||||
{errors.year && <span style={errorTextStyle}>{errors.year.message}</span>}
|
||||
</label>
|
||||
<label style={labelStyle}>
|
||||
اللون
|
||||
<input style={inputBase} {...register("color")} placeholder="أبيض" dir="rtl" />
|
||||
</label>
|
||||
<label style={labelStyle}>
|
||||
نوع اللوحة
|
||||
<input style={inputBase} {...register("plateType")} placeholder="خاص" dir="rtl" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* ── Section: Plate ── */}
|
||||
<p style={sectionHeadingStyle}>بيانات اللوحة</p>
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.75rem" }}>
|
||||
<label style={labelStyle}>
|
||||
رقم اللوحة *
|
||||
<input
|
||||
style={withError(!!errors.plateNumber)}
|
||||
{...register("plateNumber")}
|
||||
placeholder="1234"
|
||||
dir="ltr"
|
||||
/>
|
||||
{errors.plateNumber && (
|
||||
<span style={errorTextStyle}>{errors.plateNumber.message}</span>
|
||||
)}
|
||||
</label>
|
||||
<label style={labelStyle}>
|
||||
حروف اللوحة *
|
||||
<input
|
||||
style={withError(!!errors.plateLetters)}
|
||||
{...register("plateLetters")}
|
||||
placeholder="أ ب ج"
|
||||
dir="rtl"
|
||||
/>
|
||||
{errors.plateLetters && (
|
||||
<span style={errorTextStyle}>{errors.plateLetters.message}</span>
|
||||
)}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* ── Section: Registration & Legal ── */}
|
||||
<p style={sectionHeadingStyle}>الترخيص والتأمين</p>
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.75rem" }}>
|
||||
<label style={labelStyle}>
|
||||
رقم الاستمارة *
|
||||
<input
|
||||
style={withError(!!errors.registrationNumber)}
|
||||
{...register("registrationNumber")}
|
||||
placeholder="SA-001234"
|
||||
dir="ltr"
|
||||
/>
|
||||
{errors.registrationNumber && (
|
||||
<span style={errorTextStyle}>{errors.registrationNumber.message}</span>
|
||||
)}
|
||||
</label>
|
||||
<label style={labelStyle}>
|
||||
رقم الهيكل (VIN)
|
||||
<input
|
||||
style={withError(!!errors.vinNumber)}
|
||||
{...register("vinNumber")}
|
||||
placeholder="1HGBH41JXMN109186"
|
||||
dir="ltr"
|
||||
/>
|
||||
{errors.vinNumber && (
|
||||
<span style={errorTextStyle}>{errors.vinNumber.message}</span>
|
||||
)}
|
||||
</label>
|
||||
<label style={labelStyle}>
|
||||
انتهاء الاستمارة
|
||||
<input style={inputBase} type="date" {...register("registrationExpiryDate")} />
|
||||
</label>
|
||||
<label style={labelStyle}>
|
||||
حالة التأمين
|
||||
<select style={{ ...inputBase, cursor: "pointer" }} {...register("insuranceStatus")} dir="rtl">
|
||||
<option value="Valid">سارٍ</option>
|
||||
<option value="Expired">منتهي</option>
|
||||
<option value="NotInsured">غير مؤمَّن</option>
|
||||
</select>
|
||||
</label>
|
||||
<label style={labelStyle}>
|
||||
انتهاء التأمين
|
||||
<input style={inputBase} type="date" {...register("insuranceExpiryDate")} />
|
||||
</label>
|
||||
<label style={labelStyle}>
|
||||
انتهاء الفحص الدوري
|
||||
<input style={inputBase} type="date" {...register("inspectionExpiryDate")} />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* ── Section: Operational ── */}
|
||||
<p style={sectionHeadingStyle}>بيانات تشغيلية</p>
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: "0.75rem" }}>
|
||||
<label style={labelStyle}>
|
||||
الفرع
|
||||
<select style={{ ...inputBase, cursor: "pointer" }} {...register("branchId")} dir="rtl">
|
||||
<option value="">اختر الفرع</option>
|
||||
{branches.map((b) => (
|
||||
<option key={b.id} value={b.id}>
|
||||
{b.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<label style={labelStyle}>
|
||||
الحالة
|
||||
<select style={{ ...inputBase, cursor: "pointer" }} {...register("currentStatus")} dir="rtl">
|
||||
<option value="Active">نشط</option>
|
||||
<option value="InMaintenance">صيانة</option>
|
||||
<option value="InTrip">في رحلة</option>
|
||||
<option value="Inactive">غير نشط</option>
|
||||
</select>
|
||||
</label>
|
||||
<label style={labelStyle}>
|
||||
رقم GPS
|
||||
<input style={inputBase} {...register("gpsDeviceId")} placeholder="GPS-001" dir="ltr" />
|
||||
</label>
|
||||
<label style={labelStyle}>
|
||||
الطاقة الاستيعابية
|
||||
<input
|
||||
style={withError(!!errors.capacity)}
|
||||
type="number"
|
||||
min={0}
|
||||
{...numberField("capacity")}
|
||||
placeholder="0"
|
||||
dir="ltr"
|
||||
/>
|
||||
{errors.capacity && (
|
||||
<span style={errorTextStyle}>{errors.capacity.message}</span>
|
||||
)}
|
||||
</label>
|
||||
<label style={labelStyle}>
|
||||
الوزن (كجم)
|
||||
<input
|
||||
style={withError(!!errors.weight)}
|
||||
type="number"
|
||||
min={0}
|
||||
{...numberField("weight")}
|
||||
placeholder="0"
|
||||
dir="ltr"
|
||||
/>
|
||||
{errors.weight && <span style={errorTextStyle}>{errors.weight.message}</span>}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* ── Actions ── */}
|
||||
<div style={{ display: "flex", gap: "0.5rem", justifyContent: "flex-end", paddingTop: "0.5rem" }}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
disabled={isSubmitting}
|
||||
style={{
|
||||
height: 40,
|
||||
padding: "0 1.25rem",
|
||||
borderRadius: "var(--radius-md)",
|
||||
border: "1px solid var(--color-border)",
|
||||
background: "var(--color-surface)",
|
||||
fontSize: 13,
|
||||
fontWeight: 600,
|
||||
color: "var(--color-text-secondary)",
|
||||
cursor: isSubmitting ? "not-allowed" : "pointer",
|
||||
fontFamily: "var(--font-sans)",
|
||||
}}
|
||||
>
|
||||
إلغاء
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
style={{
|
||||
height: 40,
|
||||
padding: "0 1.5rem",
|
||||
borderRadius: "var(--radius-md)",
|
||||
border: "none",
|
||||
background: isSubmitting ? "var(--color-brand-400)" : "var(--color-brand-600)",
|
||||
fontSize: 13,
|
||||
fontWeight: 700,
|
||||
color: "#FFF",
|
||||
cursor: isSubmitting ? "not-allowed" : "pointer",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
fontFamily: "var(--font-sans)",
|
||||
}}
|
||||
>
|
||||
{isSubmitting && <Spinner size="sm" className="text-white" />}
|
||||
{isSubmitting ? "جارٍ الحفظ…" : isNew ? "إضافة المركبة" : "حفظ التغييرات"}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{/* ── Section: Operational ── */}
|
||||
<p style={sectionHeadingStyle}>بيانات تشغيلية</p>
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: "0.75rem" }}>
|
||||
<Select label="الفرع" {...register("branchId")} dir="rtl">
|
||||
<option value="">اختر الفرع</option>
|
||||
{branches.map((b) => (
|
||||
<option key={b.id} value={b.id}>
|
||||
{b.name}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
<Select label="الحالة" {...register("currentStatus")} dir="rtl">
|
||||
<option value="Active">نشط</option>
|
||||
<option value="InMaintenance">صيانة</option>
|
||||
<option value="InTrip">في رحلة</option>
|
||||
<option value="Inactive">غير نشط</option>
|
||||
</Select>
|
||||
<Input label="رقم GPS" {...register("gpsDeviceId")} placeholder="GPS-001" dir="ltr" />
|
||||
<Input
|
||||
label="الطاقة الاستيعابية"
|
||||
type="number"
|
||||
min={0}
|
||||
{...numberField("capacity")}
|
||||
error={errors.capacity?.message}
|
||||
placeholder="0"
|
||||
dir="ltr"
|
||||
/>
|
||||
<Input
|
||||
label="الوزن (كجم)"
|
||||
type="number"
|
||||
min={0}
|
||||
{...numberField("weight")}
|
||||
error={errors.weight?.message}
|
||||
placeholder="0"
|
||||
dir="ltr"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user