"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 */} Edit Estimate { setEditOpen(false) router.refresh() }} /> {/* Authorisation Dialog */} Store Authorisation
{isLoading && (

Loading line items…

)} {!isLoading && !hasItems && (

No line items on this estimate.

)} {servicesData.length > 0 && (
{servicesData.map((s) => ( handleToggle(`s-${s.id}`, a)} /> ))}
)} {partsData.length > 0 && (
{partsData.map((p) => ( handleToggle(`p-${p.id}`, a)} /> ))}
)} {expenseItemsData.length > 0 && (
{expenseItemsData.map((e) => ( handleToggle(`e-${e.id}`, a)} /> ))}
)}

Date

setAuthDate(v ?? "")} />

Time

setAuthTime(v ?? "")} />

Method

Employee

) }