diff --git a/src/components/dashboard/EventsSection.astro b/src/components/dashboard/EventsSection.astro index 451acce..ec70d01 100644 --- a/src/components/dashboard/EventsSection.astro +++ b/src/components/dashboard/EventsSection.astro @@ -1,6 +1,7 @@ --- import { Icon } from "astro-icon/components"; import JSZip from "jszip"; +import FilePreview from "./Officer_EventManagement/FilePreview"; --- -

- - -
- @@ -858,95 +870,8 @@ import JSZip from "jszip"; } function showFilePreview(file: { url: string; type: string; name: string }) { - const filePreviewSection = document.getElementById("filePreviewSection"); - const filesContent = document.getElementById("filesContent"); - const previewContent = document.getElementById("previewContent"); - const previewFileName = document.getElementById("previewFileName"); - const modalTitle = document.getElementById("modalTitle"); - - if ( - !filePreviewSection || - !filesContent || - !previewContent || - !previewFileName - ) - return; - - filePreviewSection.classList.remove("hidden"); - filesContent.classList.add("hidden"); - previewFileName.textContent = file.name; - if (modalTitle) modalTitle.textContent = "File Preview"; - - const fileType = file.type.toLowerCase(); - showLoading(); - - // Create the PocketBase URL - const baseUrl = "https://pocketbase.ieeeucsd.org"; - const fileUrl = `${baseUrl}/api/files/events/${currentEventId}/${file.name}`; - - if (!isPreviewableType(fileType)) { - previewContent.innerHTML = ` -
-
📄
-

- This file type (${file.type}) cannot be previewed. -
- - Open in New Tab - -

-
- `; - hideLoading(); - return; - } - - if (fileType.startsWith("image/")) { - previewContent.innerHTML = ` - ${file.name} - `; - } else if (fileType.startsWith("video/")) { - previewContent.innerHTML = ` - - `; - } else if (fileType === "application/pdf") { - previewContent.innerHTML = ` - - `; - } else if ( - fileType.startsWith("text/") || - fileType === "application/json" - ) { - previewContent.innerHTML = ` - - `; - } else if (fileType.startsWith("audio/")) { - previewContent.innerHTML = ` - - `; - } + console.log('showFilePreview called with:', file); + window.previewFileEvents(file.url, file.name); } function handlePreviewError() { @@ -954,24 +879,67 @@ import JSZip from "jszip"; const previewContent = document.getElementById("previewContent"); if (previewContent) { previewContent.innerHTML = ` -
- - - - Failed to load file preview -
- `; +
+ + + + Failed to load file preview +
+ `; } } - // Make helper functions available globally - window.showFilePreview = showFilePreview; - window.backToFileList = backToFileList; - window.handlePreviewError = handlePreviewError; - window.showLoading = showLoading; - window.hideLoading = hideLoading; + // Universal file preview function for events section + window.previewFileEvents = function (url: string, filename: string) { + console.log('previewFileEvents called with:', { url, filename }); + const modal = document.getElementById("filePreviewModal") as HTMLDialogElement; + const previewFileName = document.getElementById("previewFileName"); + const previewContent = document.getElementById("previewContent"); + + if (modal && previewFileName && previewContent) { + console.log('Found all required elements'); + // Update the filename display + previewFileName.textContent = filename; + + // Show the modal + modal.showModal(); - // Add openDetailsModal function + // Dispatch state change event + window.dispatchEvent(new CustomEvent('filePreviewStateChange', { + detail: { url, filename } + })); + } + }; + + // Close file preview for events section + window.closeFilePreviewEvents = function () { + console.log('closeFilePreviewEvents called'); + const modal = document.getElementById("filePreviewModal") as HTMLDialogElement; + const previewFileName = document.getElementById("previewFileName"); + const previewContent = document.getElementById("previewContent"); + + if (modal && previewFileName && previewContent) { + console.log('Resetting preview and closing modal'); + // Reset the preview state + window.dispatchEvent(new CustomEvent('filePreviewStateChange', { + detail: { url: "", filename: "" } + })); + + // Reset the UI + previewFileName.textContent = ""; + + // Close the modal + modal.close(); + } + }; + + // Update the showFilePreview function for events section + window.showFilePreviewEvents = function (file: { url: string; name: string }) { + console.log('showFilePreviewEvents called with:', file); + window.previewFileEvents(file.url, file.name); + }; + + // Update the openDetailsModal function to use the events-specific preview window.openDetailsModal = function (event: any) { const modal = document.getElementById( "eventDetailsModal", @@ -979,13 +947,9 @@ import JSZip from "jszip"; const filesContent = document.getElementById( "filesContent", ) as HTMLDivElement; - const filePreviewSection = document.getElementById( - "filePreviewSection", - ) as HTMLDivElement; // Reset state currentEventId = event.id; - if (filePreviewSection) filePreviewSection.classList.add("hidden"); if (filesContent) filesContent.classList.remove("hidden"); // Populate files content @@ -995,58 +959,53 @@ import JSZip from "jszip"; const recordId = event.id; filesContent.innerHTML = ` -
- - - - - - - - - ${event.files - .map((file: string) => { - const fileUrl = `${baseUrl}/api/files/${collectionId}/${recordId}/${file}`; - const fileType = getFileType(file); - return ` - - - - - `; - }) - .join("")} - -
File NameActions
${file} - - - - - - -
-
- `; +
+ + + + + + + + + ${event.files + .map((file: string) => { + const fileUrl = `${baseUrl}/api/files/${collectionId}/${recordId}/${file}`; + const fileType = getFileType(file); + const previewData = JSON.stringify({ url: fileUrl, name: file }).replace(/'/g, "\\'"); + return ` + + + + + `; + }) + .join("")} + +
File NameActions
${file} + + + + + + +
+
+ `; } else { filesContent.innerHTML = ` -
- - - -

No files attached to this event

-
- `; +
+ + + +

No files attached to this event

+
+ `; } modal.showModal(); @@ -1120,6 +1079,36 @@ import JSZip from "jszip"; } }; + // Close event details modal + window.closeEventDetailsModal = function () { + const modal = document.getElementById("eventDetailsModal") as HTMLDialogElement; + const filesContent = document.getElementById("filesContent"); + + if (modal) { + // Reset the files content + if (filesContent) { + filesContent.innerHTML = ''; + } + + // Reset any other state if needed + currentEventId = ''; + + // Close the modal + modal.close(); + } + }; + + // Make helper functions available globally + window.showFilePreview = showFilePreview; + window.handlePreviewError = handlePreviewError; + window.showLoading = showLoading; + window.hideLoading = hideLoading; + window.previewFileEvents = previewFileEvents; + window.closeFilePreviewEvents = closeFilePreviewEvents; + window.showFilePreviewEvents = showFilePreviewEvents; + window.openDetailsModal = openDetailsModal; + window.closeEventDetailsModal = closeEventDetailsModal; + // Add TypeScript interface for Window declare global { interface Window { diff --git a/src/components/dashboard/Officer_EventManagement.astro b/src/components/dashboard/Officer_EventManagement.astro index b892496..bd816a9 100644 --- a/src/components/dashboard/Officer_EventManagement.astro +++ b/src/components/dashboard/Officer_EventManagement.astro @@ -648,27 +648,7 @@ const currentPage = eventResponse.page;
@@ -1776,29 +1756,8 @@ const currentPage = eventResponse.page; // Update the showFilePreview function window.showFilePreview = function (file: { url: string; name: string }) { - const fileListSection = document.getElementById("filesContent"); - const previewSection = document.getElementById("filePreviewSection"); - const mainFilePreview = document.getElementById("mainFilePreview"); - const previewFileName = document.getElementById("previewFileName"); - - if ( - !fileListSection || - !previewSection || - !mainFilePreview || - !previewFileName - ) - return; - - // Hide file list and show preview section - fileListSection.classList.add("hidden"); - previewSection.classList.remove("hidden"); - previewFileName.textContent = file.name; - - // Dispatch a custom event to update the FilePreview - const event = new CustomEvent("updateFilePreview", { - detail: { url: file.url, filename: file.name }, - }); - mainFilePreview.dispatchEvent(event); + console.log('showFilePreview called with:', file); + window.previewFile(file.url, file.name); }; // Add backToEditForm function @@ -1829,11 +1788,13 @@ const currentPage = eventResponse.page; // Universal file preview function window.previewFile = function (url: string, filename: string) { + console.log('previewFile called with:', { url, filename }); const modal = document.getElementById("filePreviewModal") as HTMLDialogElement; - const filePreview = document.getElementById("universalFilePreview") as any; + const filePreview = document.getElementById("officerFilePreview") as any; const previewFileName = document.getElementById("previewFileName"); if (filePreview && modal && previewFileName) { + console.log('Found all required elements'); // Update the filename display previewFileName.textContent = filename; @@ -1841,29 +1802,36 @@ const currentPage = eventResponse.page; modal.showModal(); // Update the preview component - filePreview.setAttribute("url", url); - filePreview.setAttribute("filename", filename); + console.log('Dispatching updateFilePreview event'); + const event = new CustomEvent("updateFilePreview", { + detail: { url, filename } + }); + filePreview.dispatchEvent(event); + } else { + console.error('Missing required elements:', { + modal: !!modal, + filePreview: !!filePreview, + previewFileName: !!previewFileName + }); } }; // Close file preview window.closeFilePreview = function () { + console.log('closeFilePreview called'); const modal = document.getElementById("filePreviewModal") as HTMLDialogElement; - const filePreview = document.getElementById("universalFilePreview") as any; + const filePreview = document.getElementById("officerFilePreview") as any; const previewFileName = document.getElementById("previewFileName"); - const filesContent = document.getElementById("filesContent"); if (modal && filePreview && previewFileName) { + console.log('Resetting preview and closing modal'); // Reset the preview - filePreview.setAttribute("url", ""); - filePreview.setAttribute("filename", ""); + const event = new CustomEvent("updateFilePreview", { + detail: { url: "", filename: "" } + }); + filePreview.dispatchEvent(event); previewFileName.textContent = ""; modal.close(); - - // Show the files list if we're in the event details modal - if (filesContent) { - filesContent.classList.remove('hidden'); - } } }; @@ -1891,13 +1859,14 @@ const currentPage = eventResponse.page; .map( (filename) => { const fileUrl = fileManager.getFileUrl("events", eventId, filename); + const previewData = JSON.stringify({ url: fileUrl, name: filename }).replace(/'/g, "\\'"); return `
${filename}
-

{previewFilename} @@ -278,6 +278,7 @@ export default function EventEditor({ onEventSaved }: EventEditorProps) {

diff --git a/src/components/dashboard/Officer_EventManagement/FilePreview.tsx b/src/components/dashboard/Officer_EventManagement/FilePreview.tsx index bc4e11c..6c75b46 100644 --- a/src/components/dashboard/Officer_EventManagement/FilePreview.tsx +++ b/src/components/dashboard/Officer_EventManagement/FilePreview.tsx @@ -1,18 +1,57 @@ import React, { useEffect, useState } from 'react'; interface FilePreviewProps { - url: string; - filename: string; + url?: string; + filename?: string; + isModal?: boolean; } -const FilePreview: React.FC = ({ url, filename }) => { +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); 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); + + // Reset state when url is empty (modal closing) + if (!newUrl) { + setContent(null); + setError(null); + setFileType(null); + setLoading(false); + } + }; + + // 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); @@ -20,38 +59,47 @@ const FilePreview: React.FC = ({ url, filename }) => { } 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(); - // Truncate text if it's too long (e.g., more than 100KB) 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')) { - // Fallback for video files when content-type might not be correct + 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) { - setError('Failed to load file'); console.error('Error loading file:', err); + setError('Failed to load file'); } finally { + console.log('Finished loading content'); setLoading(false); } }; @@ -77,6 +125,8 @@ const FilePreview: React.FC = ({ url, filename }) => { } }; + console.log('Rendering FilePreview with:', { content, error, loading, fileType }); + return (
{/* Header with filename and download button */} diff --git a/src/components/modals/FilePreview.tsx b/src/components/modals/FilePreview.tsx deleted file mode 100644 index 31badb4..0000000 --- a/src/components/modals/FilePreview.tsx +++ /dev/null @@ -1,318 +0,0 @@ -import { useState, useEffect } from "react"; -import { FileManager } from "../pocketbase/FileManager"; - -interface FilePreviewProps { - url: string; - filename: string; - onClose?: () => void; -} - -export default function FilePreview({ url, filename, onClose }: FilePreviewProps) { - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - const [fileType, setFileType] = useState(null); - const [modalElement, setModalElement] = useState(null); - - useEffect(() => { - const modal = document.getElementById('filePreviewModal') as HTMLDialogElement; - setModalElement(modal); - - const initializeViewer = async () => { - try { - setLoading(true); - setError(null); - setFileContent(null); - - // Determine file type from extension - const extension = filename.split('.').pop()?.toLowerCase() || ''; - const type = getFileType(extension); - setFileType(type); - - // If it's a code file, fetch its content - if (type === 'code') { - await fetchCodeContent(url); - } - - setLoading(false); - } catch (err) { - setError("Failed to load file preview"); - setLoading(false); - } - }; - - // Only initialize if we have both url and filename - if (url && filename) { - initializeViewer(); - if (modal && !modal.open) { - modal.showModal(); - } - } - - // Cleanup function - return () => { - if (modal?.open) { - modal.close(); - } - setFileContent(null); - }; - }, [url, filename]); - - const handleClose = () => { - if (modalElement?.open) { - modalElement.close(); - } - onClose?.(); - }; - - const [fileContent, setFileContent] = useState(null); - - const getFileType = (extension: string): string => { - const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg']; - const videoTypes = ['mp4', 'webm', 'ogg', 'mov']; - const documentTypes = ['pdf', 'doc', 'docx', 'txt', 'md']; - const spreadsheetTypes = ['xls', 'xlsx', 'csv']; - const presentationTypes = ['ppt', 'pptx']; - const codeTypes = ['js', 'ts', 'jsx', 'tsx', 'html', 'css', 'json', 'py', 'java', 'cpp', 'h', 'c', 'cs', 'php', 'rb', 'swift', 'go', 'rs']; - - if (imageTypes.includes(extension)) return 'image'; - if (videoTypes.includes(extension)) return 'video'; - if (documentTypes.includes(extension)) return 'document'; - if (spreadsheetTypes.includes(extension)) return 'spreadsheet'; - if (presentationTypes.includes(extension)) return 'presentation'; - if (codeTypes.includes(extension)) return 'code'; - return 'other'; - }; - - // Function to fetch and set code content - const fetchCodeContent = async (url: string) => { - try { - const response = await fetch(url); - const text = await response.text(); - setFileContent(text); - } catch (err) { - console.error('Failed to fetch code content:', err); - setError('Failed to load code content'); - } - }; - - const renderFileIcon = () => { - switch (fileType) { - case 'image': - return ( - - - - ); - case 'video': - return ( - - - - ); - case 'document': - return ( - - - - ); - case 'code': - return ( - - - - ); - case 'spreadsheet': - return ( - - - - ); - default: - return ( - - - - ); - } - }; - - const renderPreview = () => { - if (loading) { - return ( -
- -
- ); - } - - if (error) { - return ( -
- - - -

{error}

-
- ); - } - - switch (fileType) { - case 'image': - return ( -
-
- {filename} setError("Failed to load image")} - /> - - Download - -
-
- ); - case 'video': - return ( -
- - - Download Video - -
- ); - case 'code': - if (fileContent !== null) { - return ( -
-
-                                {fileContent}
-                            
- -
- ); - } - return ( -
- {renderFileIcon()} -

{filename}

-
-
- ); - case 'document': - if (filename.toLowerCase().endsWith('.pdf')) { - return ( -
-