Skip to content

Commit 1642471

Browse files
thumbnail feature
1 parent 8a1e653 commit 1642471

File tree

8 files changed

+82
-52
lines changed

8 files changed

+82
-52
lines changed

src/app/adminupload/page.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ const Upload: React.FC = () => {
9898

9999
const formData = new FormData();
100100
formData.append("file", file);
101-
toast.promise(
101+
void toast.promise(
102102
//Won't refresh the page if error 401
103103
(async () => {
104104
try {
@@ -188,7 +188,7 @@ const Upload: React.FC = () => {
188188
Authorization: `Bearer ${token}`,
189189
};
190190
//won't refresh if page 401
191-
toast.promise(
191+
void toast.promise(
192192
(async () => {
193193
try {
194194
const response = await axios.delete("/api/admin/watermark", {
@@ -239,7 +239,7 @@ const Upload: React.FC = () => {
239239
files.forEach((file) => {
240240
formData.append("files", file);
241241
});
242-
toast.promise(
242+
void toast.promise(
243243
(async () => {
244244
try {
245245
const response = await axios.post<PostPDF>(
@@ -303,7 +303,7 @@ const Upload: React.FC = () => {
303303

304304
const handleDeleteMerged = async () => {
305305
if (!pdfUrl) return;
306-
toast.promise(
306+
void toast.promise(
307307
(async () => {
308308
try {
309309
const response = await axios.delete<DeletePDF>(
@@ -367,7 +367,7 @@ const Upload: React.FC = () => {
367367
exam: exam,
368368
isPdf: isPdf,
369369
};
370-
toast.promise(
370+
void toast.promise(
371371
(async () => {
372372
try {
373373
const response = await axios.post<PostPDFToCloudinary>(

src/app/api/admin/route.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export async function POST(req: Request) {
1616
const body = (await req.json()) as IAdminUpload;
1717
const { urls, slot, subject, exam, year, isPdf, publicIds } = body;
1818
let finalUrl: string | undefined = "";
19+
let thumbnailUrl: string | undefined = "";
1920
const existingPaper = await Paper.findOne({
2021
subject,
2122
slot,
@@ -56,8 +57,15 @@ export async function POST(req: Request) {
5657
);
5758
} else {
5859
finalUrl = urls[0];
60+
const thumbnailResponse = cloudinary.v2.url(finalUrl!, {
61+
format: "jpg",
62+
page: 1,
63+
transformation: [{ width: 300, height: 400, crop: "fit" }],
64+
});
65+
thumbnailUrl = thumbnailResponse;
5966
const paper = new Paper({
6067
finalUrl,
68+
thumbnailUrl,
6169
subject,
6270
slot,
6371
year,

src/app/api/papers/route.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { type IPaper } from "@/interface";
66

77
const cryptr = new Cryptr(process.env.CRYPTO_SECRET ?? "default_crypto_secret");
88

9+
export const dynamic = "force-dynamic";
10+
911
export async function GET(req: Request) {
1012
try {
1113
await connectToDatabase();

src/app/api/search/route.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import { connectToDatabase } from "@/lib/mongoose";
33
import Paper from "@/db/papers";
44
import Cryptr from "cryptr";
55

6-
const cryptr = new Cryptr(process.env.CRYPTO_SECRET || "default_crypto_secret");
6+
const cryptr = new Cryptr(process.env.CRYPTO_SECRET ?? "default_crypto_secret");
7+
8+
export const dynamic = "force-dynamic";
79

810
export async function GET(req: Request) {
911
try {

src/app/catalogue/page.tsx

Lines changed: 61 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
"use client";
22

3-
import { useSearchParams, useRouter } from "next/navigation";
3+
import { useSearchParams, useRouter } from "next/navigation";
44
import { useEffect, useState } from "react";
5-
import axios, { AxiosError } from "axios";
5+
import axios, { type AxiosError } from "axios";
66
import Cryptr from "cryptr";
7+
import { Suspense } from "react";
78

89
interface Paper {
910
_id: string;
@@ -14,89 +15,104 @@ interface Paper {
1415
year: string;
1516
}
1617

17-
const cryptr = new Cryptr(process.env.NEXT_PUBLIC_CRYPTO_SECRET ?? "default_crypto_secret");
18+
const cryptr = new Cryptr(
19+
process.env.NEXT_PUBLIC_CRYPTO_SECRET ?? "default_crypto_secret"
20+
);
1821

19-
const Catalogue = () => {
20-
const router = useRouter();
21-
const searchParams = useSearchParams();
22-
const subject = searchParams.get('subject');
22+
const CatalogueContent = () => {
23+
const router = useRouter();
24+
const searchParams = useSearchParams();
25+
const subject = searchParams.get("subject");
2326
const [papers, setPapers] = useState<Paper[]>([]);
2427
const [error, setError] = useState<string | null>(null);
25-
const [loading, setLoading] = useState<boolean>(false);
28+
const [loading, setLoading] = useState<boolean>(false);
2629

2730
useEffect(() => {
2831
if (subject) {
2932
const fetchPapers = async () => {
30-
setLoading(true);
33+
setLoading(true);
3134

3235
try {
33-
const papersResponse = await axios.get("http://localhost:3000/api/papers", {
36+
const papersResponse = await axios.get("/api/papers", {
3437
params: { subject },
3538
});
3639

3740
const { res: encryptedPapersResponse } = papersResponse.data;
38-
const decryptedPapersResponse = cryptr.decrypt(encryptedPapersResponse);
39-
// console.log("Decrypted Papers Response:", decryptedPapersResponse);
40-
41-
const papersData: Paper[] = JSON.parse(decryptedPapersResponse).papers;
41+
const decryptedPapersResponse = cryptr.decrypt(
42+
encryptedPapersResponse
43+
);
44+
const papersData: Paper[] = JSON.parse(
45+
decryptedPapersResponse
46+
).papers;
4247
setPapers(papersData);
4348
} catch (error) {
44-
4549
if (axios.isAxiosError(error)) {
4650
const axiosError = error as AxiosError<{ message?: string }>;
47-
const errorMessage = axiosError.response?.data?.message || "Error fetching papers";
51+
const errorMessage =
52+
axiosError.response?.data?.message ?? "Error fetching papers";
4853
setError(errorMessage);
49-
5054
} else {
5155
setError("Error fetching papers");
5256
}
53-
5457
} finally {
55-
setLoading(false);
58+
setLoading(false);
5659
}
5760
};
5861

59-
fetchPapers();
62+
void fetchPapers();
6063
}
61-
}, [subject]);
64+
}, [subject]);
6265

6366
return (
6467
<div className="min-h-screen bg-gray-50 p-8">
65-
66-
<button onClick={() => router.push('/')} className="mb-4 px-4 py-2 bg-blue-500 text-white rounded-md">
68+
<button
69+
onClick={() => router.push("/")}
70+
className="mb-4 rounded-md bg-blue-500 px-4 py-2 text-white"
71+
>
6772
Back to Search
6873
</button>
6974

70-
<h1 className="text-2xl font-bold mb-4">Papers for {subject}</h1>
75+
<h1 className="mb-4 text-2xl font-bold">Papers for {subject}</h1>
7176
{error && <p className="text-red-500">{error}</p>}
7277

7378
{loading ? (
7479
<p>Loading papers...</p>
80+
) : papers.length > 0 ? (
81+
<div className="grid grid-cols-1 gap-4">
82+
{papers.map((paper) => (
83+
<div
84+
key={paper._id}
85+
className="rounded-md border bg-white p-4 shadow-md"
86+
>
87+
<h3 className="text-xl font-bold">Exam: {paper.exam}</h3>
88+
<p>Slot: {paper.slot}</p>
89+
<p>Subject: {paper.subject}</p>
90+
<p>Year: {paper.year}</p>
91+
92+
<a
93+
href={paper.finalUrl}
94+
target="_blank"
95+
rel="noopener noreferrer"
96+
className="text-blue-500 hover:underline"
97+
>
98+
View Paper
99+
</a>
100+
</div>
101+
))}
102+
</div>
75103
) : (
76-
papers.length > 0 ? (
77-
<div className="grid grid-cols-1 gap-4">
78-
79-
{papers.map((paper) => (
80-
<div key={paper._id} className="border rounded-md p-4 shadow-md bg-white">
81-
82-
<h3 className="text-xl font-bold">Exam: {paper.exam}</h3>
83-
<p>Slot: {paper.slot}</p>
84-
<p>Subject: {paper.subject}</p>
85-
<p>Year: {paper.year}</p>
86-
87-
<a href={paper.finalUrl} target="_blank" rel="noopener noreferrer" className="text-blue-500 hover:underline">
88-
View Paper
89-
</a>
90-
91-
</div>
92-
))}
93-
</div>
94-
) : (
95-
<p>No papers available for this subject.</p>
96-
)
104+
<p>No papers available for this subject.</p>
97105
)}
98106
</div>
99107
);
100108
};
101109

110+
const Catalogue = () => {
111+
return (
112+
<Suspense fallback={<div>Loading catalogue...</div>}>
113+
<CatalogueContent />
114+
</Suspense>
115+
);
116+
};
117+
102118
export default Catalogue;

src/app/components/searchbar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const SearchBar = () => {
2222

2323
if (text.length > 1) {
2424
try {
25-
const searchResponse = await axios.get("http://localhost:3000/api/search", {
25+
const searchResponse = await axios.get("/api/search", {
2626
params: { text },
2727
});
2828

src/db/papers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { type IPaper } from "@/interface";
33

44
const paperSchema = new Schema<IPaper>({
55
finalUrl: { type: String, required: true },
6+
thumbnailUrl: { type: String, required: true },
67
subject: { type: String, required: true },
78
slot: { type: String, required: true },
89
year: { type: String, required: true },

src/interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export interface PostRequestBody {
3636

3737
export interface IPaper{
3838
finalUrl: string;
39+
thumbnailUrl: string;
3940
subject: string;
4041
slot: string;
4142
year: string;

0 commit comments

Comments
 (0)