From 4633e16094934143f4e76d6f7bb973b557f86f44 Mon Sep 17 00:00:00 2001 From: Tanuja Pansare Date: Fri, 10 Jul 2026 12:02:38 +0530 Subject: [PATCH] Update Document Upload module --- .../dashboard/EventDocumentsPanel.tsx | 321 ++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 src/app/components/dashboard/EventDocumentsPanel.tsx diff --git a/src/app/components/dashboard/EventDocumentsPanel.tsx b/src/app/components/dashboard/EventDocumentsPanel.tsx new file mode 100644 index 00000000..17397ee3 --- /dev/null +++ b/src/app/components/dashboard/EventDocumentsPanel.tsx @@ -0,0 +1,321 @@ +import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { AlertCircle, CalendarDays, Download, FileText, Mail, Phone, Upload } from "lucide-react"; +import { PanelShell } from "../panels/PanelShell"; +import { listMedia, uploadMediaFile } from "../../../services/api"; +import type { LibraryContent } from "../../../services/api/types"; + +const SUPPORTED_MIME_TYPES = [ + "application/pdf", + "application/msword", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "application/vnd.ms-excel", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "application/vnd.ms-powerpoint", + "application/vnd.openxmlformats-officedocument.presentationml.presentation", + "image/jpeg", + "image/png", + "image/gif", + "image/webp", + "image/bmp", +]; + +const SUPPORTED_EXTENSIONS = [ + ".pdf", + ".doc", + ".docx", + ".xls", + ".xlsx", + ".ppt", + ".pptx", + ".jpg", + ".jpeg", + ".png", + ".gif", + ".webp", + ".bmp", +]; + +function isSupportedFile(file: File) { + const name = file.name.toLowerCase(); + const hasSupportedExtension = SUPPORTED_EXTENSIONS.some((ext) => name.endsWith(ext)); + const hasSupportedMime = SUPPORTED_MIME_TYPES.includes(file.type); + return hasSupportedExtension || hasSupportedMime; +} + +function formatDateTime(value?: string) { + if (!value) return "—"; + const date = new Date(value); + if (Number.isNaN(date.getTime())) return "—"; + return new Intl.DateTimeFormat("en", { + dateStyle: "medium", + timeStyle: "short", + }).format(date); +} + +function getUploaderName(item: LibraryContent) { + if (typeof item.uploadedBy === "object" && item.uploadedBy) { + const parts = [item.uploadedBy.firstName, item.uploadedBy.lastName].filter(Boolean); + if (parts.length) return parts.join(" "); + return item.uploadedBy.email || "Unknown uploader"; + } + return ""; +} + +function getUploaderEmail(item: LibraryContent) { + if (typeof item.uploadedBy === "object" && item.uploadedBy) return item.uploadedBy.email || "—"; + return "—"; +} + +function getUploaderPhone(item: LibraryContent) { + if (typeof item.uploadedBy === "object" && item.uploadedBy) return item.uploadedBy.phone || "—"; + return "—"; +} + +export function EventDocumentsPanel({ + eventId, + eventName, + onClose, +}: { + eventId: string; + eventName?: string; + onClose: () => void; +}) { + const fileInputRef = useRef(null); + const [documents, setDocuments] = useState([]); + const [loading, setLoading] = useState(false); + const [uploading, setUploading] = useState(false); + const [error, setError] = useState(""); + const [success, setSuccess] = useState(""); + + const loadDocuments = useCallback(async () => { + if (!eventId) return; + setLoading(true); + setError(""); + try { + const res = await listMedia({ eventId, limit: 100 }); + setDocuments(res.media ?? []); + } catch (err) { + setError(err instanceof Error ? err.message : "Could not load documents."); + setDocuments([]); + } finally { + setLoading(false); + } + }, [eventId]); + + useEffect(() => { + void loadDocuments(); + }, [loadDocuments]); + + const acceptAttribute = useMemo(() => SUPPORTED_MIME_TYPES.join(","), []); + + const handleUpload = async (file: File | null) => { + if (!file) return; + if (!isSupportedFile(file)) { + setError("Only PDF, Word, Excel, PowerPoint, and image files are supported."); + return; + } + setUploading(true); + setError(""); + setSuccess(""); + try { + await uploadMediaFile(file, { eventId, module: "event-documents", visibility: "private" }); + setSuccess("Document uploaded successfully."); + await loadDocuments(); + } catch (err) { + setError(err instanceof Error ? err.message : "Upload failed."); + } finally { + setUploading(false); + if (fileInputRef.current) fileInputRef.current.value = ""; + } + }; + + return ( + +
+
+
+
+

+ Uploaded documents +

+

+ Files uploaded by you for this event appear here. +

+
+
+ + {error ? ( +
+ + {error} +
+ ) : null} + + {success ? ( +
+ + {success} +
+ ) : null} + + {loading ? ( +

Loading documents…

+ ) : documents.length === 0 ? ( +
+

+ No documents uploaded yet for this event. +

+
+ ) : ( +
+ {documents.map((item) => ( +
+
+ {/*
+
+ +
+
+

+ {item.name || "Untitled document"} +

+ • {getUploaderName(item) || "Uploaded by you"} + +

+ {getUploaderName(item) || "Uploaded by you"} +

+
+
*/} +
+
+ {/* File Name */} +

+ {item.name || "Untitled document"} +

+ + {/* Submitted by + Date */} +
+ + Submitted by {getUploaderName(item) || "You"} + + + {formatDateTime(item.createdAt)} +
+
+
+ {item.url ? ( + + ) : null} +
+ +
+ { + //
+ //

Uploaded by

+ //

{getUploaderEmail(item)}

+ //
+ //
+ //

Submitted

+ //

{formatDateTime(item.createdAt)}

+ //
+ //
+ //

Phone

+ //

{getUploaderPhone(item)}

+ //
+ } +
+
+ ))} +
+ )} +
+ +
+
+
+ +
+
+

Upload a document

+

Allowed: PDF, Word, Excel, PowerPoint, and images.

+
+
+ + { void handleUpload(e.target.files?.[0] ?? null); }} style={{ display: "none" }} /> + + + +
+
PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX
+
JPG, PNG, GIF, BMP, WEBP images
+
The uploader name, email, phone, and upload date are shown in the list.
+
Files are stored for this event and available for download.
+
+
+
+
+ ); +}