summaryrefslogtreecommitdiff
path: root/lib/project-gtc/table/view-gtc-file-dialog.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-06-20 11:37:31 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-06-20 11:37:31 +0000
commitaa86729f9a2ab95346a2851e3837de1c367aae17 (patch)
treeb601b18b6724f2fb449c7fa9ea50cbd652a8077d /lib/project-gtc/table/view-gtc-file-dialog.tsx
parent95bbe9c583ff841220da1267630e7b2025fc36dc (diff)
(대표님) 20250620 작업사항
Diffstat (limited to 'lib/project-gtc/table/view-gtc-file-dialog.tsx')
-rw-r--r--lib/project-gtc/table/view-gtc-file-dialog.tsx230
1 files changed, 230 insertions, 0 deletions
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