import React, { useEffect, useState, useCallback, useMemo } from 'react'; // Cache for file content const contentCache = new Map(); const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes interface FilePreviewProps { url?: string; filename?: string; isModal?: boolean; } const FilePreview: React.FC = ({ url: initialUrl = '', filename: initialFilename = '', isModal = false }) => { const [url, setUrl] = useState(initialUrl); const [filename, setFilename] = useState(initialFilename); const [content, setContent] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const [fileType, setFileType] = useState(null); const [isVisible, setIsVisible] = useState(false); // Memoize the truncated filename const truncatedFilename = useMemo(() => { if (!filename) return ''; const maxLength = 40; if (filename.length <= maxLength) return filename; const extension = filename.split('.').pop(); const name = filename.substring(0, filename.lastIndexOf('.')); const truncatedName = name.substring(0, maxLength - 3 - (extension?.length || 0)); return `${truncatedName}...${extension ? `.${extension}` : ''}`; }, [filename]); // Intersection Observer callback useEffect(() => { const observer = new IntersectionObserver( ([entry]) => { setIsVisible(entry.isIntersecting); }, { threshold: 0.1 } ); const previewElement = document.querySelector('.preview-content'); if (previewElement) { observer.observe(previewElement); } return () => observer.disconnect(); }, []); const loadContent = useCallback(async () => { if (!url || !filename) return; console.log('Loading content for:', { url, filename }); setLoading(true); setError(null); // Check cache first const cacheKey = `${url}_${filename}`; const cachedData = contentCache.get(cacheKey); if (cachedData && Date.now() - cachedData.timestamp < CACHE_DURATION) { console.log('Using cached content'); setContent(cachedData.content); setFileType(cachedData.fileType); setLoading(false); return; } try { console.log('Fetching file...'); const response = await fetch(url); const contentType = response.headers.get('content-type'); console.log('Received content type:', contentType); setFileType(contentType); let contentValue: string | 'image' | 'video' | 'pdf'; if (contentType?.startsWith('image/')) { contentValue = 'image'; } else if (contentType?.startsWith('video/')) { contentValue = 'video'; } else if (contentType?.startsWith('application/pdf')) { contentValue = 'pdf'; } else if (contentType?.startsWith('text/')) { const text = await response.text(); contentValue = text.length > 100000 ? text.substring(0, 100000) + '\n\n... Content truncated. Please download the file to view the complete content.' : text; } else if (filename.toLowerCase().endsWith('.mp4')) { contentValue = 'video'; } else { throw new Error(`Unsupported file type (${contentType || 'unknown'})`); } // Cache the content contentCache.set(cacheKey, { content: contentValue, fileType: contentType || 'unknown', timestamp: Date.now() }); setContent(contentValue); } catch (err) { console.error('Error loading file:', err); setError(err instanceof Error ? err.message : 'Failed to load file'); } finally { setLoading(false); } }, [url, filename]); useEffect(() => { if (isVisible) { loadContent(); } }, [isVisible, loadContent]); useEffect(() => { console.log('FilePreview component mounted'); if (isModal) { const handleStateChange = (event: CustomEvent<{ url: string; filename: string }>) => { console.log('Received state change event:', event.detail); const { url: newUrl, filename: newFilename } = event.detail; setUrl(newUrl); setFilename(newFilename); if (!newUrl) { setContent(null); setError(null); setFileType(null); setLoading(false); } }; window.addEventListener('filePreviewStateChange', handleStateChange as EventListener); return () => { window.removeEventListener('filePreviewStateChange', handleStateChange as EventListener); }; } else { setUrl(initialUrl); setFilename(initialFilename); } }, [isModal, initialUrl, initialFilename]); const handleDownload = async () => { try { const response = await fetch(url); const blob = await response.blob(); const downloadUrl = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = downloadUrl; link.download = filename; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(downloadUrl); } catch (err) { console.error('Error downloading file:', err); alert('Failed to download file. Please try again.'); } }; return (
{truncatedFilename} {fileType && ( {fileType.split('/')[1]} )}
{loading && (
)} {error && (

Preview Unavailable

{error}

)} {!loading && !error && content === 'image' && (
{filename}
)} {!loading && !error && content === 'video' && (
)} {!loading && !error && content === 'pdf' && (
)} {!loading && !error && content && !['image', 'video', 'pdf'].includes(content) && (
{content}
)}
); }; export default FilePreview;