filters , order inspections , inventory items , credit notes
This commit is contained in:
@@ -0,0 +1,282 @@
|
||||
"use client"
|
||||
|
||||
import { z } from "zod"
|
||||
import { parseAsInteger, parseAsString, parseAsBoolean } from "nuqs"
|
||||
import { toRelation, toId, type RelationFieldValue } from "@/shared/lib/utils"
|
||||
import {
|
||||
RhfAsyncSelectField,
|
||||
RhfDateField,
|
||||
RhfCheckboxField,
|
||||
RhfSelectField,
|
||||
} from "@/shared/components/form"
|
||||
import { useAuthApi } from "@/shared/useApi"
|
||||
import {
|
||||
CUSTOMER_ROUTES,
|
||||
EMPLOYEE_ROUTES,
|
||||
DEPARTMENT_ROUTES,
|
||||
VEHICLE_ROUTES,
|
||||
LABEL_ROUTES,
|
||||
INSURANCE_TYPE_ROUTES,
|
||||
JobCardStatus,
|
||||
} from "@garage/api"
|
||||
import { formatEnum } from "@/shared/utils/formatters"
|
||||
import { Separator } from "@/shared/components/ui/separator"
|
||||
import type { UseFilterParamsOptions } from "@/shared/hooks/use-filter-params"
|
||||
|
||||
// ── Schema ──
|
||||
|
||||
const relationField = z.object({ value: z.string(), label: z.string() }).nullable().optional()
|
||||
|
||||
const jobCardFilterSchema = z.object({
|
||||
customer_id: relationField,
|
||||
insurer_id: relationField,
|
||||
vehicle_id: relationField,
|
||||
department_id: relationField,
|
||||
sales_person_id: relationField,
|
||||
primary_technician_id: relationField,
|
||||
service_writer_id: relationField,
|
||||
label_ids: z.string().optional(),
|
||||
check_in_date: z.string().optional(),
|
||||
check_out_date: z.string().optional(),
|
||||
delivery_date: z.string().optional(),
|
||||
start_date: z.string().optional(),
|
||||
end_date: z.string().optional(),
|
||||
convert_invoice: z.boolean().optional(),
|
||||
has_start_or_delivery_date: z.boolean().optional(),
|
||||
has_start_date: z.boolean().optional(),
|
||||
has_delivery_date: z.boolean().optional(),
|
||||
has_both_dates: z.boolean().optional(),
|
||||
})
|
||||
|
||||
type JobCardFilterValues = z.infer<typeof jobCardFilterSchema>
|
||||
|
||||
// ── Defaults ──
|
||||
|
||||
const defaultValues: JobCardFilterValues = {
|
||||
customer_id: null,
|
||||
insurer_id: null,
|
||||
vehicle_id: null,
|
||||
department_id: null,
|
||||
sales_person_id: null,
|
||||
primary_technician_id: null,
|
||||
service_writer_id: null,
|
||||
label_ids: "",
|
||||
check_in_date: "",
|
||||
check_out_date: "",
|
||||
delivery_date: "",
|
||||
start_date: "",
|
||||
end_date: "",
|
||||
convert_invoice: false,
|
||||
has_start_or_delivery_date: false,
|
||||
has_start_date: false,
|
||||
has_delivery_date: false,
|
||||
has_both_dates: false,
|
||||
}
|
||||
|
||||
// ── nuqs Parsers ──
|
||||
|
||||
const paramsParsers = {
|
||||
customer_id: parseAsInteger,
|
||||
insurer_id: parseAsInteger,
|
||||
vehicle_id: parseAsInteger,
|
||||
department_id: parseAsInteger,
|
||||
sales_person_id: parseAsInteger,
|
||||
primary_technician_id: parseAsInteger,
|
||||
service_writer_id: parseAsInteger,
|
||||
label_ids: parseAsString,
|
||||
check_in_date: parseAsString,
|
||||
check_out_date: parseAsString,
|
||||
delivery_date: parseAsString,
|
||||
start_date: parseAsString,
|
||||
end_date: parseAsString,
|
||||
convert_invoice: parseAsBoolean,
|
||||
has_start_or_delivery_date: parseAsBoolean,
|
||||
has_start_date: parseAsBoolean,
|
||||
has_delivery_date: parseAsBoolean,
|
||||
has_both_dates: parseAsBoolean,
|
||||
}
|
||||
|
||||
// ── Mappers ──
|
||||
|
||||
function mapParamsToFormValues(params: Record<string, any>): Partial<JobCardFilterValues> {
|
||||
return {
|
||||
customer_id: params.customer_id ? toRelation(params.customer_id) : null,
|
||||
insurer_id: params.insurer_id ? toRelation(params.insurer_id) : null,
|
||||
vehicle_id: params.vehicle_id ? toRelation(params.vehicle_id) : null,
|
||||
department_id: params.department_id ? toRelation(params.department_id) : null,
|
||||
sales_person_id: params.sales_person_id ? toRelation(params.sales_person_id) : null,
|
||||
primary_technician_id: params.primary_technician_id ? toRelation(params.primary_technician_id) : null,
|
||||
service_writer_id: params.service_writer_id ? toRelation(params.service_writer_id) : null,
|
||||
label_ids: params.label_ids ?? "",
|
||||
check_in_date: params.check_in_date ?? "",
|
||||
check_out_date: params.check_out_date ?? "",
|
||||
delivery_date: params.delivery_date ?? "",
|
||||
start_date: params.start_date ?? "",
|
||||
end_date: params.end_date ?? "",
|
||||
convert_invoice: params.convert_invoice ?? false,
|
||||
has_start_or_delivery_date: params.has_start_or_delivery_date ?? false,
|
||||
has_start_date: params.has_start_date ?? false,
|
||||
has_delivery_date: params.has_delivery_date ?? false,
|
||||
has_both_dates: params.has_both_dates ?? false,
|
||||
}
|
||||
}
|
||||
|
||||
function mapFormValuesToParams(values: JobCardFilterValues): Record<string, any> {
|
||||
return {
|
||||
customer_id: toId(values.customer_id as RelationFieldValue) ?? null,
|
||||
insurer_id: toId(values.insurer_id as RelationFieldValue) ?? null,
|
||||
vehicle_id: toId(values.vehicle_id as RelationFieldValue) ?? null,
|
||||
department_id: toId(values.department_id as RelationFieldValue) ?? null,
|
||||
sales_person_id: toId(values.sales_person_id as RelationFieldValue) ?? null,
|
||||
primary_technician_id: toId(values.primary_technician_id as RelationFieldValue) ?? null,
|
||||
service_writer_id: toId(values.service_writer_id as RelationFieldValue) ?? null,
|
||||
label_ids: values.label_ids || null,
|
||||
check_in_date: values.check_in_date || null,
|
||||
check_out_date: values.check_out_date || null,
|
||||
delivery_date: values.delivery_date || null,
|
||||
start_date: values.start_date || null,
|
||||
end_date: values.end_date || null,
|
||||
convert_invoice: values.convert_invoice || null,
|
||||
has_start_or_delivery_date: values.has_start_or_delivery_date || null,
|
||||
has_start_date: values.has_start_date || null,
|
||||
has_delivery_date: values.has_delivery_date || null,
|
||||
has_both_dates: values.has_both_dates || null,
|
||||
}
|
||||
}
|
||||
|
||||
// ── Filter Config (for useFilterParams) ──
|
||||
|
||||
export const jobCardFilterConfig: UseFilterParamsOptions<JobCardFilterValues> = {
|
||||
schema: jobCardFilterSchema,
|
||||
defaultValues,
|
||||
paramsParsers,
|
||||
mapParamsToFormValues,
|
||||
mapFormValuesToParams,
|
||||
}
|
||||
|
||||
// ── Filter Fields Component ──
|
||||
|
||||
function SectionLabel({ children }: { children: React.ReactNode }) {
|
||||
return <p className="text-sm font-medium text-muted-foreground pt-2">{children}</p>
|
||||
}
|
||||
|
||||
export function JobCardFilterFields() {
|
||||
const api = useAuthApi()
|
||||
|
||||
const employeeMapOption = (item: any) => ({
|
||||
value: String(item.id),
|
||||
label: [item.first_name, item.last_name].filter(Boolean).join(" ") || `Employee #${item.id}`,
|
||||
})
|
||||
|
||||
const customerMapOption = (item: any) => {
|
||||
const name = [item.first_name, item.last_name].filter(Boolean).join(" ")
|
||||
return {
|
||||
value: String(item.id),
|
||||
label: name || item.company_name || `Customer #${item.id}`,
|
||||
}
|
||||
}
|
||||
|
||||
const vehicleMapOption = (item: any) => ({
|
||||
value: String(item.id),
|
||||
label: [item.year, item.make, item.model].filter(Boolean).join(" ") || `Vehicle #${item.id}`,
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* ── Relations ── */}
|
||||
<SectionLabel>Relations</SectionLabel>
|
||||
|
||||
<RhfAsyncSelectField
|
||||
name="customer_id"
|
||||
label="Customer"
|
||||
queryKey={[CUSTOMER_ROUTES.INDEX]}
|
||||
listFn={() => api.customers.list({ per_page: 100 })}
|
||||
mapOption={customerMapOption}
|
||||
placeholder="All customers"
|
||||
/>
|
||||
|
||||
<RhfAsyncSelectField
|
||||
name="vehicle_id"
|
||||
label="Vehicle"
|
||||
queryKey={[VEHICLE_ROUTES.INDEX]}
|
||||
listFn={() => api.vehicles.list({ per_page: 100 })}
|
||||
mapOption={vehicleMapOption}
|
||||
placeholder="All vehicles"
|
||||
/>
|
||||
|
||||
<RhfAsyncSelectField
|
||||
name="insurer_id"
|
||||
label="Insurance Type"
|
||||
queryKey={[INSURANCE_TYPE_ROUTES.INDEX]}
|
||||
listFn={() => api.insuranceTypes.list({ per_page: 100 })}
|
||||
mapOption={(item: any) => ({ value: String(item.id), label: item.title ?? item.name ?? `#${item.id}` })}
|
||||
placeholder="All insurers"
|
||||
/>
|
||||
|
||||
<RhfAsyncSelectField
|
||||
name="department_id"
|
||||
label="Department"
|
||||
queryKey={[DEPARTMENT_ROUTES.INDEX]}
|
||||
listFn={() => api.departments.list({ per_page: 100 })}
|
||||
mapOption={(item: any) => ({ value: String(item.id), label: item.title ?? item.name ?? `#${item.id}` })}
|
||||
placeholder="All departments"
|
||||
/>
|
||||
|
||||
<Separator />
|
||||
<SectionLabel>Assigned Staff</SectionLabel>
|
||||
|
||||
<RhfAsyncSelectField
|
||||
name="sales_person_id"
|
||||
label="Sales Person"
|
||||
queryKey={[EMPLOYEE_ROUTES.INDEX, "sales_person"]}
|
||||
listFn={() => api.employees.list({ per_page: 100 })}
|
||||
mapOption={employeeMapOption}
|
||||
placeholder="All sales persons"
|
||||
/>
|
||||
|
||||
<RhfAsyncSelectField
|
||||
name="primary_technician_id"
|
||||
label="Primary Technician"
|
||||
queryKey={[EMPLOYEE_ROUTES.INDEX, "technician"]}
|
||||
listFn={() => api.employees.list({ per_page: 100 })}
|
||||
mapOption={employeeMapOption}
|
||||
placeholder="All technicians"
|
||||
/>
|
||||
|
||||
<RhfAsyncSelectField
|
||||
name="service_writer_id"
|
||||
label="Service Writer"
|
||||
queryKey={[EMPLOYEE_ROUTES.INDEX, "service_writer"]}
|
||||
listFn={() => api.employees.list({ per_page: 100 })}
|
||||
mapOption={employeeMapOption}
|
||||
placeholder="All service writers"
|
||||
/>
|
||||
|
||||
{/* ── Dates ── */}
|
||||
<Separator />
|
||||
<SectionLabel>Dates</SectionLabel>
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<RhfDateField name="check_in_date" label="Check-in Date" />
|
||||
<RhfDateField name="check_out_date" label="Check-out Date" />
|
||||
</div>
|
||||
|
||||
<RhfDateField name="delivery_date" label="Delivery Date" />
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<RhfDateField name="start_date" label="Start Date" />
|
||||
<RhfDateField name="end_date" label="End Date" />
|
||||
</div>
|
||||
|
||||
{/* ── Flags ── */}
|
||||
<Separator />
|
||||
<SectionLabel>Flags</SectionLabel>
|
||||
|
||||
<RhfCheckboxField name="convert_invoice" label="Convert to Invoice" />
|
||||
<RhfCheckboxField name="has_start_or_delivery_date" label="Has Start or Delivery Date" />
|
||||
<RhfCheckboxField name="has_start_date" label="Has Start Date" />
|
||||
<RhfCheckboxField name="has_delivery_date" label="Has Delivery Date" />
|
||||
<RhfCheckboxField name="has_both_dates" label="Has Both Dates" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user