feat: implement metadata generation for file details and improve error handling
This commit is contained in:
parent
011695cf46
commit
6115851147
@ -2,8 +2,12 @@ import { notFound } from "next/navigation";
|
||||
import { FilePreview } from "~/app/_components/FilePreview";
|
||||
import { HomeButton } from "~/app/_components/HomeButton"; // Import the client component
|
||||
import { Toaster } from "react-hot-toast";
|
||||
import { FileActionsContainer, FileDescriptionContainer } from "~/app/_components/ActionButtons"; // Import the client component
|
||||
import {
|
||||
FileActionsContainer,
|
||||
FileDescriptionContainer,
|
||||
} from "~/app/_components/ActionButtons"; // Import the client component
|
||||
import Head from "next/head";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
interface FileDetails {
|
||||
name: string;
|
||||
@ -18,6 +22,46 @@ interface FileDetails {
|
||||
description: string;
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: { id?: string };
|
||||
}): Promise<Metadata> {
|
||||
const fileId = searchParams.id;
|
||||
|
||||
if (!fileId) {
|
||||
return {
|
||||
title: "File Not Found",
|
||||
description: "The file you are looking for does not exist.",
|
||||
};
|
||||
}
|
||||
|
||||
const fileDetails = await fetchFileDetails(fileId);
|
||||
|
||||
if (!fileDetails) {
|
||||
return {
|
||||
title: "File Not Found",
|
||||
description: "The file you are looking for does not exist.",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
title: fileDetails.name,
|
||||
description: fileDetails.description || fileDetails.name,
|
||||
openGraph: {
|
||||
title: fileDetails.name,
|
||||
description: fileDetails.description || fileDetails.name,
|
||||
url: `${process.env.NEXT_PUBLIC_PAGE_URL}/share?id=${fileDetails.id}`,
|
||||
images: [
|
||||
{
|
||||
url: `${process.env.NEXT_PUBLIC_PAGE_URL}/api/files/serv?id=${fileDetails.id}`,
|
||||
alt: `${fileDetails.name} preview`,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function fetchFileDetails(fileId: string): Promise<FileDetails | null> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
@ -41,10 +85,9 @@ async function fetchFileDetails(fileId: string): Promise<FileDetails | null> {
|
||||
export default async function FilePreviewContainer({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: Promise<{ id?: string }>;
|
||||
searchParams: { id?: string };
|
||||
}) {
|
||||
const resolvedSearchParams = await searchParams; // Resolve the promise
|
||||
const fileId = resolvedSearchParams.id;
|
||||
const fileId = searchParams.id;
|
||||
|
||||
if (!fileId) {
|
||||
notFound();
|
||||
@ -54,130 +97,79 @@ export default async function FilePreviewContainer({
|
||||
|
||||
if (!fileDetails) {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>No File Found</title>
|
||||
<meta property="og:title" content="No File Found" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="The file you are looking for does not exist."
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:image" content="/images/no-file.png" />
|
||||
<meta property="og:image:alt" content="No file found" />
|
||||
<meta
|
||||
property="og:url"
|
||||
content={`${process.env.NEXT_PUBLIC_PAGE_URL}/share?id=${fileId}`}
|
||||
/>
|
||||
</Head>
|
||||
<main className="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">
|
||||
<HomeButton />
|
||||
</div>
|
||||
<div className="container flex flex-col items-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%)]">No</span> File Found
|
||||
</h1>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
<main className="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">
|
||||
<HomeButton />
|
||||
</div>
|
||||
<div className="container flex flex-col items-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%)]">No</span> File Found
|
||||
</h1>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{fileDetails.name} - File Details</title>
|
||||
<meta
|
||||
property="og:title"
|
||||
content={`${fileDetails.name} - File Details`}
|
||||
/>
|
||||
<meta
|
||||
property="og:description"
|
||||
content={`Size: ${
|
||||
fileDetails.size > 1024 * 1024 * 1024
|
||||
<main className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
|
||||
<div className="absolute top-4 left-4">
|
||||
<HomeButton />
|
||||
</div>
|
||||
<Toaster position="top-right" reverseOrder={false} />
|
||||
<div className="container flex flex-col items-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 !== "unknown" && (
|
||||
<FilePreview fileId={fileDetails.id} fileType={fileDetails.type} />
|
||||
)}
|
||||
</div>
|
||||
<div className="w-full max-w-md rounded-lg bg-white/10 p-6 text-white shadow-md">
|
||||
<p>
|
||||
<strong>Name:</strong> {fileDetails.name}
|
||||
</p>
|
||||
<p>
|
||||
<strong>Size:</strong>{" "}
|
||||
{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}, Uploaded on: ${new Date(
|
||||
fileDetails.uploadDate
|
||||
).toLocaleString()}`}
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta
|
||||
property="og:image"
|
||||
content={`${process.env.NEXT_PUBLIC_PAGE_URL}/api/files/serv?id=${fileId}`}
|
||||
/>
|
||||
<meta property="og:image:alt" content={`${fileDetails.name} preview`} />
|
||||
<meta
|
||||
property="og:url"
|
||||
content={`${process.env.NEXT_PUBLIC_PAGE_URL}/share?id=${fileId}`}
|
||||
/>
|
||||
</Head>
|
||||
<main className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
|
||||
<div className="absolute top-4 left-4">
|
||||
<HomeButton />
|
||||
</div>
|
||||
<Toaster position="top-right" reverseOrder={false} />
|
||||
<div className="container flex flex-col items-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 !== "unknown" && (
|
||||
<FilePreview
|
||||
fileId={fileDetails.id}
|
||||
fileType={fileDetails.type}
|
||||
/>
|
||||
)}
|
||||
</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 * 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"}
|
||||
</p>
|
||||
<p>
|
||||
<strong>Owner:</strong>{" "}
|
||||
<img
|
||||
className="rounded-md inline size-5"
|
||||
src={fileDetails.ownerAvatar || ""}
|
||||
alt="Owner avatar"
|
||||
/>{" "}
|
||||
{fileDetails.owner}
|
||||
</p>
|
||||
<p>
|
||||
<strong>Upload Date:</strong>{" "}
|
||||
{new Date(fileDetails.uploadDate).toLocaleString()}
|
||||
</p>
|
||||
<div>
|
||||
<strong>Description:</strong>{" "}
|
||||
<FileDescriptionContainer fileId={fileDetails.id} fileDescription={fileDetails.description}/>
|
||||
</div>
|
||||
<div className="mt-4 flex justify-center">
|
||||
<FileActionsContainer
|
||||
fileId={fileDetails.id}
|
||||
fileName={fileDetails.name}
|
||||
fileUrl={fileDetails.url}
|
||||
isOwner={fileDetails.isOwner}
|
||||
/>
|
||||
</div>
|
||||
? (fileDetails.size / 1024).toFixed(2) + " KB"
|
||||
: fileDetails.size + " Bytes"}
|
||||
</p>
|
||||
<p>
|
||||
<strong>Owner:</strong>{" "}
|
||||
<img
|
||||
className="inline size-5 rounded-md"
|
||||
src={fileDetails.ownerAvatar || ""}
|
||||
alt="Owner avatar"
|
||||
/>{" "}
|
||||
{fileDetails.owner}
|
||||
</p>
|
||||
<p>
|
||||
<strong>Upload Date:</strong>{" "}
|
||||
{new Date(fileDetails.uploadDate).toLocaleString()}
|
||||
</p>
|
||||
<div>
|
||||
<strong>Description:</strong>{" "}
|
||||
<FileDescriptionContainer
|
||||
fileId={fileDetails.id}
|
||||
fileDescription={fileDetails.description}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-4 flex justify-center">
|
||||
<FileActionsContainer
|
||||
fileId={fileDetails.id}
|
||||
fileName={fileDetails.name}
|
||||
fileUrl={fileDetails.url}
|
||||
isOwner={fileDetails.isOwner}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user