- Implemented TemplateCheckpointEditDialog for creating and editing inspection checkpoints. - Added VendorActions component for managing vendor actions including edit, activate/deactivate, and delete. - Created VendorContext for managing vendor state across components. - Developed VendorGeneralInfo component to display detailed vendor information. - Introduced AedSymbol and Money components for consistent currency representation. - Added PromptDialog for user input prompts throughout the application. - Implemented RelationLink component for unified related-data display in CRUD tables. - Created InspectionTemplatesClient for API interactions related to inspection templates.
91 lines
3.2 KiB
TypeScript
91 lines
3.2 KiB
TypeScript
"use client"
|
|
|
|
import { useState } from "react"
|
|
import { FileText } from "lucide-react"
|
|
import { useQueryClient } from "@tanstack/react-query"
|
|
import { Button } from "@/shared/components/ui/button"
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/shared/components/ui/dialog"
|
|
import { ScrollArea } from "@/shared/components/ui/scroll-area"
|
|
import { BillForm } from "@/modules/bills/bill-form"
|
|
import { usePurchaseOrder } from "./purchase-order-context"
|
|
import { getFullName } from "@/shared/utils/getFullName"
|
|
import { getTodayDate } from "@/shared/lib/utils"
|
|
import { BILL_ROUTES } from "@garage/api"
|
|
|
|
// Build an API-shaped seed that BillForm's `mapToFormValues` will consume,
|
|
// so the dialog opens with PO fields, vendor/department/job_card relations,
|
|
// and line items pre-filled.
|
|
function mapPOToBillSeed(po: Record<string, any>) {
|
|
return {
|
|
title: po.title ?? "",
|
|
notes: po.notes ?? "",
|
|
bill_date: getTodayDate(),
|
|
|
|
vendor_id: po.vendor_id,
|
|
vendor: po.vendor ? { name: getFullName(po.vendor) } : undefined,
|
|
|
|
department_id: po.department_id,
|
|
department: po.department,
|
|
|
|
job_card_id: po.job_card_id,
|
|
job_card: po.job_card
|
|
? { order_number: po.job_card.order_number ?? po.job_card.title }
|
|
: undefined,
|
|
|
|
// Link bill back to the source PO
|
|
purchase_order_id: po.id,
|
|
purchase_order: { order_number: po.order_number ?? po.title },
|
|
|
|
parts: (po.parts ?? []).map((p: any) => ({
|
|
part_id: p.part_id ?? p.id,
|
|
part: { name: p.part?.title ?? p.part?.name ?? p.title ?? "" },
|
|
quantity: Number(p.quantity) || 1,
|
|
rate: Number(p.rate) || 0,
|
|
description: p.description ?? "",
|
|
})),
|
|
}
|
|
}
|
|
|
|
export function CreateBillFromPOButton() {
|
|
const [open, setOpen] = useState(false)
|
|
const poContext = usePurchaseOrder()
|
|
const queryClient = useQueryClient()
|
|
|
|
if (!poContext) return null
|
|
|
|
const initialData = poContext.data ? mapPOToBillSeed(poContext.data) : undefined
|
|
|
|
return (
|
|
<>
|
|
<Button variant="outline" size="sm" onClick={() => setOpen(true)}>
|
|
<FileText className="me-2 size-4" />
|
|
Create Bill
|
|
</Button>
|
|
|
|
<Dialog open={open} onOpenChange={setOpen}>
|
|
<DialogContent className="min-w-6xl">
|
|
<DialogHeader>
|
|
<DialogTitle>Create Bill from Purchase Order</DialogTitle>
|
|
</DialogHeader>
|
|
<ScrollArea className="max-h-[75vh] px-1">
|
|
<BillForm
|
|
initialData={initialData}
|
|
onSuccess={() => {
|
|
// Invalidate bills list so when user lands on the bills
|
|
// page the new bill is present without a manual refresh.
|
|
queryClient.invalidateQueries({ queryKey: [BILL_ROUTES.INDEX] })
|
|
setOpen(false)
|
|
}}
|
|
/>
|
|
</ScrollArea>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</>
|
|
)
|
|
}
|