Skip to content

Commit 023a0dd

Browse files
feat: related subs
1 parent e02e6b2 commit 023a0dd

File tree

4 files changed

+117
-17
lines changed

4 files changed

+117
-17
lines changed

src/app/api/related-subject/route.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { NextResponse, type NextRequest } from "next/server";
2+
import { connectToDatabase } from "@/lib/mongoose";
3+
import { IRelatedSubject } from "@/interface";
4+
import RelatedSubject from "@/db/relatedSubjects";
5+
6+
export const dynamic = "force-dynamic";
7+
8+
export async function GET(req: NextRequest) {
9+
try {
10+
await connectToDatabase();
11+
const url = req.nextUrl.searchParams;
12+
const subject = url.get("subject");
13+
const escapeRegExp = (text: string) => {
14+
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
15+
};
16+
const escapedSubject = escapeRegExp(subject ?? "");
17+
18+
if (!subject) {
19+
return NextResponse.json(
20+
{ message: "Subject query parameter is required" },
21+
{ status: 400 },
22+
);
23+
}
24+
const subjects: IRelatedSubject[] = await RelatedSubject.find({
25+
subject: { $regex: new RegExp(`${escapedSubject}`, "i") },
26+
});
27+
console.log("realted", subjects);
28+
29+
return NextResponse.json(
30+
{
31+
related_subjects: subjects[0]?.related_subjects
32+
},
33+
{ status: 200 },
34+
);
35+
} catch (error) {
36+
return NextResponse.json(
37+
{ message: "Failed to fetch related subject", error },
38+
{ status: 500 },
39+
);
40+
}
41+
}

src/components/CatalogueContent.tsx

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useSearchParams } from "next/navigation";
44
import { useCallback, useEffect, useState } from "react";
55
import axios, { type AxiosError } from "axios";
66
import { Button } from "@/components/ui/button";
7-
import { type IPaper, type Filters } from "@/interface";
7+
import { type IPaper, type Filters, IRelatedSubject, StoredSubjects } from "@/interface";
88
import Card from "./Card";
99
import { useRouter } from "next/navigation";
1010
import Loader from "./ui/loader";
@@ -13,8 +13,8 @@ import Error from "./Error";
1313
import { Filter } from "lucide-react";
1414
import { Sheet, SheetContent, SheetTrigger } from "./ui/sheet";
1515
import { Pin } from "lucide-react";
16-
import { StoredSubjects } from "@/interface";
1716
import { getSecureUrl, generateFileName, downloadFile } from "@/util/download";
17+
import Link from "next/link";
1818

1919
const CatalogueContent = () => {
2020
const router = useRouter();
@@ -39,6 +39,29 @@ const CatalogueContent = () => {
3939
const [filtersPulled, setFiltersPulled] = useState<boolean>(false);
4040
const [appliedFilters, setAppliedFilters] = useState<boolean>(false);
4141
const [pinned, setPinned] = useState<boolean>(false);
42+
const [relatedSubjects, setRelatedSubjects] = useState<string[]>([]);
43+
// Fetch related subjects when subject changes
44+
useEffect(() => {
45+
if (!subject) return;
46+
const fetchRelatedSubjects = async () => {
47+
try {
48+
const res = await axios.get<{related_subjects: string []}>("/api/related-subject", {
49+
params: { subject },
50+
});
51+
console.log(res.data)
52+
const data = res.data.related_subjects;
53+
console.log("data" , data[0], data[1]);
54+
if (data && data.length > 0) {
55+
setRelatedSubjects(data);
56+
} else {
57+
setRelatedSubjects([]);
58+
}
59+
} catch (e) {
60+
setRelatedSubjects([]);
61+
}
62+
};
63+
void fetchRelatedSubjects();
64+
}, [subject]);
4265

4366
// Set initial state from searchParams on client-side mount
4467
useEffect(() => {
@@ -317,22 +340,38 @@ const CatalogueContent = () => {
317340
</SheetContent>
318341
</Sheet>
319342

320-
<div className="flex items-center gap-2 p-7">
321-
<div>
322-
<p className="text-s font-semibold text-gray-700 dark:text-white/80">
323-
{subject?.split("[")[1]?.replace("]", "")}
324-
</p>
325-
<h2 className="text-2xl font-extrabold text-gray-700 dark:text-white md:text-3xl">
326-
{subject?.split(" [")[0]}
327-
</h2>
328-
</div>
329-
<div className="mt-7">
330-
<button onClick={handlePinToggle}>
331-
<Pin
332-
className={`h-7 w-7 ${pinned ? "fill-[#A78BFA]" : ""} stroke-gray-700 dark:stroke-white`}
333-
/>
334-
</button>
343+
<div className="p-7">
344+
<div className="flex items-center gap-2">
345+
<div>
346+
<p className="text-s font-semibold text-gray-700 dark:text-white/80">
347+
{subject?.split("[")[1]?.replace("]", "")}
348+
</p>
349+
<h2 className="text-2xl font-extrabold text-gray-700 dark:text-white md:text-3xl">
350+
{subject?.split(" [")[0]}
351+
</h2>
352+
</div>
353+
<div className="mt-7">
354+
<button onClick={handlePinToggle}>
355+
<Pin
356+
className={`h-7 w-7 ${pinned ? "fill-[#A78BFA]" : ""} stroke-gray-700 dark:stroke-white`}
357+
/>
358+
</button>
359+
</div>
335360
</div>
361+
{relatedSubjects.length > 0 && (
362+
<div className="mt-3 flex flex-wrap items-center gap-2">
363+
<span className="text-sm font-medium text-gray-500 dark:text-gray-300 mr-2">Related subjects:</span>
364+
{relatedSubjects.map((sub) => (
365+
<Link
366+
key={sub}
367+
href={`/catalogue?subject=${encodeURIComponent(sub)}`}
368+
className="rounded-full bg-violet-100 px-3 py-1 text-sm font-semibold text-violet-700 transition-colors hover:bg-violet-200 dark:bg-violet-900 dark:text-violet-200 dark:hover:bg-violet-800"
369+
>
370+
{sub}
371+
</Link>
372+
))}
373+
</div>
374+
)}
336375
</div>
337376

338377
{loading ? (

src/db/relatedSubjects.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import mongoose, { Schema, type Model } from "mongoose";
2+
import { type IRelatedSubject } from "@/interface";
3+
4+
5+
const relatedSubjectSchema = new Schema<IRelatedSubject>({
6+
subject: { type: String, required: true },
7+
related_subjects: { type: [String], required: true },
8+
});
9+
10+
const RelatedSubject: Model<IRelatedSubject> =
11+
mongoose.models.RelatedSubject ??
12+
mongoose.model<IRelatedSubject>("RelatedSubject", relatedSubjectSchema);
13+
14+
export default RelatedSubject;

src/interface.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,9 @@ export interface TransformedPaper {
209209
subject: string;
210210
slots: string[];
211211
}
212+
213+
214+
export interface IRelatedSubject {
215+
subject: string;
216+
related_subjects: string[];
217+
}

0 commit comments

Comments
 (0)