filters , order inspections , inventory items , credit notes

This commit is contained in:
2026-04-08 14:38:16 +03:00
parent 90c84a0bda
commit bb02b77be2
33 changed files with 2552 additions and 145 deletions
@@ -1,8 +1,8 @@
"use client"
import { useParams } from "next/navigation"
import { useParams, useRouter } from "next/navigation"
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
import { useState, useRef } from "react"
import { useState, useRef, useTransition } from "react"
import { Plus, Trash2, FileIcon, ImageIcon, FileTextIcon } from "lucide-react"
import { toast } from "sonner"
@@ -26,6 +26,8 @@ export default function JobCardAttachmentsPage() {
const { id: jobCardId } = useParams<{ id: string }>()
const api = useAuthApi()
const queryClient = useQueryClient()
const router = useRouter()
const [isRefreshing, startRefreshTransition] = useTransition()
const fileInputRef = useRef<HTMLInputElement>(null)
const [isUploading, setIsUploading] = useState(false)
@@ -41,6 +43,7 @@ export default function JobCardAttachmentsPage() {
onSuccess: () => {
toast.success("Attachment deleted successfully.")
queryClient.invalidateQueries({ queryKey })
startRefreshTransition(() => router.refresh())
},
onError: () => {
toast.error("Failed to delete attachment.")
@@ -74,6 +77,7 @@ export default function JobCardAttachmentsPage() {
try {
await promise
queryClient.invalidateQueries({ queryKey })
startRefreshTransition(() => router.refresh())
} finally {
setIsUploading(false)
if (fileInputRef.current) {
@@ -0,0 +1,77 @@
"use client"
import { ResourcePage } from "@/shared/data-view/resource-page"
import { ColumnHeader } from "@/shared/data-view/table-view"
import FormDialog from "@/shared/components/form-dialog"
import { InspectionForm } from "@/modules/inspections/inspection-form"
import { INSPECTION_ROUTES } from "@garage/api"
import type { InspectionsClient } from "@garage/api"
import { useRouter } from "next/navigation"
import { useJobCard } from "@/modules/job-cards/job-card-context"
export default function InspectionsPage() {
const router = useRouter()
const jobCard = useJobCard()
return (
<ResourcePage<InspectionsClient>
pageTitle="Inspections"
extraParams={{job_card_id: jobCard?.id}}
routeKey={INSPECTION_ROUTES.INDEX}
getClient={(api) => api.inspections}
onRowClick={(row) => router.push(`/sales/inspections/${(row as any).id}`)}
headerProps={({ selectedItem, invalidateQuery }) => ({
actions: (
<FormDialog title="Inspection">
{(resourceId) => (
<InspectionForm
resourceId={resourceId}
initialData={selectedItem ?? {job_card: {value: jobCard?.id, label: jobCard?.title || `Job Card #${jobCard?.id}`}}}
onSuccess={invalidateQuery}
/>
)}
</FormDialog>
),
})}
columns={({ actionsColumn }) => [
{
accessorKey: "title",
header: ({ column }) => <ColumnHeader column={column} title="Title" />,
},
{
accessorKey: "customer",
header: ({ column }) => <ColumnHeader column={column} title="Customer" />,
cell: ({ row }) => {
const c = (row.original as any).customer
return c ? `${c.first_name ?? ""} ${c.last_name ?? ""}`.trim() : "—"
},
},
{
accessorKey: "vehicle",
header: ({ column }) => <ColumnHeader column={column} title="Vehicle" />,
cell: ({ row }) => {
const v = (row.original as any).vehicle
return v ? `${v.make ?? ""} ${v.model ?? ""}`.trim() : "—"
},
},
{
accessorKey: "inspection_category",
header: ({ column }) => <ColumnHeader column={column} title="Category" />,
cell: ({ row }) => (row.original as any).inspection_category?.name ?? "—",
},
{
accessorKey: "status",
header: ({ column }) => <ColumnHeader column={column} title="Status" />,
cell: ({ row }) => {
const status = (row.original as any).status
return (
<span className={status === "completed" ? "text-green-600" : "text-yellow-600"}>
{status ?? "—"}
</span>
)
},
},
actionsColumn(),
]}
/>
)
}
@@ -39,6 +39,10 @@ export default async function JobCardDetailLayout(props: { params: Promise<{ id:
href: `/sales/job-cards/${id}/attachments`,
label: `Attachments (${docs?.length || 0})`
},
{
href: `/sales/job-cards/${id}/inspections`,
label: `Inspections (${(jobCard as any)?.inspections_count || 0})`
},
{
href: `/sales/job-cards/${id}/purchase-orders`,
label: `Purchase Orders (${jobCard?.purchase_orders_count || 0})`