4
4
import React from 'react' ;
5
5
import PT from 'prop-types' ;
6
6
import { isValidEmail } from 'utils/tc' ;
7
+ import TextInput from 'components/GUIKit/TextInput' ;
8
+ import _ from 'lodash' ;
9
+ import LoadingIndicator from 'components/LoadingIndicator' ;
10
+ import { Link } from 'topcoder-react-utils' ;
7
11
import defaulTheme from './style.scss' ;
8
12
9
13
/* Holds the base URL of Community App endpoints that proxy HTTP request to
@@ -14,95 +18,204 @@ class SubscribeMailChimpTagContainer extends React.Component {
14
18
constructor ( props ) {
15
19
super ( props ) ;
16
20
this . state = {
17
- error : '' ,
18
- subsribed : false ,
19
- disabled : true ,
20
- inputVal : '' ,
21
+ formErrors : { } ,
22
+ formData : { } ,
21
23
} ;
22
24
this . onSubscribeClick = this . onSubscribeClick . bind ( this ) ;
23
- this . onInputChange = this . onInputChange . bind ( this ) ;
25
+ this . onFormInputChange = this . onFormInputChange . bind ( this ) ;
26
+ this . validateForm = this . validateForm . bind ( this ) ;
24
27
}
25
28
26
29
onSubscribeClick ( ) {
27
- const { inputVal } = this . state ;
28
- const { listId, tags } = this . props ;
29
- const fetchUrl = `${ PROXY_ENDPOINT } /${ listId } /members/${ inputVal } /tags` ;
30
- const data = {
31
- email_address : inputVal ,
32
- status : 'subscribed' ,
33
- tags : tags . map ( t => ( { name : t , status : 'active' } ) ) ,
34
- } ;
35
- const formData = JSON . stringify ( data ) ;
36
- fetch ( fetchUrl , {
37
- method : 'POST' ,
38
- headers : {
39
- 'Content-Type' : 'application/json' ,
40
- } ,
41
- body : formData ,
42
- } ) . then ( result => result . json ( ) ) . then ( ( dataResponse ) => {
43
- if ( dataResponse . status === 204 ) {
44
- // regist success
45
- return this . setState ( {
46
- subsribed : true ,
47
- error : '' ,
48
- } ) ;
49
- }
50
- if ( dataResponse . status === 404 ) {
51
- // new email register it for list and add tags
52
- return fetch ( `${ PROXY_ENDPOINT } /${ listId } /members` , {
30
+ this . validateForm ( ) ;
31
+ // eslint-disable-next-line consistent-return
32
+ this . setState ( ( state ) => {
33
+ const { formData, formErrors } = state ;
34
+ if ( _ . isEmpty ( formErrors ) ) {
35
+ const { listId, tags } = this . props ;
36
+ const fetchUrl = `${ PROXY_ENDPOINT } /${ listId } /members/${ formData . email } /tags` ;
37
+ const data = {
38
+ email_address : formData . email ,
39
+ status : 'subscribed' ,
40
+ tags : tags . map ( t => ( { name : t , status : 'active' } ) ) ,
41
+ merge_fields : {
42
+ FNAME : formData . fname ,
43
+ LNAME : formData . lname ,
44
+ } ,
45
+ } ;
46
+ fetch ( fetchUrl , {
53
47
method : 'POST' ,
54
48
headers : {
55
49
'Content-Type' : 'application/json' ,
56
50
} ,
57
- body : JSON . stringify ( {
58
- email_address : inputVal ,
59
- status : 'subscribed' ,
60
- tags,
61
- } ) ,
62
- } )
63
- . then ( result => result . json ( ) ) . then ( ( ) => {
64
- this . setState ( {
51
+ body : JSON . stringify ( data ) ,
52
+ } ) . then ( result => result . json ( ) ) . then ( ( dataResponse ) => {
53
+ if ( dataResponse . status === 204 ) {
54
+ // regist success
55
+ return this . setState ( {
56
+ subscribing : false ,
65
57
subsribed : true ,
66
58
error : '' ,
67
59
} ) ;
60
+ }
61
+ if ( dataResponse . status === 404 ) {
62
+ // new email register it for list and add tags
63
+ data . tags = tags ;
64
+ return fetch ( `${ PROXY_ENDPOINT } /${ listId } /members` , {
65
+ method : 'POST' ,
66
+ headers : {
67
+ 'Content-Type' : 'application/json' ,
68
+ } ,
69
+ body : JSON . stringify ( data ) ,
70
+ } )
71
+ . then ( result => result . json ( ) ) . then ( ( rsp ) => {
72
+ this . setState ( {
73
+ subscribing : false ,
74
+ subsribed : ! rsp . detail ,
75
+ error : rsp . detail ? rsp . title : '' ,
76
+ } ) ;
77
+ } ) ;
78
+ }
79
+ return this . setState ( {
80
+ subscribing : false ,
81
+ subsribed : false ,
82
+ error : `Error ${ dataResponse . status } when assigning tags to ${ formData . email } ` ,
83
+ } ) ;
84
+ } )
85
+ . catch ( ( e ) => {
86
+ this . setState ( {
87
+ subscribing : false ,
88
+ subsribed : false ,
89
+ error : e . message ,
90
+ } ) ;
68
91
} ) ;
92
+ return { subscribing : true } ;
69
93
}
70
- return this . setState ( {
71
- subsribed : false ,
72
- error : `Error ${ dataResponse . status } when assign to tags` ,
73
- } ) ;
74
- } )
75
- . catch ( ( e ) => {
76
- this . setState ( {
77
- subsribed : false ,
78
- error : e . message ,
79
- } ) ;
80
- } ) ;
94
+ } ) ;
95
+ }
96
+
97
+ onFormInputChange ( key , val ) {
98
+ this . setState ( ( state ) => {
99
+ const { formData } = state ;
100
+ formData [ key ] = val ;
101
+ return {
102
+ ...state ,
103
+ formData,
104
+ } ;
105
+ } ) ;
106
+ this . validateForm ( key ) ;
81
107
}
82
108
83
- onInputChange ( event ) {
84
- this . setState ( {
85
- inputVal : event . target . value ,
86
- disabled : ! isValidEmail ( event . target . value ) ,
109
+ validateForm ( key ) {
110
+ this . setState ( ( state ) => {
111
+ const { formData, formErrors } = state ;
112
+ if ( key ) {
113
+ // validate only the key
114
+ if ( ! formData [ key ] || ! _ . trim ( formData [ key ] ) ) formErrors [ key ] = 'Required field' ;
115
+ else if ( key === 'email' && ! ( isValidEmail ( formData . email ) ) ) formErrors . email = 'Invalid email' ;
116
+ else delete formErrors [ key ] ;
117
+ } else {
118
+ _ . each ( [ 'fname' , 'lname' , 'email' ] , ( rkey ) => {
119
+ if ( ! formData [ rkey ] || ! _ . trim ( formData [ rkey ] ) ) formErrors [ rkey ] = 'Required field' ;
120
+ else if ( rkey === 'email' && ! ( isValidEmail ( formData . email ) ) ) formErrors . email = 'Invalid email' ;
121
+ else delete formErrors [ key ] ;
122
+ } ) ;
123
+ }
124
+ // updated state
125
+ return {
126
+ ...state ,
127
+ formErrors,
128
+ } ;
87
129
} ) ;
88
130
}
89
131
90
132
render ( ) {
91
133
const {
92
- disabled , inputVal , error , subsribed,
134
+ formData , formErrors , subscribing , subsribed, error ,
93
135
} = this . state ;
136
+ const {
137
+ btnText, title, successTitle, successText, successLink, successLinkText,
138
+ } = this . props ;
94
139
return (
95
140
< div className = { defaulTheme . wrapper } >
96
- < input type = "email" placeholder = "Email" value = { inputVal } onChange = { this . onInputChange } />
97
- < button type = "button" onClick = { this . onSubscribeClick } disabled = { disabled } className = { defaulTheme . button } > Subscribe</ button >
141
+ {
142
+ subscribing ? (
143
+ < div className = { defaulTheme . loadingWrap } >
144
+ < LoadingIndicator />
145
+ < p className = { defaulTheme . loadingText } >
146
+ Processing your subscription...
147
+ </ p >
148
+ </ div >
149
+ ) : null
150
+ }
151
+ {
152
+ subsribed || error ? (
153
+ < div className = { defaulTheme . subscribedWrap } >
154
+ < h4 > { error ? 'OOPS!' : successTitle } </ h4 >
155
+ < p className = { error ? defaulTheme . errorMsg : null } > { error || successText } </ p >
156
+ {
157
+ error
158
+ ? < button type = "button" onClick = { ( ) => { window . location . reload ( ) ; } } className = { defaulTheme . button } > TRY AGAIN</ button >
159
+ : < Link to = { successLink } className = { defaulTheme . button } > { successLinkText } </ Link >
160
+ }
161
+ </ div >
162
+ ) : null
163
+ }
164
+ {
165
+ ! subscribing && ! subsribed && ! error ? (
166
+ < React . Fragment >
167
+ < h6 > { title } </ h6 >
168
+ < TextInput
169
+ placeholder = "First Name"
170
+ label = "First Name"
171
+ onChange = { val => this . onFormInputChange ( 'fname' , val ) }
172
+ errorMsg = { formErrors . fname }
173
+ value = { formData . fname }
174
+ required
175
+ />
176
+ < TextInput
177
+ placeholder = "Last Name"
178
+ label = "Last Name"
179
+ onChange = { val => this . onFormInputChange ( 'lname' , val ) }
180
+ errorMsg = { formErrors . lname }
181
+ value = { formData . lname }
182
+ required
183
+ />
184
+ < TextInput
185
+ placeholder = "Email Address"
186
+ label = "Email Address"
187
+ onChange = { val => this . onFormInputChange ( 'email' , val ) }
188
+ errorMsg = { formErrors . email }
189
+ value = { formData . email }
190
+ required
191
+ />
192
+ < button type = "button" onClick = { this . onSubscribeClick } disabled = { ! _ . isEmpty ( formErrors ) || subscribing } className = { defaulTheme . button } > { btnText } </ button >
193
+ </ React . Fragment >
194
+ ) : null
195
+ }
98
196
</ div >
99
197
) ;
100
198
}
101
199
}
102
200
201
+ SubscribeMailChimpTagContainer . defaultProps = {
202
+ title : '' ,
203
+ btnText : '' ,
204
+ successTitle : 'Success!' ,
205
+ successText : '' ,
206
+ successLink : '' ,
207
+ successLinkText : '' ,
208
+ } ;
209
+
103
210
SubscribeMailChimpTagContainer . propTypes = {
104
211
listId : PT . string . isRequired ,
105
212
tags : PT . arrayOf ( PT . string ) . isRequired ,
213
+ title : PT . string ,
214
+ btnText : PT . string ,
215
+ successTitle : PT . string ,
216
+ successText : PT . string ,
217
+ successLink : PT . string ,
218
+ successLinkText : PT . string ,
106
219
} ;
107
220
108
221
export default SubscribeMailChimpTagContainer ;
0 commit comments