import React, { useState, useEffect } from 'react'; import { Modal, Text, Button, Group, Stack, Checkbox, ScrollArea, Box, Image, Badge, ThemeIcon, SimpleGrid } from '@mantine/core'; import PictureAsPdfIcon from '@mui/icons-material/PictureAsPdf'; import { useTranslation } from 'react-i18next'; interface FilePickerModalProps { opened: boolean; onClose: () => void; storedFiles: any[]; // Files from storage (FileWithUrl format) onSelectFiles: (selectedFiles: File[]) => void; } const FilePickerModal = ({ opened, onClose, storedFiles, onSelectFiles, }: FilePickerModalProps) => { const { t } = useTranslation(); const [selectedFileIds, setSelectedFileIds] = useState([]); // Reset selection when modal opens useEffect(() => { if (opened) { setSelectedFileIds([]); } }, [opened]); const toggleFileSelection = (fileId: string) => { setSelectedFileIds(prev => { return prev.includes(fileId) ? prev.filter(id => id !== fileId) : [...prev, fileId]; }); }; const selectAll = () => { setSelectedFileIds(storedFiles.map(f => f.id || f.name)); }; const selectNone = () => { setSelectedFileIds([]); }; const handleConfirm = async () => { const selectedFiles = storedFiles.filter(f => selectedFileIds.includes(f.id || f.name) ); // Convert stored files to File objects const convertedFiles = await Promise.all( selectedFiles.map(async (fileItem) => { try { // If it's already a File object, return as is if (fileItem instanceof File) { return fileItem; } // If it has a file property, use that if (fileItem.file && fileItem.file instanceof File) { return fileItem.file; } // If it's from IndexedDB storage, reconstruct the File if (fileItem.arrayBuffer && typeof fileItem.arrayBuffer === 'function') { const arrayBuffer = await fileItem.arrayBuffer(); const blob = new Blob([arrayBuffer], { type: fileItem.type || 'application/pdf' }); return new File([blob], fileItem.name, { type: fileItem.type || 'application/pdf', lastModified: fileItem.lastModified || Date.now() }); } // If it has data property, reconstruct the File if (fileItem.data) { const blob = new Blob([fileItem.data], { type: fileItem.type || 'application/pdf' }); return new File([blob], fileItem.name, { type: fileItem.type || 'application/pdf', lastModified: fileItem.lastModified || Date.now() }); } console.warn('Could not convert file item:', fileItem); return null; } catch (error) { console.error('Error converting file:', error, fileItem); return null; } }) ); // Filter out any null values and return valid Files const validFiles = convertedFiles.filter((f): f is File => f !== null); onSelectFiles(validFiles); onClose(); }; 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]; }; return ( {storedFiles.length === 0 ? ( {t("fileUpload.noFilesInStorage", "No files available in storage. Upload some files first.")} ) : ( <> {/* Selection controls */} {storedFiles.length} {t("fileUpload.filesAvailable", "files available")} {selectedFileIds.length > 0 && ( <> • {selectedFileIds.length} selected )} {/* File grid */} {storedFiles.map((file) => { const fileId = file.id || file.name; const isSelected = selectedFileIds.includes(fileId); return ( toggleFileSelection(fileId)} > toggleFileSelection(fileId)} onClick={(e) => e.stopPropagation()} /> {/* Thumbnail */} {file.thumbnail ? ( PDF thumbnail ) : ( )} {/* File info */} {file.name} {formatFileSize(file.size || (file.file?.size || 0))} ); })} {/* Selection summary */} {selectedFileIds.length > 0 && ( {selectedFileIds.length} {t("fileManager.filesSelected", "files selected")} )} )} {/* Action buttons */} ); }; export default FilePickerModal;