1- import {
2- Alert ,
3- Col ,
4- Row
5- } from 'react-bootstrap'
1+ import { Col , Row } from 'react-bootstrap'
62import { camelCase } from 'lodash-es'
73import { useMutation , useSuspenseQuery } from '@apollo/client'
84import { useParams } from 'react-router'
@@ -12,9 +8,9 @@ import React, { useCallback, useState } from 'react'
128import pluralize from 'pluralize'
139
1410import Button from '@/js/components/Button/Button'
11+ import ControlledPaginatedContent from '@/js/components/ControlledPaginatedContent/ControlledPaginatedContent'
1512import CustomModal from '@/js/components/CustomModal/CustomModal'
1613import EllipsisText from '@/js/components/EllipsisText/EllipsisText'
17- import Pagination from '@/js/components/Pagination/Pagination'
1814import Table from '@/js/components/Table/Table'
1915
2016import conceptTypeQueries from '@/js/constants/conceptTypeQueries'
@@ -41,14 +37,17 @@ const ManageCollectionAssociation = () => {
4137
4238 const { addNotification } = useNotificationsContext ( )
4339
44- const [ searchParams , setSearchParams ] = useSearchParams ( )
40+ const derivedConceptType = getConceptTypeByConceptId ( conceptId )
41+
42+ // Variables for deletion mutation
4543 const [ collectionConceptIds , setCollectionConceptIds ] = useState ( [ ] )
4644 const [ showDeleteModal , setShowDeleteModal ] = useState ( false )
45+ const [ isDeleting , setIsDeleting ] = useState ( false )
4746
48- const derivedConceptType = getConceptTypeByConceptId ( conceptId )
49-
47+ // Variables for pagination
48+ const [ searchParams , setSearchParams ] = useSearchParams ( )
49+ const [ activePage , setActivePage ] = useState ( 1 )
5050 const limit = 20
51- const activePage = parseInt ( searchParams . get ( 'page' ) , 10 ) || 1
5251 const offset = ( activePage - 1 ) * limit
5352
5453 let params = {
@@ -75,14 +74,11 @@ const ManageCollectionAssociation = () => {
7574 }
7675
7776 const { data, refetch } = useSuspenseQuery ( conceptTypeQueries [ derivedConceptType ] , {
78- variables : params
77+ variables : params ,
78+ fetchPolicy : 'network-only'
7979 } )
8080
8181 const [ deleteAssociationMutation ] = useMutation ( DELETE_ASSOCIATION , {
82- refetchQueries : [ {
83- query : conceptTypeQueries [ derivedConceptType ] ,
84- variables : params
85- } ] ,
8682 onCompleted : ( ) => {
8783 setShowDeleteModal ( false )
8884
@@ -93,8 +89,10 @@ const ManageCollectionAssociation = () => {
9389 } )
9490
9591 setCollectionConceptIds ( [ ] )
92+ refetch ( ) // Refetch the data to update the associated collections list
9693 } ,
9794 onError : ( ) => {
95+ setShowDeleteModal ( false )
9896 addNotification ( {
9997 message : 'Error disassociating collection' ,
10098 variant : 'danger'
@@ -105,13 +103,15 @@ const ManageCollectionAssociation = () => {
105103 } )
106104
107105 // Handles deleting selected collection
108- // if no collections selected, returns an error notification
109106 const handleDeleteAssociation = ( ) => {
107+ setIsDeleting ( true )
110108 deleteAssociationMutation ( {
111109 variables : {
112110 conceptId,
113111 associatedConceptIds : collectionConceptIds
114112 }
113+ } ) . finally ( ( ) => {
114+ setIsDeleting ( false )
115115 } )
116116 }
117117
@@ -124,14 +124,13 @@ const ManageCollectionAssociation = () => {
124124 if ( order === 'ascending' ) nextSortKey = `-${ key } `
125125 if ( order === 'descending' ) nextSortKey = key
126126
127- // Reset the page parameter
128- currentParams . delete ( 'page' )
129-
130127 // Set the sort key
131128 currentParams . set ( 'sortKey' , nextSortKey )
132129
133130 return Object . fromEntries ( currentParams )
134131 } )
132+
133+ setActivePage ( 1 ) // Reset to first page when sorting
135134 } , [ ] )
136135
137136 const buildEllipsisTextCell = useCallback ( ( cellData ) => (
@@ -140,8 +139,8 @@ const ManageCollectionAssociation = () => {
140139 </ EllipsisText >
141140 ) , [ ] )
142141
143- // Handles checkbox selections, if checked add the conceptId to the state variable
144- // and pops the added conceptId from the array.
142+ // Adds or removes checked collections from collectionConceptIds array
143+ // which is provided to the deleteMutation
145144 const handleCheckbox = ( event ) => {
146145 const { target } = event
147146 const { value } = target
@@ -200,11 +199,7 @@ const ManageCollectionAssociation = () => {
200199 ]
201200
202201 const setPage = ( nextPage ) => {
203- setSearchParams ( ( currentParams ) => {
204- currentParams . set ( 'page' , nextPage )
205-
206- return Object . fromEntries ( currentParams )
207- } )
202+ setActivePage ( nextPage )
208203 }
209204
210205 const toggleShowDeleteModal = ( nextState ) => {
@@ -216,91 +211,80 @@ const ManageCollectionAssociation = () => {
216211 toggleShowDeleteModal ( true )
217212 } )
218213
219- // Handle refresh, calls getMetadata to get the list of association
220- // TODO: MMT-4089 See if we can get rid of this refresh button.
221- const handleRefreshPage = ( ) => {
222- refetch ( )
223- }
224-
225- const refreshAccessibleEventProps = useAccessibleEvent ( ( ) => {
226- handleRefreshPage ( )
227- } )
228-
229214 const { [ camelCase ( derivedConceptType ) ] : concept } = data
230215
231216 const { collections : associatedCollections } = concept
232217
233218 const { items = [ ] , count } = associatedCollections
234219
235- const totalPages = Math . ceil ( count / limit )
236-
237- const currentPageIndex = Math . floor ( offset / limit )
238- const firstResultIndex = currentPageIndex * limit
239- const isLastPage = totalPages === activePage
240- const lastResultIndex = firstResultIndex + ( isLastPage ? count % limit : limit )
241-
242- const paginationMessage = count > 0
243- ? `Showing ${ totalPages > 1 ? `Collection Associations ${ firstResultIndex + 1 } -${ lastResultIndex } of ${ count } ` : `${ count } ${ pluralize ( 'Collection Association' , count ) } ` } `
244- : 'No Collection Associations found'
245-
246220 return (
247- < div className = "mt-4" >
248- < Alert className = "fst-italic fs-6" variant = "warning" >
249- < i className = "eui-icon eui-fa-info-circle" />
250- { ' ' }
251- Association operations may take some time. If you are not seeing what you expect below,
252- please
253- { ' ' }
254- < span
255- className = "text-decoration-underline"
256- style = {
257- {
258- color : 'blue' ,
259- cursor : 'pointer'
260- }
261- }
262- // eslint-disable-next-line react/jsx-props-no-spreading
263- { ...refreshAccessibleEventProps }
264- >
265- refresh the page
266- </ span >
267- </ Alert >
268- < Row className = "d-flex justify-content-between align-items-center mb-4 mt-5" >
269- < Col className = "mb-4 flex-grow-1" xs = "auto" >
270- {
271- ( ! ! count ) && (
272- < span className = "text-secondary fw-bolder" > { paginationMessage } </ span >
221+ < div >
222+ < ControlledPaginatedContent
223+ activePage = { activePage }
224+ count = { count }
225+ limit = { limit }
226+ setPage = { setPage }
227+ >
228+ {
229+ ( {
230+ totalPages,
231+ pagination,
232+ firstResultPosition,
233+ lastResultPosition
234+ } ) => {
235+ const paginationMessage = count > 0
236+ ? `Showing ${ totalPages > 1 ? `${ firstResultPosition } -${ lastResultPosition } of` : '' } ${ count } Collection ${ pluralize ( 'Association' , count ) } `
237+ : 'No collection associations found'
238+
239+ return (
240+ < >
241+ < Row className = "d-flex justify-content-between align-items-center mb-4" >
242+ < Col className = "mb-4 flex-grow-1" xs = "auto" >
243+ {
244+ ( ! ! count ) && (
245+ < span className = "text-secondary fw-bolder" > { paginationMessage } </ span >
246+ )
247+ }
248+ </ Col >
249+ < Col className = "mb-4 flex-grow-1" xs = "auto" />
250+ {
251+ totalPages > 1 && (
252+ < Col xs = "auto" >
253+ { pagination }
254+ </ Col >
255+ )
256+ }
257+ </ Row >
258+ < Table
259+ className = "m-5"
260+ columns = { columns }
261+ data = { items }
262+ generateCellKey = { ( { conceptId : conceptIdCell } , dataKey ) => `column_${ dataKey } _${ conceptIdCell } ` }
263+ generateRowKey = { ( { conceptId : conceptIdRow } ) => `row_${ conceptIdRow } ` }
264+ id = "associated-collections"
265+ limit = { count }
266+ noDataMessage = "No collection associations found."
267+ />
268+ {
269+ totalPages > 1 && (
270+ < Row >
271+ < Col xs = "12" className = "pt-4 d-flex align-items-center justify-content-center" >
272+ < div >
273+ { pagination }
274+ </ div >
275+ </ Col >
276+ </ Row >
277+ )
278+ }
279+ </ >
273280 )
274281 }
275- </ Col >
276- {
277- totalPages > 1 && (
278- < Col xs = "auto" >
279- < Pagination
280- setPage = { setPage }
281- activePage = { activePage }
282- totalPages = { totalPages }
283- />
284- </ Col >
285- )
286282 }
287- </ Row >
288- < Table
289- className = "m-5"
290- columns = { columns }
291- data = { items }
292- generateCellKey = { ( { conceptId : conceptIdCell } , dataKey ) => `column_${ dataKey } _${ conceptIdCell } ` }
293- generateRowKey = { ( { conceptId : conceptIdRow } ) => `row_${ conceptIdRow } ` }
294- id = "associated-collections"
295- limit = { count }
296- noDataMessage = "No collection associations found."
297- offset = { offset }
298- />
283+ </ ControlledPaginatedContent >
299284 < Button
300285 className = "mt-4"
301286 variant = "danger"
302- disabled = { collectionConceptIds . length === 0 }
303- // eslint-disable-next-line react/jsx-props-no-spreading
287+ disabled = { collectionConceptIds . length === 0 || isDeleting }
304288 { ...accessibleEventProps }
305289 >
306290 Delete Selected Associations
@@ -319,7 +303,8 @@ const ManageCollectionAssociation = () => {
319303 {
320304 label : 'Yes' ,
321305 variant : 'primary' ,
322- onClick : handleDeleteAssociation
306+ onClick : handleDeleteAssociation ,
307+ disabled : isDeleting
323308 }
324309 ]
325310 }
0 commit comments