feat: enhance import/export functionality with detailed results dialog and improved data handling

This commit is contained in:
2026-05-15 11:34:23 +04:00
parent fcbba6247d
commit 54d11f01b4
18 changed files with 312 additions and 59 deletions
@@ -52,6 +52,27 @@ function buildVehicleOption(item: any): VehicleOption {
}
}
function VehicleThumb({ src }: { src?: string }) {
const [broken, setBroken] = useState(false)
if (!src || broken) {
return (
<div className="flex size-9 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground border border-border">
<Car className="size-4" />
</div>
)
}
return (
<Image
height={60}
width={60}
src={src}
alt=""
onError={() => setBroken(true)}
className="size-9 shrink-0 rounded-md object-cover border border-border"
/>
)
}
function extractItems(response: unknown): any[] {
if (Array.isArray(response)) return response
const obj = response as any
@@ -168,20 +189,7 @@ export function RhfVehicleSelectField<
filtered.map((opt) => (
<ComboboxItem key={opt.value} value={opt}>
<div className="flex items-center gap-3 py-0.5 w-full min-w-0">
{/* Thumbnail */}
{opt.image_url ? (
<Image
height={60}
width={60}
src={opt.image_url}
alt=""
className="size-9 shrink-0 rounded-md object-cover border border-border"
/>
) : (
<div className="flex size-9 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground border border-border">
<Car className="size-4" />
</div>
)}
<VehicleThumb src={opt.image_url} />
{/* Identity */}
<div className="flex min-w-0 flex-1 flex-col gap-0.5">
@@ -69,6 +69,9 @@ const mapLookupOption = (item: any) => ({
const STORE_OBJECT = { getOptionValue: (o: any) => o, getOptionLabel: (o: any) => o.label }
const toFormString = (value: unknown): string =>
value == null ? "" : String(value)
function mapToFormValues(data: unknown): VehicleFormValues {
const d = (data as any)?.data ?? data ?? {}
@@ -79,16 +82,16 @@ function mapToFormValues(data: unknown): VehicleFormValues {
vehicle_transmission_id: toRelation(d.vehicle_transmission_id, d.vehicle_transmission?.title),
vehicle_color_id: toRelation(d.vehicle_color_id, d.vehicle_color?.title),
customer_id: toRelation(d.customer_id, d.customer?.name),
make: d.make || "",
model: d.model || "",
year: d.year || "",
sub_model: d.sub_model || "",
license_plate: d.license_plate || "",
vin_number: d.vin_number || "",
engine_size: d.engine_size || "",
drivetrain: d.drivetrain || "",
mileage: d.mileage || "",
note: d.note || "",
make: toFormString(d.make),
model: toFormString(d.model),
year: toFormString(d.year),
sub_model: toFormString(d.sub_model),
license_plate: toFormString(d.license_plate),
vin_number: toFormString(d.vin_number),
engine_size: toFormString(d.engine_size),
drivetrain: toFormString(d.drivetrain),
mileage: toFormString(d.mileage),
note: toFormString(d.note),
image: null,
}
}
@@ -121,7 +124,7 @@ function mapToPayload(values: VehicleFormValues) {
export function VehicleForm({ resourceId, initialData, onSuccess }: VehicleFormProps) {
const api = useAuthApi()
const { form, isEditing } = useResourceForm<VehicleFormValues, any>({
const { form, isEditing, data: resolvedData } = useResourceForm<VehicleFormValues, any>({
schema: vehicleFormSchema,
defaultValues: DEFAULT_VALUES,
resourceId,
@@ -131,6 +134,9 @@ export function VehicleForm({ resourceId, initialData, onSuccess }: VehicleFormP
mapToFormValues,
})
const existingImageUrl: string | null =
(resolvedData as any)?.data?.image_url ?? (resolvedData as any)?.image_url ?? null
const { mutate, error, isPending } = useFormMutation(form, {
mutationFn: (values: VehicleFormValues) => {
const payload = mapToPayload(values)
@@ -260,7 +266,11 @@ export function VehicleForm({ resourceId, initialData, onSuccess }: VehicleFormP
<RhfTextField name="mileage" label="Mileage" placeholder="e.g. 10000" />
</div>
<RhfImageField name="image" label="Image" />
<RhfImageField
name="image"
label="Image"
initialPreviewUrl={existingImageUrl}
/>
<RhfTextareaField name="note" label="Notes" rows={3} />