From 2acf5f8966a40c1c9a97680c8dc263ee3f1ad3d1 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Wed, 2 Jul 2025 00:45:49 +0000
Subject: (대표님/최겸) 20250702 변경사항 업데이트
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/qna/table/delete-qna-dialog.tsx | 250 ++++++++++++++++++++++++++++++++++++
 1 file changed, 250 insertions(+)
 create mode 100644 lib/qna/table/delete-qna-dialog.tsx

(limited to 'lib/qna/table/delete-qna-dialog.tsx')

diff --git a/lib/qna/table/delete-qna-dialog.tsx b/lib/qna/table/delete-qna-dialog.tsx
new file mode 100644
index 00000000..55dcd366
--- /dev/null
+++ b/lib/qna/table/delete-qna-dialog.tsx
@@ -0,0 +1,250 @@
+"use client"
+
+import * as React from "react"
+import { toast } from "sonner"
+import { Trash2 } from "lucide-react"
+
+import { Button } from "@/components/ui/button"
+import {
+  Dialog,
+  DialogContent,
+  DialogDescription,
+  DialogFooter,
+  DialogHeader,
+  DialogTitle,
+  DialogTrigger,
+} from "@/components/ui/dialog"
+import {
+  Drawer,
+  DrawerContent,
+  DrawerDescription,
+  DrawerFooter,
+  DrawerHeader,
+  DrawerTitle,
+  DrawerTrigger,
+} from "@/components/ui/drawer"
+import { Badge } from "@/components/ui/badge"
+import { ScrollArea } from "@/components/ui/scroll-area"
+
+import { QnaViewSelect } from "@/db/schema"
+import { useMediaQuery } from "@/hooks/use-media-query"
+import { deleteQna } from "../service"
+
+interface DeleteQnaDialogProps {
+  open: boolean
+  onOpenChange: (open: boolean) => void
+  qnas: QnaViewSelect[]
+  showTrigger?: boolean
+  onSuccess?: () => void
+}
+
+export function DeleteQnaDialog({ 
+  open, 
+  onOpenChange, 
+  qnas, 
+  showTrigger = true,
+  onSuccess
+}: DeleteQnaDialogProps) {
+  const [isDeletePending, startDeleteTransition] = React.useTransition()
+  const isDesktop = useMediaQuery("(min-width: 640px)")
+
+  const qnaCount = qnas.length
+  const isMultiple = qnaCount > 1
+
+  async function handleDelete() {
+    startDeleteTransition(async () => {
+      try {
+        const promises = qnas.map(qna => deleteQna(qna.id))
+        const results = await Promise.all(promises)
+        
+        const successCount = results.filter(result => result.success).length
+        const failCount = results.length - successCount
+        
+        if (successCount > 0) {
+          toast.success(
+            isMultiple 
+              ? `${successCount}개의 질문이 삭제되었습니다.`
+              : "질문이 삭제되었습니다."
+          )
+          onSuccess?.()
+        }
+        
+        if (failCount > 0) {
+          toast.error(
+            isMultiple
+              ? `${failCount}개의 질문 삭제에 실패했습니다.`
+              : "질문 삭제에 실패했습니다."
+          )
+        }
+        
+        if (successCount > 0) {
+          onOpenChange(false)
+        }
+      } catch (error) {
+        toast.error("삭제 중 오류가 발생했습니다.")
+        console.error("질문 삭제 오류:", error)
+      }
+    })
+  }
+
+  const title = isMultiple ? `${qnaCount}개 질문 삭제` : "질문 삭제"
+  const description = isMultiple 
+    ? "선택한 질문들을 정말로 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다."
+    : "이 질문을 정말로 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다."
+
+  if (isDesktop) {
+    return (
+      <Dialog open={open} onOpenChange={onOpenChange}>
+        {showTrigger && (
+          <DialogTrigger asChild>
+            <Button variant="outline" size="sm">
+              <Trash2 className="mr-2 h-4 w-4" />
+              삭제
+            </Button>
+          </DialogTrigger>
+        )}
+        <DialogContent className="max-w-2xl">
+          <DialogHeader>
+            <DialogTitle>{title}</DialogTitle>
+            <DialogDescription>{description}</DialogDescription>
+          </DialogHeader>
+          
+          {/* 삭제할 질문 목록 */}
+          <div className="max-h-[300px]">
+            <div className="text-sm font-medium mb-2">삭제 대상:</div>
+            <ScrollArea className="max-h-[250px] border rounded-md p-3">
+              <div className="space-y-3">
+                {qnas.map((qna, index) => (
+                  <div key={qna.id} className="flex items-start gap-3 p-3 border rounded-md bg-muted/50">
+                    <div className="font-mono text-xs text-muted-foreground mt-1">
+                      {index + 1}.
+                    </div>
+                    <div className="flex-1 min-w-0">
+                      <div className="font-medium text-sm line-clamp-2 mb-1">
+                        {qna.title}
+                      </div>
+                      <div className="flex items-center gap-2 text-xs text-muted-foreground">
+                        <span>{qna.authorName}</span>
+                        <span>•</span>
+                        <span>{qna.companyName || "미지정"}</span>
+                        <span>•</span>
+                        <span>답변 {qna.totalAnswers}개</span>
+                      </div>
+                      <div className="flex items-center gap-1 mt-2">
+                        {qna.hasAnswers && (
+                          <Badge variant="secondary" className="text-xs">
+                            답변있음
+                          </Badge>
+                        )}
+                        {qna.isPopular && (
+                          <Badge variant="default" className="text-xs">
+                            인기질문
+                          </Badge>
+                        )}
+                      </div>
+                    </div>
+                  </div>
+                ))}
+              </div>
+            </ScrollArea>
+          </div>
+
+          {/* 경고 메시지 */}
+          <div className="rounded-md border border-destructive/20 bg-destructive/5 p-3">
+            <div className="text-sm text-destructive">
+              <strong>주의:</strong> 질문을 삭제하면 해당 질문의 모든 답변과 댓글도 함께 삭제됩니다.
+            </div>
+          </div>
+
+          <DialogFooter>
+            <Button
+              type="button"
+              variant="outline"
+              onClick={() => onOpenChange(false)}
+              disabled={isDeletePending}
+            >
+              취소
+            </Button>
+            <Button
+              type="button"
+              variant="destructive"
+              onClick={handleDelete}
+              disabled={isDeletePending}
+            >
+              {isDeletePending ? "삭제 중..." : "삭제"}
+            </Button>
+          </DialogFooter>
+        </DialogContent>
+      </Dialog>
+    )
+  }
+
+  return (
+    <Drawer open={open} onOpenChange={onOpenChange}>
+      {showTrigger && (
+        <DrawerTrigger asChild>
+          <Button variant="outline" size="sm">
+            <Trash2 className="mr-2 h-4 w-4" />
+            삭제
+          </Button>
+        </DrawerTrigger>
+      )}
+      <DrawerContent>
+        <DrawerHeader>
+          <DrawerTitle>{title}</DrawerTitle>
+          <DrawerDescription>{description}</DrawerDescription>
+        </DrawerHeader>
+        
+        <div className="px-4 pb-4">
+          {/* 삭제할 질문 목록 */}
+          <div className="mb-4">
+            <div className="text-sm font-medium mb-2">삭제 대상:</div>
+            <div className="max-h-[200px] space-y-2 overflow-y-auto">
+              {qnas.map((qna, index) => (
+                <div key={qna.id} className="flex items-start gap-2 p-2 border rounded-md bg-muted/50">
+                  <div className="font-mono text-xs text-muted-foreground mt-1">
+                    {index + 1}.
+                  </div>
+                  <div className="flex-1 min-w-0">
+                    <div className="font-medium text-sm line-clamp-1 mb-1">
+                      {qna.title}
+                    </div>
+                    <div className="text-xs text-muted-foreground">
+                      {qna.authorName} • 답변 {qna.totalAnswers}개
+                    </div>
+                  </div>
+                </div>
+              ))}
+            </div>
+          </div>
+
+          {/* 경고 메시지 */}
+          <div className="rounded-md border border-destructive/20 bg-destructive/5 p-3 mb-4">
+            <div className="text-sm text-destructive">
+              <strong>주의:</strong> 삭제된 질문과 관련 데이터는 복구할 수 없습니다.
+            </div>
+          </div>
+        </div>
+
+        <DrawerFooter className="gap-2">
+          <Button
+            type="button"
+            variant="destructive"
+            onClick={handleDelete}
+            disabled={isDeletePending}
+          >
+            {isDeletePending ? "삭제 중..." : "삭제"}
+          </Button>
+          <Button
+            type="button"
+            variant="outline"
+            onClick={() => onOpenChange(false)}
+            disabled={isDeletePending}
+          >
+            취소
+          </Button>
+        </DrawerFooter>
+      </DrawerContent>
+    </Drawer>
+  )
+}
\ No newline at end of file
-- 
cgit v1.2.3

