"use client" import { AlertTriangle, Plus, Save } from "lucide-react" import { Button } from "@/shared/components/ui/button" import { Alert, AlertTitle } from "@/shared/components/ui/alert" import { Rhform, RhfTextField, RhfTextareaField, RhfCheckboxField, RhfSelectField, RhfAsyncSelectField, RhfDateField, RhfTimeField, RhfAutoGenerateField, } from "@/shared/components/form" import { toast } from "sonner" import { useAuthApi } from "@/shared/useApi" import { useResourceForm } from "@/shared/hooks/use-resource-form" import { useFormMutation } from "@/shared/hooks/use-form-mutation" import { toRelation, toId } from "@/shared/lib/utils" import { jobCardFormSchema, type JobCardFormValues, FUEL_LEVEL_OPTIONS, JOB_CARD_STATUS_OPTIONS, } from "./job-card.schema" import { JOB_CARD_ROUTES, EMPLOYEE_ROUTES, DEPARTMENT_ROUTES, INSURANCE_TYPE_ROUTES } from "@garage/api" import { RhfCustomerSelectField } from "@/modules/customers/rhf-customer-select-field" import { RhfVehicleSelectField } from "@/modules/vehicles/rhf-vehicle-select-field" import { RhfLabelPickerField } from "@/modules/labels/rhf-label-picker-field" import { RhfCustomerRemarksField } from "@/modules/estimates/rhf-customer-remarks-field" import { InsuranceTypeCrudDialog } from "./insurance-type-crud-dialog" // ── Props ── export type JobCardFormProps = { resourceId?: string | null initialData?: unknown onSuccess?: () => void } // ── Default values ── const DEFAULT_VALUES: JobCardFormValues = { title: "", customer: null, vehicle: null, department: null, service_writer: null, primary_technician: null, sales_person: null, insurance_type: null, insurer: null, order_number: "", estimate_number: "", status: "check_in", estimate_to: "Customer", tax_inclusive: "Tax Inclusive", discount_type: "no", discount_at: "inclusive_of_tax", order_date: new Date().toISOString().split("T")[0], check_in_date: "", check_in_time: "", start_date: "", start_time: "", delivery_date: "", delivery_time: "", km_in: "", fuel_level: "", has_insurance: false, enable_parts_issuing: false, enable_digital_authorisation: false, footer: "", customer_remarks: [], labels: [], } // ── Mapping helpers ── function mapToFormValues(data: unknown): JobCardFormValues { const d = (data as any)?.data ?? data ?? {} const mapTime = (v: unknown): string => { if (!v || typeof v !== "string") return "" if (v.includes("T")) return v.split("T")[1]?.slice(0, 8) ?? "" return v } const mapDate = (v: unknown): string => { if (!v || typeof v !== "string") return "" return v.split("T")[0] } return { title: d.title || "", customer: toRelation(d.customer_id, d.customer ? `${d.customer.first_name} ${d.customer.last_name}` : undefined), vehicle: toRelation(d.vehicle_id, d.vehicle ? (d.vehicle.plate_number ?? `${d.vehicle.make ?? ""} ${d.vehicle.model ?? ""}`.trim()) : undefined), department: toRelation(d.department_id, d.department?.name), service_writer: toRelation(d.service_writer_id, d.service_writer ? `${d.service_writer.first_name} ${d.service_writer.last_name}` : undefined), primary_technician: toRelation(d.primary_technician_id, d.primary_technician ? `${d.primary_technician.first_name} ${d.primary_technician.last_name}` : undefined), sales_person: toRelation(d.sales_person_id, d.sales_person ? `${d.sales_person.first_name} ${d.sales_person.last_name}` : undefined), insurance_type: toRelation(d.insurance_type_id, d.insurance_type?.name), insurer: toRelation(d.insurer_id, d.insurer ? `${d.insurer.first_name} ${d.insurer.last_name}`.trim() || d.insurer.company_name : undefined), order_number: d.order_number || "", estimate_number: d.estimate_number || "", status: d.status || "draft", estimate_to: d.estimate_to || "Customer", tax_inclusive: d.tax_inclusive || "Tax Inclusive", discount_type: d.discount_type || "no", discount_at: d.discount_at || "inclusive_of_tax", order_date: mapDate(d.order_date), check_in_date: mapDate(d.check_in_date), check_in_time: mapTime(d.check_in_time), start_date: mapDate(d.start_date), start_time: mapTime(d.start_time), delivery_date: mapDate(d.delivery_date), delivery_time: mapTime(d.delivery_time), km_in: d.km_in != null ? String(d.km_in) : "", fuel_level: d.fuel_level || "", has_insurance: d.has_insurance ?? false, enable_parts_issuing: d.enable_parts_issuing ?? false, enable_digital_authorisation: d.enable_digital_authorisation ?? false, footer: d.footer || "", customer_remarks: Array.isArray(d.customer_remarks) ? d.customer_remarks.map((r: any) => typeof r === "string" ? r : (r?.remark ?? "") ).filter(Boolean) : [], labels: (d.labels ?? []).map((l: any) => ({ id: l.id, title: l.title, color_code: l.color_code, })), } } function mapFormToPayload(values: JobCardFormValues) { return { title: values.title, customer_id: toId(values.customer), vehicle_id: toId(values.vehicle), department_id: toId(values.department), service_writer_id: toId(values.service_writer), primary_technician_id: toId(values.primary_technician), sales_person_id: toId(values.sales_person), insurance_type_id: values.insurance_type ? String(toId(values.insurance_type)) : null, insurer_id: values.insurer ? String(toId(values.insurer)) : null, estimate_number: values.estimate_number || undefined, order_number: values.order_number || undefined, status: values.status || undefined, estimate_to: values.estimate_to || undefined, tax_inclusive: values.tax_inclusive || undefined, discount_type: values.discount_type || undefined, discount_at: values.discount_at || undefined, order_date: values.order_date || undefined, check_in_date: values.check_in_date || undefined, check_in_time: values.check_in_time || undefined, start_date: values.start_date || undefined, start_time: values.start_time || undefined, delivery_date: values.delivery_date || undefined, delivery_time: values.delivery_time || undefined, km_in: values.km_in ? Number(values.km_in) : undefined, fuel_level: values.fuel_level || undefined, has_insurance: values.has_insurance, enable_parts_issuing: values.enable_parts_issuing, enable_digital_authorisation: values.enable_digital_authorisation, footer: values.footer || undefined, customer_remarks: values.customer_remarks?.filter(Boolean) ?? [], label_ids: values.labels?.map((l) => l.id), } } // ── Shared mapOption for async selects ── const mapLookupOption = (item: any) => ({ value: String(item.id), label: item.name, }) const mapEmployeeOption = (item: any) => ({ value: String(item.id), label: `${item.first_name} ${item.last_name}`, }) const STORE_OBJECT = { getOptionValue: (o: any) => o, getOptionLabel: (o: any) => o.label } // ── Component ── export function JobCardForm({ resourceId, initialData, onSuccess }: JobCardFormProps) { const api = useAuthApi() const { form, isEditing } = useResourceForm({ schema: jobCardFormSchema, defaultValues: DEFAULT_VALUES, resourceId, initialData, queryKey: [JOB_CARD_ROUTES.BY_ID, resourceId], mapToFormValues, }) const hasInsurance = form.watch("has_insurance") const status = form.watch("status") const isCheckIn = status === "check_in" const { mutate, error, isPending } = useFormMutation(form, { mutationFn: (values: JobCardFormValues) => { const payload = mapFormToPayload(values) const promise = (isEditing && resourceId ? api.jobCards.update(resourceId, payload) : api.jobCards.create(payload)) as Promise toast.promise(promise, { loading: isEditing ? "Updating job card..." : "Creating job card...", success: isEditing ? "Job card updated successfully" : "Job card created successfully", error: isEditing ? "Failed to update job card" : "Failed to create job card", }) return promise }, onSuccess: () => { form.reset() onSuccess?.() }, }) return ( mutate(values)}> {error && ( {isEditing ? "Failed to update job card" : "Failed to create job card"} {error.message} )}
{/* ── Left column ── */}
{hasInsurance && (
Insurance Type
api.insuranceTypes.list()} mapOption={mapLookupOption} {...STORE_OBJECT} />
)}
api.employees.list()} mapOption={mapEmployeeOption} {...STORE_OBJECT} /> api.employees.list()} mapOption={mapEmployeeOption} {...STORE_OBJECT} />
{/* ── Check-in Details (shown when status is check_in) ── */} {isCheckIn && (

Check In Details

api.departments.list()} mapOption={mapLookupOption} {...STORE_OBJECT} />
)}
{/* ── Right column ── */}
) }