fixes
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
parent
cdd1cbc31a
commit
1fda8d8d7b
@ -3,11 +3,13 @@
|
|||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { ResourcePage } from '@/shared/data-view/resource-page'
|
import { ResourcePage } from '@/shared/data-view/resource-page'
|
||||||
import { ColumnHeader } from '@/shared/data-view/table-view'
|
import { ColumnHeader } from '@/shared/data-view/table-view'
|
||||||
|
import type { ColumnDef } from '@tanstack/react-table'
|
||||||
import FormDialog from '@/shared/components/form-dialog'
|
import FormDialog from '@/shared/components/form-dialog'
|
||||||
import { ImportDataButton } from '@/shared/components/import-data-button'
|
import { ImportDataButton } from '@/shared/components/import-data-button'
|
||||||
import { ExportDataButton } from '@/shared/components/export-data-button'
|
import { ExportDataButton } from '@/shared/components/export-data-button'
|
||||||
import { DownloadSampleButton } from '@/shared/components/download-sample-button'
|
import { DownloadSampleButton } from '@/shared/components/download-sample-button'
|
||||||
import { useAuthApi } from '@/shared/useApi'
|
import { useAuthApi } from '@/shared/useApi'
|
||||||
|
import type { CrudResourceColumnHelpers, ResourceItem } from '@/shared/data-view/resource-page'
|
||||||
import { VehicleForm } from '@/modules/vehicles/vehicle-form'
|
import { VehicleForm } from '@/modules/vehicles/vehicle-form'
|
||||||
import { VEHICLE_ROUTES } from '@garage/api'
|
import { VEHICLE_ROUTES } from '@garage/api'
|
||||||
import type { VehiclesClient } from '@garage/api'
|
import type { VehiclesClient } from '@garage/api'
|
||||||
@ -49,9 +51,11 @@ export default function VehiclesPage() {
|
|||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
})}
|
})}
|
||||||
columns={({ actionsColumn }) => [
|
|
||||||
|
columns={({ actionsColumn })=> [
|
||||||
{
|
{
|
||||||
accessorKey: "name",
|
id: "name",
|
||||||
|
|
||||||
header: ({ column }) => <ColumnHeader column={column} title="Vehicle" />,
|
header: ({ column }) => <ColumnHeader column={column} title="Vehicle" />,
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const r = row.original as any
|
const r = row.original as any
|
||||||
@ -117,6 +121,14 @@ export default function VehiclesPage() {
|
|||||||
return val ? new Date(val).toLocaleDateString() : "—"
|
return val ? new Date(val).toLocaleDateString() : "—"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "customer",
|
||||||
|
header: ({ column }) => <ColumnHeader column={column} title="Customer" />,
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const val = (row.original as any).customer
|
||||||
|
return val ? val.name : "—"
|
||||||
|
},
|
||||||
|
},
|
||||||
actionsColumn(),
|
actionsColumn(),
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -252,7 +252,7 @@ export function JobCardForm({ resourceId, initialData, onSuccess }: JobCardFormP
|
|||||||
|
|
||||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||||
<RhfCustomerSelectField name="customer" />
|
<RhfCustomerSelectField name="customer" />
|
||||||
<RhfVehicleSelectField name="vehicle" customer_id={customer?.value} />
|
<RhfVehicleSelectField name="vehicle" disabled={!customer?.value} customer_id={customer?.value} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<RhfCheckboxField name="has_insurance" label="Has Insurance Work?" />
|
<RhfCheckboxField name="has_insurance" label="Has Insurance Work?" />
|
||||||
|
|||||||
@ -18,8 +18,14 @@ import type { VehicleFormValues } from "./vehicle.schema"
|
|||||||
|
|
||||||
// ── Helpers ──
|
// ── Helpers ──
|
||||||
|
|
||||||
function unique(values: (string | undefined)[]): string[] {
|
function toOptionalString(value: unknown): string | undefined {
|
||||||
return [...new Set(values.filter((v): v is string => !!v))].sort()
|
if (typeof value === "string") return value || undefined
|
||||||
|
if (typeof value === "number") return String(value)
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
function unique(values: unknown[]): string[] {
|
||||||
|
return [...new Set(values.map(toOptionalString).filter((v): v is string => !!v))].sort()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Internal combobox for a single free-text + suggestion field ──
|
// ── Internal combobox for a single free-text + suggestion field ──
|
||||||
@ -60,8 +66,9 @@ function VehicleCombobox({
|
|||||||
}, [value])
|
}, [value])
|
||||||
|
|
||||||
// Client-side filtering of suggestions based on what's been typed
|
// Client-side filtering of suggestions based on what's been typed
|
||||||
|
const normalizedInput = inputText.toLowerCase()
|
||||||
const filtered = options.filter((opt) =>
|
const filtered = options.filter((opt) =>
|
||||||
!inputText || opt.toLowerCase().includes(inputText.toLowerCase()),
|
!normalizedInput || opt.toLowerCase().includes(normalizedInput),
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -130,7 +137,7 @@ export function RhfVehicleIdentityField() {
|
|||||||
const { control, setValue } = useFormContext<VehicleFormValues>()
|
const { control, setValue } = useFormContext<VehicleFormValues>()
|
||||||
|
|
||||||
// Read shop_type to pass as shop_type_id filter to the API
|
// Read shop_type to pass as shop_type_id filter to the API
|
||||||
const shopType = useWatch({ control, name: "shop_type" })
|
const shopType = useWatch({ control, name: "shop_type_id" })
|
||||||
const shopTypeId = shopType?.value
|
const shopTypeId = shopType?.value
|
||||||
|
|
||||||
const makeCtrl = useController({ name: "make", control })
|
const makeCtrl = useController({ name: "make", control })
|
||||||
@ -158,11 +165,26 @@ export function RhfVehicleIdentityField() {
|
|||||||
drivetrain?: string
|
drivetrain?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeRecord(record: unknown): MakeAndModelRecord {
|
||||||
|
const value = record as Record<string, unknown>
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: typeof value.id === "number" ? value.id : undefined,
|
||||||
|
shop_type_id: typeof value.shop_type_id === "number" ? value.shop_type_id : undefined,
|
||||||
|
make: toOptionalString(value.make),
|
||||||
|
model: toOptionalString(value.model),
|
||||||
|
year: toOptionalString(value.year),
|
||||||
|
sub_model: toOptionalString(value.sub_model),
|
||||||
|
engine_size: toOptionalString(value.engine_size),
|
||||||
|
drivetrain: toOptionalString(value.drivetrain),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function extractRecords(response: unknown): MakeAndModelRecord[] {
|
function extractRecords(response: unknown): MakeAndModelRecord[] {
|
||||||
const obj = response as any
|
const obj = response as any
|
||||||
if (Array.isArray(obj?.data)) return obj.data
|
if (Array.isArray(obj?.data)) return obj.data.map(normalizeRecord)
|
||||||
if (Array.isArray(obj?.data?.data)) return obj.data.data
|
if (Array.isArray(obj?.data?.data)) return obj.data.data.map(normalizeRecord)
|
||||||
if (Array.isArray(obj)) return obj
|
if (Array.isArray(obj)) return obj.map(normalizeRecord)
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,8 @@ import { toRelation, toId } from "@/shared/lib/utils"
|
|||||||
import { formatUppercase } from "@/shared/utils/formatters"
|
import { formatUppercase } from "@/shared/utils/formatters"
|
||||||
|
|
||||||
import { vehicleFormSchema, type VehicleFormValues } from "./vehicle.schema"
|
import { vehicleFormSchema, type VehicleFormValues } from "./vehicle.schema"
|
||||||
|
import { CustomerForm } from "../customers/customer-form"
|
||||||
|
import { getFullName } from "@/shared/utils/getFullName"
|
||||||
|
|
||||||
// ── Props ──
|
// ── Props ──
|
||||||
|
|
||||||
@ -43,6 +45,7 @@ const DEFAULT_VALUES: VehicleFormValues = {
|
|||||||
vehicle_fuel_type_id: null,
|
vehicle_fuel_type_id: null,
|
||||||
vehicle_transmission_id: null,
|
vehicle_transmission_id: null,
|
||||||
vehicle_color_id: null,
|
vehicle_color_id: null,
|
||||||
|
customer_id: null,
|
||||||
make: "",
|
make: "",
|
||||||
model: "",
|
model: "",
|
||||||
year: "",
|
year: "",
|
||||||
@ -74,6 +77,7 @@ function mapToFormValues(data: unknown): VehicleFormValues {
|
|||||||
vehicle_fuel_type_id: toRelation(d.vehicle_fuel_type_id, d.vehicle_fuel_type?.title),
|
vehicle_fuel_type_id: toRelation(d.vehicle_fuel_type_id, d.vehicle_fuel_type?.title),
|
||||||
vehicle_transmission_id: toRelation(d.vehicle_transmission_id, d.vehicle_transmission?.title),
|
vehicle_transmission_id: toRelation(d.vehicle_transmission_id, d.vehicle_transmission?.title),
|
||||||
vehicle_color_id: toRelation(d.vehicle_color_id, d.vehicle_color?.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 || "",
|
make: d.make || "",
|
||||||
model: d.model || "",
|
model: d.model || "",
|
||||||
year: d.year || "",
|
year: d.year || "",
|
||||||
@ -95,6 +99,8 @@ function mapToPayload(values: VehicleFormValues) {
|
|||||||
vehicle_fuel_type_id: toId(values.vehicle_fuel_type_id),
|
vehicle_fuel_type_id: toId(values.vehicle_fuel_type_id),
|
||||||
vehicle_transmission_id: toId(values.vehicle_transmission_id),
|
vehicle_transmission_id: toId(values.vehicle_transmission_id),
|
||||||
vehicle_color_id: toId(values.vehicle_color_id),
|
vehicle_color_id: toId(values.vehicle_color_id),
|
||||||
|
|
||||||
|
customer_id: toId(values.customer_id),
|
||||||
make: values.make,
|
make: values.make,
|
||||||
model: values.model,
|
model: values.model,
|
||||||
year: values.year,
|
year: values.year,
|
||||||
@ -222,6 +228,20 @@ export function VehicleForm({ resourceId, initialData, onSuccess }: VehicleFormP
|
|||||||
/>
|
/>
|
||||||
<RhfTextField name="vin_number" label="VIN Number" placeholder="e.g. 1HGBH41JXMN109186" />
|
<RhfTextField name="vin_number" label="VIN Number" placeholder="e.g. 1HGBH41JXMN109186" />
|
||||||
</div>
|
</div>
|
||||||
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||||
|
<RhfAsyncSelectField
|
||||||
|
name="customer_id"
|
||||||
|
label="Customer"
|
||||||
|
placeholder="Select customer"
|
||||||
|
queryKey={["customers"]}
|
||||||
|
listFn={() => api.customers.list()}
|
||||||
|
mapOption={(op:any)=> ({ value: String(op.id), label: getFullName(op) })}
|
||||||
|
createForm={(props) => <CustomerForm {...props} />}
|
||||||
|
createLabel="Customer"
|
||||||
|
|
||||||
|
{...STORE_OBJECT}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* License & identifiers */}
|
{/* License & identifiers */}
|
||||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||||
|
|||||||
@ -11,7 +11,7 @@ export const vehicleFormSchema = z.object({
|
|||||||
vehicle_fuel_type_id: relationFieldSchema,
|
vehicle_fuel_type_id: relationFieldSchema,
|
||||||
vehicle_transmission_id: relationFieldSchema,
|
vehicle_transmission_id: relationFieldSchema,
|
||||||
vehicle_color_id: relationFieldSchema,
|
vehicle_color_id: relationFieldSchema,
|
||||||
|
customer_id: relationFieldSchema,
|
||||||
// ── Vehicle identity ──
|
// ── Vehicle identity ──
|
||||||
make: z.string().optional(),
|
make: z.string().optional(),
|
||||||
model: z.string().optional(),
|
model: z.string().optional(),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user