blob: 260167424411948acc65f4ec18c30ff2e2c190bb (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
"use client"
import * as React from "react"
import { type Table } from "@tanstack/react-table"
import { VendorInvestigationsViewWithContacts } from "@/config/vendorInvestigationsColumnsConfig"
import { Button } from "@/components/ui/button"
import { RotateCcw } from "lucide-react"
import { toast } from "sonner"
import { cancelInvestigationPlanAction } from "../service"
import { getSiteVisitRequestAction } from "@/lib/site-visit/service"
interface Props {
table: Table<VendorInvestigationsViewWithContacts>
}
export function InvestigationCancelPlanButton({ table }: Props) {
const [loading, setLoading] = React.useState(false)
const selected = table.getSelectedRowModel().rows[0]?.original as VendorInvestigationsViewWithContacts | undefined
const canCancel = React.useMemo(() => {
if (!selected) return false
// 이미 취소 상태로 되돌릴 필요가 없거나, QM_REVIEW_CONFIRMED이면 취소 불필요
if (selected.investigationStatus === "QM_REVIEW_CONFIRMED") return false
if (!selected.investigationMethod) return false
const method = selected.investigationMethod
// 1) 서류평가: 실사결과 입력 전까지 (평가 결과 없을 때)
if (method === "DOCUMENT_EVAL") {
return selected.evaluationResult == null
}
// 2) 구매자체평가: 자체평가 입력 전까지 (간주: investigationNotes가 비어있을 때)
if (method === "PURCHASE_SELF_EVAL") {
return !selected.investigationNotes && selected.evaluationResult == null
}
// 3) 방문/제품평가: 방문요청 전까지 (site visit request 없을 때)
if (method === "PRODUCT_INSPECTION" || method === "SITE_VISIT_EVAL") {
// 낙관적으로 UI에선 일단 true로 두고, 클릭 시 서버 확인
return true
}
return false
}, [selected])
const onCancel = async () => {
if (!selected) return
try {
setLoading(true)
// 방문/제품평가인 경우, 방문요청 존재 여부 서버 확인
if (selected.investigationMethod === "PRODUCT_INSPECTION" || selected.investigationMethod === "SITE_VISIT_EVAL") {
try {
const req = await getSiteVisitRequestAction(selected.investigationId)
if (req.success && req.data) {
toast.error("방문요청 이후에는 실사계획을 취소할 수 없습니다.")
setLoading(false)
return
}
} catch {}
}
const res = await cancelInvestigationPlanAction(selected.investigationId)
if (!res.success) {
toast.error(res.error || "실사계획 취소에 실패했습니다.")
setLoading(false)
return
}
toast.success("실사계획을 취소하고 상태를 'QM 검토 완료'로 되돌렸습니다.")
// 선택 해제 및 테이블 리프레시 유도
table.resetRowSelection()
} catch (e) {
toast.error("실사계획 취소 중 오류가 발생했습니다.")
} finally {
setLoading(false)
}
}
return (
<Button
variant="outline"
size="sm"
onClick={onCancel}
disabled={loading || !canCancel}
className="gap-2"
title="실사계획 취소"
>
<RotateCcw className="size-4" />
취소
</Button>
)
}
|