summaryrefslogtreecommitdiff
path: root/lib/rfq-last/attachment/delete-attachments-dialog.tsx
blob: c9041639e4aa9b9c9d43b13a116d889c79c2d82d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
"use client"

import * as React from "react"
import { Loader, Trash2 } from "lucide-react"
import { toast } from "sonner"
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"

interface DeleteAttachmentsDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  attachments: Array<{
    id: number;
    originalFileName?: string | null;
    serialNo?: string | null;
  }>;
  onSuccess?: () => void;
}

export function DeleteAttachmentsDialog({
  open,
  onOpenChange,
  attachments,
  onSuccess,
}: DeleteAttachmentsDialogProps) {
  const [isDeleting, setIsDeleting] = React.useState(false)

  async function onDelete() {
    setIsDeleting(true);
    
    try {
      // 여러 개 삭제 시 병렬 처리
      const deletePromises = attachments.map(async (attachment) => {
        const response = await fetch(`/api/rfq-attachments/${attachment.id}`, {
          method: "DELETE",
        });

        if (!response.ok) {
          const error = await response.json();
          throw new Error(error.message || "삭제 실패");
        }

        return response.json();
      });

      const results = await Promise.allSettled(deletePromises);
      
      const failures = results.filter(r => r.status === 'rejected');
      if (failures.length > 0) {
        const firstError = failures[0];
        if (firstError.status === 'rejected') {
          toast.error(`일부 파일 삭제 실패: ${firstError.reason}`);
        }
        return;
      }

      onOpenChange(false);
      toast.success(`${attachments.length}개 파일이 삭제되었습니다`);
      onSuccess?.();
    } catch (error) {
      toast.error(error instanceof Error ? error.message : "파일 삭제 중 오류가 발생했습니다");
    } finally {
      setIsDeleting(false);
    }
  }

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>파일을 삭제하시겠습니까?</DialogTitle>
          <DialogDescription>
            이 작업은 되돌릴 수 없습니다. 선택한{" "}
            <span className="font-medium">{attachments.length}개</span>의 파일이 
            영구적으로 삭제됩니다.
            {attachments[0]?.originalFileName && (
              <div className="mt-2 p-2 bg-muted rounded text-sm">
                {attachments[0].originalFileName}
                {attachments[0].serialNo && (
                  <span className="text-muted-foreground"> ({attachments[0].serialNo})</span>
                )}
              </div>
            )}
          </DialogDescription>
        </DialogHeader>
        <DialogFooter className="gap-2 sm:space-x-0">
          <DialogClose asChild>
            <Button variant="outline" disabled={isDeleting}>
              취소
            </Button>
          </DialogClose>
          <Button
            variant="destructive"
            onClick={onDelete}
            disabled={isDeleting}
          >
            {isDeleting && (
              <Loader
                className="mr-2 size-4 animate-spin"
                aria-hidden="true"
              />
            )}
            삭제
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}