@@ -72,6 +72,7 @@ function VehicleCombobox({
|
||||
</FieldLabel>
|
||||
<div ref={anchorRef}>
|
||||
<Combobox
|
||||
|
||||
value={inputText || null}
|
||||
onValueChange={(val) => {
|
||||
const str = val !== null ? String(val) : ""
|
||||
@@ -91,29 +92,20 @@ function VehicleCombobox({
|
||||
showClear={!!inputText}
|
||||
onBlur={onBlur}
|
||||
aria-invalid={!!error || undefined}
|
||||
|
||||
/>
|
||||
<ComboboxContent anchor={anchorRef}>
|
||||
<ComboboxList>
|
||||
{loading && (
|
||||
<div className="flex items-center justify-center py-4">
|
||||
<Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
|
||||
</div>
|
||||
)}
|
||||
{!loading &&
|
||||
filtered.map((opt) => (
|
||||
<ComboboxItem key={opt} value={opt}>
|
||||
{opt}
|
||||
</ComboboxItem>
|
||||
))}
|
||||
{!loading && filtered.length === 0 && (
|
||||
<ComboboxEmpty>
|
||||
{inputText
|
||||
? `No suggestions for "${inputText}"`
|
||||
: "Start typing to see suggestions"}
|
||||
</ComboboxEmpty>
|
||||
)}
|
||||
</ComboboxList>
|
||||
</ComboboxContent>
|
||||
{(loading || filtered.length > 0) && (
|
||||
<ComboboxContent anchor={anchorRef}>
|
||||
<ComboboxList>
|
||||
{!loading &&
|
||||
filtered.map((opt) => (
|
||||
<ComboboxItem key={opt} value={opt}>
|
||||
{opt}
|
||||
</ComboboxItem>
|
||||
))}
|
||||
</ComboboxList>
|
||||
</ComboboxContent>
|
||||
)}
|
||||
</Combobox>
|
||||
</div>
|
||||
{error && <FieldError>{error}</FieldError>}
|
||||
@@ -145,6 +137,8 @@ export function RhfVehicleIdentityField() {
|
||||
const modelCtrl = useController({ name: "model", control })
|
||||
const yearCtrl = useController({ name: "year", control })
|
||||
const subModelCtrl = useController({ name: "sub_model", control })
|
||||
const engineSizeCtrl = useController({ name: "engine_size", control })
|
||||
const drivetrainCtrl = useController({ name: "drivetrain", control })
|
||||
|
||||
const makeValue = makeCtrl.field.value ?? ""
|
||||
const modelValue = modelCtrl.field.value ?? ""
|
||||
@@ -160,6 +154,8 @@ export function RhfVehicleIdentityField() {
|
||||
model?: string
|
||||
year?: string
|
||||
sub_model?: string
|
||||
engine_size?: string
|
||||
drivetrain?: string
|
||||
}
|
||||
|
||||
function extractRecords(response: unknown): MakeAndModelRecord[] {
|
||||
@@ -205,10 +201,34 @@ export function RhfVehicleIdentityField() {
|
||||
.map((r) => r.sub_model),
|
||||
)
|
||||
|
||||
const engineSizes = unique(
|
||||
allRecords
|
||||
.filter(
|
||||
(r) =>
|
||||
(!makeValue || r.make === makeValue) &&
|
||||
(!modelValue || r.model === modelValue) &&
|
||||
(!yearValue || r.year === yearValue),
|
||||
)
|
||||
.map((r) => r.engine_size),
|
||||
)
|
||||
|
||||
const drivetrains = unique(
|
||||
allRecords
|
||||
.filter(
|
||||
(r) =>
|
||||
(!makeValue || r.make === makeValue) &&
|
||||
(!modelValue || r.model === modelValue) &&
|
||||
(!yearValue || r.year === yearValue),
|
||||
)
|
||||
.map((r) => r.drivetrain),
|
||||
)
|
||||
|
||||
const makesLoading = recordsLoading
|
||||
const modelsLoading = false
|
||||
const yearsLoading = false
|
||||
const subModelsLoading = false
|
||||
const engineSizesLoading = false
|
||||
const drivetrainsLoading = false
|
||||
|
||||
// ── Cascading onChange handlers ──
|
||||
|
||||
@@ -218,17 +238,23 @@ export function RhfVehicleIdentityField() {
|
||||
setValue("model", "")
|
||||
setValue("year", "")
|
||||
setValue("sub_model", "")
|
||||
setValue("engine_size", "")
|
||||
setValue("drivetrain", "")
|
||||
}
|
||||
|
||||
function handleModelChange(val: string) {
|
||||
modelCtrl.field.onChange(val)
|
||||
setValue("year", "")
|
||||
setValue("sub_model", "")
|
||||
setValue("engine_size", "")
|
||||
setValue("drivetrain", "")
|
||||
}
|
||||
|
||||
function handleYearChange(val: string) {
|
||||
yearCtrl.field.onChange(val)
|
||||
setValue("sub_model", "")
|
||||
setValue("engine_size", "")
|
||||
setValue("drivetrain", "")
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -269,6 +295,8 @@ export function RhfVehicleIdentityField() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
||||
<VehicleCombobox
|
||||
label="Sub Model"
|
||||
placeholder="e.g. LE"
|
||||
@@ -279,6 +307,27 @@ export function RhfVehicleIdentityField() {
|
||||
loading={subModelsLoading}
|
||||
error={subModelCtrl.fieldState.error?.message}
|
||||
/>
|
||||
<VehicleCombobox
|
||||
label="Engine Size"
|
||||
placeholder="e.g. 2.5L"
|
||||
value={engineSizeCtrl.field.value ?? ""}
|
||||
onChange={(val) => engineSizeCtrl.field.onChange(val)}
|
||||
onBlur={engineSizeCtrl.field.onBlur}
|
||||
options={engineSizes}
|
||||
loading={engineSizesLoading}
|
||||
error={engineSizeCtrl.fieldState.error?.message}
|
||||
/>
|
||||
<VehicleCombobox
|
||||
label="Drivetrain"
|
||||
placeholder="e.g. FWD"
|
||||
value={drivetrainCtrl.field.value ?? ""}
|
||||
onChange={(val) => drivetrainCtrl.field.onChange(val)}
|
||||
onBlur={drivetrainCtrl.field.onBlur}
|
||||
options={drivetrains}
|
||||
loading={drivetrainsLoading}
|
||||
error={drivetrainCtrl.fieldState.error?.message}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ const DEFAULT_VALUES: VehicleFormValues = {
|
||||
engine_size: "",
|
||||
drivetrain: "",
|
||||
mileage: "",
|
||||
owners_number: "",
|
||||
note: "",
|
||||
image: null,
|
||||
}
|
||||
@@ -84,7 +83,6 @@ function mapToFormValues(data: unknown): VehicleFormValues {
|
||||
engine_size: d.engine_size || "",
|
||||
drivetrain: d.drivetrain || "",
|
||||
mileage: d.mileage || "",
|
||||
owners_number: d.owners_number || "",
|
||||
note: d.note || "",
|
||||
image: null,
|
||||
}
|
||||
@@ -106,7 +104,6 @@ function mapToPayload(values: VehicleFormValues) {
|
||||
engine_size: values.engine_size || undefined,
|
||||
drivetrain: values.drivetrain || undefined,
|
||||
mileage: values.mileage || undefined,
|
||||
owners_number: values.owners_number || undefined,
|
||||
note: values.note || undefined,
|
||||
image: values.image instanceof File ? values.image : undefined,
|
||||
}
|
||||
@@ -226,14 +223,7 @@ export function VehicleForm({ resourceId, initialData, onSuccess }: VehicleFormP
|
||||
<RhfTextField name="vin_number" label="VIN Number" placeholder="e.g. 1HGBH41JXMN109186" />
|
||||
</div>
|
||||
|
||||
{/* Technical specs */}
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
<RhfTextField name="engine_size" label="Engine Size" placeholder="e.g. 2.5L" />
|
||||
<RhfTextField name="drivetrain" label="Drivetrain" placeholder="e.g. FWD" />
|
||||
</div>
|
||||
|
||||
<RhfTextField name="owners_number" label="Number of Owners" placeholder="e.g. 1" />
|
||||
|
||||
{/* License & identifiers */}
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
<RhfTextField name="license_plate" label="License Plate" placeholder="e.g. ABC-123" />
|
||||
<RhfTextField name="mileage" label="Mileage" placeholder="e.g. 10000" />
|
||||
|
||||
Reference in New Issue
Block a user