140 lines
5.0 KiB
TypeScript
140 lines
5.0 KiB
TypeScript
"use client"
|
|
|
|
import { z } from "zod"
|
|
import { useForm } from "react-hook-form"
|
|
import { zodResolver } from "@hookform/resolvers/zod"
|
|
import { toast } from "sonner"
|
|
import { useAuthApi } from "@/shared/useApi"
|
|
import {
|
|
Rhform,
|
|
RhfTextField,
|
|
RhfSelectField,
|
|
RhfDateField,
|
|
RhfTimeField,
|
|
RhfAsyncSelectField,
|
|
} from "@/shared/components/form"
|
|
import { FieldGroup } from "@/shared/components/ui/field"
|
|
import { Button } from "@/shared/components/ui/button"
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/shared/components/ui/dialog"
|
|
import { DEPARTMENT_ROUTES } from "@garage/api"
|
|
import { FUEL_LEVEL_OPTIONS } from "./job-card.schema"
|
|
import { toId } from "@/shared/lib/utils"
|
|
|
|
// ── Schema ──
|
|
|
|
const deliverySchema = z.object({
|
|
check_out_date: z.string().optional(),
|
|
check_out_time: z.string().optional(),
|
|
km_out: z.string().optional(),
|
|
fuel_level: z.string().optional(),
|
|
department: z.object({ value: z.number(), label: z.string() }).nullable().optional(),
|
|
})
|
|
|
|
type DeliveryFormValues = z.infer<typeof deliverySchema>
|
|
|
|
const mapLookupOption = (item: any) => ({
|
|
value: String(item.id),
|
|
label: item.name,
|
|
})
|
|
|
|
const STORE_OBJECT = { storeObject: true } as const
|
|
|
|
// ── Props ──
|
|
|
|
type JobCardDeliveryDialogProps = {
|
|
jobCardId: string
|
|
open: boolean
|
|
onOpenChange: (open: boolean) => void
|
|
onSuccess?: () => void
|
|
}
|
|
|
|
// ── Component ──
|
|
|
|
export function JobCardDeliveryDialog({
|
|
jobCardId,
|
|
open,
|
|
onOpenChange,
|
|
onSuccess,
|
|
}: JobCardDeliveryDialogProps) {
|
|
const api = useAuthApi()
|
|
|
|
const now = new Date()
|
|
const todayStr = now.toISOString().split("T")[0]
|
|
const currentTime = `${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}:${String(now.getSeconds()).padStart(2, "0")}`
|
|
|
|
const form = useForm<DeliveryFormValues>({
|
|
resolver: zodResolver(deliverySchema),
|
|
defaultValues: {
|
|
check_out_date: todayStr,
|
|
check_out_time: currentTime,
|
|
km_out: "",
|
|
fuel_level: "",
|
|
department: null,
|
|
},
|
|
})
|
|
|
|
const handleSubmit = async (values: DeliveryFormValues) => {
|
|
try {
|
|
await api.jobCards.delivery(jobCardId, {
|
|
check_out_date: values.check_out_date || undefined,
|
|
check_out_time: values.check_out_time || undefined,
|
|
km_out: values.km_out ? Number(values.km_out) : undefined,
|
|
fuel_level: values.fuel_level || undefined,
|
|
department_id: values.department ? Number(toId(values.department as any)) : undefined,
|
|
})
|
|
toast.success("Job card marked as delivered successfully")
|
|
form.reset()
|
|
onSuccess?.()
|
|
} catch {
|
|
toast.error("Failed to mark job card as delivered")
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent className="min-w-xl">
|
|
<DialogHeader>
|
|
<DialogTitle className="text-2xl font-bold">Delivery</DialogTitle>
|
|
</DialogHeader>
|
|
<Rhform form={form} onSubmit={handleSubmit}>
|
|
<FieldGroup>
|
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
<RhfDateField name="check_out_date" label="Check-out Date" />
|
|
<RhfTimeField name="check_out_time" label="Check-out Time" />
|
|
</div>
|
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
<RhfTextField name="km_out" label="KM Out" type="number" placeholder="e.g. 50480" />
|
|
<RhfSelectField name="fuel_level" label="Fuel Level" options={FUEL_LEVEL_OPTIONS} />
|
|
</div>
|
|
<RhfAsyncSelectField
|
|
name="department"
|
|
label="Department"
|
|
placeholder="Select department"
|
|
queryKey={[DEPARTMENT_ROUTES.INDEX]}
|
|
listFn={() => api.departments.list()}
|
|
mapOption={(op: any) => ({ value: op.id, label: op.name })}
|
|
{...STORE_OBJECT}
|
|
getOptionLabel={op => op.label}
|
|
getOptionValue={op => op}
|
|
|
|
/>
|
|
<div className="flex justify-end gap-2">
|
|
<Button type="button" variant="outline" onClick={() => onOpenChange(false)}>
|
|
Cancel
|
|
</Button>
|
|
<Button type="submit" disabled={form.formState.isSubmitting}>
|
|
{form.formState.isSubmitting ? "Delivering..." : "Mark as Delivered"}
|
|
</Button>
|
|
</div>
|
|
</FieldGroup>
|
|
</Rhform>
|
|
</DialogContent>
|
|
</Dialog>
|
|
)
|
|
}
|