summaryrefslogtreecommitdiff
path: root/lib/vendor-investigation/table/investigation-cancel-plan-button.tsx
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>
  )
}