@@ -3,6 +3,7 @@ import { useState } from '@wordpress/element';
3
3
import {
4
4
PAGINATION_CURSOR_NEXT_VARIABLE_TYPE ,
5
5
PAGINATION_CURSOR_PREVIOUS_VARIABLE_TYPE ,
6
+ PAGINATION_CURSOR_VARIABLE_TYPE ,
6
7
PAGINATION_OFFSET_VARIABLE_TYPE ,
7
8
PAGINATION_PAGE_VARIABLE_TYPE ,
8
9
PAGINATION_PER_PAGE_VARIABLE_TYPE ,
@@ -16,9 +17,6 @@ interface UsePaginationVariables {
16
17
perPage ?: number ;
17
18
setPage : ( page : number ) => void ;
18
19
setPerPage : ( perPage : number ) => void ;
19
- supportsCursorPagination : boolean ;
20
- supportsOffsetPagination : boolean ;
21
- supportsPagePagination : boolean ;
22
20
supportsPagination : boolean ;
23
21
supportsPerPage : boolean ;
24
22
totalItems ?: number ;
@@ -31,6 +29,19 @@ interface UsePaginationVariablesInput {
31
29
inputVariables : InputVariable [ ] ;
32
30
}
33
31
32
+ interface PaginationCursors {
33
+ next ?: string ;
34
+ previous ?: string ;
35
+ }
36
+
37
+ export enum PaginationType {
38
+ CURSOR_SIMPLE = 'cursor_simple' ,
39
+ CURSOR = 'cursor' ,
40
+ OFFSET = 'offset' ,
41
+ NONE = 'none' ,
42
+ PAGE = 'page' ,
43
+ }
44
+
34
45
export function usePaginationVariables ( {
35
46
initialPage = 1 ,
36
47
initialPerPage,
@@ -39,7 +50,11 @@ export function usePaginationVariables( {
39
50
const [ paginationData , setPaginationData ] = useState < RemoteDataPagination > ( ) ;
40
51
const [ page , setPage ] = useState < number > ( initialPage ) ;
41
52
const [ perPage , setPerPage ] = useState < number | null > ( initialPerPage ?? null ) ;
53
+ const [ cursors , setCursors ] = useState < PaginationCursors > ( { } ) ;
42
54
55
+ const cursorVariable = inputVariables ?. find (
56
+ input => input . type === PAGINATION_CURSOR_VARIABLE_TYPE
57
+ ) ;
43
58
const cursorNextVariable = inputVariables ?. find (
44
59
input => input . type === PAGINATION_CURSOR_NEXT_VARIABLE_TYPE
45
60
) ;
@@ -57,71 +72,83 @@ export function usePaginationVariables( {
57
72
) ;
58
73
59
74
const paginationQueryInput : RemoteDataQueryInput = { } ;
75
+ const nonFirstPage = page > 1 ;
76
+ const calculatedPerPage = perPage ?? paginationData ?. perPage ?? 10 ;
60
77
61
78
// These will be amended below.
62
- let supportsCursorPagination = false ;
63
- let supportsOffsetPagination = false ;
64
- let supportsPagePagination = false ;
79
+ let hasNextPage = Boolean ( paginationData ?. hasNextPage ?? paginationData ?. cursorNext ) ;
80
+ let paginationType = PaginationType . NONE ;
65
81
let setPageFn : ( page : number ) => void = ( ) => { } ;
66
82
67
- if ( cursorNextVariable && cursorPreviousVariable ) {
83
+ if ( cursorVariable ) {
84
+ paginationType = PaginationType . CURSOR_SIMPLE ;
85
+ setPageFn = setPageForCursorPagination ;
86
+ Object . assign ( paginationQueryInput , {
87
+ [ cursorVariable . slug ] : cursors . next ?? cursors . previous ,
88
+ } ) ;
89
+ } else if ( cursorNextVariable && cursorPreviousVariable ) {
90
+ paginationType = PaginationType . CURSOR ;
68
91
setPageFn = setPageForCursorPagination ;
69
- supportsCursorPagination = true ;
70
92
Object . assign ( paginationQueryInput , {
71
- [ cursorNextVariable . slug ] : paginationData ?. cursorNext ,
72
- [ cursorPreviousVariable . slug ] : paginationData ?. cursorPrevious ,
93
+ [ cursorNextVariable . slug ] : cursors . next ,
94
+ [ cursorPreviousVariable . slug ] : cursors . previous ,
73
95
} ) ;
74
- } else if ( offsetVariable && perPage ) {
96
+ } else if ( offsetVariable ) {
97
+ paginationType = PaginationType . OFFSET ;
75
98
setPageFn = setPage ;
76
- supportsOffsetPagination = true ;
77
- Object . assign ( paginationQueryInput , { [ offsetVariable . slug ] : page * perPage } ) ;
99
+ if ( nonFirstPage ) {
100
+ Object . assign ( paginationQueryInput , {
101
+ [ offsetVariable . slug ] : ( page - 1 ) * calculatedPerPage ,
102
+ } ) ;
103
+ }
78
104
} else if ( pageVariable ) {
105
+ paginationType = PaginationType . PAGE ;
79
106
setPageFn = setPage ;
80
- supportsPagePagination = true ;
81
107
Object . assign ( paginationQueryInput , { [ pageVariable . slug ] : page } ) ;
82
108
}
83
109
84
110
if ( perPageVariable && perPage ) {
85
111
Object . assign ( paginationQueryInput , { [ perPageVariable . slug ] : perPage } ) ;
86
112
}
87
113
114
+ const supportsPagination = paginationType !== PaginationType . NONE ;
88
115
const totalItems = paginationData ?. totalItems ;
89
- const totalPages = totalItems && perPage ? Math . ceil ( totalItems / perPage ) : undefined ;
90
- const hasNextPage = paginationData ?. hasNextPage ;
91
- const supportsPagination =
92
- supportsCursorPagination ||
93
- supportsPagePagination ||
94
- supportsOffsetPagination ||
95
- hasNextPage ||
96
- Boolean ( totalItems ) ;
116
+ const totalPages = totalItems ? Math . ceil ( totalItems / calculatedPerPage ) : undefined ;
117
+
118
+ if ( totalPages && page < totalPages ) {
119
+ hasNextPage = true ;
120
+ }
97
121
98
122
function onFetch ( remoteData : RemoteData ) : void {
99
123
if ( ! supportsPagination ) {
100
124
return ;
101
125
}
102
126
103
- setPaginationData ( remoteData . pagination ) ;
104
-
105
- // We need a perPage value to calculate the total pages, so inpsect the results.
106
- if ( ! perPage && remoteData . results . length ) {
107
- setPerPage ( remoteData . results . length ) ;
108
- }
127
+ setPaginationData ( {
128
+ perPage : perPage ?? remoteData . results . length ,
129
+ ...remoteData . pagination ,
130
+ } ) ;
109
131
}
110
132
111
133
// With cursor pagination, we can only go one page at a time.
112
134
function setPageForCursorPagination ( newPage : number ) : void {
135
+ // if page has gone up, we want to use nextCursor and set aside the current cursor as the previous one
136
+ // if the page has gone down, we want to use previousCursor and set aside the current cursor as the next one
113
137
if ( newPage > page ) {
114
- if ( totalPages ) {
115
- setPage ( Math . min ( totalPages , page + 1 ) ) ;
116
- return ;
117
- }
118
-
119
- setPage ( page + 1 ) ;
138
+ setPage ( Math . min ( totalPages ?? page + 1 , page + 1 ) ) ;
139
+ setCursors ( {
140
+ next : paginationData ?. cursorNext ?? cursors . next ,
141
+ previous : undefined ,
142
+ } ) ;
120
143
return ;
121
144
}
122
145
123
146
if ( newPage < page ) {
124
147
setPage ( Math . max ( 1 , page - 1 ) ) ;
148
+ setCursors ( {
149
+ next : undefined ,
150
+ previous : paginationData ?. cursorPrevious ?? cursors . previous ,
151
+ } ) ;
125
152
}
126
153
}
127
154
@@ -130,12 +157,9 @@ export function usePaginationVariables( {
130
157
onFetch,
131
158
page,
132
159
paginationQueryInput,
133
- perPage : perPage ?? undefined ,
160
+ perPage : perPage ?? paginationData ?. perPage ,
134
161
setPage : setPageFn ,
135
162
setPerPage : supportsPagination ? setPerPage : ( ) => { } ,
136
- supportsCursorPagination,
137
- supportsOffsetPagination,
138
- supportsPagePagination,
139
163
supportsPagination,
140
164
supportsPerPage : Boolean ( perPageVariable ) ,
141
165
totalItems,
0 commit comments