@@ -6,7 +6,7 @@ import axios, { type AxiosError } from "axios";
6
6
import Cryptr from "cryptr" ;
7
7
import { Suspense } from "react" ;
8
8
import Image from "next/image" ;
9
- import { Download , Eye } from "lucide-react" ;
9
+ import { Search , Download , Eye , Filter } from "lucide-react" ;
10
10
import { boolean } from "zod" ;
11
11
import {
12
12
Dialog ,
@@ -16,6 +16,11 @@ import {
16
16
DialogTitle ,
17
17
DialogTrigger ,
18
18
} from "@/components/ui/dialog" ;
19
+
20
+ import { MultiSelect } from "@/components/multi-select" ;
21
+ import { Button } from "@/components/ui/button" ;
22
+ import { slots } from "../upload/select_options" ;
23
+
19
24
interface Paper {
20
25
_id : string ;
21
26
exam : string ;
@@ -25,6 +30,7 @@ interface Paper {
25
30
subject : string ;
26
31
year : string ;
27
32
}
33
+
28
34
interface Filters {
29
35
paper : Paper ;
30
36
uniqueExams : string [ ] ;
@@ -39,16 +45,22 @@ const CatalogueContent = () => {
39
45
const router = useRouter ( ) ;
40
46
const searchParams = useSearchParams ( ) ;
41
47
const subject = searchParams . get ( "subject" ) ;
48
+ const exams = searchParams . get ( "exams" ) ?. split ( "," ) ;
49
+ const slots = searchParams . get ( "slots" ) ?. split ( "," ) ;
50
+ const years = searchParams . get ( "years" ) ?. split ( "," ) ;
51
+
42
52
const [ papers , setPapers ] = useState < Paper [ ] > ( [ ] ) ;
43
53
const [ error , setError ] = useState < string | null > ( null ) ;
44
54
const [ loading , setLoading ] = useState < boolean > ( false ) ;
45
- const [ filterOptions , setFilterOptions ] = useState < Filters [ ] > ( [ ] ) ;
55
+ const [ filterOptions , setFilterOptions ] = useState < Filters > ( ) ;
56
+
46
57
useEffect ( ( ) => {
47
58
if ( subject ) {
48
59
const fetchPapers = async ( ) => {
49
60
setLoading ( true ) ;
50
61
51
62
try {
63
+ console . log ( subject )
52
64
const papersResponse = await axios . get ( "/api/papers" , {
53
65
// Digital Logic and Microprocessors[BITE202L]
54
66
params : { subject } ,
@@ -60,55 +72,70 @@ const CatalogueContent = () => {
60
72
const papersData : Paper [ ] = JSON . parse (
61
73
decryptedPapersResponse ,
62
74
) . papers ;
63
- const filters : Filters [ ] = JSON . parse ( decryptedPapersResponse ) ;
75
+ const filters : Filters = JSON . parse ( decryptedPapersResponse ) ;
64
76
setFilterOptions ( filters ) ;
77
+ const papersDataWithFilters = papersData
78
+ . filter ( ( paper ) => {
79
+ const examCondition = exams && exams . length ? exams . includes ( paper . exam ) : true ;
80
+ const slotCondition = slots && slots . length ? slots . includes ( paper . slot ) : true ;
81
+ const yearCondition = years && years . length ? years . includes ( paper . year ) : true ;
82
+
83
+ return examCondition && slotCondition && yearCondition ;
84
+ } )
85
+
86
+ if ( papersDataWithFilters . length > 0 )
87
+ // setPapers(papersData);
88
+
89
+ setPapers ( papersDataWithFilters ) ;
90
+ else
65
91
setPapers ( papersData ) ;
66
- } catch ( error ) {
67
- if ( axios . isAxiosError ( error ) ) {
68
- const axiosError = error as AxiosError < { message ?: string } > ;
69
- const errorMessage =
70
- axiosError . response ?. data ?. message ?? "Error fetching papers" ;
71
- setError ( errorMessage ) ;
72
- } else {
73
- setError ( "Error fetching papers" ) ;
74
- }
75
- } finally {
76
- setLoading ( false ) ;
92
+ } catch ( error ) {
93
+ if ( axios . isAxiosError ( error ) ) {
94
+ const axiosError = error as AxiosError < { message ?: string } > ;
95
+ const errorMessage =
96
+ axiosError . response ?. data ?. message ?? "Error fetching papers" ;
97
+ setError ( errorMessage ) ;
98
+ } else {
99
+ setError ( "Error fetching papers" ) ;
77
100
}
78
- } ;
79
-
80
- void fetchPapers ( ) ;
101
+ } finally {
102
+ setLoading ( false ) ;
103
+ }
104
+ } ;
105
+
106
+ void fetchPapers ( ) ;
81
107
}
82
- } , [ subject ] ) ;
108
+ } , [ subject , searchParams ] ) ;
83
109
// console.log(papers);
84
-
110
+
85
111
return (
86
112
< div className = "min-h-screen bg-gray-50 p-8" >
87
- < button
88
- onClick = { ( ) => router . push ( "/" ) }
89
- className = "mb-4 rounded-md bg-blue-500 px-4 py-2 text-white"
90
- >
91
- Back to Search
92
- </ button >
93
- < Dialog >
94
- < DialogTrigger className = " rounded-lg bg-[#7480FF] px-8 py-3 text-white" >
95
- Filter
96
- </ DialogTrigger >
97
- < DialogContent >
98
- < DialogHeader >
99
- < DialogTitle > Choose your filters</ DialogTitle >
100
- < DialogDescription > { } </ DialogDescription >
101
- </ DialogHeader >
102
- </ DialogContent >
103
- </ Dialog >
104
-
113
+ < div className = "flex mb-4 mx-40 justify-center gap-10 items-center" >
114
+ { /* <button
115
+ onClick={() => router.push("/")}
116
+ className=" rounded-md bg-blue-500 px-4 py-2 text-white"
117
+ >
118
+ Back to Search
119
+ </button> */ }
120
+ < div className = "relative w-full" >
121
+ < div className = "absolute flex-grow flex top-3 left-2" >
122
+ < Search className = "w-5 text-gray-400" />
123
+ </ div >
124
+ < input
125
+ type = "search"
126
+ className = "border w-full px-10 py-3 bg-[#7480FF33] bg-opacity-20 rounded-2xl "
127
+ placeholder = "Search..."
128
+ > </ input >
129
+ </ div >
130
+ { subject && filterOptions && < FilterDialog subject = { subject } filterOptions = { filterOptions } /> }
131
+ </ div >
105
132
{ /* <h1 className="mb-4 text-2xl font-bold">Papers for {subject}</h1> */ }
106
133
{ error && < p className = "text-red-500" > { error } </ p > }
107
134
108
135
{ loading ? (
109
136
< p > Loading papers...</ p >
110
137
) : papers . length > 0 ? (
111
- < div className = "grid grid-cols-5 gap-10" >
138
+ < div className = "flex flex-wrap gap-10" >
112
139
{ papers . map ( ( paper ) => (
113
140
< Card key = { paper . _id } paper = { paper } />
114
141
) ) }
@@ -134,11 +161,11 @@ function Card({ paper }: { paper: Paper }) {
134
161
function handleCheckboxChange ( ) : void {
135
162
setChecked ( ! checked ) ;
136
163
}
137
-
164
+
138
165
return (
139
166
< div
140
- key = { paper . _id }
141
- className = { `space-y-1 rounded-md border border-black border-opacity-50 ${ checked ? "bg-[#EEF2FF]" : "bg-white" } p-4 ` }
167
+ key = { paper . _id }
168
+ className = { `space-y-1 w-56 rounded-md border border-black border-opacity-50 ${ checked ? "bg-[#EEF2FF]" : "bg-white" } p-4 ` }
142
169
>
143
170
< Image
144
171
src = { paper . thumbnailUrl }
@@ -147,7 +174,7 @@ function Card({ paper }: { paper: Paper }) {
147
174
width = { 320 } // Adjust width to maintain aspect ratio if needed
148
175
height = { 180 } // Fixed height
149
176
className = "mb-2 h-[180px] w-full object-cover" // Ensure it takes the full width of the container
150
- > </ Image >
177
+ > </ Image >
151
178
< div className = "text-sm font-medium" >
152
179
{ extractBracketContent ( paper . subject ) }
153
180
</ div >
@@ -166,7 +193,7 @@ function Card({ paper }: { paper: Paper }) {
166
193
onChange = { handleCheckboxChange }
167
194
className = "h-3 w-3 rounded-lg"
168
195
type = "checkbox"
169
- />
196
+ />
170
197
< p className = "text-sm" > Select</ p >
171
198
</ div >
172
199
< div className = "flex gap-2" >
@@ -175,7 +202,7 @@ function Card({ paper }: { paper: Paper }) {
175
202
target = "_blank"
176
203
rel = "noopener noreferrer"
177
204
// className="text-blue-500 hover:underline"
178
- >
205
+ >
179
206
< Eye />
180
207
</ a >
181
208
< a href = { paper . finalUrl } download >
@@ -192,6 +219,82 @@ function capsule(data: string) {
192
219
< div className = " rounded-md bg-[#7480FF] p-1 px-3 text-sm" > { data } </ div >
193
220
) ;
194
221
}
222
+ const FilterDialog = ( { subject, filterOptions} : { subject :string , filterOptions : Filters } ) => {
223
+ const router = useRouter ( )
224
+ const [ filterExams , setuniqueExams ] = useState < string [ ] > ( ) ;
225
+ const [ FilterSlots , setFilterSlots ] = useState < string [ ] > ( ) ;
226
+ const [ filterYears , setFilterYears ] = useState < string [ ] > ( ) ;
227
+ const handleFilterClick = ( ) => {
228
+ if ( subject ) {
229
+ let pushContent = "/catalogue"
230
+ if ( subject )
231
+ {
232
+ pushContent = pushContent . concat ( `?subject=${ encodeURIComponent ( subject ) } ` )
233
+ }
234
+ if ( filterExams )
235
+ {
236
+ pushContent = pushContent . concat ( `&exams=${ encodeURIComponent ( filterExams . join ( ',' ) ) } ` )
237
+ }
238
+ if ( FilterSlots )
239
+ {
240
+ pushContent = pushContent . concat ( `&slots=${ encodeURIComponent ( FilterSlots . join ( ',' ) ) } ` )
241
+ }
242
+ if ( filterYears )
243
+ {
244
+ pushContent = pushContent . concat ( `&years=${ encodeURIComponent ( filterYears . join ( ',' ) ) } ` )
245
+
246
+ }
247
+ router . push ( pushContent ) ;
248
+ }
249
+ } ;
250
+
251
+ return (
252
+ < Dialog >
253
+ < DialogTrigger className = "rounded-lg bg-[#7480FF] px-8 py-3 text-white" >
254
+ < div className = "flex gap-3" > Filter < Filter className = "" /> </ div >
255
+ </ DialogTrigger >
256
+ < DialogContent >
257
+ < DialogHeader >
258
+ < DialogTitle className = "mb-5" > Choose your filters</ DialogTitle >
259
+ < DialogDescription className = "space-y-5" >
260
+ { filterOptions && (
261
+ < div className = "space-y-5" >
262
+ < MultiSelect
263
+ options = { filterOptions . uniqueExams . map ( ( exam : string ) => ( {
264
+ label : exam ,
265
+ value : exam ,
266
+ } ) ) }
267
+ onValueChange = { setuniqueExams }
268
+ placeholder = "Exam"
269
+ />
270
+ < MultiSelect
271
+ options = { filterOptions . uniqueSlots . map ( ( slots : string ) => ( {
272
+ label : slots ,
273
+ value : slots ,
274
+ } ) ) }
275
+ onValueChange = { setFilterSlots }
276
+ placeholder = "Slots"
277
+ />
278
+ < MultiSelect
279
+ options = { filterOptions . uniqueYears . map ( ( years : string ) => ( {
280
+ label : years ,
281
+ value : years ,
282
+ } ) ) }
283
+ onValueChange = { setFilterYears }
284
+ placeholder = "Years"
285
+ />
286
+ </ div >
287
+ ) }
288
+ < Button variant = "outline" onClick = { handleFilterClick } >
289
+ Filter
290
+ </ Button >
291
+ </ DialogDescription >
292
+ </ DialogHeader >
293
+ </ DialogContent >
294
+ </ Dialog >
295
+ ) ;
296
+ } ;
297
+
195
298
196
299
function extractBracketContent ( subject : string ) : string | null {
197
300
const match = subject . match ( / \[ ( .* ?) \] / ) ;
@@ -201,3 +304,4 @@ function extractBracketContent(subject: string): string | null {
201
304
function extractWithoutBracketContent ( subject : string ) : string {
202
305
return subject . replace ( / \s * \[ .* ?\] \s * / g, "" ) . trim ( ) ;
203
306
}
307
+
0 commit comments