1
1
// @flow
2
2
3
3
import Icon from '@conveyal/woonerf/components/icon'
4
+ import { isEqual } from 'lodash'
4
5
import React , { Component } from 'react'
5
6
import {
6
7
Button ,
@@ -24,15 +25,44 @@ import type {
24
25
} from '../../../types'
25
26
26
27
type State = {
27
- activeEditingIndex : number
28
+ activeEditingIndex : number ,
29
+ // Holds the contents that should be shown in the SubstitutionRow component.
30
+ activeSubstitution : ?Substitution ,
31
+ // Last edited contents.
32
+ previousEditingIndex : number ,
33
+ previousSubstitution : ?Substitution
34
+ }
35
+
36
+ /**
37
+ * Determines whether two substitutions are equal (except for the valid field).
38
+ */
39
+ function areEqual ( sub1 : ?Substitution , sub2 : ?Substitution ) : boolean {
40
+ if ( ! sub1 || ! sub2 ) return false
41
+ return isEqual (
42
+ {
43
+ description : sub1 . description ,
44
+ normalizeSpace : sub1 . normalizeSpace ,
45
+ pattern : sub1 . pattern ,
46
+ replacement : sub1 . replacement
47
+ } ,
48
+ {
49
+ description : sub2 . description ,
50
+ normalizeSpace : sub2 . normalizeSpace ,
51
+ pattern : sub2 . pattern ,
52
+ replacement : sub2 . replacement
53
+ }
54
+ )
28
55
}
29
56
30
57
/**
31
58
* Component that renders input fields for the NormalizeFieldTransformation.
32
59
*/
33
60
export default class NormalizeField extends Component < TransformProps < NormalizeFieldFields > , State > {
34
61
state = {
35
- activeEditingIndex : - 1
62
+ activeEditingIndex : - 1 ,
63
+ activeSubstitution : null ,
64
+ previousEditingIndex : - 1 ,
65
+ previousSubstitution : null
36
66
}
37
67
38
68
componentDidMount ( ) {
@@ -42,6 +72,21 @@ export default class NormalizeField extends Component<TransformProps<NormalizeFi
42
72
componentDidUpdate ( prevProps : TransformProps < NormalizeFieldFields > ) {
43
73
if ( prevProps . transformation !== this . props . transformation ) {
44
74
this . _updateErrors ( )
75
+
76
+ // If user entered an invalid substitution pattern and clicks save,
77
+ // it will be rejected and the values entered will be lost.
78
+ // To avoid that, keep the new row visible and in editing state.
79
+ const { previousEditingIndex, previousSubstitution : editedSubstitution } = this . state
80
+ const loadedSubstitution = this . props . transformation . substitutions [ previousEditingIndex ]
81
+ if ( previousEditingIndex !== - 1 && ! areEqual ( editedSubstitution , loadedSubstitution ) ) {
82
+ this . setState ( {
83
+ activeEditingIndex : previousEditingIndex ,
84
+ activeSubstitution : {
85
+ ...editedSubstitution ,
86
+ valid : false
87
+ }
88
+ } )
89
+ }
45
90
}
46
91
}
47
92
@@ -60,12 +105,17 @@ export default class NormalizeField extends Component<TransformProps<NormalizeFi
60
105
_onChangeSubstitution = ( substitution : Substitution , index : number ) = > {
61
106
const newSubstitutions = [ ] . concat ( this . props . transformation . substitutions )
62
107
newSubstitutions [ index ] = substitution
108
+ this . setState ( {
109
+ activeSubstitution : null ,
110
+ previousSubstitution : substitution
111
+ } )
63
112
this . _updateTransformation ( { substitutions : newSubstitutions } )
64
113
}
65
114
66
115
_onRemoveSubstitution = ( index : number ) => {
67
116
const newSubstitutions = [ ] . concat ( this . props . transformation . substitutions )
68
117
newSubstitutions . splice ( index , 1 )
118
+ this . setState ( { previousEditingIndex : - 1 } )
69
119
this . _updateTransformation ( { substitutions : newSubstitutions } )
70
120
}
71
121
@@ -101,7 +151,11 @@ export default class NormalizeField extends Component<TransformProps<NormalizeFi
101
151
}
102
152
103
153
_onEndEditSubstitution = ( ) => {
104
- this . setState ( { activeEditingIndex : - 1 } )
154
+ this . setState ( {
155
+ activeEditingIndex : - 1 ,
156
+ activeSubstitution : null ,
157
+ previousEditingIndex : this . state . activeEditingIndex
158
+ } )
105
159
}
106
160
107
161
/**
@@ -129,7 +183,7 @@ export default class NormalizeField extends Component<TransformProps<NormalizeFi
129
183
130
184
render ( ) {
131
185
const { index, transformation } = this . props
132
- const { activeEditingIndex } = this . state
186
+ const { activeEditingIndex, activeSubstitution } = this . state
133
187
const {
134
188
capitalizationExceptions,
135
189
capitalize,
@@ -233,7 +287,7 @@ export default class NormalizeField extends Component<TransformProps<NormalizeFi
233
287
onChange = { this . _onChangeSubstitution }
234
288
onEndEdit = { this . _onEndEditSubstitution }
235
289
onRemove = { this . _onRemoveSubstitution }
236
- substitution = { s }
290
+ substitution = { activeEditingIndex === i ? ( activeSubstitution || s ) : s }
237
291
/>
238
292
) ) }
239
293
{ activeEditingIndex === substitutions . length &&
@@ -244,10 +298,10 @@ export default class NormalizeField extends Component<TransformProps<NormalizeFi
244
298
key = { activeEditingIndex }
245
299
onChange = { this . _onChangeSubstitution }
246
300
onEndEdit = { this . _onEndEditSubstitution }
247
- substitution = { {
248
- invalid : false ,
301
+ substitution = { activeSubstitution || {
249
302
pattern : '' ,
250
- replacement : ''
303
+ replacement : '' ,
304
+ valid : true
251
305
} }
252
306
/>
253
307
}
0 commit comments