// components/ui/file-actions.tsx // 재사용 가능한 파일 액션 컴포넌트들 "use client"; import * as React from "react"; import { Download, Eye, Paperclip, Loader2, AlertCircle, FileText, Image as ImageIcon, Archive } from "lucide-react"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; import { useMultiFileDownload } from "@/hooks/use-file-download"; import { getFileInfo, quickDownload, quickPreview, smartFileAction } from "@/lib/file-download"; import { cn } from "@/lib/utils"; /** * 파일 아이콘 컴포넌트 */ interface FileIconProps { fileName: string; className?: string; } export const FileIcon: React.FC = ({ fileName, className }) => { const fileInfo = getFileInfo(fileName); const iconMap = { pdf: FileText, document: FileText, spreadsheet: FileText, image: ImageIcon, archive: Archive, other: Paperclip, }; const IconComponent = iconMap[fileInfo.type]; return ( ); }; /** * 기본 파일 다운로드 버튼 */ interface FileDownloadButtonProps { filePath: string; fileName: string; variant?: "default" | "ghost" | "outline"; size?: "default" | "sm" | "lg" | "icon"; children?: React.ReactNode; className?: string; showIcon?: boolean; disabled?: boolean; } export const FileDownloadButton: React.FC = ({ filePath, fileName, variant = "ghost", size = "icon", children, className, showIcon = true, disabled, }) => { const { downloadFile, isFileLoading, getFileError } = useMultiFileDownload(); const isLoading = isFileLoading(filePath); const error = getFileError(filePath); const handleClick = () => { if (!disabled && !isLoading) { quickDownload(filePath, fileName); } }; if (isLoading) { return ( ); } return ( {error ? `오류: ${error} (클릭하여 재시도)` : `${fileName} 다운로드`} ); }; /** * 미리보기 버튼 */ interface FilePreviewButtonProps extends Omit { fallbackToDownload?: boolean; } export const FilePreviewButton: React.FC = ({ filePath, fileName, variant = "ghost", size = "icon", className, fallbackToDownload = true, disabled, }) => { const { isFileLoading, getFileError } = useMultiFileDownload(); const fileInfo = getFileInfo(fileName); const isLoading = isFileLoading(filePath); const error = getFileError(filePath); const handleClick = () => { if (!disabled && !isLoading) { if (fileInfo.canPreview) { quickPreview(filePath, fileName); } else if (fallbackToDownload) { quickDownload(filePath, fileName); } } }; if (!fileInfo.canPreview && !fallbackToDownload) { return ( ); } if (isLoading) { return ( ); } return ( {error ? `오류: ${error} (클릭하여 재시도)` : fileInfo.canPreview ? `${fileName} 미리보기` : `${fileName} 다운로드` } ); }; /** * 드롭다운 파일 액션 버튼 (미리보기 + 다운로드) */ interface FileActionsDropdownProps { filePath: string; fileName: string; description?: string; variant?: "default" | "ghost" | "outline"; size?: "default" | "sm" | "lg" | "icon"; className?: string; disabled?: boolean; triggerIcon?: React.ReactNode; } export const FileActionsDropdown: React.FC = ({ filePath, fileName, variant = "ghost", size = "icon", className, disabled, triggerIcon, description }) => { const { isFileLoading, getFileError } = useMultiFileDownload(); const fileInfo = getFileInfo(fileName); const isLoading = isFileLoading(filePath); const error = getFileError(filePath); const handlePreview = () => quickPreview(filePath, fileName); const handleDownload = () => quickDownload(filePath, fileName); if (isLoading) { return ( ); } if (error) { return (
오류 발생
{error}
클릭하여 재시도
); } return ( {fileInfo.canPreview && ( <> {fileInfo.icon} 미리보기 )} {description} 다운로드 ); }; /** * 스마트 파일 액션 버튼 (자동 판단) */ interface SmartFileActionButtonProps extends Omit { showLabel?: boolean; } export const SmartFileActionButton: React.FC = ({ filePath, fileName, variant = "ghost", size = "icon", className, showLabel = false, disabled, }) => { const { isFileLoading, getFileError } = useMultiFileDownload(); const fileInfo = getFileInfo(fileName); const isLoading = isFileLoading(filePath); const error = getFileError(filePath); const handleClick = () => { if (!disabled && !isLoading) { smartFileAction(filePath, fileName); } }; if (isLoading) { return ( ); } const actionText = fileInfo.canPreview ? '미리보기' : '다운로드'; const IconComponent = fileInfo.canPreview ? Eye : Download; return ( {error ? `오류: ${error} (클릭하여 재시도)` : `${fileInfo.icon} ${fileName} ${actionText}` } ); }; /** * 파일명 링크 컴포넌트 */ interface FileNameLinkProps { filePath: string; fileName: string; className?: string; showIcon?: boolean; maxLength?: number; } export const FileNameLink: React.FC = ({ filePath, fileName, className, showIcon = true, maxLength = 200, }) => { const fileInfo = getFileInfo(fileName); const handleClick = () => { smartFileAction(filePath, fileName); }; const displayName = fileName.length > maxLength ? `${fileName.substring(0, maxLength)}...` : fileName; return ( ); };