14
14
* limitations under the License.
15
15
*/
16
16
17
- import { useCallback , useMemo , useState } from 'react'
17
+ import { useEffect , useMemo , useState } from 'react'
18
18
19
- import { SortingOrder } from '@Common/Constants'
20
- import { debounce , noop } from '@Common/Helper'
21
19
import { useStateFilters } from '@Common/Hooks'
22
- import { DEFAULT_SECRET_PLACEHOLDER } from '@Shared/constants'
23
- import { stringComparatorBySortOrder } from '@Shared/Helpers'
24
20
25
- import { DynamicDataTable , DynamicDataTableCellValidationState } from '../DynamicDataTable'
26
- import { DUPLICATE_KEYS_VALIDATION_MESSAGE , EMPTY_KEY_VALIDATION_MESSAGE } from './constants'
27
- import {
28
- KeyValueTableData ,
29
- KeyValueTableDataType ,
30
- KeyValueTableInternalProps ,
31
- KeyValueTableProps ,
32
- } from './KeyValueTable.types'
21
+ import { DynamicDataTable } from '../DynamicDataTable'
22
+ import { KeyValueTableDataType , KeyValueTableInternalProps , KeyValueTableProps } from './KeyValueTable.types'
33
23
import {
34
24
getEmptyRow ,
35
25
getKeyValueHeaders ,
36
- getKeyValueInitialCellError ,
37
- getKeyValueInitialRows ,
38
- getKeyValueTableKeysFrequency ,
26
+ getKeyValueTableCellError ,
27
+ getKeyValueTableRows ,
28
+ getKeyValueTableSortedRows ,
39
29
getModifiedDataForOnChange ,
40
30
} from './utils'
41
31
42
32
import './KeyValueTable.scss'
43
33
44
34
export const KeyValueTable = ( {
45
35
headerLabel,
46
- initialRows,
36
+ rows : initialRows ,
47
37
placeholder,
48
38
maskValue,
49
39
isSortable,
@@ -53,133 +43,50 @@ export const KeyValueTable = ({
53
43
readOnly,
54
44
showError,
55
45
validationSchema : parentValidationSchema ,
56
- errorMessages : parentErrorMessages = [ ] ,
57
46
onError,
58
47
validateDuplicateKeys = false ,
59
48
validateEmptyKeys = false ,
60
49
} : KeyValueTableProps ) => {
61
50
// STATES
62
- const [ rows , setRows ] = useState < KeyValueTableInternalProps [ 'rows' ] > (
63
- getKeyValueInitialRows ( { initialRows, placeholder } ) ,
64
- )
65
-
66
- const [ cellError , setCellError ] = useState < KeyValueTableInternalProps [ 'cellError' ] > (
67
- getKeyValueInitialCellError ( rows ) ,
68
- )
51
+ const [ cellError , setCellError ] = useState < KeyValueTableInternalProps [ 'cellError' ] > ( { } )
69
52
70
53
// HOOKS
71
54
const { sortBy, sortOrder, handleSorting } = useStateFilters < KeyValueTableDataType > ( {
72
55
initialSortKey : isSortable ? 'key' : null ,
73
56
} )
74
57
75
- const rowWithMaskedValues = useMemo < typeof rows > ( ( ) => {
76
- if ( maskValue && Object . keys ( maskValue ) . length ) {
77
- return rows . map ( ( row ) => ( {
78
- ...row ,
79
- data : {
80
- ...row . data ,
81
- key : {
82
- ...row . data . key ,
83
- value : maskValue . key ? DEFAULT_SECRET_PLACEHOLDER : row . data . key . value ,
84
- } ,
85
- value : {
86
- ...row . data . value ,
87
- value : maskValue . value ? DEFAULT_SECRET_PLACEHOLDER : row . data . value . value ,
88
- } ,
89
- } ,
90
- } ) )
91
- }
92
-
93
- return rows
94
- } , [ rows , maskValue ] )
95
-
96
- const debounceOnChange = useCallback (
97
- debounce ( ( modifiedRows : KeyValueTableData [ ] ) =>
98
- typeof onChange === 'function' ? onChange ( modifiedRows ) : noop ,
99
- ) ,
100
- [ ] ,
58
+ // COMPUTED ROWS FOR DYNAMIC DATA TABLE
59
+ const rows = useMemo < KeyValueTableInternalProps [ 'rows' ] > (
60
+ ( ) => getKeyValueTableRows ( { rows : initialRows , placeholder, maskValue } ) ,
61
+ [ initialRows , placeholder , maskValue , isSortable , sortOrder , sortBy ] ,
101
62
)
102
63
103
- // METHODS
104
- const validationSchema = (
105
- value : Parameters < typeof parentValidationSchema > [ 0 ] ,
106
- key : Parameters < typeof parentValidationSchema > [ 1 ] ,
107
- rowId : Parameters < typeof parentValidationSchema > [ 2 ] ,
108
- keysFrequency : Record < string , number > = { } ,
109
- ) : DynamicDataTableCellValidationState => {
110
- const trimmedValue = value . trim ( )
111
-
112
- if ( validateDuplicateKeys && key === 'key' && ( keysFrequency [ trimmedValue ] ?? 0 ) > 1 ) {
113
- return {
114
- isValid : false ,
115
- errorMessages : [ DUPLICATE_KEYS_VALIDATION_MESSAGE ] ,
116
- }
117
- }
118
-
119
- if ( validateEmptyKeys && key === 'key' && ! trimmedValue ) {
120
- const isValuePresentAtRow = rows . some ( ( { id, data } ) => id === rowId && data . value . value . trim ( ) )
121
- if ( isValuePresentAtRow ) {
122
- return {
123
- isValid : false ,
124
- errorMessages : [ EMPTY_KEY_VALIDATION_MESSAGE ] ,
125
- }
126
- }
127
- }
128
-
129
- if ( parentValidationSchema ) {
130
- const isValid = parentValidationSchema ( value , key , rowId )
131
- return {
132
- isValid,
133
- errorMessages : ! isValid ? parentErrorMessages : [ ] ,
134
- }
135
- }
136
-
137
- return {
138
- isValid : true ,
139
- errorMessages : [ ] ,
140
- }
141
- }
64
+ // Set cell error on mount
65
+ useEffect ( ( ) => {
66
+ const { isValid, updatedCellError } = getKeyValueTableCellError ( {
67
+ rows,
68
+ validateDuplicateKeys,
69
+ validateEmptyKeys,
70
+ validationSchema : parentValidationSchema ,
71
+ } )
142
72
143
- const checkAllRowsAreValid = ( updatedRows : typeof rows ) => {
144
- let isValid = true
145
-
146
- const updatedCellError = updatedRows . reduce ( ( acc , { data, id } ) => {
147
- const keyError = validationSchema (
148
- data . key . value ,
149
- 'key' ,
150
- id ,
151
- validateDuplicateKeys ? getKeyValueTableKeysFrequency ( rows ) : { } ,
152
- )
153
- const valueError = validationSchema ( data . value . value , 'value' , id )
154
-
155
- if ( isValid && ! ( keyError . isValid && valueError . isValid ) ) {
156
- isValid = false
157
- }
158
-
159
- acc [ id ] = {
160
- key : keyError ,
161
- value : valueError ,
162
- }
163
-
164
- return acc
165
- } , { } )
166
-
167
- return { isValid, updatedCellError }
168
- }
73
+ setCellError ( updatedCellError )
74
+ onError ?.( ! isValid )
75
+ } , [ ] )
169
76
170
- const setUpdatedRows = ( updatedRows : typeof rows , shouldDebounceChange = false ) => {
171
- const { isValid, updatedCellError } = checkAllRowsAreValid ( updatedRows )
77
+ // METHODS
78
+ const setUpdatedRows = ( updatedRows : typeof rows ) => {
79
+ const { isValid, updatedCellError } = getKeyValueTableCellError ( {
80
+ rows : updatedRows ,
81
+ validateDuplicateKeys,
82
+ validateEmptyKeys,
83
+ validationSchema : parentValidationSchema ,
84
+ } )
172
85
173
- setRows ( updatedRows )
174
86
setCellError ( updatedCellError )
175
-
176
87
onError ?.( ! isValid )
177
88
178
- if ( shouldDebounceChange ) {
179
- debounceOnChange ( getModifiedDataForOnChange ( updatedRows ) )
180
- } else {
181
- onChange ?.( getModifiedDataForOnChange ( updatedRows ) )
182
- }
89
+ onChange ( getModifiedDataForOnChange ( updatedRows ) )
183
90
}
184
91
185
92
const onRowAdd = ( ) => {
@@ -211,31 +118,13 @@ export const KeyValueTable = ({
211
118
updatedRows [ rowIndex ] = selectedRow
212
119
}
213
120
214
- setUpdatedRows ( updatedRows , true )
215
- }
216
-
217
- const onSorting = ( _sortBy : KeyValueTableDataType ) => {
218
- handleSorting ( _sortBy )
219
-
220
- if ( isSortable ) {
221
- setRows ( ( prevRows ) => {
222
- const sortedRows = prevRows
223
- sortedRows . sort ( ( a , b ) =>
224
- stringComparatorBySortOrder (
225
- a . data [ _sortBy ] . value ,
226
- b . data [ _sortBy ] . value ,
227
- sortOrder === SortingOrder . ASC ? SortingOrder . DESC : SortingOrder . ASC ,
228
- ) ,
229
- )
230
- return sortedRows
231
- } )
232
- }
121
+ setUpdatedRows ( updatedRows )
233
122
}
234
123
235
124
return (
236
125
< DynamicDataTable
237
126
headers = { getKeyValueHeaders ( { headerLabel, isSortable } ) }
238
- rows = { rowWithMaskedValues }
127
+ rows = { getKeyValueTableSortedRows ( { isSortable , rows , sortBy , sortOrder } ) }
239
128
cellError = { showError ? cellError : { } }
240
129
onRowAdd = { onRowAdd }
241
130
onRowDelete = { onRowDelete }
@@ -246,7 +135,7 @@ export const KeyValueTable = ({
246
135
sortingConfig = { {
247
136
sortBy,
248
137
sortOrder,
249
- handleSorting : onSorting ,
138
+ handleSorting,
250
139
} }
251
140
/>
252
141
)
0 commit comments