@@ -5,6 +5,7 @@ import { Listbox, Transition } from '@headlessui/react';
5
5
import { CheckIcon , ChevronUpDownIcon } from '@heroicons/react/24/solid' ;
6
6
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' ;
7
7
import { faFolderOpen } from '@fortawesome/free-solid-svg-icons' ;
8
+ import { useInView } from 'react-intersection-observer' ;
8
9
9
10
function getCategoryIcon ( category ) {
10
11
switch ( category . toLowerCase ( ) ) {
@@ -136,6 +137,13 @@ export function Community({ challenges }) {
136
137
const [ results , setResults ] = useState ( [ ] ) ;
137
138
const [ filter , setFilter ] = useState ( '' ) ;
138
139
const [ solvedFilter , setSolvedFilter ] = useState ( 'all' ) ;
140
+ const [ displayedResults , setDisplayedResults ] = useState ( [ ] ) ;
141
+ const [ page , setPage ] = useState ( 1 ) ;
142
+ const itemsPerPage = 12 ;
143
+
144
+ const { ref, inView } = useInView ( {
145
+ threshold : 0 ,
146
+ } ) ;
139
147
140
148
useEffect ( ( ) => {
141
149
if ( typeof window !== 'undefined' ) {
@@ -197,8 +205,20 @@ export function Community({ challenges }) {
197
205
} ) ;
198
206
199
207
setResults ( filteredChallenges ) ;
208
+ setPage ( 1 ) ;
209
+ setDisplayedResults ( filteredChallenges . slice ( 0 , itemsPerPage ) ) ;
200
210
} , [ difficulty , category , challenges , solvedFilter ] ) ;
201
211
212
+ useEffect ( ( ) => {
213
+ if ( inView && page * itemsPerPage < results . length ) {
214
+ const startIndex = page * itemsPerPage ;
215
+ const endIndex = startIndex + itemsPerPage ;
216
+ const nextBatch = results . slice ( 0 , endIndex ) ;
217
+ setDisplayedResults ( nextBatch ) ;
218
+ setPage ( ( prev ) => prev + 1 ) ;
219
+ }
220
+ } , [ inView , results , page ] ) ;
221
+
202
222
const search = ( event ) => {
203
223
setFilter ( event . target . value ) ;
204
224
} ;
@@ -317,39 +337,42 @@ export function Community({ challenges }) {
317
337
</ div >
318
338
</ div >
319
339
< div className = "grid md:grid-cols-2 lg:grid-cols-3 gap-4 mt-6" >
320
- { results . length > 0 ? (
321
- results
322
- . filter ( ( challenge ) => {
323
- if (
324
- difficulty . toLowerCase ( ) !== 'all' &&
325
- challenge . difficulty . toLowerCase ( ) !== difficulty . toLowerCase ( )
326
- ) {
327
- return false ;
328
- }
329
- if (
330
- filter !== '' &&
331
- challenge . category . includes ( filter . toLowerCase ( ) )
332
- ) {
340
+ { displayedResults . length > 0 ? (
341
+ < >
342
+ { displayedResults
343
+ . filter ( ( challenge ) => {
344
+ if (
345
+ difficulty . toLowerCase ( ) !== 'all' &&
346
+ challenge . difficulty . toLowerCase ( ) !== difficulty . toLowerCase ( )
347
+ ) {
348
+ return false ;
349
+ }
350
+ if (
351
+ filter !== '' &&
352
+ challenge . category . includes ( filter . toLowerCase ( ) )
353
+ ) {
354
+ return true ;
355
+ }
356
+ if (
357
+ filter !== '' &&
358
+ ! (
359
+ challenge . title
360
+ . toLowerCase ( )
361
+ . includes ( filter . toLowerCase ( ) ) ||
362
+ challenge . content
363
+ . toLowerCase ( )
364
+ . includes ( filter . toLowerCase ( ) )
365
+ )
366
+ ) {
367
+ return false ;
368
+ }
333
369
return true ;
334
- }
335
- if (
336
- filter !== '' &&
337
- ! (
338
- challenge . title
339
- . toLowerCase ( )
340
- . includes ( filter . toLowerCase ( ) ) ||
341
- challenge . content
342
- . toLowerCase ( )
343
- . includes ( filter . toLowerCase ( ) )
344
- )
345
- ) {
346
- return false ;
347
- }
348
- return true ;
349
- } )
350
- . map ( ( challenge ) => (
351
- < ChallengeCard challenge = { challenge } key = { challenge . challengeId } />
352
- ) )
370
+ } )
371
+ . map ( ( challenge ) => (
372
+ < ChallengeCard challenge = { challenge } key = { challenge . challengeId } />
373
+ ) ) }
374
+ < div ref = { ref } className = "h-10 w-full col-span-full" />
375
+ </ >
353
376
) : (
354
377
// kinda hacky but it works
355
378
challenges . length != 0 && (
0 commit comments