@@ -9,10 +9,19 @@ export interface FilterState {
9
9
search : string | null ;
10
10
}
11
11
12
+ interface PaginatedResponse {
13
+ items : Problem [ ] ;
14
+ pagination : {
15
+ page : number ;
16
+ limit : number ;
17
+ total : number ;
18
+ totalPages : number ;
19
+ } ;
20
+ }
21
+
12
22
const PAGE_SIZE = 20 ;
13
23
14
24
export function useFilteredProblems ( ) {
15
- // States for both filtering and pagination
16
25
const [ problems , setProblems ] = useState < Problem [ ] > ( [ ] ) ;
17
26
const [ filters , setFilters ] = useState < FilterState > ( {
18
27
difficulty : null ,
@@ -21,59 +30,60 @@ export function useFilteredProblems() {
21
30
search : null ,
22
31
} ) ;
23
32
const [ isLoading , setIsLoading ] = useState ( true ) ;
24
- const [ page , setPage ] = useState ( 1 ) ;
25
33
const [ hasMore , setHasMore ] = useState ( true ) ;
34
+ const [ isEmpty , setIsEmpty ] = useState ( false ) ;
26
35
const seenIds = useRef ( new Set < number > ( ) ) ;
36
+ const currentPage = useRef ( 1 ) ;
27
37
28
38
const fetchProblems = useCallback (
29
- async ( pageNum : number , isLoadingMore = false ) => {
39
+ async ( isLoadingMore = false ) => {
30
40
if ( ! isLoadingMore ) {
31
41
seenIds . current . clear ( ) ;
42
+ currentPage . current = 1 ;
43
+ setIsEmpty ( false ) ;
32
44
}
33
45
34
46
setIsLoading ( true ) ;
35
47
36
48
try {
37
49
const params = new URLSearchParams ( ) ;
38
- params . append ( 'page' , pageNum . toString ( ) ) ;
50
+ params . append ( 'page' , currentPage . current . toString ( ) ) ;
39
51
params . append ( 'limit' , PAGE_SIZE . toString ( ) ) ;
40
52
41
- // Apply filters to query
42
53
if ( filters . difficulty ) params . append ( 'difficulty' , filters . difficulty ) ;
43
54
if ( filters . status ) params . append ( 'status' , filters . status ) ;
44
55
if ( filters . topics ?. length ) {
45
- filters . topics . forEach ( ( topic ) => params . append ( 'topics' , topic ) ) ;
56
+ params . append ( 'topics' , filters . topics . join ( ',' ) ) ;
46
57
}
47
58
if ( filters . search ) params . append ( 'search' , filters . search ) ;
48
59
49
60
const url = `/questions?${ params . toString ( ) } ` ;
50
- const response = await axiosClient . get < Problem [ ] > ( url ) ;
51
- const newProblems = response . data ;
61
+ const response = await axiosClient . get < PaginatedResponse > ( url ) ;
62
+ const { items : newProblems } = response . data ;
52
63
53
- if ( newProblems . length === 0 ) {
64
+ if ( ! isLoadingMore && newProblems . length === 0 ) {
65
+ setIsEmpty ( true ) ;
66
+ setProblems ( [ ] ) ;
54
67
setHasMore ( false ) ;
55
68
return ;
56
69
}
57
70
58
71
if ( isLoadingMore ) {
59
- console . log ( 'Fetching a page of 20 items' ) ;
60
- const uniqueNewProblems : Problem [ ] = [ ] ;
61
- let foundDuplicate = false ;
62
-
63
- for ( const problem of newProblems ) {
72
+ const uniqueNewProblems = newProblems . filter ( ( problem ) => {
64
73
if ( seenIds . current . has ( problem . _id ) ) {
65
- foundDuplicate = true ;
66
- break ;
74
+ return false ;
67
75
}
68
76
seenIds . current . add ( problem . _id ) ;
69
- uniqueNewProblems . push ( problem ) ;
70
- }
77
+ return true ;
78
+ } ) ;
71
79
72
- if ( foundDuplicate || uniqueNewProblems . length === 0 ) {
80
+ if ( uniqueNewProblems . length === 0 ) {
73
81
setHasMore ( false ) ;
82
+ return ;
74
83
}
75
84
76
85
setProblems ( ( prev ) => [ ...prev , ...uniqueNewProblems ] ) ;
86
+ setHasMore ( newProblems . length === PAGE_SIZE ) ;
77
87
} else {
78
88
newProblems . forEach ( ( problem ) => seenIds . current . add ( problem . _id ) ) ;
79
89
setProblems ( newProblems ) ;
@@ -82,14 +92,17 @@ export function useFilteredProblems() {
82
92
} catch ( error ) {
83
93
console . error ( 'Error fetching problems:' , error ) ;
84
94
setHasMore ( false ) ;
95
+ if ( ! isLoadingMore ) {
96
+ setIsEmpty ( true ) ;
97
+ setProblems ( [ ] ) ;
98
+ }
85
99
} finally {
86
100
setIsLoading ( false ) ;
87
101
}
88
102
} ,
89
103
[ filters ] ,
90
- ) ; // Note filters dependency
104
+ ) ;
91
105
92
- // Filter functions
93
106
const updateFilter = useCallback (
94
107
( key : keyof FilterState , value : string | string [ ] | null ) => {
95
108
setFilters ( ( prev ) => ( {
@@ -113,20 +126,16 @@ export function useFilteredProblems() {
113
126
} ) ) ;
114
127
} , [ ] ) ;
115
128
116
- // Reset and fetch when filters change
117
129
useEffect ( ( ) => {
118
- setPage ( 1 ) ;
119
- fetchProblems ( 1 , false ) ;
130
+ fetchProblems ( false ) ;
120
131
} , [ filters , fetchProblems ] ) ;
121
132
122
- // Load more function for infinite scroll
123
133
const loadMore = useCallback ( ( ) => {
124
134
if ( ! isLoading && hasMore ) {
125
- const nextPage = page + 1 ;
126
- setPage ( nextPage ) ;
127
- fetchProblems ( nextPage , true ) ;
135
+ currentPage . current += 1 ;
136
+ fetchProblems ( true ) ;
128
137
}
129
- } , [ isLoading , hasMore , page , fetchProblems ] ) ;
138
+ } , [ isLoading , hasMore , fetchProblems ] ) ;
130
139
131
140
return {
132
141
problems,
@@ -135,7 +144,7 @@ export function useFilteredProblems() {
135
144
removeFilter,
136
145
isLoading,
137
146
hasMore,
147
+ isEmpty,
138
148
loadMore,
139
- fetchProblems,
140
149
} ;
141
150
}
0 commit comments