"use client" import { useRef, useState } from "react" import { useFormContext, useController, type FieldValues, type FieldPath } from "react-hook-form" import { useQuery, useQueryClient } from "@tanstack/react-query" import { Car, Loader2, PlusIcon } from "lucide-react" import { useAuthApi } from "@/shared/useApi" import { VEHICLE_ROUTES } from "@garage/api" import { Field, FieldLabel, FieldError, FieldDescription } from "@/shared/components/ui/field" import { Button } from "@/shared/components/ui/button" import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/shared/components/ui/dialog" import { ScrollArea } from "@/shared/components/ui/scroll-area" import { Combobox, ComboboxInput, ComboboxContent, ComboboxList, ComboboxItem, ComboboxEmpty, } from "@/shared/components/ui/combobox" import Image from "next/image" import { VehicleForm } from "./vehicle-form" // ── Vehicle option type (enriched for display) ── type VehicleOption = { value: string label: string make?: string model?: string year?: string sub_model?: string license_plate?: string image_url?: string mileage?: string } function buildVehicleOption(item: any): VehicleOption { const label = [item.year, item.make, item.model].filter(Boolean).join(" ") || `Vehicle #${item.id}` return { value: String(item.id), label, make: item.make, model: item.model, year: item.year, sub_model: item.sub_model, license_plate: item.license_plate, image_url: item.image_url, mileage: item.mileage, } } function extractItems(response: unknown): any[] { if (Array.isArray(response)) return response const obj = response as any if (Array.isArray(obj?.data?.data)) return obj.data.data if (Array.isArray(obj?.data)) return obj.data return [] } // ── Props ── export type RhfVehicleSelectFieldProps< TValues extends FieldValues, TName extends FieldPath, > = { name: TName label?: string description?: string required?: boolean disabled?: boolean placeholder?: string } // ── Component ── export function RhfVehicleSelectField< TValues extends FieldValues, TName extends FieldPath, >({ name, label = "Vehicle", description, required, disabled, placeholder = "Search by make, model, year, or plate...", }: RhfVehicleSelectFieldProps) { const api = useAuthApi() const anchorRef = useRef(null) const [inputValue, setInputValue] = useState("") const [isCreateOpen, setIsCreateOpen] = useState(false) const queryClient = useQueryClient() const { control } = useFormContext() const { field, fieldState: { error }, } = useController({ name, control, disabled }) const { data: options = [], isLoading } = useQuery({ queryKey: [VEHICLE_ROUTES.INDEX, "vehicle-select"], queryFn: async () => { const res = await api.vehicles.list() return extractItems(res).map(buildVehicleOption) }, staleTime: 5 * 60 * 1000, }) const filtered = inputValue ? options.filter((v) => [v.year, v.make, v.model, v.sub_model, v.license_plate] .filter(Boolean) .join(" ") .toLowerCase() .includes(inputValue.toLowerCase()), ) : options const handleCreateSuccess = (data?: any) => { const item = data?.data ?? data if (item?.id) { field.onChange(buildVehicleOption(item)) } queryClient.invalidateQueries({ queryKey: [VEHICLE_ROUTES.INDEX, "vehicle-select"] }) setIsCreateOpen(false) } const combobox = (
{ const single = Array.isArray(val) ? val[0] ?? null : val // Store only { value, label } to stay compatible with relationFieldSchema field.onChange( single ? { value: single.value, label: single.label } : null, ) }} disabled={field.disabled} onInputValueChange={(val: string, { reason }: { reason: string }) => { if (reason === "input-change") setInputValue(val) }} // Compare by id string so the selected item highlights correctly // even when the stored form value has fewer fields than VehicleOption isItemEqualToValue={(item: VehicleOption, val: any) => item?.value === val?.value } > {isLoading && (
)} {!isLoading && filtered.map((opt) => (
{/* Thumbnail */} {opt.image_url ? ( ) : (
)} {/* Identity */}
{[opt.year, opt.make, opt.model] .filter(Boolean) .join(" ")} {opt.sub_model && ( {opt.sub_model} )} {opt.license_plate && ( {opt.license_plate} )}
))} {!isLoading && filtered.length === 0 && ( No vehicles found )}
) return ( {label && (
{label} {required && *}
)} {combobox} {description && {description}} {error?.message && {error.message}} { if (!v) setIsCreateOpen(false) }}> Add {label}
) }