summaryrefslogtreecommitdiff
path: root/lib/basic-contract/status-detail
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-11-21 09:44:33 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-11-21 09:44:33 +0000
commita2e0785c8749c4d3766ecf3b70edfb7c2fe4df20 (patch)
tree4b03bbec838baf307b38e0c5692da8da7bde2f9b /lib/basic-contract/status-detail
parent204fbfb126daf057a4567f64cfb7ab03a5679e82 (diff)
(임수민) 준법 Red Flag 해제, 코멘트 수정
Diffstat (limited to 'lib/basic-contract/status-detail')
-rw-r--r--lib/basic-contract/status-detail/basic-contract-detail-table-toolbar-actions.tsx16
-rw-r--r--lib/basic-contract/status-detail/basic-contracts-detail-columns.tsx74
-rw-r--r--lib/basic-contract/status-detail/basic-contracts-detail-table.tsx46
3 files changed, 121 insertions, 15 deletions
diff --git a/lib/basic-contract/status-detail/basic-contract-detail-table-toolbar-actions.tsx b/lib/basic-contract/status-detail/basic-contract-detail-table-toolbar-actions.tsx
index daa410f0..e62a6cb7 100644
--- a/lib/basic-contract/status-detail/basic-contract-detail-table-toolbar-actions.tsx
+++ b/lib/basic-contract/status-detail/basic-contract-detail-table-toolbar-actions.tsx
@@ -414,15 +414,17 @@ export function BasicContractDetailTableToolbarActions({
const contractIds = redFlagResolutionContracts.map(c => c.id)
const result = await requestRedFlagResolution(contractIds)
- if (result.success) {
- toast.success(result.message)
- table.toggleAllPageRowsSelected(false)
- } else {
- toast.error(result.message)
- }
+ toast.success("RED FLAG 해소요청 결재가 상신되었습니다.", {
+ description: `결재 ID: ${result.approvalId}`,
+ })
+ table.toggleAllPageRowsSelected(false)
} catch (error) {
console.error("RED FLAG 해소요청 오류:", error)
- toast.error("RED FLAG 해소요청 중 오류가 발생했습니다")
+ toast.error(
+ error instanceof Error
+ ? error.message
+ : "RED FLAG 해소요청 중 오류가 발생했습니다."
+ )
} finally {
setLoading(false)
}
diff --git a/lib/basic-contract/status-detail/basic-contracts-detail-columns.tsx b/lib/basic-contract/status-detail/basic-contracts-detail-columns.tsx
index b2c811fd..2ab39880 100644
--- a/lib/basic-contract/status-detail/basic-contracts-detail-columns.tsx
+++ b/lib/basic-contract/status-detail/basic-contracts-detail-columns.tsx
@@ -32,13 +32,21 @@ import { toast } from "sonner"
import { useRouter } from "next/navigation"
import { getComplianceResponseByBasicContractId } from "@/lib/compliance/services"
-interface GetColumnsProps {
+type RedFlagResolutionState = {
+ resolved: boolean
+ resolvedAt: Date | null
+ pendingApprovalId: string | null
+}
+
+export interface GetColumnsProps {
setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<BasicContractView> | null>>
gtcData: Record<number, { gtcDocumentId: number | null; hasComments: boolean }>
isLoadingGtcData: boolean
+ agreementCommentData: Record<number, { hasComments: boolean; commentCount: number }>
+ isLoadingAgreementCommentData: boolean
redFlagData: Record<number, boolean>
isLoadingRedFlagData: boolean
- redFlagResolutionData: Record<number, { resolved: boolean; resolvedAt: Date | null }>
+ redFlagResolutionData: Record<number, RedFlagResolutionState>
isLoadingRedFlagResolutionData: boolean
isComplianceTemplate: boolean
router: NextRouter;
@@ -61,6 +69,8 @@ export function getDetailColumns({
setRowAction,
gtcData,
isLoadingGtcData,
+ agreementCommentData,
+ isLoadingAgreementCommentData,
redFlagData,
isLoadingRedFlagData,
redFlagResolutionData,
@@ -134,7 +144,7 @@ export function getDetailColumns({
}
const handleResend = () => {
- setRowAction({ type: "resend", row })
+ setRowAction({ type: "resend", row } as DataTableRowAction<BasicContractView>)
}
return (
@@ -256,6 +266,19 @@ export function getDetailColumns({
</div>
);
}
+
+ if (resolution?.pendingApprovalId) {
+ return (
+ <div className="text-sm">
+ <Badge variant="secondary" className="font-medium">
+ 해소요청 진행중
+ </Badge>
+ <div className="text-xs text-gray-500 mt-1">
+ 결재 ID: {resolution.pendingApprovalId.slice(-6)}
+ </div>
+ </div>
+ );
+ }
return (
<div className="text-sm text-gray-400">-</div>
@@ -296,7 +319,10 @@ export function getDetailColumns({
const name = row.getValue("vendorName") as string | null
const contract = row.original
const isGTCTemplate = contract.templateName?.includes('GTC')
+ const isComplianceContract = contract.templateName?.includes('준법')
const contractGtcData = gtcData[contract.id]
+ const complianceNegotiation = agreementCommentData[contract.id]
+ const isNegotiationCompleted = !!contract.negotiationCompletedAt
const handleOpenGTC = (e: React.MouseEvent) => {
e.stopPropagation()
@@ -345,6 +371,48 @@ export function getDetailColumns({
)}
</div>
)}
+ {isComplianceContract && (
+ <div className="flex items-center gap-1">
+ {isLoadingAgreementCommentData ? (
+ <Loader2 className="h-3 w-3 animate-spin text-gray-400" />
+ ) : isNegotiationCompleted ? (
+ <Badge
+ variant="outline"
+ className="text-xs bg-green-50 text-green-700 border-green-200"
+ >
+ <MessageCircle className="h-3 w-3 mr-1" />
+ 협의 완료
+ </Badge>
+ ) : complianceNegotiation?.hasComments ? (
+ <Badge
+ variant="outline"
+ className="text-xs bg-orange-50 text-orange-700 border-orange-200"
+ title={`협의 코멘트 ${complianceNegotiation.commentCount}개`}
+ onClick={(event) => {
+ event.stopPropagation();
+ if (typeof window === "undefined") return;
+ const params = new URLSearchParams();
+ if (contract.templateId) {
+ params.set("templateId", contract.templateId.toString());
+ }
+ if (contract.vendorId) {
+ params.set("vendorId", contract.vendorId.toString());
+ }
+ if (contract.vendorName) {
+ params.set("vendorName", contract.vendorName);
+ }
+ const query = params.toString();
+ const complianceUrl = `/evcp/basic-contract/compliance-comments/${contract.id}${query ? `?${query}` : ""}`;
+ window.open(complianceUrl, "_blank", "noopener,noreferrer");
+ }}
+ style={{ cursor: "pointer" }}
+ >
+ <MessageCircle className="h-3 w-3 mr-1" />
+ 협의 진행중 ({complianceNegotiation.commentCount})
+ </Badge>
+ ) : null}
+ </div>
+ )}
</div>
)
},
diff --git a/lib/basic-contract/status-detail/basic-contracts-detail-table.tsx b/lib/basic-contract/status-detail/basic-contracts-detail-table.tsx
index 2d747c85..010b4713 100644
--- a/lib/basic-contract/status-detail/basic-contracts-detail-table.tsx
+++ b/lib/basic-contract/status-detail/basic-contracts-detail-table.tsx
@@ -11,6 +11,7 @@ import type {
import { getDetailColumns } from "./basic-contracts-detail-columns"
import { getBasicContractsByTemplateId } from "@/lib/basic-contract/service"
import { checkGTCCommentsForContracts } from "@/lib/basic-contract/actions/check-gtc-comments"
+import { checkAgreementCommentsForContracts } from "@/lib/basic-contract/agreement-comments/actions"
import { checkRedFlagsForContracts } from "@/lib/basic-contract/actions/check-red-flags"
import { checkRedFlagResolutionForContracts } from "@/lib/basic-contract/actions/check-red-flag-resolution"
import { BasicContractView } from "@/db/schema"
@@ -35,20 +36,27 @@ export function BasicContractsDetailTable({ templateId, promises }: BasicContrac
const [gtcData, setGtcData] = React.useState<Record<number, { gtcDocumentId: number | null; hasComments: boolean }>>({})
const [isLoadingGtcData, setIsLoadingGtcData] = React.useState(false)
+ // 협의 코멘트 상태 (준법 포함) 관리
+ const [agreementCommentData, setAgreementCommentData] = React.useState<Record<number, { hasComments: boolean; commentCount: number }>>({})
+ const [isLoadingAgreementCommentData, setIsLoadingAgreementCommentData] = React.useState(false)
+
// Red Flag data 상태 관리
const [redFlagData, setRedFlagData] = React.useState<Record<number, boolean>>({})
const [isLoadingRedFlagData, setIsLoadingRedFlagData] = React.useState(false)
+type RedFlagResolutionState = {
+ resolved: boolean
+ resolvedAt: Date | null
+ pendingApprovalId: string | null
+}
+
// Red Flag 해제 data 상태 관리
- const [redFlagResolutionData, setRedFlagResolutionData] = React.useState<Record<number, { resolved: boolean; resolvedAt: Date | null }>>({})
+ const [redFlagResolutionData, setRedFlagResolutionData] = React.useState<Record<number, RedFlagResolutionState>>({})
const [isLoadingRedFlagResolutionData, setIsLoadingRedFlagResolutionData] = React.useState(false)
const [{ data, pageCount }] = React.use(promises)
const router = useRouter()
- console.log(gtcData, "gtcData")
- console.log(data, "data")
-
// GTC data 로딩
React.useEffect(() => {
const loadGtcData = async () => {
@@ -76,6 +84,32 @@ export function BasicContractsDetailTable({ templateId, promises }: BasicContrac
loadGtcData();
}, [data]);
+ // 협의 코멘트 상태 로딩 (준법 포함)
+ React.useEffect(() => {
+ const loadAgreementComments = async () => {
+ if (!data || data.length === 0) return;
+
+ const hasNegotiationTemplates = data.some(contract =>
+ contract.templateName?.includes('준법') || contract.templateName?.includes('GTC')
+ );
+
+ if (!hasNegotiationTemplates) return;
+
+ setIsLoadingAgreementCommentData(true);
+ try {
+ const results = await checkAgreementCommentsForContracts(data);
+ setAgreementCommentData(results);
+ } catch (error) {
+ console.error('협의 코멘트 정보를 불러오는데 실패했습니다:', error);
+ toast.error("협의 코멘트 정보를 불러오는데 실패했습니다.");
+ } finally {
+ setIsLoadingAgreementCommentData(false);
+ }
+ };
+
+ loadAgreementComments();
+ }, [data]);
+
// Red Flag data 로딩
React.useEffect(() => {
const loadRedFlagData = async () => {
@@ -141,6 +175,8 @@ export function BasicContractsDetailTable({ templateId, promises }: BasicContrac
setRowAction,
gtcData,
isLoadingGtcData,
+ agreementCommentData,
+ isLoadingAgreementCommentData,
redFlagData,
isLoadingRedFlagData,
redFlagResolutionData,
@@ -148,7 +184,7 @@ export function BasicContractsDetailTable({ templateId, promises }: BasicContrac
isComplianceTemplate,
router
}),
- [setRowAction, gtcData, isLoadingGtcData, redFlagData, isLoadingRedFlagData, redFlagResolutionData, isLoadingRedFlagResolutionData, isComplianceTemplate, router]
+ [setRowAction, gtcData, isLoadingGtcData, agreementCommentData, isLoadingAgreementCommentData, redFlagData, isLoadingRedFlagData, redFlagResolutionData, isLoadingRedFlagResolutionData, isComplianceTemplate, router]
)
const advancedFilterFields: DataTableAdvancedFilterField<BasicContractView>[] = [