summaryrefslogtreecommitdiff
path: root/lib/basic-contract/gtc-vendor/delete-gtc-clauses-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/basic-contract/gtc-vendor/delete-gtc-clauses-dialog.tsx')
-rw-r--r--lib/basic-contract/gtc-vendor/delete-gtc-clauses-dialog.tsx175
1 files changed, 175 insertions, 0 deletions
diff --git a/lib/basic-contract/gtc-vendor/delete-gtc-clauses-dialog.tsx b/lib/basic-contract/gtc-vendor/delete-gtc-clauses-dialog.tsx
new file mode 100644
index 00000000..885a78e0
--- /dev/null
+++ b/lib/basic-contract/gtc-vendor/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<typeof AlertDialog> {
+ 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 (
+ <AlertDialog {...props}>
+ {showTrigger && (
+ <AlertDialogTrigger asChild>
+ <Button variant="outline" size="sm">
+ <Trash2 className="mr-2 h-4 w-4" />
+ 삭제 ({gtcClauses.length})
+ </Button>
+ </AlertDialogTrigger>
+ )}
+
+ <AlertDialogContent className="max-w-md">
+ <AlertDialogHeader>
+ <div className="flex items-center gap-2">
+ <AlertTriangle className="h-5 w-5 text-destructive" />
+ <AlertDialogTitle>조항 삭제</AlertDialogTitle>
+ </div>
+ <AlertDialogDescription asChild>
+ <div className="space-y-3">
+ <p>
+ 선택한 {gtcClauses.length}개의 조항을 <strong>완전히 삭제</strong>하시겠습니까?
+ 이 작업은 되돌릴 수 없습니다.
+ </p>
+
+ {/* 삭제할 조항 목록 */}
+ <div className="space-y-2">
+ <div className="text-sm font-medium">삭제할 조항:</div>
+ <div className="max-h-32 overflow-y-auto space-y-1">
+ {gtcClauses.map((clause) => (
+ <div key={clause.id} className="flex items-center gap-2 text-sm p-2 bg-muted/50 rounded">
+ <Badge variant="outline" className="text-xs">
+ {clause.itemNumber}
+ </Badge>
+ <span className="flex-1 truncate">{clause.subtitle}</span>
+ {clause.childrenCount > 0 && (
+ <Badge variant="destructive" className="text-xs">
+ 하위 {clause.childrenCount}개
+ </Badge>
+ )}
+ </div>
+ ))}
+ </div>
+ </div>
+
+ {/* 하위 조항 경고 */}
+ {hasChildrenWarning && (
+ <div className="p-3 bg-destructive/10 border border-destructive/20 rounded-md">
+ <div className="flex items-center gap-2 text-destructive text-sm font-medium mb-2">
+ <AlertTriangle className="h-4 w-4" />
+ 중요: 하위 조항 포함 삭제
+ </div>
+ <div className="space-y-1 text-sm text-destructive/80">
+ <p>하위 조항이 있는 조항을 삭제하면 모든 하위 조항도 함께 삭제됩니다.</p>
+ <p className="font-medium">
+ 총 삭제될 조항: {gtcClauses.length + totalChildrenCount}개
+ <span className="text-xs ml-1">
+ (선택한 {gtcClauses.length}개 + 하위 {totalChildrenCount}개)
+ </span>
+ </p>
+ </div>
+ <div className="mt-2 text-xs text-destructive/70">
+ 영향받는 조항: {clausesWithChildren.map(c => c.itemNumber).join(', ')}
+ </div>
+ </div>
+ )}
+
+ <div className="p-2 bg-amber-50 border border-amber-200 rounded text-xs text-amber-800">
+ ⚠️ <strong>실제 삭제</strong>: 데이터베이스에서 완전히 제거되며 복구할 수 없습니다.
+ </div>
+ </div>
+ </AlertDialogDescription>
+ </AlertDialogHeader>
+
+ <AlertDialogFooter>
+ <AlertDialogCancel disabled={isDeletePending}>
+ Cancel
+ </AlertDialogCancel>
+ <AlertDialogAction
+ onClick={onDelete}
+ disabled={isDeletePending}
+ className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
+ >
+ {isDeletePending && (
+ <Loader
+ className="mr-2 size-4 animate-spin"
+ aria-hidden="true"
+ />
+ )}
+ <Trash2 className="mr-2 h-4 w-4" />
+ Delete Permanently
+ </AlertDialogAction>
+ </AlertDialogFooter>
+ </AlertDialogContent>
+ </AlertDialog>
+ )
+} \ No newline at end of file