diff --git a/apps/dashboard/app/(authenticated)/sales/invoice/[id]/layout.tsx b/apps/dashboard/app/(authenticated)/sales/invoice/[id]/layout.tsx index 5f49848..ea5d981 100644 --- a/apps/dashboard/app/(authenticated)/sales/invoice/[id]/layout.tsx +++ b/apps/dashboard/app/(authenticated)/sales/invoice/[id]/layout.tsx @@ -16,7 +16,6 @@ export default async function InvoiceDetailLayout(props: { params: Promise<{ id: return ( } diff --git a/apps/dashboard/app/(authenticated)/sales/invoice/page.tsx b/apps/dashboard/app/(authenticated)/sales/invoice/page.tsx index c655779..780427d 100644 --- a/apps/dashboard/app/(authenticated)/sales/invoice/page.tsx +++ b/apps/dashboard/app/(authenticated)/sales/invoice/page.tsx @@ -5,18 +5,74 @@ import { ResourcePage } from "@/shared/data-view/resource-page" import { ColumnHeader } from "@/shared/data-view/table-view" import FormDialog from "@/shared/components/form-dialog" import { InvoiceForm } from "@/modules/invoices/invoice-form" +import { Badge } from "@/shared/components/ui/badge" +import { formatCurrency, formatDate, formatEnum } from "@/shared/utils/formatters" import { INVOICE_ROUTES } from "@garage/api" import type { InvoicesClient } from "@garage/api" type InvoiceItem = { id: number subject?: string + invoice_title?: string invoice_number?: string customer_name?: string status?: string invoice_date?: string due_date?: string created_at?: string + total?: number | string + balance_due?: number | string + customer?: { + first_name?: string + last_name?: string + company_name?: string + phone?: string + } | null + vehicle?: { + make?: string + model?: string + sub_model?: string + year?: number | string + license_plate?: string + } | null +} + +function getCustomerLabel(item: InvoiceItem): string { + const firstName = item.customer?.first_name?.trim() + const lastName = item.customer?.last_name?.trim() + const fullName = [firstName, lastName].filter(Boolean).join(" ").trim() + + return fullName || item.customer_name || item.customer?.company_name || "—" +} + +function getVehicleLabel(item: InvoiceItem): string { + const vehicle = item.vehicle + if (!vehicle) return "—" + + const core = [vehicle.make, vehicle.model, vehicle.sub_model].filter(Boolean).join(" ") + const suffix = [vehicle.year, vehicle.license_plate].filter(Boolean).join(" • ") + + if (core && suffix) return `${core} (${suffix})` + return core || suffix || "—" +} + +function getDueMeta(dueDate?: string) { + if (!dueDate) return { text: "No due date", tone: "muted" as const } + + const due = new Date(dueDate) + if (isNaN(due.getTime())) return { text: "Invalid due date", tone: "muted" as const } + + const today = new Date() + today.setHours(0, 0, 0, 0) + due.setHours(0, 0, 0, 0) + + const days = Math.ceil((due.getTime() - today.getTime()) / (1000 * 60 * 60 * 24)) + + if (days < 0) return { text: `${Math.abs(days)} day(s) overdue`, tone: "danger" as const } + if (days === 0) return { text: "Due today", tone: "warning" as const } + if (days <= 3) return { text: `Due in ${days} day(s)`, tone: "warning" as const } + + return { text: `Due in ${days} day(s)`, tone: "ok" as const } } export default function InvoicesPage() { @@ -44,15 +100,66 @@ export default function InvoicesPage() { columns={({ actionsColumn }) => [ { accessorKey: "subject", - header: ({ column }) => , + header: ({ column }) => , + cell: ({ row }) => { + const item = row.original as unknown as InvoiceItem + const title = item.subject || item.invoice_title || "Untitled invoice" + + return ( +
+

{title}

+

+ {item.invoice_number || "No invoice number"} +

+
+ ) + }, }, { accessorKey: "invoice_number", header: ({ column }) => , + cell: ({ row }) => { + const item = row.original as unknown as InvoiceItem + + return ( + + {item.invoice_number || "—"} + + ) + }, }, { accessorKey: "customer_name", header: ({ column }) => , + cell: ({ row }) => { + const item = row.original as unknown as InvoiceItem + const customerLabel = getCustomerLabel(item) + + return ( +
+

{customerLabel}

+

+ {item.customer?.phone || item.customer?.company_name || "—"} +

+
+ ) + }, + }, + { + id: "vehicle", + header: ({ column }) => , + cell: ({ row }) => { + const item = row.original as unknown as InvoiceItem + + return ( +
+

{getVehicleLabel(item)}

+

+ {item.vehicle?.license_plate || "—"} +

+
+ ) + }, }, { accessorKey: "status", @@ -60,27 +167,71 @@ export default function InvoicesPage() { cell: ({ row }) => { const item = row.original as unknown as InvoiceItem const status = item.status - const colorMap: Record = { - draft: "text-muted-foreground", - open: "text-blue-600", - paid: "text-green-600", - overdue: "text-red-600", - void: "text-gray-400", + const classMap: Record = { + draft: "bg-slate-100 text-slate-700", + open: "bg-blue-100 text-blue-700", + paid: "bg-emerald-100 text-emerald-700", + over_due: "bg-red-100 text-red-700", + un_paid: "bg-orange-100 text-orange-700", + partially_paid: "bg-amber-100 text-amber-700", + void: "bg-zinc-100 text-zinc-700", } + return ( - - {status ? status.charAt(0).toUpperCase() + status.slice(1) : "—"} - + + {formatEnum(status) || "—"} + ) }, }, { accessorKey: "invoice_date", header: ({ column }) => , + cell: ({ row }) => { + const item = row.original as unknown as InvoiceItem + return formatDate(item.invoice_date) + }, }, { accessorKey: "due_date", header: ({ column }) => , + cell: ({ row }) => { + const item = row.original as unknown as InvoiceItem + const dueMeta = getDueMeta(item.due_date) + const toneClassMap = { + danger: "text-red-600", + warning: "text-amber-600", + ok: "text-emerald-600", + muted: "text-muted-foreground", + } + + return ( +
+

{formatDate(item.due_date)}

+

+ {dueMeta.text} +

+
+ ) + }, + }, + { + id: "amounts", + header: ({ column }) => , + cell: ({ row }) => { + const item = row.original as unknown as InvoiceItem + + return ( +
+

+ Total: {formatCurrency(item.total ?? 0)} +

+

+ Due: {formatCurrency(item.balance_due ?? 0)} +

+
+ ) + }, }, actionsColumn(), ]} diff --git a/apps/dashboard/app/(authenticated)/sales/job-cards/page.tsx b/apps/dashboard/app/(authenticated)/sales/job-cards/page.tsx index e83069e..561465d 100644 --- a/apps/dashboard/app/(authenticated)/sales/job-cards/page.tsx +++ b/apps/dashboard/app/(authenticated)/sales/job-cards/page.tsx @@ -67,7 +67,7 @@ export default function JobCardsPage() { actions: (
- + {(resourceId, {close}) => ( >({}) @@ -218,6 +220,10 @@ export function EstimateActions({ estimateId }: EstimateActionsProps) { Edit + print("estimate", estimateId, "print")} disabled={isPrinting}> + + {isPrinting ? "Printing..." : "Print"} + Store Authorisation diff --git a/apps/dashboard/modules/inspections/inspection-actions.tsx b/apps/dashboard/modules/inspections/inspection-actions.tsx index 4777161..110467c 100644 --- a/apps/dashboard/modules/inspections/inspection-actions.tsx +++ b/apps/dashboard/modules/inspections/inspection-actions.tsx @@ -12,10 +12,11 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/shared/components/ui/dropdown-menu" -import { Ellipsis, Pencil, Trash2, Play, CheckCircle2 } from "lucide-react" +import { Ellipsis, Pencil, Trash2, Play, CheckCircle2, Printer } from "lucide-react" import { toast } from "sonner" import { useFormDialog } from "@/shared/components/form-dialog" import { InspectionForm } from "./inspection-form" +import { useDocumentPrint } from "@/shared/hooks/use-document-print" type InspectionActionsProps = { inspectionId: string @@ -32,6 +33,7 @@ export function InspectionActions({ inspectionId, status, onStatusChange }: Insp const api = useAuthApi() const router = useRouter() const editDialog = useFormDialog("inspection-details-edit") + const { print, isPrinting } = useDocumentPrint() const handleDelete = async () => { const promise = api.inspections.destroy(inspectionId) @@ -73,6 +75,10 @@ export function InspectionActions({ inspectionId, status, onStatusChange }: Insp Edit + print("inspection", inspectionId, "print")} disabled={isPrinting}> + + {isPrinting ? "Printing..." : "Print"} + {transition && ( handleStatusChange(transition.next)}> diff --git a/apps/dashboard/modules/invoices/invoice-actions.tsx b/apps/dashboard/modules/invoices/invoice-actions.tsx index dab9c8d..f8f58ec 100644 --- a/apps/dashboard/modules/invoices/invoice-actions.tsx +++ b/apps/dashboard/modules/invoices/invoice-actions.tsx @@ -2,7 +2,6 @@ import { useAuthApi } from "@/shared/useApi" import { useRouter } from "next/navigation" -import { useState } from "react" import { Button } from "@/shared/components/ui/button" import { DropdownMenu, @@ -10,10 +9,8 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from "@/shared/components/ui/dropdown-menu" -import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/shared/components/ui/dialog" -import { Ellipsis, Pencil, Trash2 } from "lucide-react" -import { InvoiceEditForm } from "./invoice-edit-form" -import { useInvoice } from "./invoice-context" +import { Ellipsis, Printer, Trash2 } from "lucide-react" +import { useDocumentPrint } from "@/shared/hooks/use-document-print" type InvoiceActionsProps = { invoiceId: string @@ -22,12 +19,7 @@ type InvoiceActionsProps = { export function InvoiceActions({ invoiceId }: InvoiceActionsProps) { const api = useAuthApi() const router = useRouter() - const [isEditOpen, setIsEditOpen] = useState(false) - const invoice = useInvoice() - const handleEditSuccess = () => { - setIsEditOpen(false) - router.refresh() - } + const { print, isPrinting } = useDocumentPrint() const handleDelete = async () => { await api.invoices.destroy(invoiceId) @@ -43,31 +35,16 @@ export function InvoiceActions({ invoiceId }: InvoiceActionsProps) { - {/* setIsEditOpen(true)}> - - Edit - */} + print("invoice", invoiceId, "print")} disabled={isPrinting}> + + {isPrinting ? "Printing..." : "Print"} + Delete - - {/* - - - Edit Invoice - - - - */} ) } diff --git a/apps/dashboard/modules/job-cards/job-card-expense-item-form.tsx b/apps/dashboard/modules/job-cards/job-card-expense-item-form.tsx index a1dd230..c2bd0b7 100644 --- a/apps/dashboard/modules/job-cards/job-card-expense-item-form.tsx +++ b/apps/dashboard/modules/job-cards/job-card-expense-item-form.tsx @@ -26,9 +26,18 @@ import { useJobCard } from "./job-card-context" const relationFieldSchema = z.object({ value: z.string(), label: z.string() }).nullable() +const requiredRelationFieldSchema = relationFieldSchema.superRefine((value, ctx) => { + if (!value?.value) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "This field is required", + }) + } +}) + const jobCardExpenseItemFormSchema = z.object({ expense_item: relationFieldSchema, - department: relationFieldSchema.optional(), + department: requiredRelationFieldSchema, tax: relationFieldSchema.optional(), quantity: z.coerce.number().min(1, "Quantity is required"), rate: z.coerce.number().min(0, "Rate is required"), @@ -62,14 +71,22 @@ const DEFAULT_VALUES: JobCardExpenseItemFormValues = { const STORE_OBJECT = { getOptionValue: (o: any) => o, getOptionLabel: (o: any) => o.label } +function mapDepartmentOption(item: any) { + const id = item?.id ?? item?.department_id + return { + value: String(id), + label: item?.name ?? item?.title ?? item?.department_name ?? String(id), + } +} + function mapToFormValues(data: unknown): JobCardExpenseItemFormValues { const d = (data as any) ?? {} return { expense_item: d.expense_item ? { value: String(d.expense_item.id), label: d.expense_item.item_name ?? String(d.expense_item.id) } : null, - department: d.department - ? { value: String(d.department.id), label: d.department.name ?? String(d.department.id) } + department: (d.department || d.department_id != null) + ? mapDepartmentOption(d.department ?? { id: d.department_id, name: d.department_name ?? d.department_title }) : null, tax: d.tax_id != null ? { value: String(d.tax_id), label: formatTaxLabel(d.tax, String(d.tax_id)) } @@ -82,6 +99,18 @@ function mapToFormValues(data: unknown): JobCardExpenseItemFormValues { } } +function mapJobCardDepartmentToRelation(jobCard: unknown) { + const d = (jobCard as any) ?? {} + const departmentId = d.department_id ?? d.department?.id + if (departmentId == null) { + return null + } + return { + value: String(departmentId), + label: d.department?.name ?? d.department_name ?? d.department_title ?? String(departmentId), + } +} + // ── Component ── export function JobCardExpenseItemForm({ @@ -100,7 +129,10 @@ export function JobCardExpenseItemForm({ resolver: zodResolver(jobCardExpenseItemFormSchema) as any, defaultValues: initialData ? mapToFormValues(initialData) - : DEFAULT_VALUES, + : { + ...DEFAULT_VALUES, + department: mapJobCardDepartmentToRelation(jobCard), + }, }) const [error, setError] = React.useState(null) @@ -126,10 +158,15 @@ export function JobCardExpenseItemForm({ } ) } else { + if (!values.department?.value) { + setError("Department is required") + return + } + await toast.promise( api.jobCards.addExpenseItem(jobCardId, { expense_item_id: values.expense_item ? Number(values.expense_item.value) : undefined, - department_id: values.department ? Number(values.department.value) : undefined, + department_id: Number(values.department.value), tax_id: values.tax ? Number(values.tax.value) : undefined, quantity: values.quantity, rate: values.rate, @@ -215,12 +252,10 @@ export function JobCardExpenseItemForm({ name="department" label="Department" placeholder="Select department" + required queryKey={[DEPARTMENT_ROUTES.INDEX]} listFn={() => api.departments.list()} - mapOption={(item: any) => ({ - value: String(item.id), - label: item.name ?? String(item.id), - })} + mapOption={mapDepartmentOption} createForm={(props) => } createLabel="Department" {...STORE_OBJECT} diff --git a/apps/dashboard/modules/job-cards/job-card-form.tsx b/apps/dashboard/modules/job-cards/job-card-form.tsx index 34f55d2..23ebf09 100644 --- a/apps/dashboard/modules/job-cards/job-card-form.tsx +++ b/apps/dashboard/modules/job-cards/job-card-form.tsx @@ -118,7 +118,7 @@ function mapToFormValues(data: unknown): JobCardFormValues { customer: toRelation(d.customer_id, d.customer ? `${d.customer.first_name} ${d.customer.last_name}` : undefined), vehicle: toRelation(d.vehicle_id, d.vehicle ? (d.vehicle.plate_number ?? `${d.vehicle.make ?? ""} ${d.vehicle.model ?? ""}`.trim()) : undefined), estimate: toRelation(d.estimate_id, d.estimate?.estimate_number), - department: toRelation(d.department_id, d.department?.name), + department: toRelation(d.department_id, d.department?.name ?? d.department_name ?? d.department_title), service_writer: toRelation(d.service_writer_id, d.service_writer ? `${d.service_writer.first_name} ${d.service_writer.last_name}` : undefined), primary_technician: toRelation(d.primary_technician_id, d.primary_technician ? `${d.primary_technician.first_name} ${d.primary_technician.last_name}` : undefined), sales_person: toRelation(d.sales_person_id, d.sales_person ? `${d.sales_person.first_name} ${d.sales_person.last_name}` : undefined), @@ -211,11 +211,13 @@ function mapFormToPayload(values: JobCardFormValues) { // ── Shared mapOption for async selects ── -const mapLookupOption = (item: any) => ({ +const mapLookupOption = (item: any, labelKey: string = "name") => ({ value: String(item.id), - label: item.name, + label: item[labelKey], }) + + const mapEmployeeOption = (item: any) => ({ value: String(item.id), label: `${item.first_name} ${item.last_name}`, @@ -320,7 +322,7 @@ export function JobCardForm({ resourceId, initialData, onSuccess }: JobCardFormP placeholder="Select insurance type" queryKey={[INSURANCE_TYPE_ROUTES.INDEX]} listFn={() => api.insuranceTypes.list()} - mapOption={mapLookupOption} + mapOption={(op) => (mapLookupOption(op, 'title'))} {...STORE_OBJECT} />
@@ -341,7 +343,7 @@ export function JobCardForm({ resourceId, initialData, onSuccess }: JobCardFormP label="Service Writer" placeholder="Select service writer" {...STORE_OBJECT} - /> + /> api.departments.list()} mapOption={mapLookupOption} diff --git a/apps/dashboard/modules/job-cards/job-card-part-form.tsx b/apps/dashboard/modules/job-cards/job-card-part-form.tsx index 35206f4..0ade8b7 100644 --- a/apps/dashboard/modules/job-cards/job-card-part-form.tsx +++ b/apps/dashboard/modules/job-cards/job-card-part-form.tsx @@ -62,14 +62,22 @@ const DEFAULT_VALUES: JobCardPartFormValues = { const STORE_OBJECT = { getOptionValue: (o: any) => o, getOptionLabel: (o: any) => o.label } +function mapDepartmentOption(item: any) { + const id = item?.id ?? item?.department_id + return { + value: String(id), + label: item?.name ?? item?.title ?? item?.department_name ?? String(id), + } +} + function mapToFormValues(data: unknown): JobCardPartFormValues { const d = (data as any) ?? {} return { part: d.part ? { value: String(d.part.id), label: d.part.title ?? String(d.part.id) } : null, - department: d.department - ? { value: String(d.department.id), label: d.department.name ?? String(d.department.id) } + department: (d.department || d.department_id != null) + ? mapDepartmentOption(d.department ?? { id: d.department_id, name: d.department_name ?? d.department_title }) : null, tax: d.tax_id != null ? { value: String(d.tax_id), label: formatTaxLabel(d.tax, String(d.tax_id)) } @@ -82,6 +90,18 @@ function mapToFormValues(data: unknown): JobCardPartFormValues { } } +function mapJobCardDepartmentToRelation(jobCard: unknown) { + const d = (jobCard as any) ?? {} + const departmentId = d.department_id ?? d.department?.id + if (departmentId == null) { + return null + } + return { + value: String(departmentId), + label: d.department?.name ?? d.department_name ?? d.department_title ?? String(departmentId), + } +} + // ── Component ── export function JobCardPartForm({ @@ -100,7 +120,10 @@ export function JobCardPartForm({ resolver: zodResolver(jobCardPartFormSchema) as any, defaultValues: initialData ? mapToFormValues(initialData) - : DEFAULT_VALUES, + : { + ...DEFAULT_VALUES, + department: mapJobCardDepartmentToRelation(jobCard), + }, }) const [error, setError] = React.useState(null) @@ -126,10 +149,15 @@ export function JobCardPartForm({ } ) } else { + if (!values.department?.value) { + setError("Department is required") + return + } + await toast.promise( api.jobCards.addPart(jobCardId, { part_id: values.part ? Number(values.part.value) : undefined, - department_id: values.department ? Number(values.department.value) : undefined, + department_id: Number(values.department.value), tax_id: values.tax ? Number(values.tax.value) : undefined, quantity: values.quantity, rate: values.rate, @@ -215,12 +243,10 @@ export function JobCardPartForm({ name="department" label="Department" placeholder="Select department" + required queryKey={[DEPARTMENT_ROUTES.INDEX]} listFn={() => api.departments.list()} - mapOption={(item: any) => ({ - value: String(item.id), - label: item.name ?? String(item.id), - })} + mapOption={mapDepartmentOption} createForm={(props) => } createLabel="Department" {...STORE_OBJECT} diff --git a/apps/dashboard/modules/job-cards/job-card-service-form.tsx b/apps/dashboard/modules/job-cards/job-card-service-form.tsx index 2faa41c..e23bb9f 100644 --- a/apps/dashboard/modules/job-cards/job-card-service-form.tsx +++ b/apps/dashboard/modules/job-cards/job-card-service-form.tsx @@ -71,14 +71,22 @@ const DEFAULT_VALUES: JobCardServiceFormValues = { const STORE_OBJECT = { getOptionValue: (o: any) => o, getOptionLabel: (o: any) => o.label } +function mapDepartmentOption(item: any) { + const id = item?.id ?? item?.department_id + return { + value: String(id), + label: item?.name ?? item?.title ?? item?.department_name ?? String(id), + } +} + function mapToFormValues(data: unknown): JobCardServiceFormValues { const d = (data as any) ?? {} return { service: d.service ? { value: String(d.service.id), label: d.service.labor_name ?? String(d.service.id) } : null, - department: d.department - ? { value: String(d.department.id), label: d.department.name ?? String(d.department.id) } + department: (d.department || d.department_id != null) + ? mapDepartmentOption(d.department ?? { id: d.department_id, name: d.department_name ?? d.department_title }) : undefined as any, tax: d.tax_id != null ? { value: String(d.tax_id), label: formatTaxLabel(d.tax, String(d.tax_id)) } @@ -97,6 +105,18 @@ function mapToFormValues(data: unknown): JobCardServiceFormValues { } } +function mapJobCardDepartmentToRelation(jobCard: unknown) { + const d = (jobCard as any) ?? {} + const departmentId = d.department_id ?? d.department?.id + if (departmentId == null) { + return undefined as any + } + return { + value: String(departmentId), + label: d.department?.name ?? d.department_name ?? d.department_title ?? String(departmentId), + } +} + const RATE_TYPE_OPTIONS = RateType.map((v) => ({ value: v, label: v === "flat_rate" ? "Flat Rate" : "Hourly", @@ -120,7 +140,10 @@ export function JobCardServiceForm({ resolver: zodResolver(jobCardServiceFormSchema) as any, defaultValues: initialData ? mapToFormValues(initialData) - : DEFAULT_VALUES, + : { + ...DEFAULT_VALUES, + department: mapJobCardDepartmentToRelation(jobCard), + }, }) const rateType = form.watch("rate_type") @@ -149,10 +172,15 @@ export function JobCardServiceForm({ } ) } else { + if (!values.department?.value) { + setError("Department is required") + return + } + await toast.promise( api.jobCards.addService(jobCardId, { service_id: values.service ? Number(values.service.value) : undefined, - department_id: values.department ? Number(values.department.value) : undefined, + department_id: Number(values.department.value), tax_id: values.tax ? Number(values.tax.value) : undefined, rate_type: values.rate_type || undefined, labor_rate_id: values.labor_rate ? Number(values.labor_rate.value) : undefined, @@ -283,10 +311,7 @@ export function JobCardServiceForm({ required queryKey={[DEPARTMENT_ROUTES.INDEX]} listFn={() => api.departments.list()} - mapOption={(item: any) => ({ - value: String(item.id), - label: item.name ?? String(item.id), - })} + mapOption={mapDepartmentOption} createForm={(props) => } createLabel="Department" {...STORE_OBJECT} diff --git a/apps/dashboard/modules/purchase-orders/purchase-order-actions.tsx b/apps/dashboard/modules/purchase-orders/purchase-order-actions.tsx index 7c5cbef..e786941 100644 --- a/apps/dashboard/modules/purchase-orders/purchase-order-actions.tsx +++ b/apps/dashboard/modules/purchase-orders/purchase-order-actions.tsx @@ -10,8 +10,9 @@ import { DropdownMenuTrigger, } from "@/shared/components/ui/dropdown-menu" import { confirm } from "@/shared/components/confirm-dialog" -import { Ellipsis, Pencil, Trash2 } from "lucide-react" +import { Ellipsis, Printer, Trash2 } from "lucide-react" import { toast } from "sonner" +import { useDocumentPrint } from "@/shared/hooks/use-document-print" type PurchaseOrderActionsProps = { purchaseOrderId: string @@ -20,6 +21,7 @@ type PurchaseOrderActionsProps = { export function PurchaseOrderActions({ purchaseOrderId }: PurchaseOrderActionsProps) { const api = useAuthApi() const router = useRouter() + const { print, isPrinting } = useDocumentPrint() const handleDelete = async () => { const confirmed = await confirm({ @@ -48,6 +50,10 @@ export function PurchaseOrderActions({ purchaseOrderId }: PurchaseOrderActionsPr + print("purchase_order", purchaseOrderId, "print")} disabled={isPrinting}> + + {isPrinting ? "Printing..." : "Print"} + Delete diff --git a/apps/dashboard/shared/utils/formatters.ts b/apps/dashboard/shared/utils/formatters.ts index fce0a55..fb82a47 100644 --- a/apps/dashboard/shared/utils/formatters.ts +++ b/apps/dashboard/shared/utils/formatters.ts @@ -91,7 +91,7 @@ export function formatNumber(value?: number | string | null): string { */ export function formatCurrency( value?: number | string | null, - currency = "USD", + currency = "AED", locale?: string, ): string { if (value == null || value === "") return "—" diff --git a/packages/api/src/clients/document-print.ts b/packages/api/src/clients/document-print.ts index 09f7d25..608173f 100644 --- a/packages/api/src/clients/document-print.ts +++ b/packages/api/src/clients/document-print.ts @@ -5,7 +5,15 @@ export const DOCUMENT_PRINT_ROUTES = { INDEX: "/api/document-print", } as const satisfies Record -export type DocumentPrintType = "job_card" | "invoice" | "estimate" | "purchase_order" | "bill" | string +export type DocumentPrintType = + | "inspection" + | "estimate" + | "job_card" + | "invoice" + | "payment_received" + | "purchase_order" + | "bill" + | string export type DocumentPrintMode = "print" | "download"