"use client" import { useRef, useState } from "react" import { useFormContext, useController, type FieldValues, type FieldPath } from "react-hook-form" import { useQuery } from "@tanstack/react-query" import { Building2, Loader2 } from "lucide-react" import { useAuthApi } from "@/shared/useApi" import { CUSTOMER_ROUTES } from "@garage/api" import { FieldShell } from "@/shared/components/form/field-shell" import { Combobox, ComboboxInput, ComboboxContent, ComboboxList, ComboboxItem, ComboboxEmpty, } from "@/shared/components/ui/combobox" // ── Customer option type (enriched for display) ── type CustomerOption = { value: string label: string first_name?: string last_name?: string company_name?: string email?: string phone?: string } function buildCustomerOption(item: any): CustomerOption { const name = [item.first_name, item.last_name].filter(Boolean).join(" ") const label = name || item.company_name || `Customer #${item.id}` return { value: String(item.id), label, first_name: item.first_name, last_name: item.last_name, company_name: item.company_name, email: item.email, phone: item.phone, } } 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 [] } function getInitials(opt: CustomerOption): string { if (opt.first_name || opt.last_name) { return [opt.first_name?.[0], opt.last_name?.[0]].filter(Boolean).join("").toUpperCase() } if (opt.company_name) return opt.company_name[0].toUpperCase() return "?" } // ── Props ── export type RhfCustomerSelectFieldProps< TValues extends FieldValues, TName extends FieldPath, > = { name: TName label?: string description?: string required?: boolean disabled?: boolean placeholder?: string } // ── Component ── export function RhfCustomerSelectField< TValues extends FieldValues, TName extends FieldPath, >({ name, label = "Customer", description, required, disabled, placeholder = "Search by name, company, or phone...", }: RhfCustomerSelectFieldProps) { const api = useAuthApi() const anchorRef = useRef(null) const [inputValue, setInputValue] = useState("") const { control } = useFormContext() const { field, fieldState: { error }, } = useController({ name, control, disabled }) const { data: options = [], isLoading } = useQuery({ queryKey: [CUSTOMER_ROUTES.INDEX, "customer-select"], queryFn: async () => { const res = await api.customers.list() return extractItems(res).map(buildCustomerOption) }, staleTime: 5 * 60 * 1000, }) const filtered = inputValue ? options.filter((c) => [c.first_name, c.last_name, c.company_name, c.email, c.phone] .filter(Boolean) .join(" ") .toLowerCase() .includes(inputValue.toLowerCase()), ) : options return (
{ const single = Array.isArray(val) ? val[0] ?? null : val 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) }} isItemEqualToValue={(item: CustomerOption, val: any) => item?.value === val?.value } > {isLoading && (
)} {!isLoading && filtered.map((opt) => (
{/* Avatar circle with initials */}
{getInitials(opt)}
{/* Identity */}
{opt.label}
{opt.company_name && opt.label !== opt.company_name && ( {opt.company_name} )} {opt.phone && ( {opt.phone} )}
))} {!isLoading && filtered.length === 0 && ( No customers found )}
) }