"use client"; import React, { useState, useEffect } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { FileInfo } from "./types"; import { Download, X, AlertTriangle, FileText, Image as ImageIcon } from "lucide-react"; import { formatFileSize } from "@/lib/utils"; interface FileViewerModalProps { file: FileInfo | null; isOpen: boolean; onClose: () => void; onDownload?: (file: FileInfo) => void; } /** * 파일 뷰어 모달 컴포넌트 * 다양한 파일 타입에 대한 미리보기 기능 제공 */ export const FileViewerModal: React.FC = ({ file, isOpen, onClose, onDownload, }) => { const [previewUrl, setPreviewUrl] = useState(null); const [previewError, setPreviewError] = useState(null); const [isLoading, setIsLoading] = useState(false); // 파일이 변경될 때마다 미리보기 URL 생성 useEffect(() => { if (!file || !isOpen) { setPreviewUrl(null); setPreviewError(null); return; } setIsLoading(true); setPreviewError(null); // 로컬 파일인 경우 if (file._file) { const url = URL.createObjectURL(file._file); setPreviewUrl(url); setIsLoading(false); return () => URL.revokeObjectURL(url); } // 서버 파일인 경우 - 미리보기 API 호출 const generatePreviewUrl = async () => { try { const fileExt = file.fileExt.toLowerCase(); // 미리보기 지원 파일 타입 정의 const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg']; const documentExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'rtf', 'odt', 'ods', 'odp', 'hwp', 'hwpx', 'hwpml', 'hcdt', 'hpt', 'pages', 'numbers', 'keynote']; const textExtensions = ['txt', 'md', 'json', 'xml', 'csv']; const mediaExtensions = ['mp4', 'webm', 'ogg', 'mp3', 'wav']; const supportedExtensions = [ ...imageExtensions, ...documentExtensions, ...textExtensions, ...mediaExtensions ]; if (supportedExtensions.includes(fileExt)) { // 실제 환경에서는 파일 서빙 API 엔드포인트 사용 const url = `/api/files/preview/${file.objid}`; setPreviewUrl(url); } else { // 지원하지 않는 파일 타입 setPreviewError(`${file.fileExt.toUpperCase()} 파일은 미리보기를 지원하지 않습니다.`); } } catch (error) { console.error('미리보기 URL 생성 오류:', error); setPreviewError('미리보기를 불러오는데 실패했습니다.'); } finally { setIsLoading(false); } }; generatePreviewUrl(); }, [file, isOpen]); if (!file) return null; // 파일 타입별 미리보기 컴포넌트 const renderPreview = () => { if (isLoading) { return (
); } if (previewError) { return (

미리보기 불가

{previewError}

); } const fileExt = file.fileExt.toLowerCase(); // 이미지 파일 if (['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'].includes(fileExt)) { return (
{file.realFileName} setPreviewError('이미지를 불러올 수 없습니다.')} />
); } // 텍스트 파일 if (['txt', 'md', 'json', 'xml', 'csv'].includes(fileExt)) { return (