- Introduced ShareDocumentButton component for sharing documents. - Added ShareDocumentDialog for email and WhatsApp sharing options. - Integrated document sharing in estimates, invoices, inspections, job cards, bills, and purchase orders. - Implemented useDocumentShare hook for handling share logic. - Created DocumentShareClient for API interactions related to document sharing. - Updated layouts and actions to include sharing options for relevant entities.
67 lines
2.5 KiB
TypeScript
67 lines
2.5 KiB
TypeScript
"use client"
|
|
|
|
import { useState } from "react"
|
|
import { ClipboardList, Loader2 } from "lucide-react"
|
|
import { useRouter } from "next/navigation"
|
|
import { ApiError } from "@garage/api"
|
|
import { Button } from "@/shared/components/ui/button"
|
|
import { confirm } from "@/shared/components/confirm-dialog"
|
|
import { toast } from "sonner"
|
|
import { useAuthApi } from "@/shared/useApi"
|
|
import { useEstimate } from "./estimate-context"
|
|
|
|
export function CreateJobCardFromEstimateButton() {
|
|
const [isConverting, setIsConverting] = useState(false)
|
|
const estimateContext = useEstimate()
|
|
const api = useAuthApi()
|
|
const router = useRouter()
|
|
|
|
const estimateId = String(estimateContext?.id ?? "")
|
|
|
|
if (!estimateContext || !estimateId) return null
|
|
|
|
const handleConvert = async () => {
|
|
const confirmed = await confirm({
|
|
title: "Generate Job Card",
|
|
description: "This will create a job card from this estimate. Do you want to continue?",
|
|
confirmLabel: "Generate",
|
|
})
|
|
|
|
if (!confirmed) return
|
|
|
|
setIsConverting(true)
|
|
const promise = api.estimates.convertToJobCard(estimateId, {})
|
|
toast.promise(promise, {
|
|
loading: "Generating job card...",
|
|
success: "Estimate converted to job card successfully",
|
|
error: (error: unknown) =>
|
|
error instanceof ApiError && error.status === 409
|
|
? "A job card already exists for this estimate."
|
|
: "Failed to convert estimate to job card",
|
|
})
|
|
try {
|
|
const response = await promise
|
|
const jobCardId = response?.data?.id
|
|
if (jobCardId) {
|
|
router.push(`/sales/job-cards/${jobCardId}`)
|
|
return
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof ApiError && error.status === 409) {
|
|
const jobCardId = (error.payload?.data as { job_card_id?: number } | undefined)?.job_card_id
|
|
if (jobCardId) {
|
|
router.push(`/sales/job-cards/${jobCardId}`)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
setIsConverting(false)
|
|
}
|
|
|
|
return (
|
|
<Button variant="outline" size="sm" onClick={handleConvert} disabled={isConverting}>
|
|
{isConverting ? <Loader2 className="me-2 size-4 animate-spin" /> : <ClipboardList className="me-2 size-4" />}
|
|
{isConverting ? "Generating..." : "Generate Job Card"}
|
|
</Button>
|
|
)
|
|
} |