summaryrefslogtreecommitdiff
path: root/lib/evaluation-target-list/table/delete-targets-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/evaluation-target-list/table/delete-targets-dialog.tsx')
-rw-r--r--lib/evaluation-target-list/table/delete-targets-dialog.tsx181
1 files changed, 181 insertions, 0 deletions
diff --git a/lib/evaluation-target-list/table/delete-targets-dialog.tsx b/lib/evaluation-target-list/table/delete-targets-dialog.tsx
new file mode 100644
index 00000000..5414d281
--- /dev/null
+++ b/lib/evaluation-target-list/table/delete-targets-dialog.tsx
@@ -0,0 +1,181 @@
+"use client"
+
+import * as React from "react"
+import { Trash2, AlertTriangle } from "lucide-react"
+import { toast } from "sonner"
+
+import { Button } from "@/components/ui/button"
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import { Badge } from "@/components/ui/badge"
+import { ScrollArea } from "@/components/ui/scroll-area"
+import { EvaluationTargetWithDepartments } from "@/db/schema"
+import { deleteEvaluationTargets } from "../service"
+interface DeleteTargetsDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+ targets: EvaluationTargetWithDepartments[]
+ onSuccess?: () => void
+}
+
+export function DeleteTargetsDialog({
+ open,
+ onOpenChange,
+ targets,
+ onSuccess
+}: DeleteTargetsDialogProps) {
+ const [isLoading, setIsLoading] = React.useState(false)
+
+ // PENDING 상태인 타겟들만 필터링 (추가 안전장치)
+ const pendingTargets = React.useMemo(() => {
+ return targets.filter(target => target.status === "PENDING")
+ }, [targets])
+
+ console.log(pendingTargets,"pendingTargets")
+
+ const handleDelete = async () => {
+ if (pendingTargets.length === 0) {
+ toast.error("삭제할 수 있는 평가 대상이 없습니다.")
+ return
+ }
+
+ setIsLoading(true)
+ try {
+ const targetIds = pendingTargets.map(target => target.id)
+ const result = await deleteEvaluationTargets(targetIds)
+
+ if (result.success) {
+ toast.success(result.message || "평가 대상이 성공적으로 삭제되었습니다.", {
+ description: `${result.deletedCount || pendingTargets.length}개의 항목이 삭제되었습니다.`
+ })
+ onSuccess?.()
+ onOpenChange(false)
+ } else {
+ toast.error(result.error || "삭제 중 오류가 발생했습니다.")
+ }
+ } catch (error) {
+ console.error('Error deleting targets:', error)
+ toast.error("삭제 중 오류가 발생했습니다.")
+ } finally {
+ setIsLoading(false)
+ }
+ }
+
+ const handleCancel = () => {
+ if (!isLoading) {
+ onOpenChange(false)
+ }
+ }
+
+ return (
+ <Dialog open={open} onOpenChange={onOpenChange}>
+ <DialogContent className="max-w-2xl">
+ <DialogHeader>
+ <DialogTitle className="flex items-center gap-2">
+ <Trash2 className="size-5 text-destructive" />
+ 평가 대상 삭제
+ </DialogTitle>
+ <DialogDescription>
+ 선택한 평가 대상을 영구적으로 삭제합니다. 이 작업은 되돌릴 수 없습니다.
+ </DialogDescription>
+ </DialogHeader>
+
+ {pendingTargets.length > 0 ? (
+ <div className="space-y-4">
+ {/* 경고 메시지 */}
+ <div className="flex items-start gap-3 p-4 bg-destructive/10 rounded-lg border border-destructive/20">
+ <AlertTriangle className="size-5 text-destructive mt-0.5 flex-shrink-0" />
+ <div className="space-y-1">
+ <p className="font-medium text-destructive">
+ 주의: 삭제된 데이터는 복구할 수 없습니다
+ </p>
+ <p className="text-sm text-muted-foreground">
+ PENDING 상태의 평가 대상만 삭제할 수 있습니다.
+ 확정(CONFIRMED)되거나 제외(EXCLUDED)된 대상은 삭제할 수 없습니다.
+ </p>
+ </div>
+ </div>
+
+ {/* 삭제 대상 목록 */}
+ <div className="space-y-2">
+ <div className="flex items-center justify-between">
+ <h4 className="font-medium">삭제될 평가 대상 ({pendingTargets.length}개)</h4>
+ <Badge variant="destructive" className="gap-1">
+ <Trash2 className="size-3" />
+ 삭제 예정
+ </Badge>
+ </div>
+
+ <ScrollArea className="h-40 w-full border rounded-md">
+ <div className="p-4 space-y-2">
+ {pendingTargets.map((target) => (
+ <div
+ key={target.id}
+ className="flex items-center justify-between p-2 bg-muted/50 rounded text-sm"
+ >
+ <div className="space-y-1">
+ <div className="font-medium">
+ {target.vendorName || '알 수 없는 업체'}
+ </div>
+ <div className="text-xs text-muted-foreground">
+ • {target.evaluationYear}년
+ </div>
+ </div>
+ <div className="flex items-center gap-2">
+ <Badge variant="secondary" className="text-xs">
+ {target.status}
+ </Badge>
+ </div>
+ </div>
+ ))}
+ </div>
+ </ScrollArea>
+ </div>
+ </div>
+ ) : (
+ <div className="flex items-center justify-center py-8 text-muted-foreground">
+ <div className="text-center space-y-2">
+ <Trash2 className="size-8 mx-auto opacity-50" />
+ <p>삭제할 수 있는 평가 대상이 없습니다.</p>
+ <p className="text-xs">PENDING 상태의 대상만 삭제할 수 있습니다.</p>
+ </div>
+ </div>
+ )}
+
+ <DialogFooter>
+ <Button
+ variant="outline"
+ onClick={handleCancel}
+ disabled={isLoading}
+ >
+ 취소
+ </Button>
+ <Button
+ variant="destructive"
+ onClick={handleDelete}
+ disabled={isLoading || pendingTargets.length === 0}
+ className="gap-2"
+ >
+ {isLoading ? (
+ <>
+ <div className="size-4 border-2 border-current border-r-transparent rounded-full animate-spin" />
+ 삭제 중...
+ </>
+ ) : (
+ <>
+ <Trash2 className="size-4" />
+ {pendingTargets.length}개 삭제
+ </>
+ )}
+ </Button>
+ </DialogFooter>
+ </DialogContent>
+ </Dialog>
+ )
+} \ No newline at end of file