1
+ import { xor } from 'lodash' ;
1
2
import { useEffect , useState } from 'react' ;
2
3
import { Location , useLocation , useNavigate } from 'react-router-dom' ;
3
4
import { translations } from '~app/common/config' ;
4
5
import ConfirmationStep from '~app/components/applications/SSV/MyAccount/components/Validator/BulkActions/ConfirmationStep' ;
5
6
import ExitFinishPage from '~app/components/applications/SSV/MyAccount/components/Validator/BulkActions/ExitFinishPage' ;
6
7
import NewBulkActions from '~app/components/applications/SSV/MyAccount/components/Validator/BulkActions/NewBulkActions' ;
8
+ import { BULK_FLOWS } from '~app/enums/bulkFlow.enum.ts' ;
9
+ import { useClusterValidators } from '~app/hooks/cluster/useClusterValidators' ;
7
10
import { useAppDispatch , useAppSelector } from '~app/hooks/redux.hook' ;
8
11
import { IOperator } from '~app/model/operator.model' ;
9
- import { BULK_FLOWS } from '~app/enums/bulkFlow.enum.ts' ;
10
- import { BulkValidatorData , IValidator } from '~app/model/validator.model' ;
12
+ import { getSelectedCluster , setExcludedCluster } from '~app/redux/account.slice.ts' ;
11
13
import { getNetworkFeeAndLiquidationCollateral } from '~app/redux/network.slice' ;
12
14
import { getAccountAddress , getIsContractWallet } from '~app/redux/wallet.slice' ;
15
+ import { BulkActionRouteState } from '~app/Routes' ;
13
16
import { MAXIMUM_VALIDATOR_COUNT_FLAG } from '~lib/utils/developerHelper' ;
14
17
import { add0x } from '~lib/utils/strings' ;
15
18
import { exitValidators , removeValidators } from '~root/services/validatorContract.service' ;
16
- import { getSelectedCluster , setExcludedCluster } from '~app/redux/account.slice.ts' ;
17
- import { BulkActionRouteState } from '~app/Routes' ;
18
19
19
20
enum BULK_STEPS {
20
21
BULK_ACTIONS = 'BULK_ACTIONS' ,
@@ -27,123 +28,87 @@ const BULK_FLOWS_ACTION_TITLE = {
27
28
[ BULK_FLOWS . BULK_EXIT ] : translations . VALIDATOR . REMOVE_EXIT_VALIDATOR . BULK_TITLES . SELECT_EXIT_VALIDATORS
28
29
} ;
29
30
30
- const MAX_VALIDATORS_COUNT = Number ( window . localStorage . getItem ( MAXIMUM_VALIDATOR_COUNT_FLAG ) ) || 100 ;
31
-
32
- const BULK_ACTIONS_TOOLTIP_TITLES = {
33
- [ BULK_FLOWS . BULK_REMOVE ] : translations . VALIDATOR . REMOVE_EXIT_VALIDATOR . BULK_TOOLTIPS . REMOVE_VALIDATORS ( MAX_VALIDATORS_COUNT ) ,
34
- [ BULK_FLOWS . BULK_EXIT ] : translations . VALIDATOR . REMOVE_EXIT_VALIDATOR . BULK_TOOLTIPS . EXIT_VALIDATORS ( MAX_VALIDATORS_COUNT )
35
- } ;
36
-
37
- const BULK_ACTIONS_TOOLTIP_CHECKBOX_TITLES = {
38
- [ BULK_FLOWS . BULK_REMOVE ] : translations . VALIDATOR . REMOVE_EXIT_VALIDATOR . BULK_TOOLTIPS . REMOVE_VALIDATORS_CHECKBOX ( MAX_VALIDATORS_COUNT ) ,
39
- [ BULK_FLOWS . BULK_EXIT ] : translations . VALIDATOR . REMOVE_EXIT_VALIDATOR . BULK_TOOLTIPS . EXIT_VALIDATORS_CHECKBOX ( MAX_VALIDATORS_COUNT )
40
- } ;
31
+ export const MAX_VALIDATORS_COUNT = Number ( window . localStorage . getItem ( MAXIMUM_VALIDATOR_COUNT_FLAG ) ) || 100 ;
41
32
42
33
const BULK_FLOWS_CONFIRMATION_DATA = {
43
34
[ BULK_FLOWS . BULK_REMOVE ] : translations . VALIDATOR . REMOVE_EXIT_VALIDATOR . FLOW_CONFIRMATION_DATA . REMOVE ,
44
35
[ BULK_FLOWS . BULK_EXIT ] : translations . VALIDATOR . REMOVE_EXIT_VALIDATOR . FLOW_CONFIRMATION_DATA . EXIT
45
36
} ;
46
37
47
38
const BulkComponent = ( ) => {
48
- const [ selectedValidators , setSelectedValidators ] = useState < Record < string , BulkValidatorData > > ( { } ) ;
39
+ const [ selectedValidators , setSelectedValidators ] = useState < string [ ] > ( [ ] ) ;
49
40
const [ currentStep , setCurrentStep ] = useState ( BULK_STEPS . BULK_ACTIONS ) ;
50
41
const navigate = useNavigate ( ) ;
51
42
const accountAddress = useAppSelector ( getAccountAddress ) ;
52
43
const isContractWallet = useAppSelector ( getIsContractWallet ) ;
53
44
const cluster = useAppSelector ( getSelectedCluster ) ;
45
+
54
46
const { liquidationCollateralPeriod, minimumLiquidationCollateral } = useAppSelector ( getNetworkFeeAndLiquidationCollateral ) ;
55
47
48
+ const { infiniteQuery, fetchAll, validators } = useClusterValidators ( cluster ) ;
49
+ const maxSelectable = cluster . validatorCount ;
50
+
51
+ const isAllSelected = selectedValidators . length === maxSelectable ;
52
+
56
53
const location : Location < BulkActionRouteState > = useLocation ( ) ;
57
54
const { validator, currentBulkFlow } = location . state ;
58
55
59
- const [ isLoading , setIsLoading ] = useState ( false ) ;
60
56
const dispatch = useAppDispatch ( ) ;
61
57
62
58
useEffect ( ( ) => {
63
59
if ( validator ) {
64
- setSelectedValidators ( {
65
- [ add0x ( validator . public_key ) ] : {
66
- validator,
67
- isSelected : true
68
- }
69
- } ) ;
60
+ setSelectedValidators ( [ add0x ( validator . public_key ) ] ) ;
70
61
setCurrentStep ( BULK_STEPS . BULK_CONFIRMATION ) ;
71
62
}
72
63
} , [ ] ) ;
73
64
74
- const selectMaxValidatorsCount = ( validators : IValidator [ ] , validatorList : Record < string , BulkValidatorData > ) : Record < string , BulkValidatorData > => {
75
- const isSelected = Object . values ( selectedValidators ) . every ( ( validator : { validator : IValidator ; isSelected : boolean } ) => ! validator . isSelected ) ;
76
- validators . forEach ( ( validator : IValidator , index : number ) => {
77
- validatorList [ add0x ( validator . public_key ) ] = {
78
- validator,
79
- isSelected : isSelected && index < MAX_VALIDATORS_COUNT
80
- } ;
81
- } ) ;
82
- return validatorList ;
83
- } ;
65
+ const onToggleAll = ( ) => {
66
+ if ( ! isAllSelected && validators . length < maxSelectable ) {
67
+ return fetchAll . mutateAsync ( ) . then ( ( data ) => {
68
+ if ( ! data ) return ;
69
+ return setSelectedValidators ( data . slice ( 0 , maxSelectable ) ?. map ( ( validator ) => add0x ( validator . public_key ) ) ) ;
70
+ } ) ;
71
+ }
84
72
85
- const fillSelectedValidators = ( validators : IValidator [ ] , selectAll : boolean = false ) => {
86
- if ( validators ) {
87
- let validatorList : Record < string , BulkValidatorData > = { } ;
88
- if ( selectAll ) {
89
- validatorList = selectMaxValidatorsCount ( validators , validatorList ) ;
90
- } else {
91
- validators . forEach ( ( validator : IValidator ) => {
92
- validatorList [ add0x ( validator . public_key ) ] = {
93
- validator,
94
- isSelected : selectedValidators [ add0x ( validator . public_key ) ] ?. isSelected || false
95
- } ;
96
- } ) ;
97
- }
98
- setSelectedValidators ( validatorList ) ;
73
+ if ( ! isAllSelected ) {
74
+ setSelectedValidators ( validators . slice ( 0 , maxSelectable ) . map ( ( validator ) => add0x ( validator . public_key ) ) ) ;
75
+ } else {
76
+ setSelectedValidators ( [ ] ) ;
99
77
}
100
78
} ;
101
79
102
- const onCheckboxClickHandler = ( { publicKey } : { publicKey : string } ) => {
103
- setSelectedValidators ( ( prevState : any ) => {
104
- prevState [ publicKey ] . isSelected = ! prevState [ publicKey ] . isSelected ;
105
- return { ...prevState } ;
106
- } ) ;
80
+ const onValidatorToggle = ( publicKey : string ) => {
81
+ setSelectedValidators ( ( prev ) => xor ( prev , [ publicKey ] ) ) ;
107
82
} ;
108
83
109
84
const backToSingleClusterPage = ( validatorsCount ?: number ) => {
110
85
navigate ( validatorsCount === cluster . validatorCount && cluster . isLiquidated ? - 2 : - 1 ) ;
111
86
} ;
112
87
113
88
const nextStep = async ( ) => {
114
- const selectedValidatorKeys = Object . keys ( selectedValidators ) ;
115
- const selectedValidatorValues = Object . values ( selectedValidators ) ;
116
89
let res ;
117
- const selectedValidatorsCount = selectedValidatorValues . filter ( ( validator ) => validator . isSelected ) . length ;
118
- const isBulk = selectedValidatorsCount > 1 ;
90
+ const selectedValidatorsCount = selectedValidators . length ;
91
+ const isBulk = selectedValidators . length > 1 ;
92
+ const validatorPks = isBulk ? selectedValidators : selectedValidators [ 0 ] ;
119
93
if ( currentStep === BULK_STEPS . BULK_ACTIONS ) {
120
94
setCurrentStep ( BULK_STEPS . BULK_CONFIRMATION ) ;
121
95
} else if ( currentStep === BULK_STEPS . BULK_CONFIRMATION && currentBulkFlow === BULK_FLOWS . BULK_EXIT ) {
122
- setIsLoading ( true ) ;
123
- const validatorIds = isBulk
124
- ? selectedValidatorKeys . filter ( ( publicKey : string ) => selectedValidators [ publicKey ] . isSelected )
125
- : add0x ( selectedValidatorValues . filter ( ( selectedValidator ) => selectedValidator . isSelected ) [ 0 ] . validator . public_key ) ;
126
96
res = await exitValidators ( {
127
97
isContractWallet,
128
- validatorIds,
98
+ validatorIds : validatorPks ,
129
99
operatorIds : cluster . operators . map ( ( operator : IOperator ) => operator . id ) ,
130
100
isBulk,
131
101
dispatch
132
102
} ) ;
133
103
if ( res && ! isContractWallet ) {
134
104
setCurrentStep ( BULK_STEPS . BULK_EXIT_FINISH ) ;
135
105
}
136
- setIsLoading ( false ) ;
137
106
} else if ( currentStep === BULK_STEPS . BULK_EXIT_FINISH ) {
138
107
backToSingleClusterPage ( ) ;
139
108
} else {
140
- setIsLoading ( true ) ;
141
109
if ( selectedValidatorsCount === cluster . validatorCount && cluster . isLiquidated ) {
142
110
dispatch ( setExcludedCluster ( cluster ) ) ;
143
111
}
144
- const validatorPks = isBulk
145
- ? selectedValidatorKeys . filter ( ( publicKey : string ) => selectedValidators [ publicKey ] . isSelected )
146
- : add0x ( validator ?. public_key || selectedValidatorValues . filter ( ( selectedValidator ) => selectedValidator . isSelected ) [ 0 ] . validator . public_key ) ;
147
112
res = await removeValidators ( {
148
113
cluster,
149
114
accountAddress,
@@ -158,7 +123,6 @@ const BulkComponent = () => {
158
123
if ( res && ! isContractWallet ) {
159
124
backToSingleClusterPage ( selectedValidatorsCount ) ;
160
125
}
161
- setIsLoading ( false ) ;
162
126
}
163
127
} ;
164
128
@@ -167,14 +131,20 @@ const BulkComponent = () => {
167
131
if ( currentStep === BULK_STEPS . BULK_ACTIONS && ! validator ) {
168
132
return (
169
133
< NewBulkActions
170
- nextStep = { nextStep }
171
- tooltipTitle = { BULK_ACTIONS_TOOLTIP_TITLES [ currentBulkFlow ?? BULK_FLOWS . BULK_REMOVE ] }
172
- checkboxTooltipTitle = { BULK_ACTIONS_TOOLTIP_CHECKBOX_TITLES [ currentBulkFlow ?? BULK_FLOWS . BULK_REMOVE ] }
173
- maxValidatorsCount = { MAX_VALIDATORS_COUNT }
174
134
title = { BULK_FLOWS_ACTION_TITLE [ currentBulkFlow ?? BULK_FLOWS . BULK_REMOVE ] }
175
- fillSelectedValidators = { fillSelectedValidators }
176
- selectedValidators = { selectedValidators }
177
- onCheckboxClickHandler = { onCheckboxClickHandler }
135
+ nextStep = { nextStep }
136
+ listProps = { {
137
+ type : 'select' ,
138
+ validators : validators ,
139
+ withoutSettings : true ,
140
+ onToggleAll,
141
+ maxSelectable,
142
+ selectedValidators,
143
+ onValidatorToggle,
144
+ isEmpty : infiniteQuery . isSuccess && validators . length === 0 ,
145
+ infiniteScroll : infiniteQuery ,
146
+ isFetchingAll : fetchAll . isPending
147
+ } }
178
148
/>
179
149
) ;
180
150
}
@@ -184,16 +154,16 @@ const BulkComponent = () => {
184
154
< ConfirmationStep
185
155
stepBack = { ! validator ? stepBack : undefined }
186
156
flowData = { BULK_FLOWS_CONFIRMATION_DATA [ currentBulkFlow ?? BULK_FLOWS . BULK_REMOVE ] }
187
- selectedValidators = { Object . keys ( selectedValidators ) . filter ( ( publicKey : string ) => selectedValidators [ publicKey ] . isSelected ) }
188
- isLoading = { isLoading }
157
+ selectedValidators = { selectedValidators }
158
+ isLoading = { false }
189
159
currentBulkFlow = { currentBulkFlow ?? BULK_FLOWS . BULK_REMOVE }
190
160
nextStep = { nextStep }
191
161
/>
192
162
) ;
193
163
}
194
164
195
165
// BULK_STEPS.BULK_EXIT_FINISH === currentStep
196
- return < ExitFinishPage nextStep = { nextStep } selectedValidators = { Object . keys ( selectedValidators ) . filter ( ( publicKey : string ) => selectedValidators [ publicKey ] . isSelected ) } /> ;
166
+ return < ExitFinishPage nextStep = { nextStep } selectedValidators = { selectedValidators } /> ;
197
167
} ;
198
168
199
169
export default BulkComponent ;
0 commit comments