diff options
Diffstat (limited to 'lib/rfq-last/attachment/delete-attachments-dialog.tsx')
| -rw-r--r-- | lib/rfq-last/attachment/delete-attachments-dialog.tsx | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/lib/rfq-last/attachment/delete-attachments-dialog.tsx b/lib/rfq-last/attachment/delete-attachments-dialog.tsx new file mode 100644 index 00000000..c9041639 --- /dev/null +++ b/lib/rfq-last/attachment/delete-attachments-dialog.tsx @@ -0,0 +1,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> + ) +}
\ No newline at end of file |
