Skip to content

Commit eb16c7f

Browse files
indi page
1 parent 25c9336 commit eb16c7f

File tree

8 files changed

+705
-146
lines changed

8 files changed

+705
-146
lines changed

next.config.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,18 @@ await import("./src/env.js");
66

77
/** @type {import("next").NextConfig} */
88
const config = {
9-
images: {
10-
domains: ["res.cloudinary.com"],
11-
},
9+
images: {
10+
domains: ["res.cloudinary.com"],
11+
},
12+
webpack: (
13+
config, options
14+
) => {
15+
config.module.rules.push({
16+
test: /\.node/,
17+
use: 'raw-loader',
18+
});
19+
return config;
20+
},
1221
};
1322

1423
export default config;

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
"@radix-ui/react-separator": "^1.1.0",
1919
"@radix-ui/react-slot": "^1.1.0",
2020
"@radix-ui/react-switch": "^1.1.1",
21+
"@react-pdf-viewer/core": "3.12.0",
22+
"@react-pdf-viewer/default-layout": "^3.12.0",
23+
"@react-pdf-viewer/full-screen": "^3.12.0",
24+
"@react-pdf-viewer/zoom": "^3.12.0",
2125
"@t3-oss/env-nextjs": "^0.10.1",
2226
"@types/mongoose": "^5.11.97",
2327
"axios": "^1.7.2",
@@ -45,6 +49,7 @@
4549
"nodemailer": "^6.9.13",
4650
"pdf-compressor": "^1.0.5",
4751
"pdf-lib": "^1.17.1",
52+
"pdfjs-dist": "^3.4.120",
4853
"react": "^18.3.0",
4954
"react-camera-pro": "^1.4.0",
5055
"react-dom": "^18.3.0",
@@ -75,6 +80,7 @@
7580
"postcss": "^8.4.34",
7681
"prettier": "^3.2.5",
7782
"prettier-plugin-tailwindcss": "^0.5.14",
83+
"raw-loader": "^4.0.2",
7884
"tailwindcss": "^3.4.3",
7985
"typescript": "^5.4.2"
8086
},

pnpm-lock.yaml

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

src/app/api/paper-by-id/[id]/route.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { NextResponse } from "next/server";
2+
import { connectToDatabase } from "@/lib/mongoose";
3+
import Paper from "@/db/papers";
4+
import { Types } from "mongoose";
5+
6+
export async function GET(req: Request, { params }: { params: { id: string } }) {
7+
try {
8+
await connectToDatabase();
9+
10+
const { id } = params;
11+
12+
if (!Types.ObjectId.isValid(id)) {
13+
return NextResponse.json({ message: "Invalid paper ID" }, { status: 400 });
14+
}
15+
16+
const paper = await Paper.findById(id);
17+
18+
if (!paper) {
19+
return NextResponse.json({ message: "Paper not found" }, { status: 404 });
20+
}
21+
22+
return NextResponse.json(paper, { status: 200 });
23+
} catch (error) {
24+
console.error(error);
25+
return NextResponse.json(
26+
{ message: "Failed to fetch paper", error },
27+
{ status: 500 },
28+
);
29+
}
30+
}

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

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
"use client";
2+
import { useState, useEffect } from "react";
3+
import axios, { type AxiosResponse } from "axios";
4+
import Footer from "@/components/Footer";
5+
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";
25+
import Loader from "@/components/ui/loader";
26+
import Link from "next/link";
27+
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 {
41+
params: { id: string };
42+
}
43+
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();
48+
49+
const zoomPluginInstance = zoomPlugin();
50+
const { CurrentScale, ZoomIn, ZoomOut } = zoomPluginInstance;
51+
const fullScreenPluginInstance = fullScreenPlugin();
52+
const EnterFullScreen = fullScreenPluginInstance.EnterFullScreen.bind(
53+
fullScreenPluginInstance,
54+
);
55+
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+
}
71+
} else {
72+
setError("An unknown error occurred");
73+
}
74+
}
75+
};
76+
77+
if (params.id) {
78+
void fetchPaper();
79+
}
80+
}, [params.id, router]);
81+
82+
if (error) {
83+
return <div>Error: {error}</div>;
84+
}
85+
86+
if (!paper) {
87+
return <Loader prop="h-screen w-screen" />;
88+
}
89+
90+
return (
91+
<div>
92+
<Navbar />
93+
{/* <embed src={paper.finalUrl}></embed> */}
94+
95+
<div className="flex flex-col items-center justify-center">
96+
<h1 className="jost mb-4 text-center text-2xl font-semibold md:mb-10 md:text-3xl">
97+
{paper.subject} {paper.exam} {paper.slot} {paper.year}
98+
</h1>
99+
<div className="flex w-[95%] items-center justify-between bg-gray-900 px-4 py-4 md:w-[80%]">
100+
<div className="flex gap-x-4">
101+
<ZoomOut>
102+
{(props: RenderZoomOutProps) => (
103+
<button onClick={props.onClick}>
104+
<ZoomOutIcon />
105+
</button>
106+
)}
107+
</ZoomOut>
108+
<CurrentScale>
109+
{(props: RenderCurrentScaleProps) => (
110+
<>{`${Math.round(props.scale * 100)}%`}</>
111+
)}
112+
</CurrentScale>
113+
<ZoomIn>
114+
{(props: RenderZoomInProps) => (
115+
<button onClick={props.onClick}>
116+
<ZoomInIcon />
117+
</button>
118+
)}
119+
</ZoomIn>
120+
</div>
121+
<div className="hidden gap-x-4 md:flex">
122+
<EnterFullScreen>
123+
{(props: RenderEnterFullScreenProps) => (
124+
<button onClick={() => props.onClick()}>
125+
<Maximize />
126+
</button>
127+
)}
128+
</EnterFullScreen>
129+
</div>
130+
<Link className="flex md:hidden" href={paper.finalUrl}>
131+
<Eye size={20} />
132+
</Link>
133+
</div>
134+
135+
<Worker workerUrl="https://unpkg.com/[email protected]/build/pdf.worker.min.js">
136+
<div className="border-1 w-[95%] overflow-x-hidden md:w-[80%]">
137+
<Viewer
138+
fileUrl={paper.finalUrl}
139+
plugins={[zoomPluginInstance, fullScreenPluginInstance]}
140+
/>
141+
</div>
142+
</Worker>
143+
</div>
144+
<Footer />
145+
</div>
146+
);
147+
}

