import React, { useState, useCallback, useRef, useEffect } from 'react'; import { Text, Checkbox, Tooltip, ActionIcon, Badge } from '@mantine/core'; import { useTranslation } from 'react-i18next'; import CloseIcon from '@mui/icons-material/Close'; import PushPinIcon from '@mui/icons-material/PushPin'; import PushPinOutlinedIcon from '@mui/icons-material/PushPinOutlined'; import DragIndicatorIcon from '@mui/icons-material/DragIndicator'; import { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'; import styles from './PageEditor.module.css'; import { useFileContext } from '../../contexts/FileContext'; interface FileItem { id: string; name: string; pageCount: number; thumbnail: string; size: number; splitBefore?: boolean; } interface FileThumbnailProps { file: FileItem; index: number; totalFiles: number; selectedFiles: string[]; selectionMode: boolean; onToggleFile: (fileId: string) => void; onDeleteFile: (fileId: string) => void; onViewFile: (fileId: string) => void; onSetStatus: (status: string) => void; onReorderFiles?: (sourceFileId: string, targetFileId: string, selectedFileIds: string[]) => void; toolMode?: boolean; isSupported?: boolean; } const FileThumbnail = ({ file, index, totalFiles, selectedFiles, selectionMode, onToggleFile, onDeleteFile, onViewFile, onSetStatus, onReorderFiles, toolMode = false, isSupported = true, }: FileThumbnailProps) => { const { t } = useTranslation(); const { pinnedFiles, pinFile, unpinFile, isFilePinned, activeFiles } = useFileContext(); // Drag and drop state const [isDragging, setIsDragging] = useState(false); const dragElementRef = useRef(null); // Find the actual File object that corresponds to this FileItem const actualFile = activeFiles.find(f => f.name === file.name && f.size === file.size); const formatFileSize = (bytes: number) => { if (bytes === 0) 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(1)) + ' ' + sizes[i]; }; // Setup drag and drop using @atlaskit/pragmatic-drag-and-drop const fileElementRef = useCallback((element: HTMLDivElement | null) => { if (!element) return; dragElementRef.current = element; const dragCleanup = draggable({ element, getInitialData: () => ({ type: 'file', fileId: file.id, fileName: file.name, selectedFiles: [file.id] // Always drag only this file, ignore selection state }), onDragStart: () => { setIsDragging(true); }, onDrop: () => { setIsDragging(false); } }); const dropCleanup = dropTargetForElements({ element, getData: () => ({ type: 'file', fileId: file.id }), canDrop: ({ source }) => { const sourceData = source.data; return sourceData.type === 'file' && sourceData.fileId !== file.id; }, onDrop: ({ source }) => { const sourceData = source.data; if (sourceData.type === 'file' && onReorderFiles) { const sourceFileId = sourceData.fileId as string; const selectedFileIds = sourceData.selectedFiles as string[]; onReorderFiles(sourceFileId, file.id, selectedFileIds); } } }); return () => { dragCleanup(); dropCleanup(); }; }, [file.id, file.name, selectionMode, selectedFiles, onReorderFiles]); return (
{selectionMode && (
e.stopPropagation()} onDragStart={(e) => { e.preventDefault(); e.stopPropagation(); }} > { event.stopPropagation(); if (isSupported) { onToggleFile(file.id); } }} onClick={(e) => e.stopPropagation()} disabled={!isSupported} size="sm" />
)} {/* File content area */}
{/* Stacked file effect - multiple shadows to simulate pages */}
{file.name} { // Hide broken image if blob URL was revoked const img = e.target as HTMLImageElement; img.style.display = 'none'; }} style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain', borderRadius: 2, }} />
{/* Page count badge - only show for PDFs */} {file.pageCount > 0 && ( {file.pageCount} {file.pageCount === 1 ? 'page' : 'pages'} )} {/* Unsupported badge */} {!isSupported && ( {t("fileManager.unsupported", "Unsupported")} )} {/* File name overlay */} {file.name} {/* Hover controls */}
{actualFile && ( { e.stopPropagation(); if (isFilePinned(actualFile)) { unpinFile(actualFile); onSetStatus(`Unpinned ${file.name}`); } else { pinFile(actualFile); onSetStatus(`Pinned ${file.name}`); } }} > {isFilePinned(actualFile) ? ( ) : ( )} )} { e.stopPropagation(); onDeleteFile(file.id); onSetStatus(`Closed ${file.name}`); }} >
{/* File info */}
{file.name} {formatFileSize(file.size)}
); }; export default FileThumbnail;