Skip to content

Commit 4033edf

Browse files
Merge remote-tracking branch 'refs/remotes/origin/staging' into staging
2 parents 0391f9a + 39243bd commit 4033edf

File tree

5 files changed

+255
-48
lines changed

5 files changed

+255
-48
lines changed

src/app/request/page.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import PapersPage from "@/components/screens/PapersPage";
2+
3+
export default function RequestPage() {
4+
return <PapersPage />;
5+
}

src/components/CatalogueContent.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export async function downloadFile(url: string, filename: string) {
2323
link.download = filename;
2424
link.click();
2525
window.URL.revokeObjectURL(link.href);
26-
} catch (error) {}
26+
} catch (error) { }
2727
}
2828

2929
const CatalogueContent = () => {
@@ -76,7 +76,7 @@ const CatalogueContent = () => {
7676
try {
7777
const papersResponse = await axios.get<Filters>("/api/papers", {
7878
params: { subject },
79-
});
79+
});g
8080
const data: Filters = papersResponse.data;
8181
const papersData = data.papers;
8282
setFilterOptions(data);
@@ -99,7 +99,7 @@ const CatalogueContent = () => {
9999
? selectedCampuses.includes(paper.campus)
100100
: true;
101101
const answerkeyCondition = selectedAnswerKeyIncluded
102-
? paper.answerKeyIncluded
102+
? paper.answerKeyIncluded === true
103103
: true;
104104
return (
105105
examCondition &&
@@ -118,7 +118,7 @@ const CatalogueContent = () => {
118118
setError(
119119
axios.isAxiosError(axiosError)
120120
? ((axiosError.response?.data as { message?: string })?.message ??
121-
"Error fetching papers")
121+
"Error fetching papers")
122122
: "Error fetching papers",
123123
);
124124
} finally {
@@ -149,13 +149,21 @@ const CatalogueContent = () => {
149149
);
150150

151151
const handleDownloadAll = useCallback(async () => {
152+
/* if (typeof window !== "undefined" && window.gtag) {
153+
window.gtag("event", "download_all_clicked", {
154+
event_category: "Paper Downloads",
155+
event_label: "Download All Clicked",
156+
});
157+
} */
158+
152159
for (const paper of selectedPapers) {
153160
const extension = paper.finalUrl.split(".").pop();
154161
const fileName = `${extractBracketContent(paper.subject)}-${paper.exam}-${paper.slot}-${paper.year}.${extension}`;
155162
await downloadFile(paper.finalUrl, fileName);
156163
}
157164
}, [selectedPapers]);
158165

166+
159167
const handleApplyFilters = useCallback(
160168
(
161169
exams: string[],
@@ -198,7 +206,7 @@ const CatalogueContent = () => {
198206
const campusCondition = campus.length
199207
? campus.includes(paper.campus)
200208
: true;
201-
const answerkeyCondition = anskey ? paper.answerKeyIncluded : true;
209+
const answerkeyCondition = anskey ? paper.answerKeyIncluded === true : true;
202210
return (
203211
examCondition &&
204212
slotCondition &&

src/components/screens/Faq.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ function Faq() {
5757
<>
5858
<div
5959
id="faq"
60-
className="font-vipnabd mb-8 w-full px-6 text-center text-4xl font-bold text-[#120020] dark:text-white lg:text-left lg:text-5xl"
60+
className="font-vipnabd mb-8 w-full px-6 pt-16 text-center text-4xl font-bold text-[#120020] dark:text-white lg:text-left lg:text-5xl"
6161
>
6262
Frequently Asked Questions
6363
</div>

src/components/screens/Info.tsx

Lines changed: 59 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,72 @@
1-
import { User, Download, Check, Filter, Book } from "lucide-react";
1+
import { User, Download, Check, Filter, Book, ArrowUpRight } from "lucide-react";
22
import Image from "next/image";
33
import man from "@/assets/man.svg" assert { type: "image/svg" };
44
import man1 from "@/assets/man1.svg" assert { type: "image/svg" };
5+
import Link from "next/link";
6+
import { Button } from "@/components/ui/button";
57

68
function Info() {
79
return (
8-
<section
9-
id="features"
10-
className="flex scroll-mt-24 flex-col items-center justify-between px-6 py-12 md:scroll-mt-32 lg:flex-row"
11-
>
12-
<div className="w-full text-center lg:w-[50%] lg:text-left">
13-
<div className="font-vipnabd mb-8 block text-3xl font-extrabold text-black dark:text-white lg:text-5xl">
14-
<span>Prepare to excel in </span>
15-
<span>your CATs and FATs </span>
16-
<span>with CodeChef-</span>
17-
<span>VIT’s dedicated </span>
18-
<span>repository of past </span>
19-
<span>exam papers</span>
10+
<>
11+
<section
12+
id="features"
13+
className="flex scroll-mt-24 flex-col items-center justify-between px-6 py-12 md:scroll-mt-32 lg:flex-row"
14+
>
15+
<div className="w-full text-center lg:w-[50%] lg:text-left">
16+
<div className="font-vipnabd mb-8 block text-3xl font-extrabold text-black dark:text-white lg:text-5xl">
17+
<span>Prepare to excel in </span>
18+
<span>your CATs and FATs </span>
19+
<span>with CodeChef-</span>
20+
<span>VIT’s dedicated </span>
21+
<span>repository of past </span>
22+
<span>exam papers</span>
23+
</div>
24+
<div className="font-play grid gap-4 text-[12px] text-black dark:text-white md:grid-cols-3 xl:text-[16px]">
25+
<FeatureCard icon={<User size={32} />} text="No Sign-up required" />
26+
<FeatureCard
27+
isHighlight
28+
highlightText="1200+"
29+
subText="Past Year Papers"
30+
/>
31+
<FeatureCard icon={<Download size={32} />} text="Flexible Downloads" />
32+
<FeatureCard icon={<Check size={32} />} text="Answer Key Available" />
33+
<FeatureCard icon={<Filter size={32} />} text="Filtered Search" />
34+
</div>
2035
</div>
21-
<div className="font-play grid gap-4 text-[12px] text-black dark:text-white md:grid-cols-3 xl:text-[16px]">
22-
<FeatureCard icon={<User size={32} />} text="No Sign-up required" />
23-
<FeatureCard
24-
isHighlight
25-
highlightText="1200+"
26-
subText="Past Year Papers"
36+
<div className="mb-10 hidden h-[450px] w-[450px] justify-center p-5 lg:flex lg:h-[600px] lg:w-[500px]">
37+
<Image
38+
src={man1 as string}
39+
height={600}
40+
width={500}
41+
alt="man-light"
42+
className="block dark:hidden"
2743
/>
28-
<FeatureCard
29-
icon={<Download size={32} />}
30-
text="Flexible Downloads"
44+
<Image
45+
src={man as string}
46+
height={600}
47+
width={500}
48+
alt="man-dark"
49+
className="hidden dark:block"
3150
/>
32-
<FeatureCard icon={<Check size={32} />} text="Answer Key Available" />
33-
<FeatureCard icon={<Filter size={32} />} text="Filtered Search" />
3451
</div>
35-
</div>
36-
<div className="mb-10 hidden h-[450px] w-[450px] justify-center p-5 lg:flex lg:h-[600px] lg:w-[500px]">
37-
<Image
38-
src={man1 as string}
39-
height={600}
40-
width={500}
41-
alt="man-light"
42-
className="block dark:hidden"
43-
/>
44-
<Image
45-
src={man as string}
46-
height={600}
47-
width={500}
48-
alt="man-dark"
49-
className="hidden dark:block"
50-
/>
51-
</div>
52-
</section>
52+
</section>
53+
54+
{/* Create Request Section */}
55+
<section className="flex flex-col items-center justify-center gap-4 px-6 py-12 text-center">
56+
<h2 className="font-vipnabd text-2xl font-semibold text-black dark:text-white md:text-3xl">
57+
Can’t Find a Specific Paper?
58+
</h2>
59+
<Link href="/request">
60+
<Button
61+
variant="outline"
62+
className="group border-[1.5px] border-[#4A55FF] bg-transparent px-6 py-3 text-sm font-medium text-[#4A55FF] transition-all duration-200 hover:bg-[#4A55FF] hover:text-white dark:border-[#9EA8FF] dark:text-[#9EA8FF] dark:hover:bg-[#9EA8FF] dark:hover:text-black"
63+
>
64+
Create Request
65+
<ArrowUpRight className="ml-2 h-4 w-4 transition-transform group-hover:translate-x-0.5 group-hover:-translate-y-0.5" />
66+
</Button>
67+
</Link>
68+
</section>
69+
</>
5370
);
5471
}
5572

src/components/screens/PapersPage.tsx

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
"use client"
2+
3+
import { useEffect, useState, useRef, useMemo } from "react"
4+
import { Button } from "@/components/ui/button"
5+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
6+
import { exams, slots, years } from "@/components/select_options"
7+
import { Input } from "@/components/ui/input"
8+
import axios from "axios"
9+
import Fuse from "fuse.js"
10+
import { ArrowRight } from "lucide-react"
11+
import Image from "next/image"
12+
13+
export default function PapersPage() {
14+
const [subjects, setSubjects] = useState<string[]>([])
15+
const [searchText, setSearchText] = useState("")
16+
const [suggestions, setSuggestions] = useState<string[]>([])
17+
const [selectedSubject, setSelectedSubject] = useState<string | null>(null)
18+
const [selectedExam, setSelectedExam] = useState<string | null>(null)
19+
const [selectedSlot, setSelectedSlot] = useState<string | null>(null)
20+
const [selectedYear, setSelectedYear] = useState<string | null>(null)
21+
const suggestionsRef = useRef<HTMLUListElement | null>(null)
22+
23+
useEffect(() => {
24+
async function fetchSubjects() {
25+
try {
26+
const response = await axios.get(`${process.env.NEXT_PUBLIC_SERVER_URL}/api/course-list`)
27+
const names = response.data.map((course: any) => course.name || course.courseName || course.title)
28+
setSubjects(names)
29+
} catch (err) {
30+
console.error("Error fetching subjects:", err)
31+
}
32+
}
33+
fetchSubjects()
34+
}, [])
35+
36+
const fuse = useMemo(() => new Fuse(subjects, { includeScore: true, threshold: 0.3 }), [subjects])
37+
38+
useEffect(() => {
39+
if (!searchText.trim()) {
40+
setSuggestions([])
41+
return
42+
}
43+
44+
if (selectedSubject && searchText === selectedSubject) {
45+
setSuggestions([])
46+
return
47+
}
48+
49+
const results = fuse.search(searchText)
50+
setSuggestions(results.map(r => r.item).slice(0, 10))
51+
}, [searchText, fuse, selectedSubject])
52+
53+
54+
const handleSelectSubject = (subject: string) => {
55+
setSelectedSubject(subject)
56+
setSearchText(subject)
57+
setSuggestions([])
58+
setSelectedExam(null)
59+
setSelectedSlot(null)
60+
setSelectedYear(null)
61+
}
62+
63+
useEffect(() => {
64+
function handleClickOutside(event: MouseEvent) {
65+
if (suggestionsRef.current && !suggestionsRef.current.contains(event.target as Node)) {
66+
setSuggestions([])
67+
}
68+
}
69+
document.addEventListener("mousedown", handleClickOutside)
70+
return () => document.removeEventListener("mousedown", handleClickOutside)
71+
}, [])
72+
73+
const handleSubmit = () => {
74+
if (!selectedSubject || !selectedExam || !selectedSlot || !selectedYear) {
75+
alert("Please fill all fields before submitting")
76+
return
77+
}
78+
console.log({ subject: selectedSubject, exam: selectedExam, slot: selectedSlot, year: selectedYear })
79+
}
80+
81+
return (
82+
<div className="min-h-screen bg-[#F3F5FF] dark:bg-[#070114] text-black dark:text-white px-6 py-12">
83+
<main>
84+
<div className="max-w-4xl mx-auto text-center mb-16">
85+
<h2 className="font-vipnabd text-3xl md:text-4xl font-extrabold mb-12">Specific Paper Request</h2>
86+
87+
<div className="relative max-w-xl mx-auto mb-8 font-play">
88+
<Input
89+
type="text"
90+
value={searchText}
91+
onChange={(e) => setSearchText(e.target.value)}
92+
placeholder="Search by subject..."
93+
className={`text-md rounded-lg bg-[#B2B8FF] px-4 py-6 pr-10 font-play tracking-wider
94+
text-black shadow-sm ring-0 placeholder:text-black focus:outline-none focus:ring-0
95+
dark:bg-[#7480FF66] dark:text-white placeholder:dark:text-white
96+
${suggestions.length > 0 ? "rounded-b-none" : ""}`}
97+
/>
98+
<button type="button" className="absolute inset-y-0 right-0 flex items-center pr-3">
99+
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-black dark:text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
100+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M21 21l-4.35-4.35M17 11a6 6 0 11-12 0 6 6 0 0112 0z" />
101+
</svg>
102+
</button>
103+
{suggestions.length > 0 && (
104+
<ul ref={suggestionsRef} className="absolute z-20 max-h-[250px] w-full max-w-xl overflow-y-auto rounded-md rounded-t-none border border-t-0 bg-white text-center shadow-lg dark:bg-[#303771]">
105+
{suggestions.map((s, idx) => (
106+
<li key={idx} onClick={() => handleSelectSubject(s)} className="cursor-pointer truncate p-2 hover:bg-gray-100 dark:hover:bg-gray-800">
107+
{s}
108+
</li>
109+
))}
110+
</ul>
111+
)}
112+
</div>
113+
114+
<div className="flex justify-center gap-4 mb-8">
115+
<Select onValueChange={setSelectedExam} disabled={!selectedSubject}>
116+
<SelectTrigger className="w-32"><SelectValue placeholder="Exam" /></SelectTrigger>
117+
<SelectContent>{exams.map((exam) => <SelectItem key={exam} value={exam}>{exam}</SelectItem>)}</SelectContent>
118+
</Select>
119+
<Select onValueChange={setSelectedSlot} disabled={!selectedSubject}>
120+
<SelectTrigger className="w-32"><SelectValue placeholder="Slot" /></SelectTrigger>
121+
<SelectContent>{slots.map((slot) => <SelectItem key={slot} value={slot}>{slot}</SelectItem>)}</SelectContent>
122+
</Select>
123+
<Select onValueChange={setSelectedYear} disabled={!selectedSubject}>
124+
<SelectTrigger className="w-32"><SelectValue placeholder="Year" /></SelectTrigger>
125+
<SelectContent>
126+
{[...years].sort((a, b) => Number(b) - Number(a)).map((year) => (
127+
<SelectItem key={year} value={year}>{year}</SelectItem>
128+
))}
129+
</SelectContent>
130+
131+
</Select>
132+
</div>
133+
134+
<Button className="px-8 py-3 rounded-lg text-base bg-[#4A55FF] hover:bg-[#3A44CC] text-white dark:bg-[#9EA8FF] dark:hover:bg-[#7D86E5] dark:text-black" onClick={handleSubmit}>Submit</Button>
135+
</div>
136+
137+
{ }
138+
<div className="max-w-6xl mx-auto mt-16 text-center">
139+
<div className="relative mb-8 text-center">
140+
<h3 className="font-vipnabd text-2xl font-bold">Explore More</h3>
141+
<div className="absolute right-0 top-1/2 -translate-y-1/2">
142+
<Button variant="outline" className="border-gray-300 dark:border-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800">
143+
View All
144+
<ArrowRight className="w-4 h-4 ml-2" />
145+
</Button>
146+
</div>
147+
</div>
148+
149+
150+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 justify-center">
151+
{[1, 2, 3, 4].map((index) => (
152+
<div key={index} className="bg-white dark:bg-[#303771] rounded-lg overflow-hidden shadow-md">
153+
<div className="aspect-[4/3] bg-gray-200 dark:bg-gray-700 relative">
154+
<Image
155+
src="/placeholder.svg?height=200&width=300&text=Paper"
156+
alt={`Paper ${index}`}
157+
width={300}
158+
height={200}
159+
className="w-full h-full object-cover opacity-60"
160+
/>
161+
</div>
162+
<div className="p-4">
163+
<div className="flex flex-wrap gap-2">
164+
<span className="bg-[#4A55FF]/20 dark:bg-[#9EA8FF]/20 text-[#4A55FF] dark:text-[#9EA8FF] px-2 py-1 rounded text-xs">C1</span>
165+
<span className="bg-[#4A55FF]/20 dark:bg-[#9EA8FF]/20 text-[#4A55FF] dark:text-[#9EA8FF] px-2 py-1 rounded text-xs">CAT-1</span>
166+
<span className="bg-[#4A55FF]/20 dark:bg-[#9EA8FF]/20 text-[#4A55FF] dark:text-[#9EA8FF] px-2 py-1 rounded text-xs">2024</span>
167+
<span className="bg-[#4A55FF]/20 dark:bg-[#9EA8FF]/20 text-[#4A55FF] dark:text-[#9EA8FF] px-2 py-1 rounded text-xs">Fall</span>
168+
</div>
169+
</div>
170+
</div>
171+
))}
172+
</div>
173+
</div>
174+
</main>
175+
</div>
176+
)
177+
}

0 commit comments

Comments
 (0)