@@ -17,9 +17,13 @@ export function InsuranceTypeCrudDialog() {
|
||||
resourceLabel="insurance type"
|
||||
columns={() => [
|
||||
{
|
||||
accessorKey: "name",
|
||||
accessorKey: "title",
|
||||
header: ({ column }) => <ColumnHeader column={column} title="Name" />,
|
||||
},
|
||||
{
|
||||
accessorKey: "description",
|
||||
header: ({ column }) => <ColumnHeader column={column} title="Description" />,
|
||||
},
|
||||
]}
|
||||
renderForm={({ resourceId, initialData, onSuccess }) => (
|
||||
<InsuranceTypeForm
|
||||
|
||||
@@ -6,7 +6,7 @@ import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { Plus, Save } from "lucide-react"
|
||||
import { Button } from "@/shared/components/ui/button"
|
||||
import { FieldGroup } from "@/shared/components/ui/field"
|
||||
import { Rhform, RhfTextField } from "@/shared/components/form"
|
||||
import { Rhform, RhfTextField, RhfTextareaField } from "@/shared/components/form"
|
||||
import { toast } from "sonner"
|
||||
import { useAuthApi } from "@/shared/useApi"
|
||||
import { useEffect } from "react"
|
||||
@@ -15,6 +15,7 @@ import { useEffect } from "react"
|
||||
|
||||
const insuranceTypeSchema = z.object({
|
||||
name: z.string().min(1, "Name is required"),
|
||||
description: z.string().min(1, "Description is required"),
|
||||
})
|
||||
|
||||
type InsuranceTypeFormValues = z.infer<typeof insuranceTypeSchema>
|
||||
@@ -35,22 +36,22 @@ export function InsuranceTypeForm({ resourceId, initialData, onSuccess }: Insura
|
||||
|
||||
const form = useForm<InsuranceTypeFormValues>({
|
||||
resolver: zodResolver(insuranceTypeSchema),
|
||||
defaultValues: { name: "" },
|
||||
defaultValues: { name: "", description: "" },
|
||||
})
|
||||
|
||||
// Pre-fill when editing
|
||||
useEffect(() => {
|
||||
if (initialData) {
|
||||
const d = initialData?.data ?? initialData
|
||||
form.reset({ name: d.name ?? "" })
|
||||
form.reset({ name: d.title ?? "", description: d.description ?? "" })
|
||||
}
|
||||
}, [initialData, form])
|
||||
|
||||
const handleSubmit = async (values: InsuranceTypeFormValues) => {
|
||||
try {
|
||||
const promise = isEditing
|
||||
? api.insuranceTypes.update(resourceId!, { title: values.name } as any)
|
||||
: api.insuranceTypes.create({ title: values.name } as any)
|
||||
? api.insuranceTypes.update(resourceId!, { title: values.name, description: values.description } as any)
|
||||
: api.insuranceTypes.create({ title: values.name, description: values.description } as any)
|
||||
|
||||
toast.promise(promise, {
|
||||
loading: isEditing ? "Updating..." : "Creating...",
|
||||
@@ -75,6 +76,13 @@ export function InsuranceTypeForm({ resourceId, initialData, onSuccess }: Insura
|
||||
placeholder="e.g. Comprehensive"
|
||||
required
|
||||
/>
|
||||
<RhfTextareaField
|
||||
name="description"
|
||||
label="Description"
|
||||
placeholder="e.g. Comprehensive insurance coverage for vehicles"
|
||||
rows={3}
|
||||
required
|
||||
/>
|
||||
<Button type="submit" disabled={form.formState.isSubmitting}>
|
||||
{isEditing ? <Save className="h-4 w-4" /> : <Plus className="h-4 w-4" />}
|
||||
{form.formState.isSubmitting
|
||||
|
||||
@@ -20,7 +20,7 @@ import { Calendar } from "@/shared/components/ui/calendar"
|
||||
import { toast } from "sonner"
|
||||
import { Pencil, CalendarIcon, UserCog, UserCheck, Loader2 } from "lucide-react"
|
||||
import { format } from "date-fns"
|
||||
import { EmployeeCombobox } from "@/modules/employees/employee-combobox"
|
||||
import { EmployeeCombobox, type EmployeeOption } from "@/modules/employees/employee-combobox"
|
||||
|
||||
type JobCardActionsProps = {
|
||||
jobCardId: string
|
||||
@@ -82,6 +82,16 @@ function EmployeePickerDialog({
|
||||
isPending,
|
||||
onSelect,
|
||||
}: EmployeePickerDialogProps) {
|
||||
const handleSelect = (emp: EmployeeOption | null) => {
|
||||
console.log('Selected employee object:', emp, 'Value:', emp?.value, 'Type of value:', typeof emp?.value)
|
||||
if (emp && emp.value) {
|
||||
const employeeId = Number(emp.value)
|
||||
console.log('Parsed employee ID:', employeeId, 'Type:', typeof employeeId)
|
||||
onSelect(employeeId)
|
||||
onOpenChange(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="sm:max-w-md">
|
||||
@@ -91,9 +101,7 @@ function EmployeePickerDialog({
|
||||
</DialogHeader>
|
||||
<EmployeeCombobox
|
||||
value={null}
|
||||
onValueChange={(emp) => {
|
||||
if (emp) onSelect(Number(emp.value))
|
||||
}}
|
||||
onValueChange={handleSelect}
|
||||
disabled={isPending}
|
||||
placeholder="Search employees..."
|
||||
showClear={false}
|
||||
@@ -131,7 +139,8 @@ export function JobCardActions({ jobCardId, orderDate, serviceWriterName, salesP
|
||||
})
|
||||
|
||||
const changeServiceWriterMutation = useMutation({
|
||||
mutationFn: (employeeId: number) => {
|
||||
mutationFn: async (employeeId: number) => {
|
||||
console.log('Sending service writer ID:', employeeId, 'Type:', typeof employeeId)
|
||||
const promise = api.jobCards.changeServiceWriter(jobCardId, { service_writer_id: employeeId })
|
||||
toast.promise(promise, {
|
||||
loading: "Updating service writer...",
|
||||
@@ -147,7 +156,8 @@ export function JobCardActions({ jobCardId, orderDate, serviceWriterName, salesP
|
||||
})
|
||||
|
||||
const changeSalesPersonMutation = useMutation({
|
||||
mutationFn: (employeeId: number) => {
|
||||
mutationFn: async (employeeId: number) => {
|
||||
console.log('Sending sales person ID:', employeeId, 'Type:', typeof employeeId)
|
||||
const promise = api.jobCards.changeSalesPerson(jobCardId, { sales_person_id: employeeId })
|
||||
toast.promise(promise, {
|
||||
loading: "Updating sales person...",
|
||||
@@ -162,6 +172,23 @@ export function JobCardActions({ jobCardId, orderDate, serviceWriterName, salesP
|
||||
},
|
||||
})
|
||||
|
||||
const changePrimaryTechnicianMutation = useMutation({
|
||||
mutationFn: async (employeeId: number) => {
|
||||
console.log('Sending primary technician ID:', employeeId, 'Type:', typeof employeeId)
|
||||
const promise = api.jobCards.changeTechnician(jobCardId, { technician_id: employeeId })
|
||||
toast.promise(promise, {
|
||||
loading: "Updating primary technician...",
|
||||
success: "Primary technician updated successfully",
|
||||
error: "Failed to update primary technician",
|
||||
})
|
||||
return promise
|
||||
},
|
||||
onSuccess: () => {
|
||||
setPrimaryTechnicianDialogOpen(false)
|
||||
router.refresh()
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
|
||||
return (
|
||||
@@ -226,7 +253,7 @@ export function JobCardActions({ jobCardId, orderDate, serviceWriterName, salesP
|
||||
icon={UserCheck}
|
||||
label="Primary Technician"
|
||||
value={primaryTechnicianName ?? null}
|
||||
isPending={false}
|
||||
isPending={changePrimaryTechnicianMutation.isPending}
|
||||
/>
|
||||
</button>
|
||||
|
||||
@@ -239,7 +266,10 @@ export function JobCardActions({ jobCardId, orderDate, serviceWriterName, salesP
|
||||
title="Change Service Writer"
|
||||
description="Search and select an employee to assign as service writer."
|
||||
isPending={changeServiceWriterMutation.isPending}
|
||||
onSelect={(id) => changeServiceWriterMutation.mutate(id)}
|
||||
onSelect={(id) => {
|
||||
console.log('Service Writer dialog onSelect called with:', id, 'Type:', typeof id)
|
||||
changeServiceWriterMutation.mutate(id)
|
||||
}}
|
||||
/>
|
||||
|
||||
<EmployeePickerDialog
|
||||
@@ -248,24 +278,22 @@ export function JobCardActions({ jobCardId, orderDate, serviceWriterName, salesP
|
||||
title="Change Sales Person"
|
||||
description="Search and select an employee to assign as sales person."
|
||||
isPending={changeSalesPersonMutation.isPending}
|
||||
onSelect={(id) => changeSalesPersonMutation.mutate(id)}
|
||||
/>
|
||||
<EmployeePickerDialog
|
||||
open={salesPersonDialogOpen}
|
||||
onOpenChange={setSalesPersonDialogOpen}
|
||||
title="Change Sales Person"
|
||||
description="Search and select an employee to assign as sales person."
|
||||
isPending={changeSalesPersonMutation.isPending}
|
||||
onSelect={(id) => changeSalesPersonMutation.mutate(id)}
|
||||
onSelect={(id) => {
|
||||
console.log('Dialog onSelect called with:', id, 'Type:', typeof id)
|
||||
changeSalesPersonMutation.mutate(id)
|
||||
}}
|
||||
/>
|
||||
|
||||
<EmployeePickerDialog
|
||||
open={primaryTechnicianDialogOpen}
|
||||
onOpenChange={setPrimaryTechnicianDialogOpen}
|
||||
title="Change Primary Technician"
|
||||
description="Search and select an employee to assign as primary technician."
|
||||
isPending={false}
|
||||
onSelect={()=>{}}
|
||||
// onSelect={(id) => changePrimaryTechnicianMutation.mutate(id)}
|
||||
isPending={changePrimaryTechnicianMutation.isPending}
|
||||
onSelect={(id) => {
|
||||
console.log('Primary Technician dialog onSelect called with:', id, 'Type:', typeof id)
|
||||
changePrimaryTechnicianMutation.mutate(id)
|
||||
}}
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -69,9 +69,10 @@ const DEFAULT_VALUES: JobCardFormValues = {
|
||||
check_in_date: "",
|
||||
check_in_time: "",
|
||||
start_date: "",
|
||||
start_time: "",
|
||||
// Must be initialized with 00:00:00
|
||||
start_time: "00:00:00",
|
||||
delivery_date: "",
|
||||
delivery_time: "",
|
||||
delivery_time: "00:00:00",
|
||||
km_in: "",
|
||||
fuel_level: "",
|
||||
has_insurance: false,
|
||||
|
||||
@@ -79,7 +79,7 @@ export function JobCardGeneralInfo({ jobCard }: { jobCard: JobCard }) {
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<JobCardActions
|
||||
jobCardId={String(jobCard)}
|
||||
jobCardId={String(jobCard.id )}
|
||||
orderDate={jobCard.order_date ?? null}
|
||||
serviceWriterName={jobCard.service_writer?.first_name}
|
||||
salesPersonName={jobCard.sales_person?.first_name}
|
||||
|
||||
@@ -47,6 +47,7 @@ export default function JobCardPaymentsReceived() {
|
||||
<PaymentReceivedForm
|
||||
resourceId={resourceId}
|
||||
defaultJobCard={{ id: jobCard?.id, title: jobCard?.title }}
|
||||
invoiceCustomer={jobCard?.customer as any}
|
||||
onSuccess={invalidateQuery}
|
||||
/>
|
||||
)}
|
||||
@@ -83,14 +84,14 @@ export default function JobCardPaymentsReceived() {
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "payment_mode_name",
|
||||
accessorKey: "payment_mode",
|
||||
header: ({ column }) => <ColumnHeader column={column} title="Payment Mode" />,
|
||||
cell: ({ row }) => {
|
||||
const item = row.original as any
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<CreditCardIcon className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="capitalize">{item.payment_mode_name || "—"}</span>
|
||||
<span className="capitalize">{(item.payment_mode?.title) || "—"}</span>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user