|
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"; |
4 | 2 | import Footer from "@/components/Footer";
|
5 | 3 | 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"; |
25 | 5 | 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 |
27 | 10 |
|
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 | +}: { |
41 | 14 | params: { id: string };
|
42 |
| -} |
| 15 | +}): Promise<Metadata> { |
| 16 | + const paper: PaperResponse | null = await fetchPaperID(params.id); |
43 | 17 |
|
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 | + } |
48 | 30 |
|
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)) { |
55 | 42 |
|
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("/"); |
71 | 46 | } else {
|
72 |
| - setError("An unknown error occurred"); |
| 47 | + return errorResponse?.data?.message ?? "Failed to fetch paper"; |
73 | 48 | }
|
| 49 | + } else { |
| 50 | + return "An unknown error occurred"; |
74 | 51 | }
|
75 |
| - }; |
76 |
| - |
77 |
| - if (params.id) { |
78 |
| - void fetchPaper(); |
79 | 52 | }
|
80 |
| - }, [params.id, router]); |
81 |
| - |
82 |
| - if (error) { |
83 |
| - return <div>Error: {error}</div>; |
84 | 53 | }
|
85 |
| - |
| 54 | + const paper = await getPaper(); |
86 | 55 | if (!paper) {
|
87 | 56 | return <Loader prop="h-screen w-screen" />;
|
88 | 57 | }
|
89 |
| - |
90 | 58 | return (
|
91 | 59 | <div>
|
92 | 60 | <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> |
131 | 65 | </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 | + )} |
132 | 76 |
|
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> |
142 | 77 | <Footer />
|
143 | 78 | </div>
|
144 | 79 | );
|
145 |
| -} |
| 80 | +}; |
| 81 | +export default PaperPage; |
0 commit comments