"use client"
import { useAuthApi } from "@/shared/useApi"
import { useRouter } from "next/navigation"
import { Button } from "@/shared/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/shared/components/ui/dropdown-menu"
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogFooter,
} from "@/shared/components/ui/dialog"
import { ScrollArea } from "@/shared/components/ui/scroll-area"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/shared/components/ui/select"
import { Ellipsis, Pencil, Trash2, ShieldCheck, Check, X } from "lucide-react"
import { useState } from "react"
import { useMutation, useQuery } from "@tanstack/react-query"
import { toast } from "sonner"
import { EstimateForm } from "./estimate-form"
import { ESTIMATE_ROUTES } from "@garage/api"
import { DatePickerField, TimePickerField } from "@/shared/components/form"
import { cn } from "@/shared/lib/utils"
import { EmployeeCombobox, type EmployeeOption } from "../employees/employee-combobox"
type EstimateActionsProps = {
estimateId: string
}
const AUTHORISATION_METHOD_OPTIONS = [
{ value: "in_person", label: "In Person" },
{ value: "phone", label: "Phone" },
{ value: "email", label: "Email" },
{ value: "online", label: "Online" },
]
type ServiceLine = { id: number; labor_name?: string; title?: string; quantity: number; rate: number | string; description?: string }
type PartLine = { id: number; title?: string; quantity: number; rate: number | string; description?: string }
type ExpenseLine = { id: number; item_name?: string; title?: string; quantity: number; rate: number | string; description?: string }
function toggleStatus(current: string, action: "accepted" | "rejected"): string {
return current === action ? "pending" : action
}
function ItemStatusRow({
name,
rate,
quantity,
description,
status,
onToggle,
}: {
name: string
rate: number | string
quantity: number
description?: string
status: string
onToggle: (action: "accepted" | "rejected") => void
}) {
const rateNum = Number(rate)
const amount = rateNum * quantity
return (
{name}
{quantity} qty
·
Rate {rateNum.toFixed(2)}
·
{amount.toFixed(2)}
{description && (
{description}
)}
)
}
function SectionHeading({ title }: { title: string }) {
return (
{title}
)
}
export function EstimateActions({ estimateId }: EstimateActionsProps) {
const api = useAuthApi()
const router = useRouter()
const [editOpen, setEditOpen] = useState(false)
const [authOpen, setAuthOpen] = useState(false)
const [itemStatuses, setItemStatuses] = useState>({})
const [authMethod, setAuthMethod] = useState("in_person")
const [employee, setEmployee] = useState(null)
const [authDate, setAuthDate] = useState("")
const [authTime, setAuthTime] = useState("")
const { data: servicesData = [], isLoading: loadingServices } = useQuery({
queryKey: [ESTIMATE_ROUTES.SERVICES, estimateId, "auth"],
queryFn: async () => {
const res = await api.estimates.listServices(estimateId)
return ((res as any)?.data ?? []) as ServiceLine[]
},
enabled: authOpen,
})
const { data: partsData = [], isLoading: loadingParts } = useQuery({
queryKey: [ESTIMATE_ROUTES.PARTS, estimateId, "auth"],
queryFn: async () => {
const res = await api.estimates.listParts(estimateId)
return ((res as any)?.data ?? []) as PartLine[]
},
enabled: authOpen,
})
const { data: expenseItemsData = [], isLoading: loadingExpenseItems } = useQuery({
queryKey: [ESTIMATE_ROUTES.EXPENSE_ITEMS, estimateId, "auth"],
queryFn: async () => {
const res = await api.estimates.listExpenseItems(estimateId)
return ((res as any)?.data ?? []) as ExpenseLine[]
},
enabled: authOpen,
})
const isLoading = loadingServices || loadingParts || loadingExpenseItems
const hasItems = servicesData.length > 0 || partsData.length > 0 || expenseItemsData.length > 0
const getStatus = (key: string) => itemStatuses[key] ?? "pending"
const handleToggle = (key: string, action: "accepted" | "rejected") =>
setItemStatuses((prev) => ({ ...prev, [key]: toggleStatus(prev[key] ?? "pending", action) }))
const handleDelete = async () => {
await api.estimates.destroy(estimateId)
router.push("/sales/estimates")
}
const authMutation = useMutation({
mutationFn: () =>
api.estimates.storeAuthorisation(estimateId, {
estimate_services: servicesData.map((s) => ({ id: s.id, status: getStatus(`s-${s.id}`) })),
estimate_parts: partsData.map((p) => ({ id: p.id, status: getStatus(`p-${p.id}`) })),
estimate_expense_items: expenseItemsData.map((e) => ({ id: e.id, status: getStatus(`e-${e.id}`) })),
authorisation_method: authMethod,
employee_id: employee ? Number(employee.value) : undefined,
}),
onSuccess: () => {
toast.success("Authorisation stored successfully")
setAuthOpen(false)
router.refresh()
},
onError: () => toast.error("Failed to store authorisation"),
})
const openAuthDialog = () => {
setItemStatuses({})
setAuthMethod("in_person")
setEmployee(null)
const n = new Date()
setAuthDate(n.toISOString().split("T")[0])
setAuthTime(`${String(n.getHours()).padStart(2, "0")}:${String(n.getMinutes()).padStart(2, "0")}:00`)
setAuthOpen(true)
}
return (
<>
setEditOpen(true)}>
Edit
Store Authorisation
Delete
{/* Edit Dialog */}
{/* Authorisation Dialog */}
>
)
}