Skip to content

Commit 38d9e90

Browse files
Merge pull request #55 from abhitrueprogrammer/staging
added ssr and metadata and a pdf download button for paper/id
2 parents 60c2fb9 + 9636e1e commit 38d9e90

File tree

6 files changed

+198
-130
lines changed

6 files changed

+198
-130
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"@react-pdf-viewer/core": "3.12.0",
2222
"@react-pdf-viewer/default-layout": "^3.12.0",
2323
"@react-pdf-viewer/full-screen": "^3.12.0",
24+
"@react-pdf-viewer/get-file": "^3.12.0",
2425
"@react-pdf-viewer/zoom": "^3.12.0",
2526
"@t3-oss/env-nextjs": "^0.10.1",
2627
"@types/mongoose": "^5.11.97",

pnpm-lock.yaml

Lines changed: 12 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/actions/get-papers-by-id.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// "use server";
2+
import { ErrorResponse, PaperResponse } from "@/interface";
3+
import axios, { AxiosResponse } from "axios";
4+
5+
export const fetchPaperID = async (
6+
id: string,
7+
) => {
8+
try {
9+
const response: AxiosResponse<PaperResponse> = await axios.get(
10+
`http://localhost:3000/api/paper-by-id/${id}`,
11+
);
12+
return response.data;
13+
} catch (err: unknown) {
14+
throw err;
15+
16+
}
17+
};

src/app/paper/[id]/page.tsx

Lines changed: 57 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,145 +1,81 @@
1-
"use client";
2-
import { useState, useEffect } from "react";
3-
import axios, { type AxiosResponse } from "axios";
1+
import { fetchPaperID } from "@/app/actions/get-papers-by-id";
42
import Footer from "@/components/Footer";
53
import Navbar from "@/components/Navbar";
6-
import { Eye, Maximize } from "lucide-react";
7-
import { useRouter } from "next/navigation";
8-
import { Worker } from "@react-pdf-viewer/core";
9-
import { Viewer } from "@react-pdf-viewer/core";
10-
import {
11-
zoomPlugin,
12-
ZoomInIcon,
13-
ZoomOutIcon,
14-
type RenderZoomOutProps,
15-
type RenderZoomInProps,
16-
type RenderCurrentScaleProps,
17-
} from "@react-pdf-viewer/zoom";
18-
import {
19-
fullScreenPlugin,
20-
type RenderEnterFullScreenProps,
21-
} from "@react-pdf-viewer/full-screen";
22-
import "@react-pdf-viewer/full-screen/lib/styles/index.css";
23-
import "@react-pdf-viewer/core/lib/styles/index.css";
24-
import "@react-pdf-viewer/zoom/lib/styles/index.css";
4+
import PdfViewer from "@/components/pdfViewer";
255
import Loader from "@/components/ui/loader";
26-
import Link from "next/link";
6+
import { ErrorResponse, PaperResponse } from "@/interface";
7+
import axios, { AxiosResponse } from "axios";
8+
import { Metadata } from "next";
9+
import { redirect } from "next/navigation"; // Import redirect
2710

