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 { FilePreview } from "~/app/_components/FilePreview";
|
||||||
import { HomeButton } from "~/app/_components/HomeButton"; // Import the client component
|
import { HomeButton } from "~/app/_components/HomeButton"; // Import the client component
|
||||||
import { Toaster } from "react-hot-toast";
|
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 Head from "next/head";
|
||||||
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
interface FileDetails {
|
interface FileDetails {
|
||||||
name: string;
|
name: string;
|
||||||
@ -18,6 +22,46 @@ interface FileDetails {
|
|||||||
description: string;
|
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> {
|
async function fetchFileDetails(fileId: string): Promise<FileDetails | null> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
@ -41,10 +85,9 @@ async function fetchFileDetails(fileId: string): Promise<FileDetails | null> {
|
|||||||
export default async function FilePreviewContainer({
|
export default async function FilePreviewContainer({
|
||||||
searchParams,
|
searchParams,
|
||||||
}: {
|
}: {
|
||||||
searchParams: Promise<{ id?: string }>;
|
searchParams: { id?: string };
|
||||||
}) {
|
}) {
|
||||||
const resolvedSearchParams = await searchParams; // Resolve the promise
|
const fileId = searchParams.id;
|
||||||
const fileId = resolvedSearchParams.id;
|
|
||||||
|
|
||||||
if (!fileId) {
|
if (!fileId) {
|
||||||
notFound();
|
notFound();
|
||||||
@ -54,130 +97,79 @@ export default async function FilePreviewContainer({
|
|||||||
|
|
||||||
if (!fileDetails) {
|
if (!fileDetails) {
|
||||||
return (
|
return (
|
||||||
<>
|
<main className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
|
||||||
<Head>
|
<Toaster position="top-right" reverseOrder={false} />
|
||||||
<title>No File Found</title>
|
<div className="absolute top-4 left-4">
|
||||||
<meta property="og:title" content="No File Found" />
|
<HomeButton />
|
||||||
<meta
|
</div>
|
||||||
property="og:description"
|
<div className="container flex flex-col items-center gap-12 px-4 py-16">
|
||||||
content="The file you are looking for does not exist."
|
<h1 className="text-5xl font-extrabold tracking-tight sm:text-[5rem]">
|
||||||
/>
|
<span className="text-[hsl(280,100%,70%)]">No</span> File Found
|
||||||
<meta property="og:type" content="website" />
|
</h1>
|
||||||
<meta property="og:image" content="/images/no-file.png" />
|
</div>
|
||||||
<meta property="og:image:alt" content="No file found" />
|
</main>
|
||||||
<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>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<main className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
|
||||||
<Head>
|
<div className="absolute top-4 left-4">
|
||||||
<title>{fileDetails.name} - File Details</title>
|
<HomeButton />
|
||||||
<meta
|
</div>
|
||||||
property="og:title"
|
<Toaster position="top-right" reverseOrder={false} />
|
||||||
content={`${fileDetails.name} - File Details`}
|
<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]">
|
||||||
<meta
|
<span className="text-[hsl(280,100%,70%)]">File</span> Details
|
||||||
property="og:description"
|
</h1>
|
||||||
content={`Size: ${
|
<div className="mt-6">
|
||||||
fileDetails.size > 1024 * 1024 * 1024
|
{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 * 1024)).toFixed(2) + " GB"
|
||||||
: fileDetails.size > 1024 * 1024
|
: 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 * 1024)).toFixed(2) + " MB"
|
||||||
: fileDetails.size > 1024
|
: fileDetails.size > 1024
|
||||||
? (fileDetails.size / 1024).toFixed(2) + " KB"
|
? (fileDetails.size / 1024).toFixed(2) + " KB"
|
||||||
: fileDetails.size + " Bytes"}
|
: fileDetails.size + " Bytes"}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<strong>Owner:</strong>{" "}
|
<strong>Owner:</strong>{" "}
|
||||||
<img
|
<img
|
||||||
className="rounded-md inline size-5"
|
className="inline size-5 rounded-md"
|
||||||
src={fileDetails.ownerAvatar || ""}
|
src={fileDetails.ownerAvatar || ""}
|
||||||
alt="Owner avatar"
|
alt="Owner avatar"
|
||||||
/>{" "}
|
/>{" "}
|
||||||
{fileDetails.owner}
|
{fileDetails.owner}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<strong>Upload Date:</strong>{" "}
|
<strong>Upload Date:</strong>{" "}
|
||||||
{new Date(fileDetails.uploadDate).toLocaleString()}
|
{new Date(fileDetails.uploadDate).toLocaleString()}
|
||||||
</p>
|
</p>
|
||||||
<div>
|
<div>
|
||||||
<strong>Description:</strong>{" "}
|
<strong>Description:</strong>{" "}
|
||||||
<FileDescriptionContainer fileId={fileDetails.id} fileDescription={fileDetails.description}/>
|
<FileDescriptionContainer
|
||||||
</div>
|
fileId={fileDetails.id}
|
||||||
<div className="mt-4 flex justify-center">
|
fileDescription={fileDetails.description}
|
||||||
<FileActionsContainer
|
/>
|
||||||
fileId={fileDetails.id}
|
</div>
|
||||||
fileName={fileDetails.name}
|
<div className="mt-4 flex justify-center">
|
||||||
fileUrl={fileDetails.url}
|
<FileActionsContainer
|
||||||
isOwner={fileDetails.isOwner}
|
fileId={fileDetails.id}
|
||||||
/>
|
fileName={fileDetails.name}
|
||||||
</div>
|
fileUrl={fileDetails.url}
|
||||||
|
isOwner={fileDetails.isOwner}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</div>
|
||||||
</>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user