"use client" import { useEffect, useState } from "react" import { useForm } from "react-hook-form" import { zodResolver } from "@hookform/resolvers/zod" import { z } from "zod" import { toast } from "sonner" import { ClipboardList, Plus } from "lucide-react" import { Button } from "@/shared/components/ui/button" import { FieldGroup } from "@/shared/components/ui/field" import { Rhform, RhfTextField, RhfTextareaField, RhfDateField, RhfTimeField, } from "@/shared/components/form" import { useAuthApi } from "@/shared/useApi" import type { InspectionTemplate } from "@garage/api" import { RhfCustomerSelectField } from "@/modules/customers/rhf-customer-select-field" import { RhfVehicleSelectField } from "@/modules/vehicles/rhf-vehicle-select-field" import { RhfEmployeeSelectField } from "@/modules/employees/rhf-employee-select-field" import { RhfAsyncSelectField } from "@/shared/components/form" import { DEPARTMENT_ROUTES } from "@garage/api" import { useFormContext, useWatch } from "react-hook-form" import { useEffect as useReactEffect, useRef } from "react" const relationFieldSchema = z .object({ value: z.string(), label: z.string() }) .nullable() const schema = z.object({ customer: relationFieldSchema.refine((v) => !!v?.value, "Customer is required"), vehicle: relationFieldSchema.refine((v) => !!v?.value, "Vehicle is required"), department: relationFieldSchema.refine((v) => !!v?.value, "Department is required"), employee: relationFieldSchema.refine((v) => !!v?.value, "Employee is required"), title: z.string().min(1, "Title is required").max(100), order_number: z.string().min(1, "Order number is required").max(100), date: z.string().min(1, "Date is required"), time: z.string().min(1, "Time is required"), odometer: z.coerce.number().int().min(0).optional().or(z.literal("")).transform(v => v === "" ? undefined : v), note: z.string().optional(), }) type FormValues = z.infer const STORE_OBJECT = { getOptionValue: (o: any) => o, getOptionLabel: (o: any) => o.label } const mapLookupOption = (item: any) => ({ value: String(item.id), label: item.name ?? item.title ?? String(item.id) }) // Scope vehicle picker to selected customer function CustomerScopedVehicleField() { const { setValue, control, getValues } = useFormContext() const customer = useWatch({ control, name: "customer" }) const customerId = customer?.value ?? null const lastRef = useRef(customerId) useReactEffect(() => { if (lastRef.current !== customerId) { if (getValues("vehicle")) { setValue("vehicle", null, { shouldDirty: true, shouldValidate: false }) } lastRef.current = customerId } }, [customerId, setValue, getValues]) return ( ) } export function InspectionFromTemplateForm({ onSuccess }: { onSuccess?: (inspectionId: number) => void }) { const api = useAuthApi() const [step, setStep] = useState<"pick-template" | "fill-details">("pick-template") const [templates, setTemplates] = useState([]) const [selectedTemplate, setSelectedTemplate] = useState(null) const [loadingTemplates, setLoadingTemplates] = useState(true) const form = useForm({ resolver: zodResolver(schema) as any, defaultValues: { customer: null, vehicle: null, department: null, employee: null, title: "", order_number: "", date: new Date().toISOString().slice(0, 10), time: new Date().toTimeString().slice(0, 8), odometer: undefined, note: "", }, }) useEffect(() => { let cancelled = false setLoadingTemplates(true) api.inspectionTemplates.list({ is_active: true }).then((res) => { if (!cancelled) { setTemplates(res.data ?? []) setLoadingTemplates(false) } }).catch((e: any) => { if (!cancelled) { toast.error(e?.message ?? "Failed to load templates") setLoadingTemplates(false) } }) return () => { cancelled = true } }, []) const pickTemplate = (t: InspectionTemplate) => { setSelectedTemplate(t) form.setValue("title", t.name) setStep("fill-details") } const handleSubmit = async (values: FormValues) => { if (!selectedTemplate) return try { const res = await api.inspections.createFromTemplate({ template_id: selectedTemplate.id, title: values.title, customer_id: values.customer!.value, vehicle_id: values.vehicle!.value, department_id: values.department!.value, employee_id: values.employee!.value, order_number: values.order_number, date: values.date, time: values.time, odometer: values.odometer as any, note: values.note || undefined, }) const created = (res as any)?.data toast.success("Inspection created with checkpoints from template") onSuccess?.(created?.id) } catch (e: any) { const errors = e?.payload?.errors const firstError = errors && typeof errors === "object" ? (Object.values(errors)[0] as string[])?.[0] : null toast.error(firstError ?? e?.message ?? "Failed to create inspection") } } if (step === "pick-template") { return (

Choose an inspection template

The selected template's sections and checkpoints will be cloned onto the new inspection.

{loadingTemplates && (
Loading templates…
)} {!loadingTemplates && templates.length === 0 && (
No active templates. Create one under Settings → Inspection Templates.
)} {!loadingTemplates && templates.length > 0 && (
{templates.map((t) => { const sectionCount = t.sections?.length ?? 0 const cpCount = (t.sections ?? []).reduce((s, sec) => s + (sec.check_points?.length ?? 0), 0) const empty = cpCount === 0 return ( ) })}
)}
) } return (
Template:{" "} {selectedTemplate?.name}
api.departments.list()} mapOption={mapLookupOption} {...STORE_OBJECT} />
) }