2025-04-15 09:29:47 +02:00

261 lines
9.1 KiB
TypeScript

"use client";
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";
interface FileDetails {
name: string;
size: number;
owner: string;
uploadDate: string;
id: string;
isOwner: boolean;
type: string;
url: string;
}
function UploadsPage() {
const searchParams = useSearchParams();
const router = useRouter();
const fileId = searchParams.get("id");
const [fileDetails, setFileDetails] = useState<FileDetails | null>(null);
const [error, setError] = useState<string | null>(null);
// const mediasrc = SharePage() as string; // Replace with a valid string URL or logic to generate the URL
useEffect(() => {
if (!fileId) {
setError("File name is required.");
return;
}
const fetchFileDetails = async () => {
try {
const response = await fetch(`/api/share?id=${encodeURIComponent(fileId)}`);
if (!response.ok) {
throw new Error("Failed to fetch file details");
}
const data: FileDetails = await response.json(); // Explicitly type the response
setFileDetails(data);
} catch (err) {
console.error(err);
setError("Failed to load file details.");
}
};
void fetchFileDetails(); // Use `void` to mark the promise as intentionally ignored
}, [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 <div className="text-red-500">{error}</div>;
}
if (!fileDetails) {
return (
<main className="relative flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
<Toaster position="top-right" reverseOrder={false} />
<div className="absolute top-4 left-4">
<button
onClick={() => router.push("/")}
className="rounded-full bg-white/10 px-4 py-2 font-semibold no-underline transition hover:bg-white/20"
>
Home
</button>
</div>
<div className="container flex flex-col items-center justify-center gap-12 px-4 py-16">
<h1 className="text-5xl font-extrabold tracking-tight sm:text-[5rem]">
<span className="text-[hsl(280,100%,70%)]">File</span> Details
</h1>
</div>
</main>
);
}
return (
<main className="relative flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
<Toaster position="top-right" reverseOrder={false} />
<div className="absolute top-4 left-4">
<button
onClick={() => router.push("/")}
className="rounded-full bg-white/10 px-4 py-2 font-semibold no-underline transition hover:bg-white/20"
>
Home
</button>
</div>
<div className="container flex flex-col items-center justify-center gap-12 px-4 py-16">
<h1 className="text-5xl font-extrabold tracking-tight sm:text-[5rem]">
<span className="text-[hsl(280,100%,70%)]">File</span> Details
</h1>
<div className="mt-6">
{/* {(fileDetails.type.startsWith(".png") ||
fileDetails.type.startsWith(".jpg") ||
fileDetails.type.startsWith(".jpeg") ||
fileDetails.type.startsWith(".gif")) && (mediasrc && <img src={mediasrc} alt="Media preview" />)}
{(fileDetails.type.startsWith(".mp4") ||
fileDetails.type.startsWith(".webm") ||
fileDetails.type.startsWith(".ogg")) &&
(mediasrc &&
<video controls className="max-w-full max-h-96 rounded-lg shadow-md">
<source src={mediasrc} type="video" />
Your browser does not support the video tag.
</video>
)} */}
</div>
<div className="bg-white/10 shadow-md rounded-lg p-6 w-full max-w-md text-white">
<p>
<strong>Name:</strong> {fileDetails.name}
</p>
<p>
<strong>Size:</strong> {(fileDetails.size / 1024).toFixed(2)} KB
</p>
<p>
<strong>Owner:</strong> {fileDetails.owner}
</p>
<p>
<strong>Upload Date:</strong> {new Date(fileDetails.uploadDate).toLocaleString()}
</p>
</div>
<div className="flex gap-4 mt-6">
<button
onClick={handleDownload}
className="rounded-full bg-blue-500 px-10 py-3 font-semibold no-underline transition hover:bg-blue-600"
>
Download
</button>
{fileDetails.isOwner && (
<>
<button
onClick={handleShare}
className="rounded-full bg-green-500 px-10 py-3 font-semibold no-underline transition hover:bg-green-600"
>
Share
</button>
<button
onClick={handleRemove}
className="rounded-full bg-red-500 px-10 py-3 font-semibold no-underline transition hover:bg-red-600"
>
Remove
</button>
</>
)}
</div>
</div>
</main>
);
}
export default function Page() {
return (
<Suspense fallback={<div>Loading...</div>}>
<UploadsPage />
</Suspense>
);
}