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