28-
interface PaperResponse {
29-
finalUrl: string;
30-
subject: string;
31-
year: string;
32-
slot: string;
33-
exam: string;
34-
}
35-
36-
interface ErrorResponse {
37-
message: string;
38-
}
39-
40-
interface Params {
11+
export async function generateMetadata({
12+
params,
13+
}: {
4114
params: { id: string };
42-
}
15+
}): Promise<Metadata> {
16+
const paper: PaperResponse | null = await fetchPaperID(params.id);
4317

44-
export default function PaperPage({ params }: Params) {
45-
const [paper, setPaper] = useState<PaperResponse | null>(null);
46-
const [error, setError] = useState<string | null>(null);
47-
const router = useRouter();
18+
if (paper) {
19+
const subject = paper.subject;
20+
return {
21+
title: `Papers | ${subject}`,
22+
openGraph: {
23+
title: `Papers | ${subject}`,
24+
},
25+
twitter: {
26+
title: `Papers | ${subject}`,
27+
},
28+
};
29+
}
4830

49-
const zoomPluginInstance = zoomPlugin();
50-
const { CurrentScale, ZoomIn, ZoomOut } = zoomPluginInstance;
51-
const fullScreenPluginInstance = fullScreenPlugin();
52-
const EnterFullScreen = fullScreenPluginInstance.EnterFullScreen.bind(
53-
fullScreenPluginInstance,
54-
);
31+
return {
32+
title: "Paper not found",
33+
};
34+
}
35+
const PaperPage = async ({ params }: { params: { id: string } }) => {
36+
async function getPaper() {
37+
try {
38+
const paper = await fetchPaperID(params.id);
39+
return paper;
40+
} catch (err) {
41+
if (axios.isAxiosError(err)) {
5542

56-
useEffect(() => {
57-
const fetchPaper = async (): Promise<void> => {
58-
try {
59-
const response: AxiosResponse<PaperResponse> = await axios.get(
60-
`/api/paper-by-id/${params.id}`,
61-
);
62-
setPaper(response.data);
63-
} catch (err: unknown) {
64-
if (axios.isAxiosError(err)) {
65-
const errorResponse = err.response as AxiosResponse<ErrorResponse>;
66-
if (errorResponse?.status === 400 || errorResponse?.status === 404) {
67-
router.push("/");
68-
} else {
69-
setError(errorResponse?.data?.message ?? "Failed to fetch paper");
70-
}
43+
const errorResponse = err.response as AxiosResponse<ErrorResponse>;
44+
if (errorResponse?.status === 400 || errorResponse?.status === 404) {
45+
redirect("/");
7146
} else {
72-
setError("An unknown error occurred");
47+
return errorResponse?.data?.message ?? "Failed to fetch paper";
7348
}
49+
} else {
50+
return "An unknown error occurred";
7451
}
75-
};
76-
77-
if (params.id) {
78-
void fetchPaper();
7952
}
80-
}, [params.id, router]);
81-
82-
if (error) {
83-
return <div>Error: {error}</div>;
8453
}
85-
54+
const paper = await getPaper();
8655
if (!paper) {
8756
return <Loader prop="h-screen w-screen" />;
8857
}
89-
9058
return (
9159
<div>
9260
<Navbar />
93-
<div className="flex flex-col items-center justify-center">
94-
<h1 className="jost mb-4 text-center text-2xl font-semibold md:mb-10 md:text-3xl">
95-
{paper.subject} {paper.exam} {paper.slot} {paper.year}
96-
</h1>
97-
<div className="flex w-[95%] items-center justify-between bg-gray-900 px-4 py-4 md:w-[80%]">
98-
<div className="flex gap-x-4">
99-
<ZoomOut>
100-
{(props: RenderZoomOutProps) => (
101-
<button onClick={props.onClick}>
102-
<ZoomOutIcon />
103-
</button>
104-
)}
105-
</ZoomOut>
106-
<CurrentScale>
107-
{(props: RenderCurrentScaleProps) => (
108-
<>{`${Math.round(props.scale * 100)}%`}</>
109-
)}
110-
</CurrentScale>
111-
<ZoomIn>
112-
{(props: RenderZoomInProps) => (
113-
<button onClick={props.onClick}>
114-
<ZoomInIcon />
115-
</button>
116-
)}
117-
</ZoomIn>
118-
</div>
119-
<div className="hidden gap-x-4 md:flex">
120-
<EnterFullScreen>
121-
{(props: RenderEnterFullScreenProps) => (
122-
<button onClick={() => props.onClick()}>
123-
<Maximize />
124-
</button>
125-
)}
126-
</EnterFullScreen>
127-
</div>
128-
<Link className="flex md:hidden" href={paper.finalUrl}>
129-
<Eye size={20} />
130-
</Link>
61+
{typeof paper === "string" ? (
62+
<div className="text-center text-red-500">
63+
<h1 className="text-xl font-semibold">Error</h1>
64+
<p>{paper}</p>
13165
</div>
66+
) : (
67+
<>
68+
<h1 className="jost mb-4 text-center text-2xl font-semibold md:mb-10 md:text-3xl">
69+
{paper.subject} {paper.exam} {paper.slot} {paper.year}
70+
</h1>
71+
<center>
72+
<PdfViewer url={paper.finalUrl}></PdfViewer>
73+
</center>
74+
</>
75+
)}
13276

133-
<Worker workerUrl="https://unpkg.com/[email protected]/build/pdf.worker.min.js">
134-
<div className="border-1 w-[95%] overflow-x-hidden md:w-[80%]">
135-
<Viewer
136-
fileUrl={paper.finalUrl}
137-
plugins={[zoomPluginInstance, fullScreenPluginInstance]}
138-
/>
139-
</div>
140-
</Worker>
141-
</div>
14277
<Footer />
14378
</div>
14479
);
145-
}
80+
};
81+
export default PaperPage;

0 commit comments

Comments
 (0)