Skip to content

Commit 30bf8db

Browse files
Merge pull request #71 from CodeChefVIT/staging
Staging
2 parents 090674f + 368b1c9 commit 30bf8db

File tree

5 files changed

+98
-35
lines changed

5 files changed

+98
-35
lines changed

src/app/api/course-list/route.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { NextResponse } from "next/server";
2+
import { connectToDatabase } from "@/lib/mongoose";
3+
import { Course } from "@/db/papers";
4+
5+
export const dynamic = "force-dynamic";
6+
7+
export async function GET() {
8+
try {
9+
await connectToDatabase();
10+
const courses = await Course.find().lean();
11+
12+
return NextResponse.json(courses, { status: 200 });
13+
} catch (error) {
14+
console.error(error);
15+
return NextResponse.json(
16+
{ message: "Failed to fetch courses", error },
17+
{ status: 500 }
18+
);
19+
}
20+
}

src/app/api/upload/route.ts

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
import { NextRequest, NextResponse } from "next/server";
1+
import { NextResponse } from "next/server";
22
import { PDFDocument } from "pdf-lib";
3-
import {courses, slots, years} from "@/components/select_options"
3+
import { slots, years } from "@/components/select_options";
44
import { connectToDatabase } from "@/lib/mongoose";
55
import cloudinary from "cloudinary";
6-
import {
7-
8-
CloudinaryUploadResult,
9-
} from "@/interface";
10-
import {PaperAdmin} from "@/db/papers";
6+
import { type ICourses, type CloudinaryUploadResult } from "@/interface";
7+
import { PaperAdmin } from "@/db/papers";
8+
import axios from "axios";
119
// TODO: REMOVE THUMBNAIL FROM admin-buffer DB
1210
cloudinary.v2.config({
1311
cloud_name: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME,
@@ -29,14 +27,19 @@ export async function POST(req: Request) {
2927
const year = formData.get("year") as string;
3028
const exam = formData.get("exam") as string;
3129
const isPdf = formData.get("isPdf") === "true"; // Convert string to boolean
32-
if(!(courses.includes(subject) && slots.includes(slot) && years.includes(year)))
33-
{
34-
return NextResponse.json(
35-
{ message: "Bad Request" },
36-
37-
{ status: 400 },
38-
);
30+
31+
const { data } = await axios.get<ICourses[]>(`${process.env.SERVER_URL}/api/course-list`);
32+
const courses = data.map((course: { name: string }) => course.name);
33+
if (
34+
!(
35+
courses.includes(subject) &&
36+
slots.includes(slot) &&
37+
years.includes(year)
38+
)
39+
) {
40+
return NextResponse.json({ message: "Bad Request" }, { status: 400 });
3941
}
42+
4043
await connectToDatabase();
4144
let finalUrl: string | undefined = "";
4245
let public_id_cloudinary: string | undefined = "";
@@ -53,18 +56,25 @@ export async function POST(req: Request) {
5356
if (!process.env.NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET) {
5457
return;
5558
}
56-
59+
5760
const mergedPdfBytes = await CreatePDF(files);
58-
[public_id_cloudinary, finalUrl] = await uploadPDFFile(mergedPdfBytes, uploadPreset);
61+
[public_id_cloudinary, finalUrl] = await uploadPDFFile(
62+
mergedPdfBytes,
63+
uploadPreset,
64+
);
5965
} catch (error) {
6066
return NextResponse.json(
6167
{ error: "Failed to process PDF" },
6268
{ status: 500 },
6369
);
6470
}
6571
} else {
66-
[public_id_cloudinary, finalUrl] = await uploadPDFFile(files[0]!, uploadPreset);
72+
[public_id_cloudinary, finalUrl] = await uploadPDFFile(
73+
files[0]!,
74+
uploadPreset,
75+
);
6776
}
77+
6878
const thumbnailResponse = cloudinary.v2.image(finalUrl!, {
6979
format: "jpg",
7080
});
@@ -73,7 +83,6 @@ export async function POST(req: Request) {
7383
.replace("upload", "upload/w_400,h_400,c_fill")
7484
.replace(/<img src='|'\s*\/>/g, "");
7585
const paper = new PaperAdmin({
76-
7786
public_id_cloudinary,
7887
finalUrl,
7988
thumbnailUrl,
@@ -91,35 +100,39 @@ export async function POST(req: Request) {
91100
console.error(error);
92101
return NextResponse.json(
93102
{ message: "Failed to upload papers", error },
94-
95103
{ status: 500 },
96104
);
97105
}
98106
}
99107

100-
101108
async function uploadPDFFile(file: File | ArrayBuffer, uploadPreset: string) {
102109
let bytes;
103-
if(file instanceof File) //for pdf
104-
{
110+
if (file instanceof File) {
105111
bytes = await file.arrayBuffer();
106-
}
107-
else // for images that are pdf
108-
{
112+
} else {
109113
bytes = file;
110114
}
111-
return uploadFile(bytes, uploadPreset, "application/pdf")
115+
return uploadFile(bytes, uploadPreset, "application/pdf");
112116
}
113-
async function uploadFile(bytes: ArrayBuffer, uploadPreset: string, fileType: string) {
117+
118+
async function uploadFile(
119+
bytes: ArrayBuffer,
120+
uploadPreset: string,
121+
fileType: string,
122+
) {
114123
try {
115124
const buffer = Buffer.from(bytes);
116125
const dataUrl = `data:${fileType};base64,${buffer.toString("base64")}`;
117-
const uploadResult = await cloudinary.v2.uploader.unsigned_upload(dataUrl, uploadPreset) as CloudinaryUploadResult;
118-
return [uploadResult.public_id, uploadResult.secure_url ];
126+
const uploadResult = (await cloudinary.v2.uploader.unsigned_upload(
127+
dataUrl,
128+
uploadPreset,
129+
)) as CloudinaryUploadResult;
130+
return [uploadResult.public_id, uploadResult.secure_url];
119131
} catch (e) {
120-
throw (e);
132+
throw e;
121133
}
122134
}
135+
123136
async function CreatePDF(files: File[]) {
124137
const pdfDoc = await PDFDocument.create();
125138

src/components/searchbarSubjectList.tsx

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
import { useState, useCallback, useRef, useEffect } from "react";
33
import { Search } from "lucide-react";
44
import debounce from "debounce";
5+
import axios from "axios";
56
import { Input } from "@/components/ui/input";
6-
import { courses } from "./select_options";
7+
import { type ICourses } from "@/interface";
78

89
function SearchbarSubjectList({
910
setSubject,
@@ -16,10 +17,28 @@ function SearchbarSubjectList({
1617
const [suggestions, setSuggestions] = useState<string[]>([]);
1718
const [error, setError] = useState<string | null>(null);
1819
const [loading, setLoading] = useState(false);
20+
const [courses, setCourses] = useState<string[]>([]);
1921
const suggestionsRef = useRef<HTMLUListElement | null>(null);
2022

23+
const fetchCourses = async () => {
24+
try {
25+
setLoading(true);
26+
const response = await axios.get<ICourses[]>("/api/course-list");
27+
const fetchedCourses = response.data.map((course: { name: string }) => course.name);
28+
setCourses(fetchedCourses);
29+
setLoading(false);
30+
} catch (err) {
31+
setError("Failed to fetch courses");
32+
setLoading(false);
33+
}
34+
};
35+
36+
useEffect(() => {
37+
void fetchCourses();
38+
}, []);
39+
2140
const debouncedSearch = useCallback(
22-
debounce(async (text: string) => {
41+
debounce((text: string) => {
2342
if (text.length > 0) {
2443
setLoading(true);
2544
const escapedSearchText = text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -32,6 +51,7 @@ function SearchbarSubjectList({
3251
if (filteredSubjects.length === 0) {
3352
setError("Subject not found");
3453
setSuggestions([]);
54+
setLoading(false);
3555
return;
3656
}
3757
setSuggestions(filteredSubjects);
@@ -41,7 +61,7 @@ function SearchbarSubjectList({
4161
setSuggestions([]);
4262
}
4363
}, 500),
44-
[],
64+
[courses]
4565
);
4666

4767
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
@@ -50,7 +70,7 @@ function SearchbarSubjectList({
5070
if (text.length <= 0) {
5171
setSuggestions([]);
5272
}
53-
void debouncedSearch(text);
73+
debouncedSearch(text);
5474
};
5575

5676
const handleSelectSuggestion = (suggestion: string) => {

src/db/papers.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import mongoose, { Schema, type Model } from "mongoose";
2-
import { type IPaper } from "@/interface";
2+
import { type IPaper, type ICourses } from "@/interface";
33

44
const paperSchema = new Schema<IPaper>({
55
public_id_cloudinary: { type: String, required: true },
@@ -12,10 +12,16 @@ const paperSchema = new Schema<IPaper>({
1212
isSelected: { type: Boolean, default: false },
1313
});
1414

15+
const courseSchema = new Schema<ICourses>({
16+
name: { type: String, required: true },
17+
});
18+
1519
paperSchema.index({ subject: 1 });
1620

1721
export const PaperAdmin: Model<IPaper> =
1822
mongoose.models.Admin ?? mongoose.model<IPaper>("Admin", paperSchema);
23+
export const Course: Model<ICourses> =
24+
mongoose.models.Course ?? mongoose.model("Course", courseSchema);
1925
const Paper: Model<IPaper> =
2026
mongoose.models.Paper ?? mongoose.model<IPaper>("Paper", paperSchema);
2127

src/interface.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ export interface IPaper{
7373
exam: "CAT-1" | "CAT-2" | "FAT";
7474
isSelected: boolean;
7575
}
76+
77+
export interface ICourses{
78+
name: string;
79+
}
7680
export interface IAdminUpload{
7781
formData: FormData;
7882
files: File[];

0 commit comments

Comments
 (0)