@@ -78,6 +78,34 @@ function SubsampleDetails({ search }: SubsampleDetailsArgs) {
78
78
const theme = useTheme ( ) ;
79
79
const cardId = React . useId ( ) ;
80
80
81
+ /*
82
+ * Below the details card are two buttons that allow the user to enumerate
83
+ * through the subsamples. This state variable is true whilst the onClick
84
+ * handlers for those buttons are doing their processing. This includes not
85
+ * just updating search.activeResult but also fetching the previous/next
86
+ * page of results if the activeResult is currently the first/last result
87
+ * in the page and the previous/next button has been tapped, respectively.
88
+ */
89
+ const [ processingCardNav , setProcessingCardNav ] = React . useState ( false ) ;
90
+
91
+ /*
92
+ * If the search results have changed, then we want to update
93
+ * search.activeResult, and consequently the subsamples whose details we
94
+ * are showing, so that we don't end up showing the details of a subsample
95
+ * that is no longer visible in the table of results.
96
+ */
97
+ React . useEffect ( ( ) => {
98
+ /*
99
+ * We don't change the activeResult if processingCardNav is true
100
+ * because otherwise when the user is currently viewing the details
101
+ * of the first subsample in the page and presses the previous button,
102
+ * they would end up viewing the first result of the previous page and
103
+ * not the last result of that previous page which is what they intend.
104
+ */
105
+ if ( search . filteredResults . length > 0 && ! processingCardNav )
106
+ void search . setActiveResult ( search . filteredResults [ 0 ] ) ;
107
+ } , [ search . filteredResults ] ) ;
108
+
81
109
const subsample = search . activeResult ;
82
110
if ( subsample === null || typeof subsample === "undefined" )
83
111
return < Wrapper > No subsamples</ Wrapper > ;
@@ -153,11 +181,18 @@ function SubsampleDetails({ search }: SubsampleDetailsArgs) {
153
181
aria-controls = { cardId }
154
182
size = "small"
155
183
onClick = { doNotAwait ( async ( ) => {
156
- if ( index + 1 > search . filteredResults . length - 1 )
157
- await search . setPage ( search . fetcher . pageNumber + 1 ) ;
158
- await search . setActiveResult (
159
- search . filteredResults [ ( index + 1 ) % search . fetcher . pageSize ]
160
- ) ;
184
+ setProcessingCardNav ( true ) ;
185
+ try {
186
+ if ( index + 1 > search . filteredResults . length - 1 )
187
+ await search . setPage ( search . fetcher . pageNumber + 1 ) ;
188
+ await search . setActiveResult (
189
+ search . filteredResults [
190
+ ( index + 1 ) % search . fetcher . pageSize
191
+ ]
192
+ ) ;
193
+ } finally {
194
+ setProcessingCardNav ( false ) ;
195
+ }
161
196
} ) }
162
197
disabled = {
163
198
index +
@@ -174,13 +209,18 @@ function SubsampleDetails({ search }: SubsampleDetailsArgs) {
174
209
aria-controls = { cardId }
175
210
size = "small"
176
211
onClick = { doNotAwait ( async ( ) => {
177
- if ( index === 0 )
178
- await search . setPage ( search . fetcher . pageNumber - 1 ) ;
179
- await search . setActiveResult (
180
- search . filteredResults [
181
- modulo ( index - 1 , search . fetcher . pageSize )
182
- ]
183
- ) ;
212
+ setProcessingCardNav ( true ) ;
213
+ try {
214
+ if ( index === 0 )
215
+ await search . setPage ( search . fetcher . pageNumber - 1 ) ;
216
+ await search . setActiveResult (
217
+ search . filteredResults [
218
+ modulo ( index - 1 , search . fetcher . pageSize )
219
+ ]
220
+ ) ;
221
+ } finally {
222
+ setProcessingCardNav ( false ) ;
223
+ }
184
224
} ) }
185
225
disabled = {
186
226
index + search . fetcher . pageSize * search . fetcher . pageNumber ===
0 commit comments