src/app/upload/select_options.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ const courses = [
6767
"Parallel Computing [BITE406L]",
6868
"Special Project [BITE397J]",
6969
"Machine Learning [BITE410L]",
70+
"Machine Learning [BCSE209L]",
7071
"Cloud Computing [BITE412L]",
7172
"Mobile Application Development [BITE409L]",
7273
"Network Management [BITE408L]",
@@ -153,7 +154,7 @@ const courses = [
153154
"Rocket Propulsion [CFOC235M]",
154155
"Natural Hazards [CFOC203M]",
155156
"Training of Trainers [CFOC119M]",
156-
"Compiler Design [CFOC218M]",
157+
"Compiler Design [BCSE307L]",
157158
"Business Statistics [CFOC498M]",
158159
"Entrepreneurship Essentials [CFOC384M]",
159160
"Public Speaking [CFOC570M]",
@@ -213,6 +214,12 @@ const courses = [
213214
"Foundations of Data Analytics [BCSE351E]",
214215
"Embedded Systems Design [BECE403E]",
215216
"Electronic Devices and Circuits [BECE205L]",
217+
"Linear Algebra [UMAT201L]",
218+
"Digital Watermarking and Steganography [BCSE323L]",
219+
"Electronic Circuits [BEVD204L]",
220+
"Digital Signal Processing [BECE301L]",
221+
"Signals and Systems [BECE202L]",
222+
"Engineering Electromagnetics [BECE205L]",
216223
];
217224

218225
const slots: string[] = [

src/components/ui/loader.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
const Loader = () => {
1+
function Loader ({prop = "m-52"}) {
22
return (
3-
<div className="m-52 flex justify-center items-center bg-gradient-to-br ">
3+
<div className={`${prop} flex justify-center items-center bg-gradient-to-br`}>
44
<div className="relative">
55
<div className="absolute inset-0 rounded-full bg-gradient-to-r from-white to-transparent opacity-30 animate-ping"></div>
66
<div className="animate-spin rounded-full h-20 w-20 border-t-4 border-b-4 border-transparent border-t-white border-b-gray-800 shadow-lg"></div>

src/styles/globals.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
}
102102
.dark ::-webkit-scrollbar {
103103
width: 0.4rem;
104+
height: 0.4rem;
104105
background: #535253;
105106
}
106107

@@ -117,6 +118,7 @@
117118
}
118119
::-webkit-scrollbar {
119120
width: 0.4rem;
121+
height: 0.4rem;
120122
background: #535253;
121123
}
122124
::-webkit-scrollbar-track {
@@ -127,4 +129,8 @@
127129
::-webkit-scrollbar-thumb {
128130
background: #929292;
129131
border-radius: 1rem;
132+
}
133+
134+
.rpv-full-screen__overlay {
135+
display: none !important;
130136
}

0 commit comments

Comments
 (0)