"use client" import { use, useState } from "react" import { useRouter } from "next/navigation" import { useQuery, useQueryClient } from "@tanstack/react-query" import { useAuthApi } from "@/shared/useApi" import { ColumnHeader, DataTable } from "@/shared/data-view/table-view" import { Button } from "@/shared/components/ui/button" import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, } from "@/shared/components/ui/dialog" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/shared/components/ui/dropdown-menu" import { confirm } from "@/shared/components/confirm-dialog" import { toast } from "sonner" import { Ellipsis, Plus } from "lucide-react" import type { ColumnDef } from "@tanstack/react-table" import { JobCardExpenseItemForm } from "@/modules/job-cards/job-card-expense-item-form" import { formatDate } from "@/shared/utils/formatters" // TODO: expense items invalidation is not working properly when create new expense item line. Need to investigate why and fix it. export default function JobCardExpenseItemsPage({ params, }: { params: Promise<{ id: string }> }) { const { id: jobCardId } = use(params) const api = useAuthApi() const queryClient = useQueryClient() const router = useRouter() const queryKey = ["job-card-expense-items", jobCardId] const [dialogOpen, setDialogOpen] = useState(false) const [editItem, setEditItem] = useState(null) const { data, isLoading } = useQuery({ queryKey, queryFn: () => api.jobCards.getExpenseItems(jobCardId), }) const rows = (data as any)?.data ?? [] const invalidate = () => queryClient.invalidateQueries({ queryKey }).then(() => router.refresh()) async function handleDelete(row: any) { const confirmed = await confirm({ title: "Delete this expense item?", description: `Remove "${row.expense_item?.item_name ?? "this expense item"}" from the job card?`, }) if (!confirmed) return const promise = api.jobCards.deleteExpenseItem(jobCardId, row.id) toast.promise(promise, { loading: "Deleting...", success: "Expense item deleted", error: "Failed to delete expense item", }) await promise invalidate() } const columns: ColumnDef[] = [ { accessorKey: "expense_item.item_name", header: ({ column }) => , cell: ({ row }) => { const item = row.original.expense_item return item ? (
{item.item_name} {item.sku && ( {item.sku} )}
) : "—" }, }, { accessorKey: "quantity", header: ({ column }) => , cell: ({ row }) => row.original.quantity ?? "—", }, { accessorKey: "rate", header: ({ column }) => , cell: ({ row }) => { const val = row.original.rate return val != null ? `$${Number(val).toFixed(2)}` : "—" }, }, { accessorKey: "discount_amount", header: ({ column }) => , cell: ({ row }) => { const val = row.original.discount_amount return val != null && val > 0 ? `$${Number(val).toFixed(2)}` : "—" }, }, { accessorKey: "tax_id", header: ({ column }) => , cell: ({ row }) => row.original.tax_id ?? "—", }, { accessorKey: "department.name", header: ({ column }) => , cell: ({ row }) => row.original.department?.name || "—", }, { accessorKey: "description", header: ({ column }) => , cell: ({ row }) => row.original.description || "—", }, { accessorKey: "created_at", header: ({ column }) => , cell: ({ row }) => formatDate(row.original.created_at), }, { id: "actions", cell: ({ row }) => ( { setEditItem(row.original) setDialogOpen(true) }} > Edit handleDelete(row.original)} > Delete ), }, ] return (
{ setDialogOpen(open) if (!open) setEditItem(null) }} > {editItem ? "Edit Expense Item" : "Add Expense Item"} { setDialogOpen(false) setEditItem(null) invalidate() }} onCancel={() => { setDialogOpen(false) setEditItem(null) }} />
) }