Skip to content

Commit 43869b4

Browse files
fix: preview now uses content type to preview, rather than file extension
1 parent acb4eb0 commit 43869b4

2 files changed

Lines changed: 66 additions & 71 deletions

File tree

app/components/PreviewModal.tsx

Lines changed: 40 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { getFile, UrlString } from "@inrupt/solid-client";
77
import { getAuthenticatedSession } from "../lib/helpers";
88
import { FileItemData } from "./FileItem";
99
import LoadingSpinner from "./shared/LoadingSpinner";
10-
import { getFileType } from "../lib/helpers";
1110

1211
interface PreviewModalProps {
1312
isOpen: boolean;
@@ -57,97 +56,68 @@ export default function PreviewModal({
5756

5857
try {
5958
const { fetch: fetchFn } = getAuthenticatedSession();
60-
const fileTypeDetected = getFileType(file.url, file.mimeType, file.name);
61-
setFileType(fileTypeDetected);
62-
63-
// PDFs open directly in a new tab
64-
if (fileTypeDetected === "pdf") {
65-
if (blobUrlRef.current) {
66-
URL.revokeObjectURL(blobUrlRef.current);
67-
}
68-
// For PDFs, fetch as blob and open in new tab
69-
const fileBlob = await getFile(file.url as UrlString, { fetch: fetchFn });
70-
const blobUrl = URL.createObjectURL(fileBlob);
71-
blobUrlRef.current = blobUrl;
59+
60+
// Fetch the file using getFile from solid-client
61+
const fileBlob = await getFile(file.url as UrlString, { fetch: fetchFn });
62+
63+
// Get the content-type from the blob's type property (set from HTTP response header)
64+
// Remove any charset or other parameters (e.g., "text/plain; charset=utf-8" -> "text/plain")
65+
const actualMimeType = fileBlob.type ? fileBlob.type.split(";")[0].trim() : "";
66+
67+
if (blobUrlRef.current) {
68+
URL.revokeObjectURL(blobUrlRef.current);
69+
}
70+
71+
const blobUrl = URL.createObjectURL(fileBlob);
72+
blobUrlRef.current = blobUrl;
73+
74+
// PDFs: open in new tab
75+
if (actualMimeType === "application/pdf") {
7276
window.open(blobUrl, "_blank");
73-
7477
onClose();
7578
setIsLoading(false);
7679
return;
7780
}
78-
79-
// Word documents - browsers can't natively view them, so we'll fetch and open as blob
80-
// This will trigger a download, but ensures authenticated access works
81-
if (fileTypeDetected === "doc") {
82-
// Clean up previous blob URL if it exists
83-
if (blobUrlRef.current) {
84-
URL.revokeObjectURL(blobUrlRef.current);
85-
}
86-
// For Word docs, fetch as blob and create a download link
87-
// Note: Browsers can't natively view Word documents, so this will download
88-
// External viewers (Google Docs, Office Online) require public URLs and won't work with authenticated resources
89-
const fileBlob = await getFile(file.url as UrlString, { fetch: fetchFn });
90-
const blobUrl = URL.createObjectURL(fileBlob);
91-
blobUrlRef.current = blobUrl;
92-
93-
// Create a temporary anchor element to trigger download with proper filename
81+
82+
// Word documents: browsers can't natively view them, trigger download
83+
if (actualMimeType.startsWith("application/msword") ||
84+
actualMimeType.includes("wordprocessingml") ||
85+
actualMimeType.includes("ms-word")) {
9486
const link = document.createElement("a");
9587
link.href = blobUrl;
9688
link.download = file.name;
9789
link.target = "_blank";
9890
document.body.appendChild(link);
9991
link.click();
10092
document.body.removeChild(link);
101-
102-
// Close the modal
10393
onClose();
10494
setIsLoading(false);
10595
return;
10696
}
107-
108-
if (fileTypeDetected === "image") {
109-
// Clean up previous blob URL if it exists
110-
if (blobUrlRef.current) {
111-
URL.revokeObjectURL(blobUrlRef.current);
112-
}
113-
// For images, fetch as blob and create blob URL for authenticated access
114-
const fileBlob = await getFile(file.url as UrlString, { fetch: fetchFn });
115-
const blobUrl = URL.createObjectURL(fileBlob);
116-
blobUrlRef.current = blobUrl;
97+
98+
// Images: display in modal
99+
if (actualMimeType.startsWith("image/")) {
117100
setPreviewUrl(blobUrl);
101+
setFileType("image");
118102
setIsLoading(false);
119-
} else if (fileTypeDetected === "text") {
120-
// For text files, fetch and display content
121-
const fileBlob = await getFile(file.url as UrlString, { fetch: fetchFn });
103+
return;
104+
}
105+
106+
// For all other file types, try to read as text
107+
try {
122108
const text = await fileBlob.text();
123-
setPreviewContent(text);
124-
setIsLoading(false);
125-
} else {
126-
// For other file types, try to read as text as a fallback
127-
try {
128-
const fileBlob = await getFile(file.url as UrlString, { fetch: fetchFn });
129-
// Check if the blob type suggests it's text
130-
if (fileBlob.type && (fileBlob.type.startsWith("text/") || fileBlob.type === "application/json" || fileBlob.type === "application/xml")) {
131-
const text = await fileBlob.text();
132-
setPreviewContent(text);
133-
setFileType("text");
134-
setIsLoading(false);
135-
} else {
136-
const text = await fileBlob.text();
137-
// If we can read it as text and it's not too large, treat it as text
138-
if (text.length > 0 && text.length < 10 * 1024 * 1024) { // Less than 10MB
139-
setPreviewContent(text);
140-
setFileType("text");
141-
setIsLoading(false);
142-
} else {
143-
setIsLoading(false);
144-
}
145-
}
146-
} catch (err) {
147-
// If reading as text fails, it's not a text file
109+
if (text.length > 0 && text.length < 10 * 1024 * 1024) { // Less than 10MB
110+
setPreviewContent(text);
111+
setFileType("text");
148112
setIsLoading(false);
113+
return;
149114
}
115+
} catch (err) {
116+
console.error("Failed to load preview:", err);
150117
}
118+
119+
setFileType("other");
120+
setIsLoading(false);
151121
} catch (err) {
152122
console.error("Failed to load preview:", err);
153123
setError(err instanceof Error ? err.message : "Failed to load preview");

app/lib/helpers/fileTypeUtils.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,40 @@ export function getFileType(
1010
mimeType?: string,
1111
fileName?: string
1212
): "image" | "pdf" | "doc" | "text" | "other" {
13+
// Prioritize MIME type (content type) over file extension
1314
if (mimeType) {
15+
// Images
1416
if (mimeType.startsWith("image/")) return "image";
17+
18+
// PDFs
1519
if (mimeType === "application/pdf") return "pdf";
20+
21+
// Word documents
1622
if (
1723
mimeType === "application/msword" ||
18-
mimeType === "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
24+
mimeType === "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ||
25+
mimeType === "application/vnd.ms-word.document.macroEnabled.12"
1926
)
2027
return "doc";
28+
29+
// Text files - check various text MIME types
2130
if (mimeType.startsWith("text/")) return "text";
31+
32+
// JSON, XML, and other text-based formats
33+
if (
34+
mimeType === "application/json" ||
35+
mimeType === "application/xml" ||
36+
mimeType === "text/xml" ||
37+
mimeType === "application/javascript" ||
38+
mimeType === "application/x-javascript" ||
39+
mimeType === "text/javascript" ||
40+
mimeType === "application/x-sh" ||
41+
mimeType === "application/x-yaml" ||
42+
mimeType === "text/yaml" ||
43+
mimeType === "application/x-csv" ||
44+
mimeType === "text/csv"
45+
)
46+
return "text";
2247
}
2348

2449
// Check for common text file names without extensions

0 commit comments

Comments
 (0)