From aa86729f9a2ab95346a2851e3837de1c367aae17 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Fri, 20 Jun 2025 11:37:31 +0000
Subject: (대표님) 20250620 작업사항
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/project-gtc/table/view-gtc-file-dialog.tsx | 230 +++++++++++++++++++++++++
 1 file changed, 230 insertions(+)
 create mode 100644 lib/project-gtc/table/view-gtc-file-dialog.tsx

(limited to 'lib/project-gtc/table/view-gtc-file-dialog.tsx')

diff --git a/lib/project-gtc/table/view-gtc-file-dialog.tsx b/lib/project-gtc/table/view-gtc-file-dialog.tsx
new file mode 100644
index 00000000..f8cfecd9
--- /dev/null
+++ b/lib/project-gtc/table/view-gtc-file-dialog.tsx
@@ -0,0 +1,230 @@
+"use client"
+
+import * as React from "react"
+import { Download, FileText, Calendar, HardDrive } from "lucide-react"
+
+import { Button } from "@/components/ui/button"
+import {
+  Dialog,
+  DialogContent,
+  DialogDescription,
+  DialogFooter,
+  DialogHeader,
+  DialogTitle,
+} from "@/components/ui/dialog"
+import { Badge } from "@/components/ui/badge"
+import { format } from "date-fns"
+import { ko } from "date-fns/locale"
+import type { ProjectGtcView } from "@/db/schema"
+
+interface ViewGtcFileDialogProps {
+  project: ProjectGtcView | null
+  open: boolean
+  onOpenChange: (open: boolean) => void
+}
+
+// 파일 크기 포맷팅 함수
+function formatBytes(bytes: number | null): string {
+  if (!bytes) return "0 B"
+  
+  const k = 1024
+  const sizes = ['B', 'KB', 'MB', 'GB']
+  const i = Math.floor(Math.log(bytes) / Math.log(k))
+  
+  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
+}
+
+export function ViewGtcFileDialog({
+  project,
+  open,
+  onOpenChange,
+}: ViewGtcFileDialogProps) {
+  if (!project || !project.gtcFileId) return null
+
+  const handleDownload = async () => {
+    try {
+      // API를 통해 파일 다운로드
+      const response = await fetch(`/api/project-gtc?action=download&projectId=${project.id}`, {
+        method: 'GET',
+      });
+
+      if (!response.ok) {
+        throw new Error('파일 다운로드에 실패했습니다.');
+      }
+
+      // 파일 blob 생성
+      const blob = await response.blob();
+      
+      // 다운로드 링크 생성
+      const url = window.URL.createObjectURL(blob);
+      const link = document.createElement('a');
+      link.href = url;
+      link.download = project.originalFileName || 'gtc-file';
+      document.body.appendChild(link);
+      link.click();
+      document.body.removeChild(link);
+      
+      // 메모리 정리
+      window.URL.revokeObjectURL(url);
+    } catch (error) {
+      console.error("파일 다운로드 오류:", error);
+    }
+  }
+
+  const handlePreview = async () => {
+    try {
+      // API를 통해 파일 다운로드
+      const response = await fetch(`/api/project-gtc?action=download&projectId=${project.id}`, {
+        method: 'GET',
+      });
+
+      if (!response.ok) {
+        throw new Error('파일을 열 수 없습니다.');
+      }
+
+      // 파일 blob 생성
+      const blob = await response.blob();
+      
+      // PDF 파일인 경우 새 탭에서 열기
+      if (project.mimeType === 'application/pdf') {
+        const url = window.URL.createObjectURL(blob);
+        window.open(url, '_blank');
+        // 메모리 정리는 브라우저가 탭을 닫을 때 자동으로 처리됨
+      } else {
+        // 다른 파일 타입은 다운로드
+        const url = window.URL.createObjectURL(blob);
+        const link = document.createElement('a');
+        link.href = url;
+        link.download = project.originalFileName || 'gtc-file';
+        document.body.appendChild(link);
+        link.click();
+        document.body.removeChild(link);
+        window.URL.revokeObjectURL(url);
+      }
+    } catch (error) {
+      console.error("파일 미리보기 오류:", error);
+    }
+  }
+
+  const getFileIcon = () => {
+    if (project.mimeType?.includes('pdf')) {
+      return "📄"
+    } else if (project.mimeType?.includes('word') || project.mimeType?.includes('document')) {
+      return "📝"
+    } else if (project.mimeType?.includes('text')) {
+      return "📃"
+    }
+    return "📎"
+  }
+
+  return (
+    <Dialog open={open} onOpenChange={onOpenChange}>
+      <DialogContent className="sm:max-w-[500px]">
+        <DialogHeader>
+          <DialogTitle>GTC 파일 정보</DialogTitle>
+          <DialogDescription>
+            프로젝트 &quot;{project.name}&quot; ({project.code})의 GTC 파일 정보입니다.
+          </DialogDescription>
+        </DialogHeader>
+        
+        <div className="space-y-4">
+          {/* 프로젝트 정보 */}
+          <div className="p-4 bg-muted rounded-lg">
+            <h4 className="font-medium mb-2">프로젝트 정보</h4>
+            <div className="space-y-2 text-sm">
+              <div className="flex justify-between">
+                <span className="text-muted-foreground">프로젝트 코드:</span>
+                <span className="font-medium">{project.code}</span>
+              </div>
+              <div className="flex justify-between">
+                <span className="text-muted-foreground">프로젝트명:</span>
+                <span className="font-medium">{project.name}</span>
+              </div>
+              <div className="flex justify-between">
+                <span className="text-muted-foreground">프로젝트 타입:</span>
+                <Badge variant="secondary">{project.type}</Badge>
+              </div>
+            </div>
+          </div>
+
+          {/* 파일 정보 */}
+          <div className="p-4 bg-muted rounded-lg">
+            <h4 className="font-medium mb-2">파일 정보</h4>
+            <div className="space-y-3">
+              <div className="flex items-center space-x-3">
+                <span className="text-2xl">{getFileIcon()}</span>
+                <div className="flex-1">
+                  <div className="font-medium">{project.originalFileName}</div>
+                  <div className="text-sm text-muted-foreground">
+                    {project.fileName}
+                  </div>
+                </div>
+              </div>
+              
+              <div className="grid grid-cols-2 gap-4 text-sm">
+                <div className="flex items-center space-x-2">
+                  <HardDrive className="h-4 w-4 text-muted-foreground" />
+                  <span className="text-muted-foreground">파일 크기:</span>
+                  <span className="font-medium">
+                    {project.fileSize ? formatBytes(project.fileSize) : '알 수 없음'}
+                  </span>
+                </div>
+                <div className="flex items-center space-x-2">
+                  <FileText className="h-4 w-4 text-muted-foreground" />
+                  <span className="text-muted-foreground">파일 타입:</span>
+                  <span className="font-medium">
+                    {project.mimeType || '알 수 없음'}
+                  </span>
+                </div>
+                <div className="flex items-center space-x-2">
+                  <Calendar className="h-4 w-4 text-muted-foreground" />
+                  <span className="text-muted-foreground">업로드일:</span>
+                  <span className="font-medium">
+                    {project.gtcCreatedAt ? 
+                      format(new Date(project.gtcCreatedAt), "yyyy-MM-dd HH:mm", { locale: ko }) : 
+                      '알 수 없음'
+                    }
+                  </span>
+                </div>
+                <div className="flex items-center space-x-2">
+                  <Calendar className="h-4 w-4 text-muted-foreground" />
+                  <span className="text-muted-foreground">수정일:</span>
+                  <span className="font-medium">
+                    {project.gtcUpdatedAt ? 
+                      format(new Date(project.gtcUpdatedAt), "yyyy-MM-dd HH:mm", { locale: ko }) : 
+                      '알 수 없음'
+                    }
+                  </span>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+
+        <DialogFooter className="flex space-x-2">
+          <Button
+            type="button"
+            variant="outline"
+            onClick={() => onOpenChange(false)}
+          >
+            닫기
+          </Button>
+          <Button
+            type="button"
+            variant="outline"
+            onClick={handlePreview}
+          >
+            미리보기
+          </Button>
+          <Button
+            type="button"
+            onClick={handleDownload}
+          >
+            <Download className="mr-2 h-4 w-4" />
+            다운로드
+          </Button>
+        </DialogFooter>
+      </DialogContent>
+    </Dialog>
+  )
+} 
\ No newline at end of file
-- 
cgit v1.2.3

