finish bills , po , jobcards relational fields creation
This commit is contained in:
@@ -4,14 +4,13 @@ import { AlertTriangle, Plus, Save } from "lucide-react"
|
||||
|
||||
import { Button } from "@/shared/components/ui/button"
|
||||
import { Alert, AlertTitle } from "@/shared/components/ui/alert"
|
||||
import { FieldGroup } from "@/shared/components/ui/field"
|
||||
import {
|
||||
Rhform,
|
||||
RhfTextField,
|
||||
RhfTextareaField,
|
||||
RhfCheckboxField,
|
||||
RhfAsyncSelectField,
|
||||
RhfAsyncMultiSelectField,
|
||||
RhfDateField,
|
||||
RhfAutoGenerateField,
|
||||
} from "@/shared/components/form"
|
||||
import { toast } from "sonner"
|
||||
import { useAuthApi } from "@/shared/useApi"
|
||||
@@ -23,9 +22,11 @@ import {
|
||||
estimateFormSchema,
|
||||
type EstimateFormValues,
|
||||
} from "./estimate.schema"
|
||||
import { ESTIMATE_ROUTES, DEPARTMENT_ROUTES, LABEL_ROUTES } from "@garage/api"
|
||||
import { ESTIMATE_ROUTES, DEPARTMENT_ROUTES } from "@garage/api"
|
||||
import { RhfCustomerSelectField } from "@/modules/customers/rhf-customer-select-field"
|
||||
import { RhfVehicleSelectField } from "@/modules/vehicles/rhf-vehicle-select-field"
|
||||
import { RhfLabelPickerField, type LabelItem } from "@/modules/labels/rhf-label-picker-field"
|
||||
import { RhfCustomerRemarksField } from "./rhf-customer-remarks-field"
|
||||
|
||||
// ── Props ──
|
||||
|
||||
@@ -46,7 +47,7 @@ const DEFAULT_VALUES: EstimateFormValues = {
|
||||
estimate_number: "",
|
||||
date: "",
|
||||
has_insurance: false,
|
||||
remarks: "",
|
||||
remarks: [],
|
||||
labels: [],
|
||||
}
|
||||
|
||||
@@ -61,12 +62,16 @@ function mapToFormValues(data: unknown): EstimateFormValues {
|
||||
vehicle: toRelation(d.vehicle_id, d.vehicle_name),
|
||||
department: toRelation(d.department_id, d.department_name),
|
||||
estimate_number: d.estimate_number || "",
|
||||
date: d.date || "",
|
||||
date: d.date ? d.date.split("T")[0] : "",
|
||||
has_insurance: d.has_insurance ?? false,
|
||||
remarks: Array.isArray(d.remarks) ? d.remarks.join("\n") : d.remarks || "",
|
||||
labels: Array.isArray(d.labels)
|
||||
? d.labels.map((l: any) => ({ value: String(l.id), label: l.name }))
|
||||
remarks: Array.isArray(d.remarks)
|
||||
? d.remarks.map((r: any) => (typeof r === "string" ? r : (r?.remark ?? ""))).filter(Boolean)
|
||||
: [],
|
||||
labels: (d.labels ?? []).map((l: any): LabelItem => ({
|
||||
id: l.id,
|
||||
title: l.title ?? l.name ?? "",
|
||||
color_code: l.color_code ?? "",
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,10 +84,8 @@ function mapFormToPayload(values: EstimateFormValues) {
|
||||
estimate_number: values.estimate_number || undefined,
|
||||
date: values.date || undefined,
|
||||
has_insurance: values.has_insurance,
|
||||
remarks: values.remarks
|
||||
? values.remarks.split("\n").filter(Boolean)
|
||||
: [],
|
||||
label_ids: values.labels.map((l) => Number(l.value)),
|
||||
remarks: values.remarks?.filter(Boolean) ?? [],
|
||||
label_ids: values.labels?.map((l) => l.id) ?? [],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,20 +143,17 @@ export function EstimateForm({ resourceId, initialData, onSuccess }: EstimateFor
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<FieldGroup>
|
||||
<RhfTextField name="title" label="Title" placeholder="Estimate title" required />
|
||||
<div className="space-y-4">
|
||||
<RhfLabelPickerField name="labels" label="Labels" />
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
<RhfTextField name="estimate_number" label="Estimate Number" placeholder="EST-001" />
|
||||
<RhfTextField name="date" label="Date" type="date" />
|
||||
</div>
|
||||
<RhfTextField name="title" label="Title" placeholder="Estimate title" required />
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
<RhfCustomerSelectField name="customer" />
|
||||
<RhfVehicleSelectField name="vehicle" />
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
||||
<RhfAsyncSelectField
|
||||
name="department"
|
||||
label="Department"
|
||||
@@ -163,21 +163,13 @@ export function EstimateForm({ resourceId, initialData, onSuccess }: EstimateFor
|
||||
mapOption={mapLookupOption}
|
||||
{...STORE_OBJECT}
|
||||
/>
|
||||
<RhfAsyncMultiSelectField
|
||||
name="labels"
|
||||
label="Labels"
|
||||
placeholder="Select labels"
|
||||
multiple
|
||||
queryKey={[LABEL_ROUTES.INDEX]}
|
||||
listFn={() => api.labels.list()}
|
||||
mapOption={mapLookupOption}
|
||||
{...STORE_OBJECT}
|
||||
/>
|
||||
<RhfDateField name="date" label="Date" />
|
||||
<RhfAutoGenerateField autoFetch name="estimate_number" label="Estimate#" placeholder="EST-001" table="estimates" />
|
||||
</div>
|
||||
|
||||
<RhfCheckboxField name="has_insurance" label="Has Insurance" />
|
||||
|
||||
<RhfTextareaField name="remarks" label="Remarks" placeholder="Enter remarks (one per line)" rows={3} />
|
||||
<RhfCustomerRemarksField name="remarks" />
|
||||
|
||||
<Button type="submit" variant="default" disabled={isPending}>
|
||||
{isEditing ? <Save /> : <Plus />}
|
||||
@@ -185,7 +177,7 @@ export function EstimateForm({ resourceId, initialData, onSuccess }: EstimateFor
|
||||
? (isEditing ? "Updating..." : "Creating...")
|
||||
: (isEditing ? "Update Estimate" : "Create Estimate")}
|
||||
</Button>
|
||||
</FieldGroup>
|
||||
</div>
|
||||
</Rhform>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -17,12 +17,20 @@ const estimateFormSchema = z.object({
|
||||
estimate_number: z.string().optional(),
|
||||
date: z.string().optional(),
|
||||
has_insurance: z.boolean().default(false),
|
||||
remarks: z.string().optional(),
|
||||
|
||||
// ── Multi-select relations ──
|
||||
// ── Remarks (array of strings) ──
|
||||
remarks: z.array(z.string()).optional(),
|
||||
|
||||
// ── Labels ──
|
||||
labels: z
|
||||
.array(z.object({ value: z.string(), label: z.string() }))
|
||||
.default([]),
|
||||
.array(
|
||||
z.object({
|
||||
id: z.number(),
|
||||
title: z.string(),
|
||||
color_code: z.string(),
|
||||
}),
|
||||
)
|
||||
.optional(),
|
||||
})
|
||||
|
||||
type EstimateFormValues = z.infer<typeof estimateFormSchema>
|
||||
|
||||
Reference in New Issue
Block a user