From c228a89c2834ee63b209bad608837c39643f350e Mon Sep 17 00:00:00 2001 From: dujinkim Date: Mon, 28 Jul 2025 11:44:16 +0000 Subject: (대표님) 의존성 docx 추가, basicContract API, gtc(계약일반조건), 벤더평가 esg 평가데이터 내보내기 개선, S-EDP 피드백 대응(CLS_ID, ITEM NO 등) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../table/delete-gtc-clauses-dialog.tsx | 175 +++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 lib/gtc-contract/gtc-clauses/table/delete-gtc-clauses-dialog.tsx (limited to 'lib/gtc-contract/gtc-clauses/table/delete-gtc-clauses-dialog.tsx') diff --git a/lib/gtc-contract/gtc-clauses/table/delete-gtc-clauses-dialog.tsx b/lib/gtc-contract/gtc-clauses/table/delete-gtc-clauses-dialog.tsx new file mode 100644 index 00000000..29483c57 --- /dev/null +++ b/lib/gtc-contract/gtc-clauses/table/delete-gtc-clauses-dialog.tsx @@ -0,0 +1,175 @@ +"use client" + +import * as React from "react" +import { Loader, Trash2, AlertTriangle } from "lucide-react" +import { toast } from "sonner" + +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "@/components/ui/alert-dialog" +import { Button } from "@/components/ui/button" +import { Badge } from "@/components/ui/badge" + +import { type GtcClauseTreeView } from "@/db/schema/gtc" +import { useSession } from "next-auth/react" +import { deleteGtcClauses } from "../service" + +interface DeleteGtcClausesDialogProps + extends React.ComponentPropsWithRef { + gtcClauses: GtcClauseTreeView[] + showTrigger?: boolean + onSuccess?: () => void +} + +export function DeleteGtcClausesDialog({ + gtcClauses, + showTrigger = true, + onSuccess, + ...props +}: DeleteGtcClausesDialogProps) { + const [isDeletePending, startDeleteTransition] = React.useTransition() + const { data: session } = useSession() + + const currentUserId = React.useMemo(() => { + return session?.user?.id ? Number(session.user.id) : null + }, [session]) + + function onDelete() { + startDeleteTransition(async () => { + if (!currentUserId) { + toast.error("로그인이 필요합니다") + return + } + + try { + // ✅ 한 번에 모든 조항 삭제 (배열로 전달) + const ids = gtcClauses.map(clause => clause.id) + const result = await deleteGtcClauses(ids) + + if (result.error) { + toast.error(`삭제 중 오류가 발생했습니다: ${result.error}`) + return + } + + props.onOpenChange?.(false) + toast.success( + `${result.deletedCount}개의 조항이 삭제되었습니다.` + ) + onSuccess?.() + } catch (error) { + console.error("Delete error:", error) + toast.error("조항 삭제 중 오류가 발생했습니다.") + } + }) + } + + const clausesWithChildren = gtcClauses.filter(clause => clause.childrenCount > 0) + const hasChildrenWarning = clausesWithChildren.length > 0 + + // 총 삭제될 하위 조항 수 계산 + const totalChildrenCount = clausesWithChildren.reduce((sum, clause) => sum + clause.childrenCount, 0) + + return ( + + {showTrigger && ( + + + + )} + + + +
+ + 조항 삭제 +
+ +
+

+ 선택한 {gtcClauses.length}개의 조항을 완전히 삭제하시겠습니까? + 이 작업은 되돌릴 수 없습니다. +

+ + {/* 삭제할 조항 목록 */} +
+
삭제할 조항:
+
+ {gtcClauses.map((clause) => ( +
+ + {clause.itemNumber} + + {clause.subtitle} + {clause.childrenCount > 0 && ( + + 하위 {clause.childrenCount}개 + + )} +
+ ))} +
+
+ + {/* 하위 조항 경고 */} + {hasChildrenWarning && ( +
+
+ + 중요: 하위 조항 포함 삭제 +
+
+

하위 조항이 있는 조항을 삭제하면 모든 하위 조항도 함께 삭제됩니다.

+

+ 총 삭제될 조항: {gtcClauses.length + totalChildrenCount}개 + + (선택한 {gtcClauses.length}개 + 하위 {totalChildrenCount}개) + +

+
+
+ 영향받는 조항: {clausesWithChildren.map(c => c.itemNumber).join(', ')} +
+
+ )} + +
+ ⚠️ 실제 삭제: 데이터베이스에서 완전히 제거되며 복구할 수 없습니다. +
+
+
+
+ + + + Cancel + + + {isDeletePending && ( + + +
+
+ ) +} \ No newline at end of file -- cgit v1.2.3