diff --git a/src/components/dashboard/Officer_EventManagement/FilePreview.tsx b/src/components/dashboard/Officer_EventManagement/FilePreview.tsx index 6c75b46..a9f242a 100644 --- a/src/components/dashboard/Officer_EventManagement/FilePreview.tsx +++ b/src/components/dashboard/Officer_EventManagement/FilePreview.tsx @@ -1,4 +1,8 @@ -import React, { useEffect, useState } from 'react'; +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; @@ -13,6 +17,100 @@ const FilePreview: React.FC = ({ url: initialUrl = '', filenam 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'); @@ -24,7 +122,6 @@ const FilePreview: React.FC = ({ url: initialUrl = '', filenam setUrl(newUrl); setFilename(newFilename); - // Reset state when url is empty (modal closing) if (!newUrl) { setContent(null); setError(null); @@ -33,80 +130,16 @@ const FilePreview: React.FC = ({ url: initialUrl = '', filenam } }; - // Add event listener only for modal mode window.addEventListener('filePreviewStateChange', handleStateChange as EventListener); - - // Cleanup return () => { window.removeEventListener('filePreviewStateChange', handleStateChange as EventListener); }; } else { - // For integrated preview, use props directly setUrl(initialUrl); setFilename(initialFilename); } }, [isModal, initialUrl, initialFilename]); - useEffect(() => { - console.log('FilePreview state updated:', { url, filename }); - - if (!url || !filename) { - console.log('No URL or filename, resetting state'); - setContent(null); - setError(null); - setFileType(null); - return; - } - - const loadContent = async () => { - console.log('Loading content for:', { url, filename }); - setLoading(true); - setError(null); - - 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); - - if (contentType?.startsWith('image/')) { - console.log('Setting content type as image'); - setContent('image'); - } else if (contentType?.startsWith('video/')) { - console.log('Setting content type as video'); - setContent('video'); - } else if (contentType?.startsWith('application/pdf')) { - console.log('Setting content type as pdf'); - setContent('pdf'); - } else if (contentType?.startsWith('text/')) { - console.log('Loading text content'); - const text = await response.text(); - if (text.length > 100000) { - console.log('Text content truncated due to length'); - setContent(text.substring(0, 100000) + '\n\n... Content truncated. Please download the file to view the complete content.'); - } else { - setContent(text); - } - } else if (filename.toLowerCase().endsWith('.mp4')) { - console.log('Fallback to video for .mp4 file'); - setContent('video'); - } else { - console.log('Unsupported file type'); - setError(`This file type (${contentType || 'unknown'}) is not supported for preview. Please download the file to view it.`); - } - } catch (err) { - console.error('Error loading file:', err); - setError('Failed to load file'); - } finally { - console.log('Finished loading content'); - setLoading(false); - } - }; - - loadContent(); - }, [url, filename]); - const handleDownload = async () => { try { const response = await fetch(url); @@ -125,21 +158,18 @@ const FilePreview: React.FC = ({ url: initialUrl = '', filenam } }; - console.log('Rendering FilePreview with:', { content, error, loading, fileType }); - return (
- {/* Header with filename and download button */}
- {filename} + {truncatedFilename} {fileType && ( - {fileType.split('/')[1]} + {fileType.split('/')[1]} )}
- {/* Preview content */}
{loading && (
@@ -181,7 +210,12 @@ const FilePreview: React.FC = ({ url: initialUrl = '', filenam {!loading && !error && content === 'image' && (
- {filename} + {filename}
)} @@ -191,6 +225,7 @@ const FilePreview: React.FC = ({ url: initialUrl = '', filenam controls className="max-w-full rounded-lg" style={{ maxHeight: '600px' }} + preload="metadata" > Your browser does not support the video tag. @@ -204,6 +239,7 @@ const FilePreview: React.FC = ({ url: initialUrl = '', filenam src={url} className="w-full h-full rounded-lg" title={filename} + loading="lazy" >
)}