import React, { useState, useCallback, useEffect } from 'react'; import { Modal } from '@mantine/core'; import { Dropzone } from '@mantine/dropzone'; import { useTranslation } from 'react-i18next'; import { FileWithUrl } from '../../types/file'; import { useFileManager } from '../../hooks/useFileManager'; import { useFilesModalContext } from '../../contexts/FilesModalContext'; import { Tool } from '../../types/tool'; import MobileLayout from './fileManager/MobileLayout'; import DesktopLayout from './fileManager/DesktopLayout'; import DragOverlay from './fileManager/DragOverlay'; import { FileManagerProvider } from './fileManager/FileManagerContext'; interface FileManagerProps { selectedTool?: Tool | null; } const FileManager: React.FC = ({ selectedTool }) => { const { t } = useTranslation(); const { isFilesModalOpen, closeFilesModal, onFileSelect, onFilesSelect } = useFilesModalContext(); const [recentFiles, setRecentFiles] = useState([]); const [isDragging, setIsDragging] = useState(false); const [isMobile, setIsMobile] = useState(false); const { loadRecentFiles, handleRemoveFile, storeFile, convertToFile, touchFile } = useFileManager(); // File management handlers const isFileSupported = useCallback((fileName: string) => { if (!selectedTool?.supportedFormats) return true; const extension = fileName.split('.').pop()?.toLowerCase(); return selectedTool.supportedFormats.includes(extension || ''); }, [selectedTool?.supportedFormats]); const refreshRecentFiles = useCallback(async () => { const files = await loadRecentFiles(); setRecentFiles(files); }, [loadRecentFiles]); const handleFilesSelected = useCallback(async (files: FileWithUrl[]) => { try { const fileObjects = await Promise.all( files.map(async (fileWithUrl) => { if (fileWithUrl.file) { return fileWithUrl.file; } return await convertToFile(fileWithUrl); }) ); onFilesSelect(fileObjects); } catch (error) { console.error('Failed to process selected files:', error); } }, [convertToFile, onFilesSelect]); const handleNewFileUpload = useCallback(async (files: File[]) => { if (files.length > 0) { try { // Store files and refresh recent files await Promise.all(files.map(file => storeFile(file))); onFilesSelect(files); await refreshRecentFiles(); } catch (error) { console.error('Failed to process dropped files:', error); } } }, [storeFile, onFilesSelect, refreshRecentFiles]); const handleRemoveFileByIndex = useCallback(async (index: number) => { await handleRemoveFile(index, recentFiles, setRecentFiles); }, [handleRemoveFile, recentFiles]); useEffect(() => { const checkMobile = () => setIsMobile(window.innerWidth < 1030); checkMobile(); window.addEventListener('resize', checkMobile); return () => window.removeEventListener('resize', checkMobile); }, []); useEffect(() => { if (isFilesModalOpen) { refreshRecentFiles(); } else { // Reset state when modal is closed setIsDragging(false); } }, [isFilesModalOpen, refreshRecentFiles]); // Cleanup any blob URLs when component unmounts useEffect(() => { return () => { // Clean up blob URLs from recent files recentFiles.forEach(file => { if (file.url && file.url.startsWith('blob:')) { URL.revokeObjectURL(file.url); } }); }; }, [recentFiles]); // Modal size constants for consistent scaling const modalHeight = '80vh'; const modalWidth = isMobile ? '100%' : '80vw'; const modalMaxWidth = isMobile ? '100%' : '1200px'; const modalMaxHeight = '1200px'; const modalMinWidth = isMobile ? '320px' : '800px'; return (
setIsDragging(true)} onDragLeave={() => setIsDragging(false)} accept={["*/*"]} multiple={true} activateOnClick={false} style={{ height: '100%', width: '100%', border: 'none', borderRadius: '30px', backgroundColor: 'var(--bg-file-manager)' }} styles={{ inner: { pointerEvents: 'all' } }} > {isMobile ? : }
); }; export default FileManager;