Skip to content

Commit 703725c

Browse files
committed
fix: #267
1 parent d26e0f8 commit 703725c

File tree

10 files changed

+4832
-2499
lines changed

10 files changed

+4832
-2499
lines changed

pnpm-lock.yaml

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

src/app/pinned/page.tsx

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,18 @@
1-
"use client";
2-
31
import React from "react";
42
import SearchBar from "@/components/Searchbar/searchbar";
53
import PinnedPapersCarousel from "@/components/PinnedPapersCarousel";
6-
import { type IUpcomingPaper } from "@/interface";
7-
import { useState } from "react";
84

95
const Pinned = () => {
10-
const [displayPapers, setDisplayPapers] = useState<IUpcomingPaper[]>([]);
11-
126
return (
137
<div id="pinned" className="mt-5 flex flex-col justify-between">
148
<h1 className="mx-auto my-8 text-center font-vipnabd text-xl font-extrabold sm:text-2xl md:text-3xl">
159
Pinned Subjects
1610
</h1>
1711
<div className="mb-3 flex w-full flex-col items-center gap-2 px-6">
1812
<div className="w-full">
19-
<SearchBar type="pinned" displayPapers={displayPapers.length > 0} />
13+
<SearchBar type="pinned" />
2014
</div>
2115
</div>
22-
<div className="min-h-[40vh]">
23-
<PinnedPapersCarousel
24-
carouselType="users"
25-
displayPapers={displayPapers}
26-
setDisplayPapers={setDisplayPapers}
27-
/>
28-
</div>
2916
{/* <div className="mt-6 flex w-full items-center justify-center">
3017
<p>You can pin upto 8 Subjects here</p>
3118
</div> */}

src/components/Navbar.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
DropdownMenuItem,
2525
} from "@/components/ui/dropdown-menu";
2626
import { useCourses } from "@/context/courseContext";
27+
import PinnedModal from "./ui/PinnedModal";
2728
import CookoffBanner from "./CookoffBanner";
2829

2930
function Navbar() {
@@ -38,12 +39,19 @@ function Navbar() {
3839

3940
const renderHomePageButtons = () => (
4041
<>
41-
<Link href="/pinned" className="ml-2">
42+
{/* <Link href="/pinned" className="ml-2">
4243
<div className="flex h-8 items-center gap-1 rounded-full border border-[#3A3745] bg-[#e8e9ff] px-2.5 py-1 text-xs font-semibold text-gray-700 transition hover:bg-slate-50 dark:bg-black dark:text-white dark:hover:bg-[#1A1823] sm:h-9 sm:gap-2 sm:px-3.5 sm:py-1.5 sm:text-sm md:h-10 md:px-4 md:py-2 md:text-base">
4344
<Pin className="h-3.5 w-3.5 sm:h-4 sm:w-4" />
4445
<span className="truncate">Pinned Subjects</span>
4546
</div>
46-
</Link>
47+
</Link> */}
48+
49+
<div className="flex h-8 items-center gap-1 rounded-full border border-[#3A3745] bg-[#e8e9ff] px-2.5 py-1 text-xs font-semibold text-gray-700 transition hover:bg-slate-50 dark:bg-black dark:text-white dark:hover:bg-[#1A1823] sm:h-9 sm:gap-2 sm:px-3.5 sm:py-1.5 sm:text-sm md:h-10 md:px-4 md:py-2 md:text-base">
50+
<Pin className="h-3.5 w-3.5 sm:h-4 sm:w-4" />
51+
<span className="truncate">
52+
<PinnedModal/>
53+
</span>
54+
</div>
4755

4856
<Link href="/request" className="ml-2 mt-2 sm:mt-0">
4957
<div className="flex h-8 items-center gap-1 rounded-full border border-[#3A3745] bg-[#e8e9ff] px-2.5 py-1 text-xs font-semibold text-gray-700 transition hover:bg-slate-50 dark:bg-black dark:text-white dark:hover:bg-[#1A1823] sm:h-9 sm:gap-2 sm:px-3.5 sm:py-1.5 sm:text-sm md:h-10 md:px-4 md:py-2 md:text-base">
@@ -104,10 +112,7 @@ function Navbar() {
104112
align="start"
105113
>
106114
<DropdownMenuItem asChild>
107-
<Link href="/pinned" className="flex items-center gap-3">
108-
<Pin className="h-4 w-4" />
109-
<span className="font-medium">Pinned Subjects</span>
110-
</Link>
115+
<PinnedModal/>
111116
</DropdownMenuItem>
112117
<DropdownMenuItem asChild>
113118
<Link href="/request" className="flex items-center gap-3">

src/components/PinButton.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ export default function PinButton({
1515
<button
1616
type="submit"
1717
onClick={onToggle}
18-
className={`flex items-center gap-2 rounded-full border border-[#3A3745] px-3 py-3 sm:px-4 sm:py-2 text-sm font-medium transition ${
18+
className={`cursor-pointer flex items-center gap-2 rounded-full border border-[#3A3745] px-3 py-3 sm:px-4 sm:py-2 text-sm font-medium transition ${
1919
isPinned
2020
? "bg-purple-700 text-white hover:bg-purple-600 dark:bg-purple-600 dark:hover:bg-purple-500"
2121
: "bg-[#e8e9ff] text-gray-700 hover:bg-slate-50 dark:bg-black dark:text-white dark:hover:bg-[#1A1823]"
2222
}`}
2323
disabled={disabled}
2424
>
25-
{isPinned ? <Pin className="h-4 w-4" /> : <PinOff className="h-4 w-4" />}
26-
<span className="hidden sm:inline">{isPinned ? "Pinned" : "Pin"}</span>
25+
{isPinned ? <PinOff className="h-4 w-4" /> : <Pin className="h-4 w-4" />}
26+
<span className="hidden sm:inline">{isPinned ? "Unpin" : "Pin"}</span>
2727
</button>
2828
);
2929
}

src/components/PinnedPapersCarousel.tsx

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use client";
22

3+
import { Pin } from "lucide-react";
34
import { useEffect, useState } from "react";
45
import axios from "axios";
56
import { type IUpcomingPaper } from "@/interface";
@@ -18,21 +19,17 @@ import Autoplay from "embla-carousel-autoplay";
1819
import { chunkArray } from "@/util/utils";
1920
import { StoredSubjects } from "@/interface";
2021
import SkeletonPaperCard from "./SkeletonPaperCard";
21-
22+
import PinnedModal from "./ui/PinnedModal";
2223
type PinnedPapersCarouselProps = {
2324
carouselType: "users" | "upcoming",
24-
displayPapers: IUpcomingPaper[],
25-
setDisplayPapers: React.Dispatch<React.SetStateAction<IUpcomingPaper[]>>
2625
}
2726

2827
function PinnedPapersCarousel({
2928
carouselType = "upcoming",
30-
displayPapers,
31-
setDisplayPapers
3229
} : PinnedPapersCarouselProps) {
3330
const [isLoading, setIsLoading] = useState(true);
3431
const [chunkSize, setChunkSize] = useState<number>(4);
35-
32+
const [displayPapers, setDisplayPapers] = useState<IUpcomingPaper[]>([]);
3633
useEffect(() => {
3734
const handleResize = () => {
3835
if(window.innerWidth <= 540){
@@ -96,8 +93,39 @@ function PinnedPapersCarousel({
9693
}, []);
9794

9895
useEffect(() => {
99-
const handleSubjectsChange = () => {
100-
void fetchPapers();
96+
const handleSubjectsChange = async() => {
97+
try {
98+
const storedSubjects = JSON.parse(
99+
localStorage.getItem("userSubjects") ?? "[]",
100+
) as StoredSubjects;
101+
102+
const response = await axios.post<{ subject: string; slots: string[] }[]>(
103+
"/api/user-papers",
104+
storedSubjects,
105+
);
106+
107+
const fetchedPapers = response.data;
108+
109+
const fetchedSubjectsSet = new Set(
110+
fetchedPapers.map((paper) => paper.subject),
111+
);
112+
113+
const storedSubjectsArray = Array.isArray(storedSubjects)
114+
? storedSubjects
115+
: [];
116+
const missingSubjects = storedSubjectsArray
117+
.filter((subject: string) => !fetchedSubjectsSet.has(subject))
118+
.map((subject: string) => ({
119+
subject,
120+
slots: [],
121+
})) as { subject: string; slots: string[] }[];
122+
123+
const allDisplayPapers = [...fetchedPapers, ...missingSubjects];
124+
125+
setDisplayPapers(allDisplayPapers);
126+
} catch (error) {
127+
console.error("Failed to fetch papers:", error);
128+
}
101129
};
102130

103131
window.addEventListener("userSubjectsChanged", handleSubjectsChange);
@@ -164,7 +192,6 @@ function PinnedPapersCarousel({
164192
window.dispatchEvent(new Event("addButtonClicked"));
165193
}}
166194
>
167-
<AddPapers />
168195
</div>
169196
)}
170197
</CarouselItem>
@@ -173,9 +200,15 @@ function PinnedPapersCarousel({
173200
)}
174201
</CarouselContent>
175202
</Carousel> :
176-
<div className={`relative flex justify-center gap-4 items-center h-max text-center my-48 font-bold`}
203+
<div className={`relative flex flex-col justify-center gap-4 items-center h-max text-center my-48 font-bold`}
177204
>
178205
Start pinning subjects for quick and easy access.
206+
<div className="flex h-8 items-center gap-1 rounded-full border border-[#3A3745] bg-[#e8e9ff] px-2.5 py-1 text-xs font-semibold text-gray-700 transition hover:bg-slate-50 dark:bg-black dark:text-white dark:hover:bg-[#1A1823] sm:h-9 sm:gap-2 sm:px-3.5 sm:py-1.5 sm:text-sm md:h-10 md:px-4 md:py-2 md:text-base">
207+
<Pin className="h-3.5 w-3.5 sm:h-4 sm:w-4" />
208+
<span className="truncate">
209+
<PinnedModal/>
210+
</span>
211+
</div>
179212
</div>}
180213
</div>
181214
</div>

src/components/Searchbar/pinned-searchbar.tsx

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@ import NavDropdownButton from "../NavDropdownButton";
1010
import { StoredSubjects } from "@/interface";
1111
import FloatingControls from "./floating-controls";
1212
import { type ICourseWithCount } from "@/interface";
13+
import { IUpcomingPaper } from "@/interface";
1314

1415
function PinnedSearchBar({
1516
initialSubjects,
16-
displayPapers,
17+
setDisplayPapers,
1718
filtersNotPulled,
1819
}: {
1920
initialSubjects: ICourseWithCount[];
20-
displayPapers: boolean;
21+
setDisplayPapers: React.Dispatch<React.SetStateAction<IUpcomingPaper[]>>;
2122
filtersNotPulled?: () => void;
2223
}) {
2324
const router = useRouter();
@@ -104,6 +105,7 @@ function PinnedSearchBar({
104105
const updated = current
105106
? [...new Set([...saved, searchText])]
106107
: saved.filter((s) => s !== searchText);
108+
107109

108110
if (updated.length === 0) {
109111
setShowControls(false);
@@ -112,7 +114,17 @@ function PinnedSearchBar({
112114
}
113115

114116
localStorage.setItem("userSubjects", JSON.stringify(updated));
115-
window.dispatchEvent(new Event("userSubjectsChanged"));
117+
118+
setDisplayPapers((prev) => {
119+
if (current) {
120+
if (!prev.find((paper) => paper.subject === searchText)) {
121+
return [...prev, { subject: searchText, slots: [] }];
122+
}
123+
return prev;
124+
} else {
125+
return prev.filter((paper) => paper.subject !== searchText);
126+
}
127+
});
116128

117129
setSearchText("");
118130
setPinned(false);
@@ -203,28 +215,10 @@ function PinnedSearchBar({
203215
onToggle={handlePinToggle}
204216
disabled={!showControls || searchText.trim() === ""}
205217
/>
206-
{displayPapers && <button
207-
onClick={() => {
208-
handleRemoveAll();
209-
}}
210-
className="items-center gap-2 rounded-full border border-[#3A3745] bg-[#e8e9ff] px-3 py-1.5 text-sm font-semibold text-gray-700 transition hover:bg-slate-50 dark:bg-black dark:text-white dark:hover:bg-[#1A1823] hidden sm:flex"
211-
>
212-
213-
Remove All <X className="h-4 w-4" />
214-
</button>}
215218
</div>
216219
</form>
217220
</div>
218221
</div>
219-
220-
{displayPapers && <button
221-
onClick={() => {
222-
handleRemoveAll();
223-
}}
224-
className="sm:hidden mt-4 flex items-center gap-2 rounded-full border border-[#3A3745] bg-[#e8e9ff] px-3 py-1.5 text-sm font-semibold text-gray-700 transition hover:bg-slate dark:bg-black dark:text-white dark:hover:bg-[#1A1823]"
225-
>
226-
Remove All <X className="h-4 w-4" />
227-
</button>}
228222
</div>
229223
);
230224
}

src/components/Searchbar/searchbar.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,19 @@ import React from "react";
44
import SearchBarChild from "./searchbar-child";
55
import PinnedSearchBar from "./pinned-searchbar";
66
import { useCourses } from "@/context/courseContext";
7+
import { type IUpcomingPaper } from "@/interface";
78

89
export default function SearchBar({
910
type = "default",
10-
displayPapers,
11+
setDisplayPapers,
1112
}: {
12-
type?: "default" | "pinned";
13-
displayPapers?: boolean;
13+
type?: "default" | "pinned",
14+
setDisplayPapers?: React.Dispatch<React.SetStateAction<IUpcomingPaper[]>>
1415
}) {
1516
const { courses, loading, error, refetch } = useCourses();
1617

17-
return type === "pinned" && displayPapers !== undefined ? (
18-
<PinnedSearchBar initialSubjects={courses} displayPapers={displayPapers} />
18+
return type === "pinned" && setDisplayPapers !== undefined ? (
19+
<PinnedSearchBar initialSubjects={courses} setDisplayPapers={setDisplayPapers} />
1920
) : (
2021
<SearchBarChild initialSubjects={courses} />
2122
);

src/components/screens/Hero.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from "react";
22
import SearchBar from "../Searchbar/searchbar";
33
import PapersCarousel from "../PapersCarousel";
4+
import PinnedPapersCarousel from "../PinnedPapersCarousel";
45

56
const Hero = () => {
67
return (
@@ -11,6 +12,14 @@ const Hero = () => {
1112
<div className="mt-5 px-6">
1213
<SearchBar />
1314
</div>
15+
<p className="my-8 hidden text-center font-play text-lg font-semibold md:block">
16+
Pinned Subjects
17+
</p>
18+
<div className="min-h-[40vh]">
19+
<PinnedPapersCarousel
20+
carouselType="users"
21+
/>
22+
</div>
1423
<PapersCarousel />
1524
</div>
1625
);

0 commit comments

Comments
 (0)