diff options
Diffstat (limited to 'lib/vendor-investigation/table/investigation-cancel-plan-button.tsx')
| -rw-r--r-- | lib/vendor-investigation/table/investigation-cancel-plan-button.tsx | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/lib/vendor-investigation/table/investigation-cancel-plan-button.tsx b/lib/vendor-investigation/table/investigation-cancel-plan-button.tsx new file mode 100644 index 00000000..26016742 --- /dev/null +++ b/lib/vendor-investigation/table/investigation-cancel-plan-button.tsx @@ -0,0 +1,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> + ) +} + + |
