From dd326585003690edfc010afb1199704f2b13eab3 Mon Sep 17 00:00:00 2001 From: Mohammad Khyata Date: Thu, 7 May 2026 15:04:05 +0300 Subject: [PATCH] fix bugs Co-authored-by: Copilot --- .../sales/vehicles/[id]/mileage/page.tsx | 74 +++++++++-- .../modules/job-cards/job-card-form.tsx | 124 ++++++++++++------ .../modules/vehicles/mileage-form.tsx | 55 ++++++-- .../modules/vehicles/mileage.schema.ts | 7 +- .../data-view/resource-page/crud-resource.tsx | 6 +- apps/dashboard/tsconfig.json | 2 - build.log | Bin 0 -> 18732 bytes packages/api/tsconfig.json | 2 - 8 files changed, 199 insertions(+), 71 deletions(-) create mode 100644 build.log diff --git a/apps/dashboard/app/(authenticated)/sales/vehicles/[id]/mileage/page.tsx b/apps/dashboard/app/(authenticated)/sales/vehicles/[id]/mileage/page.tsx index f7c0ff8..469e22a 100644 --- a/apps/dashboard/app/(authenticated)/sales/vehicles/[id]/mileage/page.tsx +++ b/apps/dashboard/app/(authenticated)/sales/vehicles/[id]/mileage/page.tsx @@ -25,11 +25,23 @@ import { DropdownMenuTrigger, } from "@/shared/components/ui/dropdown-menu" import { MileageForm } from "@/modules/vehicles/mileage-form" -import DashboardPage from "@/base/components/layout/dashboard/dashboard-page" +import { formatDate, formatDateTime } from "@/shared/utils/formatters" type MileageRecord = { id: number - name: string + vehicle_id?: number + miles?: number | null + fuel_level?: number | null + date?: string | null + time?: string | null + note?: string | null + vehicle?: { + id?: number + make?: string | null + model?: string | null + year?: number | null + license_plate?: string | null + } | null created_at: string updated_at: string } @@ -64,9 +76,10 @@ export default function VehicleMileagePage() { }) const handleDelete = async (record: MileageRecord) => { + const label = record.miles != null ? `${record.miles} mi` : `Record #${record.id}` const confirmed = await confirm({ title: "Delete Mileage Record", - description: `Are you sure you want to delete this mileage record?`, + description: `Are you sure you want to delete ${label}?`, confirmLabel: "Delete", variant: "destructive", }) @@ -87,16 +100,59 @@ export default function VehicleMileagePage() { const columns: ColumnDef[] = [ { - accessorKey: "name", - header: ({ column }) => , + accessorKey: "miles", + header: ({ column }) => , + cell: ({ getValue }) => { + const value = getValue() + return value == null ? "—" : value.toLocaleString() + }, + }, + { + accessorKey: "fuel_level", + header: ({ column }) => , + cell: ({ getValue }) => { + const value = getValue() + return value == null ? "—" : `${value}%` + }, + }, + { + accessorKey: "date", + header: ({ column }) => , + cell: ({ getValue }) => formatDate(getValue()), + }, + { + accessorKey: "time", + header: ({ column }) => , + cell: ({ getValue }) => { + const value = getValue() + if (!value) return "—" + if (value.includes("T")) { + const timePart = value.split("T")[1] + return timePart ? timePart.slice(0, 5) : "—" + } + return value.slice(0, 5) + }, + }, + { + accessorKey: "note", + header: ({ column }) => , + cell: ({ getValue }) => getValue() || "—", + }, + { + id: "vehicle", + header: ({ column }) => , + cell: ({ row }) => { + const vehicle = row.original.vehicle + if (!vehicle) return "—" + const details = [vehicle.make, vehicle.model, vehicle.year].filter(Boolean).join(" ") + return details || vehicle.license_plate || "—" + }, + enableSorting: false, }, { accessorKey: "created_at", header: ({ column }) => , - cell: ({ getValue }) => { - const val = getValue() - return val ? new Date(val).toLocaleDateString() : "—" - }, + cell: ({ getValue }) => formatDateTime(getValue()), }, { id: "actions", diff --git a/apps/dashboard/modules/job-cards/job-card-form.tsx b/apps/dashboard/modules/job-cards/job-card-form.tsx index e03f828..4304c2e 100644 --- a/apps/dashboard/modules/job-cards/job-card-form.tsx +++ b/apps/dashboard/modules/job-cards/job-card-form.tsx @@ -1,9 +1,18 @@ "use client" +import { useState } from "react" import { AlertTriangle, Plus, Save } from "lucide-react" import { Button } from "@/shared/components/ui/button" import { Alert, AlertTitle } from "@/shared/components/ui/alert" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/shared/components/ui/dialog" import { Rhform, RhfTextField, @@ -197,6 +206,7 @@ const STORE_OBJECT = { getOptionValue: (o: any) => o, getOptionLabel: (o: any) = export function JobCardForm({ resourceId, initialData, onSuccess }: JobCardFormProps) { const api = useAuthApi() + const [isCheckInDialogOpen, setIsCheckInDialogOpen] = useState(false) const { form, isEditing } = useResourceForm({ schema: jobCardFormSchema, @@ -210,7 +220,7 @@ export function JobCardForm({ resourceId, initialData, onSuccess }: JobCardFormP const hasInsurance = form.watch("has_insurance") const status = form.watch("status") const customer = form.watch("customer") - const isCheckIn = status === "check_in" + const shouldCollectCheckInDetails = status === "check_in" const { mutate, error, isPending } = useFormMutation(form, { mutationFn: (values: JobCardFormValues) => { @@ -226,13 +236,27 @@ export function JobCardForm({ resourceId, initialData, onSuccess }: JobCardFormP return promise }, onSuccess: () => { + setIsCheckInDialogOpen(false) form.reset() onSuccess?.() }, }) + const handleSubmit = (values: JobCardFormValues) => { + if (values.status === "check_in" && !isCheckInDialogOpen) { + setIsCheckInDialogOpen(true) + return + } + + mutate(values) + } + + const handleCheckInConfirm = () => { + void form.handleSubmit(handleSubmit)() + } + return ( - mutate(values)}> + {error && ( @@ -305,45 +329,6 @@ export function JobCardForm({ resourceId, initialData, onSuccess }: JobCardFormP {...STORE_OBJECT} /> - - - {/* ── Check-in Details (shown when status is check_in) ── */} - {isCheckIn && ( -
-

Check In Details

- -
- - -
- -
- - - - -
- -
- api.departments.list()} - mapOption={mapLookupOption} - {...STORE_OBJECT} - /> - - -
-
- )} {/* ── Right column ── */} @@ -392,9 +377,64 @@ export function JobCardForm({ resourceId, initialData, onSuccess }: JobCardFormP {isEditing ? : } {isPending ? (isEditing ? "Updating..." : "Creating...") - : (isEditing ? "Update Job Card" : "Create Job Card")} + : shouldCollectCheckInDetails + ? "Continue to Check In" + : (isEditing ? "Update Job Card" : "Create Job Card")} + + + + + Check In Details + + Fill the vehicle intake details, then confirm the check in to submit the job card. + + + +
+
+ + +
+ +
+ + + + +
+ +
+ api.departments.list()} + mapOption={mapLookupOption} + {...STORE_OBJECT} + /> + + +
+
+ + + + + +
+
) } diff --git a/apps/dashboard/modules/vehicles/mileage-form.tsx b/apps/dashboard/modules/vehicles/mileage-form.tsx index 06056a5..67ad54c 100644 --- a/apps/dashboard/modules/vehicles/mileage-form.tsx +++ b/apps/dashboard/modules/vehicles/mileage-form.tsx @@ -5,7 +5,7 @@ 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 } from "@/shared/components/form" +import { Rhform, RhfDateField, RhfTextField, RhfTimeField, RhfTextareaField } from "@/shared/components/form" import { toast } from "sonner" import { useAuthApi } from "@/shared/useApi" import { useResourceForm } from "@/shared/hooks/use-resource-form" @@ -25,19 +25,31 @@ export type MileageFormProps = { // ── Default values ── const DEFAULT_VALUES: MileageFormValues = { - mileage: 0, + miles: 0, + fuel_level: undefined, date: "", time: "", + note: "", } // ── Mapping helpers ── function mapToFormValues(data: unknown): MileageFormValues { const d = (data as any)?.data ?? data ?? {} + + const date = d.date ? String(d.date).split("T")[0] : "" + const time = d.time + ? String(d.time).includes("T") + ? String(d.time).split("T")[1]?.slice(0, 8) ?? "" + : String(d.time).slice(0, 8) + : "" + return { - mileage: d.mileage ?? 0, - date: d.date || "", - time: d.time || "", + miles: d.miles ?? d.mileage ?? 0, + fuel_level: d.fuel_level ?? undefined, + date, + time, + note: d.note || "", } } @@ -56,7 +68,13 @@ export function MileageForm({ vehicleId, resourceId, initialData, onSuccess }: M const { mutate, error, isPending } = useFormMutation(form, { mutationFn: (values: MileageFormValues) => { - const payload = { mileage: values.mileage, date: values.date, time: values.time } + const payload = { + miles: values.miles, + fuel_level: values.fuel_level, + date: values.date, + time: values.time, + note: values.note || undefined, + } const promise = isEditing && resourceId ? api.vehicleDocuments.updateMileage(resourceId, payload as any) : api.vehicleDocuments.createMileage({ vehicle_id: Number(vehicleId), ...payload } as any) @@ -87,28 +105,39 @@ export function MileageForm({ vehicleId, resourceId, initialData, onSuccess }: M + +
- -
+ +