diff --git a/src/app/api/papers/route.ts b/src/app/api/papers/route.ts index 12186d0..5a33b13 100644 --- a/src/app/api/papers/route.ts +++ b/src/app/api/papers/route.ts @@ -29,7 +29,7 @@ export async function GET(req: NextRequest) { if (papers.length === 0) { return NextResponse.json( { message: "No papers found for the specified subject" }, - { status: 404 }, + { status: 200 }, ); } diff --git a/src/app/api/upcoming-papers/route.ts b/src/app/api/upcoming-papers/route.ts index 83f78b0..8b426fa 100644 --- a/src/app/api/upcoming-papers/route.ts +++ b/src/app/api/upcoming-papers/route.ts @@ -18,8 +18,13 @@ export async function GET() { { status: 404 }, ); } - const nextSlot = String.fromCharCode(slot.charCodeAt(0) + 1) - const correspondingSlots = [slot + "1", slot + "2", nextSlot + "1", nextSlot + "2"]; + const nextSlot = String.fromCharCode(slot.charCodeAt(0) + 1); + const correspondingSlots = [ + slot + "1", + slot + "2", + nextSlot + "1", + nextSlot + "2", + ]; const selectedSubjects = await UpcomingSubject.find({ slots: { $in: correspondingSlots }, }); diff --git a/src/app/api/user-papers/route.ts b/src/app/api/user-papers/route.ts new file mode 100644 index 0000000..7cef1f4 --- /dev/null +++ b/src/app/api/user-papers/route.ts @@ -0,0 +1,50 @@ +import { NextResponse } from "next/server"; +import { connectToDatabase } from "@/lib/mongoose"; +import Paper from "@/db/papers"; + +export const dynamic = "force-dynamic"; + +export async function POST(req: Request) { + try { + await connectToDatabase(); + const body = await req.json(); + + const subjects: string[] = body; + + const usersPapers = await Paper.find({ + subject: { $in: subjects }, + }); + + const transformedPapers = usersPapers.reduce((acc, paper) => { + const existing = acc.find((item) => item.subject === paper.subject); + + if (existing) { + existing.slots.push(paper.slot); + } else { + acc.push({ subject: paper.subject, slots: [paper.slot] }); + } + + return acc; + }, []); + + // check duplicates + const seenSubjects = new Set(); + const uniquePapers = transformedPapers.filter((paper) => { + if (seenSubjects.has(paper.subject)) return false; + seenSubjects.add(paper.subject); + return true; + }); + + return NextResponse.json(uniquePapers, { + status: 200, + }); + } catch (error) { + console.error("Error fetching papers:", error); + return NextResponse.json( + { + error: "Failed to fetch papers.", + }, + { status: 500 }, + ); + } +} diff --git a/src/components/StoredPapers.tsx b/src/components/PapersCarousel.tsx similarity index 72% rename from src/components/StoredPapers.tsx rename to src/components/PapersCarousel.tsx index 5e84ce3..287e6a6 100644 --- a/src/components/StoredPapers.tsx +++ b/src/components/PapersCarousel.tsx @@ -15,7 +15,11 @@ import { import Autoplay from "embla-carousel-autoplay"; import { chunkArray } from "@/util/utils"; -function StoredPapers() { +function PapersCarousel({ + carouselType, +}: { + carouselType: "users" | "default"; +}) { const [displayPapers, setDisplayPapers] = useState([]); const [isLoading, setIsLoading] = useState(true); const [chunkSize, setChunkSize] = useState(4); @@ -29,6 +33,17 @@ function StoredPapers() { } }; + localStorage.setItem( + "userSubjects", + JSON.stringify([ + "Information Security [CBS3002]", + "Foundations of Data Analytics [BCSE351E]", + "Design and Analysis of Algorithms [MCSE502L]", + "Complex Variables and Linear Algebra [BMAT201L]", + "Differential Equations and Transforms [BMAT102L]", + ]), + ); + handleResize(); window.addEventListener("resize", handleResize); @@ -43,10 +58,18 @@ function StoredPapers() { async function fetchPapers() { try { setIsLoading(true); - const response = await axios.get( - "/api/upcoming-papers", - ); - setDisplayPapers(response.data); + if (carouselType === "users") { + const storedSubjects = JSON.parse( + localStorage.getItem("userSubjects"), + ); + const response = await axios.post("/api/user-papers", storedSubjects); + setDisplayPapers(response.data); + } else { + const response = await axios.get( + "/api/upcoming-papers", + ); + setDisplayPapers(response.data); + } } catch (error) { console.error("Failed to fetch papers:", error); } finally { @@ -66,7 +89,7 @@ function StoredPapers() { return (

- Upcoming Papers + {carouselType === "users" ? "Your Papers" : "Upcoming Papers"}

@@ -107,4 +130,4 @@ function StoredPapers() { ); } -export default StoredPapers; +export default PapersCarousel; diff --git a/src/components/Searchbar/searchbar-child.tsx b/src/components/Searchbar/searchbar-child.tsx index eb4c159..3e7ba10 100644 --- a/src/components/Searchbar/searchbar-child.tsx +++ b/src/components/Searchbar/searchbar-child.tsx @@ -5,6 +5,7 @@ import { Search } from "lucide-react"; import { useRouter } from "next/navigation"; import { Input } from "@/components/ui/input"; import Fuse from "fuse.js"; +import axios from "axios"; function SearchBarChild({ initialSubjects, @@ -19,7 +20,26 @@ function SearchBarChild({ const suggestionsRef = useRef(null); const fuzzy = new Fuse(initialSubjects); - const handleSearchChange = (e: React.ChangeEvent) => { + const fetchPaperQuantityByName = async (subjectName: string) => { + try { + const response = await axios.get("/api/papers", { + params: { subject: subjectName }, + }); + + if ( + response.data.message === "No papers found for the specified subject" + ) { + return 0; + } + + return response.data.papers.length; + } catch (error) { + console.error("Error fetching paper quantity:", error); + return "request-error"; + } + }; + + const handleSearchChange = async (e: React.ChangeEvent) => { const text = e.target.value; setSearchText(text); @@ -32,7 +52,16 @@ function SearchBarChild({ .map((item) => item.item) .slice(0, 10); - setSuggestions(filteredSuggestions); + const suggestionsWithCount = await Promise.all( + filteredSuggestions.map(async (suggestion) => { + const count = await fetchPaperQuantityByName(suggestion); + return count !== "request-error" + ? `${suggestion} (${count})` + : suggestion; + }), + ); + + setSuggestions(suggestionsWithCount); } else { setSuggestions([]); } @@ -62,7 +91,7 @@ function SearchBarChild({ }, []); return ( -
+
{ e.preventDefault(); @@ -78,7 +107,7 @@ function SearchBarChild({ value={searchText} onChange={handleSearchChange} placeholder="Search by subject..." - className={`text-md font-play rounded-lg bg-[#B2B8FF] px-4 py-6 pr-10 tracking-wider text-black shadow-sm ring-0 placeholder:text-black focus:outline-none focus:ring-0 dark:bg-[#7480FF66] dark:text-white placeholder:dark:text-white ${suggestions.length > 0 ? "rounded-b-none" : ""}`} + className={`text-md rounded-lg bg-[#B2B8FF] px-4 py-6 pr-10 font-play tracking-wider text-black shadow-sm ring-0 placeholder:text-black focus:outline-none focus:ring-0 dark:bg-[#7480FF66] dark:text-white placeholder:dark:text-white ${suggestions.length > 0 ? "rounded-b-none" : ""}`} />