From caedd0ae88e54689c0e4b652434ec6eb3fe7ffc8 Mon Sep 17 00:00:00 2001 From: ZareMate <0.zaremate@gmail.com> Date: Wed, 16 Apr 2025 02:20:32 +0200 Subject: [PATCH] refactor: update file retrieval logic and enhance media handling in SharePage component --- src/app/_components/SharePage.tsx | 68 +++++++++++ src/app/api/serv/route.ts | 26 +++- src/app/api/share/route.ts | 3 +- src/app/share/page.tsx | 195 +++++++----------------------- src/components/SharePage.tsx | 52 -------- 5 files changed, 139 insertions(+), 205 deletions(-) create mode 100644 src/app/_components/SharePage.tsx delete mode 100644 src/components/SharePage.tsx diff --git a/src/app/_components/SharePage.tsx b/src/app/_components/SharePage.tsx new file mode 100644 index 0000000..a6b67c1 --- /dev/null +++ b/src/app/_components/SharePage.tsx @@ -0,0 +1,68 @@ +"use client"; + +import { useEffect, useState } from "react"; + +interface SharePageProps { + fileId: string; + fileType: string; // Pass the file type as a prop +} + +export function SharePage({ fileId, fileType }: SharePageProps) { + const [mediaSrc, setMediaSrc] = useState(null); + const [error, setError] = useState(null); + + useEffect(() => { + if (!fileId) { + setError("File ID is required."); + return; + } + + let objectUrl: string | null = null; + + const fetchMedia = async () => { + try { + const response = await fetch(`/api/serv?id=${encodeURIComponent(fileId)}`); + if (!response.ok) { + throw new Error("Failed to fetch media"); + } + + const blob = await response.blob(); + objectUrl = URL.createObjectURL(blob); + setMediaSrc(objectUrl); + } catch (err) { + console.error(err); + setError("Failed to load media."); + } + }; + + fetchMedia(); + + return () => { + if (objectUrl) { + URL.revokeObjectURL(objectUrl); + } + }; + }, [fileId]); + + if (error) { + return
{error}
; + } + + if (!mediaSrc) { + return
Loading...
; + } + + if (fileType.startsWith("video")) { + return ( + + ); + } + + return Media preview; +} \ No newline at end of file diff --git a/src/app/api/serv/route.ts b/src/app/api/serv/route.ts index c2560c1..3788aa3 100644 --- a/src/app/api/serv/route.ts +++ b/src/app/api/serv/route.ts @@ -14,7 +14,7 @@ export async function GET(req: Request) { try { // Fetch file metadata from the database const file = await db.file.findFirst({ - where: { name: fileId }, + where: { id: fileId }, }); if (!file) { @@ -22,15 +22,35 @@ export async function GET(req: Request) { } // Construct the file path - const filePath = path.join(process.cwd(), "uploads", file.name); + const filePath = path.join(process.cwd(), "uploads", file.id); // Read the file from the filesystem const fileBuffer = await fs.readFile(filePath); + const mimeType = file.extension === ".mp4" + ? "video/mp4" + : file.extension === ".webm" + ? "video/webm" + : file.extension === ".ogg" + ? "video/ogg" + : file.extension === ".jpg" || file.extension === ".jpeg" + ? "image/jpeg" + : file.extension === ".png" + ? "image/png" + : file.extension === ".gif" + ? "image/gif" + : file.extension === ".svg" + ? "image/svg+xml" + : file.extension === ".mp3" + ? "audio/mpeg" + : file.extension === ".wav" + ? "audio/wav" + : "application/octet-stream"; + // Return the file as a binary response return new Response(fileBuffer, { headers: { - "Content-Type": file.extension.startsWith(".png") ? "image/png" : "application/octet-stream", + "Content-Type": mimeType, "Content-Disposition": `inline; filename="${file.name}"`, }, }); diff --git a/src/app/api/share/route.ts b/src/app/api/share/route.ts index 03d3b2c..d26be8c 100644 --- a/src/app/api/share/route.ts +++ b/src/app/api/share/route.ts @@ -24,7 +24,8 @@ export async function GET(req: Request) { return NextResponse.json({ name: file.name, size: file.size, - owner: file.uploadedBy?.name ?? "Unknown", // Use nullish coalescing + owner: file.uploadedBy?.name ?? null, // Use nullish coalescing + owneravatar: file.uploadedBy?.image ?? null, uploadDate: file.uploadDate, id: file.id, isOwner: session?.user?.id === file.uploadedById, diff --git a/src/app/share/page.tsx b/src/app/share/page.tsx index 29b2eaa..2fbbd9e 100644 --- a/src/app/share/page.tsx +++ b/src/app/share/page.tsx @@ -4,15 +4,13 @@ import { Suspense } from "react"; import { useEffect, useState } from "react"; import { useSearchParams, useRouter } from "next/navigation"; import toast, { Toaster } from "react-hot-toast"; -import Head from "next/head"; -import { number } from "zod"; - -// import { SharePage } from "~/components/SharePage"; +import { SharePage } from "~/app/_components/SharePage"; interface FileDetails { name: string; size: number; owner: string; + owneravatar: string | null; uploadDate: string; id: string; isOwner: boolean; @@ -20,13 +18,35 @@ interface FileDetails { url: string; } -function UploadsPage() { + +function Details() { const searchParams = useSearchParams(); const router = useRouter(); const fileId = searchParams.get("id"); const [fileDetails, setFileDetails] = useState(null); const [error, setError] = useState(null); - // const mediasrc = SharePage() as string; // Replace with a valid string URL or logic to generate the URL + + // Determine the file type based on the file extension + const fileType = fileDetails?.type === ".mp4" + ? "video/mp4" + : fileDetails?.type === ".webm" + ? "video/webm" + : fileDetails?.type === ".ogg" + ? "video/ogg" + : fileDetails?.type === ".jpg" || fileDetails?.type === ".jpeg" + ? "image/jpeg" + : fileDetails?.type === ".png" + ? "image/png" + : fileDetails?.type === ".gif" + ? "image/gif" + : fileDetails?.type === ".svg" + ? "image/svg+xml" + : fileDetails?.type === ".mp3" + ? "audio/mpeg" + : fileDetails?.type === ".wav" + ? "audio/wav" + // if fileType is not one of the above, set it to unknown + : "unknown"; useEffect(() => { if (!fileId) { @@ -41,7 +61,7 @@ function UploadsPage() { throw new Error("Failed to fetch file details"); } - const data: FileDetails = await response.json(); // Explicitly type the response + const data: FileDetails = await response.json(); setFileDetails(data); } catch (err) { console.error(err); @@ -49,110 +69,9 @@ function UploadsPage() { } }; - void fetchFileDetails(); // Use `void` to mark the promise as intentionally ignored + fetchFileDetails(); }, [fileId]); - // set page og meta tags - useEffect(() => { - if (fileDetails) { - const ogTitle = `File Details: ${fileDetails.name}`; - // proper size conversion - const sizeInKB = fileDetails.size / 1024; - const sizeInMB = sizeInKB / 1024; - const sizeInGB = sizeInMB / 1024; - let sizeDescription: string = `${sizeInKB.toFixed(2)} KB`; - if (sizeInMB >= 1) { - sizeDescription = `${sizeInMB.toFixed(2)} MB`; - } else if (sizeInGB >= 1) { - sizeDescription = `${sizeInGB.toFixed(2)} GB`; - } - const ogDescription = `File Name: ${fileDetails.name}, Size: ${sizeDescription}, Owner: ${fileDetails.owner}, Upload Date: ${new Date(fileDetails.uploadDate).toLocaleString()}`; - - // document.title = ogTitle; - // if meta og tags are not present, create them - if (!document.querySelector('meta[name="description"]')) { - const metaDescription = document.createElement("meta"); - metaDescription.name = "description"; - document.head.appendChild(metaDescription); - } - if (!document.querySelector('meta[property="og:title"]')) { - const metaOgTitle = document.createElement("meta"); - metaOgTitle.setAttribute("property", "og:title"); - document.head.appendChild(metaOgTitle); - } - if (!document.querySelector('meta[property="og:description"]')) { - const metaOgDescription = document.createElement("meta"); - metaOgDescription.setAttribute("property", "og:description"); - document.head.appendChild(metaOgDescription); - } - document.querySelector('meta[name="description"]')?.setAttribute("content", ogDescription); - document.querySelector('meta[property="og:title"]')?.setAttribute("content", ogTitle); - document.querySelector('meta[property="og:description"]')?.setAttribute("content", ogDescription); - - - } - }, [fileDetails]); - - const handleDownload = async () => { - try { - if (!fileDetails) { - toast.error("File details not available."); - return; - } - const response = await fetch(`/api/files/download?fileId=${encodeURIComponent(fileDetails.id)}&fileName=${encodeURIComponent(fileDetails.name)}`); - if (!response.ok) { - throw new Error("Failed to download file"); - } - // Download the file with the correct filename - const blob = await response.blob(); - const url = window.URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = fileDetails.name; - document.body.appendChild(a); - a.click(); - a.remove(); - window.URL.revokeObjectURL(url); - - toast.success(`File "${fileDetails.name}" downloaded successfully!`); - } catch (err) { - console.error(err); - toast.error("Failed to download file."); - } - }; - - const handleShare = () => { - if (fileDetails) { - const shareableLink = `${window.location.origin}/share?id=${fileDetails.id}`; - navigator.clipboard - .writeText(shareableLink) - .then(() => toast.success("Shareable link copied to clipboard!")) - .catch(() => toast.error("Failed to copy link.")); - } - }; - - const handleRemove = async () => { - try { - const response = await fetch(`/api/remove`, { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ id: fileDetails?.id }), // Use optional chaining - }); - - if (!response.ok) { - throw new Error("Failed to remove file"); - } - - toast.success("File removed successfully!"); - router.push("/"); - } catch (err) { - console.error(err); - toast.error("Failed to remove file."); - } - }; - if (error) { return
{error}
; } @@ -194,58 +113,36 @@ function UploadsPage() { File Details
- {/* {(fileDetails.type.startsWith(".png") || - fileDetails.type.startsWith(".jpg") || - fileDetails.type.startsWith(".jpeg") || - fileDetails.type.startsWith(".gif")) && (mediasrc && Media preview)} - {(fileDetails.type.startsWith(".mp4") || - fileDetails.type.startsWith(".webm") || - fileDetails.type.startsWith(".ogg")) && - (mediasrc && - - )} */} + {// if fileType is not ubknown, show the media player + fileType && !fileType.startsWith("unknown") ? ( + + ) : null} +

Name: {fileDetails.name}

- Size: {(fileDetails.size / 1024).toFixed(2)} KB + Size: { // format size + fileDetails.size > 1024 * 1024 * 1024 * 1024 + ? (fileDetails.size / (1024 * 1024 * 1024 * 1024)).toFixed(2) + " TB" + : fileDetails.size > 1024 * 1024 * 1024 + ? (fileDetails.size / (1024 * 1024 * 1024)).toFixed(2) + " GB" + : fileDetails.size > 1024 * 1024 + ? (fileDetails.size / (1024 * 1024)).toFixed(2) + " MB" + : fileDetails.size > 1024 + ? (fileDetails.size / 1024).toFixed(2) + " KB" + : fileDetails.size + " Bytes" + }

- Owner: {fileDetails.owner} + Owner: owner image {fileDetails.owner}

Upload Date: {new Date(fileDetails.uploadDate).toLocaleString()}

-
- - {fileDetails.isOwner && ( - <> - - - - )} -
); @@ -254,7 +151,7 @@ function UploadsPage() { export default function Page() { return ( Loading...}> - +
); } diff --git a/src/components/SharePage.tsx b/src/components/SharePage.tsx deleted file mode 100644 index a2a13c3..0000000 --- a/src/components/SharePage.tsx +++ /dev/null @@ -1,52 +0,0 @@ -"use client"; - -import { useEffect, useState } from "react"; -import { useSearchParams } from "next/navigation"; - -export function SharePage() { - const searchParams = useSearchParams(); - const fileId = searchParams.get("id"); - const [imageSrc, setImageSrc] = useState(null); - const [error, setError] = useState(null); - - useEffect(() => { - const fetchImage = async () => { - try { - if (!fileId) { - throw new Error("File name is required."); - } - const response = await fetch(`/api/serv?id=${encodeURIComponent(fileId)}`); - if (!response.ok) { - throw new Error("Failed to fetch image"); - } - - const blob = await response.blob(); - const objectUrl = URL.createObjectURL(blob); - setImageSrc(objectUrl); - } catch (err) { - console.error(err); - setError("Failed to load image."); - } - }; - - void fetchImage(); - - return () => { - if (imageSrc) { - URL.revokeObjectURL(imageSrc); - } - }; - }, [fileId, imageSrc]); - - if (error) { - return
{error}
; - } - - if (!imageSrc) { - return
Loading...
; - } - - return ( - imageSrc - ); -} \ No newline at end of file