Skip to content

Commit 7ee7ca8

Browse files
committed
fix: Upload metadata & simplified PDF viewer
1 parent a833043 commit 7ee7ca8

4 files changed

Lines changed: 70 additions & 60 deletions

File tree

src/components/common/FilePreviewModal.tsx

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"use client";
22

33
import { X, ExternalLink, Download } from "lucide-react";
4-
import PDFViewer from "./PDFViewer";
54

65
interface FilePreviewModalProps {
76
isOpen: boolean;
@@ -14,26 +13,25 @@ interface FilePreviewModalProps {
1413
export default function FilePreviewModal({ isOpen, onClose, fileUrl, fileName, fileType }: FilePreviewModalProps) {
1514
if (!isOpen) return null;
1615

17-
const safeFileType = fileType || "";
18-
const safeFileName = fileName || "";
16+
// 1. Robust File Type Detection
17+
// Prefer extension from URL as it's the most reliable source of truth
18+
const urlExtension = fileUrl.split('.').pop()?.toLowerCase() || "";
19+
const titleExtension = fileName.split('.').pop()?.toLowerCase() || "";
20+
const effectiveExtension = urlExtension.length > 1 && urlExtension.length < 5 ? urlExtension : titleExtension;
1921

20-
const isImage = safeFileType.includes("image") || safeFileName.match(/\.(jpg|jpeg|png|gif|webp|svg|bmp)$/i);
21-
const isVideo = safeFileType.includes("video") || safeFileName.match(/\.(mp4|webm|ogg|mov)$/i);
22-
const isPDF = safeFileType.includes("pdf") || safeFileName.match(/\.pdf$/i);
22+
// MIME type check as backup
23+
const mimeType = fileType || "";
2324

24-
// Generic check for any document that isn't media or PDF
25-
// Google Viewer supports many formats including .ai, .psd, .dxf, .svg, .eps, .ps, .ttf, .xps, .zip, .rar
26-
const isGoogleDocSupported =
27-
!isImage &&
28-
!isVideo &&
29-
!isPDF &&
30-
(
31-
safeFileType.includes("application/") ||
32-
safeFileType.includes("text/") ||
33-
safeFileName.match(/\.(doc|docx|xls|xlsx|ppt|pptx|txt|rtf|csv|odt|ods|odp|ai|psd|dxf|eps|ps|xps|ttf|pages|numbers|key|json|xml|c|cpp|h|java|py|js|ts|html|css|php|rb|go|rs|swift|kt)$/i)
34-
);
25+
// 2. Strict Category Checks
26+
const isImage = mimeType.includes("image") || ["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp", "ico", "tiff"].includes(effectiveExtension);
27+
const isVideo = mimeType.includes("video") || ["mp4", "webm", "ogg", "mov", "avi", "mkv", "wmv"].includes(effectiveExtension);
28+
const isPDF = mimeType.includes("pdf") || effectiveExtension === "pdf";
3529

36-
const showGoogleViewer = isGoogleDocSupported;
30+
// 3. Universal Catch-All Strategy
31+
// If it's not media (Image/Video) and not PDF (Custom Viewer),
32+
// we send IT ALL to Google Docs Viewer.
33+
// Google Viewer handles Office, Text, Code, Adobe, CAD, and gives a decent fallback for others.
34+
const showGoogleViewer = !isImage && !isVideo && !isPDF;
3735

3836
return (
3937
<div style={{
@@ -75,7 +73,11 @@ export default function FilePreviewModal({ isOpen, onClose, fileUrl, fileName, f
7573
)}
7674

7775
{isPDF && (
78-
<PDFViewer fileUrl={fileUrl} fileName={fileName} />
76+
<iframe
77+
src={fileUrl}
78+
style={{ width: "100%", height: "100%", border: "none", borderRadius: "8px" }}
79+
title={fileName}
80+
/>
7981
)}
8082

8183
{showGoogleViewer && (
@@ -87,10 +89,16 @@ export default function FilePreviewModal({ isOpen, onClose, fileUrl, fileName, f
8789
)}
8890

8991
{!isImage && !isVideo && !isPDF && !showGoogleViewer && (
90-
<div style={{ textAlign: "center", color: "#64748b" }}>
91-
<p style={{ marginBottom: "1rem" }}>Preview not available for this file type.</p>
92-
<a href={fileUrl} download className="btn btn-primary" style={{ display: "inline-flex", alignItems: "center", gap: "0.5rem", padding: "0.5rem 1rem", background: "#2563eb", color: "white", borderRadius: "6px", textDecoration: "none" }}>
93-
<Download size={18} /> Download to View
92+
<div style={{ textAlign: "center", color: "#64748b", padding: "2rem" }}>
93+
<p style={{ marginBottom: "1rem", fontSize: "1.1rem" }}>Preview unavailable for this file.</p>
94+
<a
95+
href={fileUrl}
96+
target="_blank"
97+
rel="noreferrer"
98+
className="btn btn-primary"
99+
style={{ display: "inline-flex", alignItems: "center", gap: "0.5rem", padding: "0.5rem 1rem", background: "#2563eb", color: "white", borderRadius: "6px", textDecoration: "none" }}
100+
>
101+
<Download size={18} /> Open in New Tab
94102
</a>
95103
</div>
96104
)}

src/components/public/FilePreviewModal.tsx

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -171,26 +171,25 @@ export default function FilePreviewModal({ file, onClose }: FilePreviewModalProp
171171
}
172172
};
173173

174-
const fileType = file.fileType || "";
175-
const fileName = file.title || "";
174+
// 1. Robust File Type Detection
175+
// Prefer extension from URL as it's the most reliable source of truth
176+
const urlExtension = file.fileUrl.split('.').pop()?.toLowerCase() || "";
177+
const titleExtension = file.title.split('.').pop()?.toLowerCase() || "";
178+
const effectiveExtension = urlExtension.length > 1 && urlExtension.length < 5 ? urlExtension : titleExtension;
176179

177-
const isImage = fileType.startsWith("image/") || fileName.match(/\.(jpg|jpeg|png|gif|webp|svg|bmp)$/i);
178-
const isVideo = fileType.startsWith("video/") || fileName.match(/\.(mp4|webm|ogg|mov)$/i);
179-
// Explicitly check for PDF via type or extension
180-
const isPdf = fileType.includes("pdf") || fileName.match(/\.pdf$/i);
180+
// MIME type check as backup
181+
const mimeType = file.fileType || "";
181182

182-
// Expanded support for Google Drive Viewer (Docs, Sheets, Slides, Text, Code, etc)
183-
const isGoogleDocSupported =
184-
!isImage &&
185-
!isVideo &&
186-
!isPdf &&
187-
(
188-
fileName.match(/\.(doc|docx|xls|xlsx|ppt|pptx|txt|rtf|csv|odt|ods|odp|ai|psd|dxf|eps|ps|xps|ttf|pages|numbers|key|json|xml|c|cpp|h|java|py|js|ts|html|css|php|rb|go|rs|swift|kt)$/i) ||
189-
fileType.includes("application/") ||
190-
fileType.includes("text/")
191-
);
183+
// 2. Strict Category Checks
184+
const isImage = mimeType.startsWith("image/") || ["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp", "ico", "tiff"].includes(effectiveExtension);
185+
const isVideo = mimeType.startsWith("video/") || ["mp4", "webm", "ogg", "mov", "avi", "mkv", "wmv"].includes(effectiveExtension);
186+
const isPdf = mimeType.includes("pdf") || effectiveExtension === "pdf";
192187

193-
const showGoogleViewer = isGoogleDocSupported;
188+
// 3. Universal Catch-All Strategy
189+
// If it's not media (Image/Video) and not PDF (Custom Viewer),
190+
// we send IT ALL to Google Docs Viewer.
191+
// Google Viewer handles Office, Text, Code, Adobe, CAD, and gives a decent fallback for others.
192+
const showGoogleViewer = !isImage && !isVideo && !isPdf;
194193

195194
return (
196195
<div
@@ -318,9 +317,11 @@ export default function FilePreviewModal({ file, onClose }: FilePreviewModalProp
318317
)}
319318

320319
{isPdf && (
321-
<div style={{ width: "100%", height: "100%", display: "flex", flexDirection: "column" }}>
322-
<PDFViewer fileUrl={file.fileUrl} fileName={file.title} />
323-
</div>
320+
<iframe
321+
src={file.fileUrl}
322+
style={{ width: "100%", height: "100%", border: "none", borderRadius: "8px", background: "white" }}
323+
title={file.title}
324+
/>
324325
)}
325326

326327
{showGoogleViewer && (
@@ -339,21 +340,17 @@ export default function FilePreviewModal({ file, onClose }: FilePreviewModalProp
339340
)}
340341

341342
{!isImage && !isVideo && !isPdf && !showGoogleViewer && (
342-
<div style={{
343-
background: "var(--surface)",
344-
padding: "3rem",
345-
borderRadius: "12px",
346-
textAlign: "center",
347-
color: "var(--text-main)"
348-
}}>
349-
<FileText size={64} style={{ marginBottom: "1rem" }} />
350-
<h3 style={{ marginBottom: "0.5rem" }}>Preview not available</h3>
351-
<p style={{ color: "var(--text-muted)", marginBottom: "2rem" }}>
352-
This file type cannot be previewed directly.
353-
</p>
354-
<button onClick={handleDownload} className="btn btn-primary">
355-
<Download size={18} style={{ marginRight: "0.5rem" }} /> Download
356-
</button>
343+
<div style={{ textAlign: "center", color: "var(--text-muted)", padding: "2rem" }}>
344+
<p style={{ marginBottom: "1rem", fontSize: "1.1rem" }}>Preview unavailable for this file.</p>
345+
<a
346+
href={file.fileUrl}
347+
target="_blank"
348+
rel="noreferrer"
349+
className="btn btn-primary"
350+
style={{ display: "inline-flex", alignItems: "center", gap: "0.5rem" }}
351+
>
352+
<Download size={18} /> Open in New Tab
353+
</a>
357354
</div>
358355
)}
359356
</div>

src/lib/firebase/storage.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import { ref, uploadBytes, getDownloadURL, deleteObject } from "firebase/storage
33

44
export const uploadFile = async (file: File, path: string) => {
55
const fileRef = ref(storage, path);
6-
const snapshot = await uploadBytes(fileRef, file, { contentType: file.type });
6+
const snapshot = await uploadBytes(fileRef, file, {
7+
contentType: file.type,
8+
contentDisposition: 'inline'
9+
});
710
const url = await getDownloadURL(snapshot.ref);
811
return url;
912
};

src/lib/supabase/storage.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ export const uploadFile = async (file: File, path: string) => {
88
.upload(path, file, {
99
cacheControl: '3600',
1010
upsert: false,
11-
contentType: file.type
11+
contentType: file.type,
12+
// Supabase technically handles disposition via download/transform usually,
13+
// but ensuring type is key.
1214
});
1315

1416
if (error) {

0 commit comments

Comments
 (0)