3
3
* License: MS-RSL – see LICENSE.md for details
4
4
*/
5
5
6
- import { Component , Rendered , ReactDOM } from "../../app-framework" ;
7
- import { alert_message } from "../../alerts" ;
8
- import { log } from "../../user-tracking" ;
9
- import { ErrorDisplay , LabeledRow , Saving } from "../../components" ;
6
+ import { FormattedMessage , useIntl } from "react-intl" ;
7
+
8
+ import { alert_message } from "@cocalc/frontend/alerts" ;
10
9
import {
11
10
Button ,
12
11
ButtonToolbar ,
13
- Well ,
14
- FormGroup ,
15
12
FormControl ,
16
- } from "../../antd-bootstrap" ;
17
- import { webapp_client } from "../../webapp-client" ;
13
+ FormGroup ,
14
+ Well ,
15
+ } from "@cocalc/frontend/antd-bootstrap" ;
16
+ import {
17
+ ReactDOM ,
18
+ Rendered ,
19
+ useRef ,
20
+ useState ,
21
+ } from "@cocalc/frontend/app-framework" ;
22
+ import { ErrorDisplay , LabeledRow , Saving } from "@cocalc/frontend/components" ;
23
+ import { labels } from "@cocalc/frontend/i18n" ;
24
+ import { log } from "@cocalc/frontend/user-tracking" ;
25
+ import { webapp_client } from "@cocalc/frontend/webapp-client" ;
26
+ import { COLORS } from "@cocalc/util/theme" ;
18
27
19
28
interface Props {
20
29
account_id : string ;
@@ -24,77 +33,59 @@ interface Props {
24
33
verify_emails ?: boolean ;
25
34
}
26
35
27
- interface State {
28
- state : "view" | "edit" | "saving" ; // view --> edit --> saving --> view or edit
29
- password : string ;
30
- email_address : string ; // The new email address
31
- error : string ;
32
- }
36
+ export const EmailAddressSetting = ( props : Readonly < Props > ) => {
37
+ const intl = useIntl ( ) ;
33
38
34
- export class EmailAddressSetting extends Component < Props , State > {
35
- constructor ( props , state ) {
36
- super ( props , state ) ;
37
- this . state = { state : "view" , password : "" , email_address : "" , error : "" } ;
38
- }
39
+ const emailRef = useRef < FormControl > ( null ) ;
40
+ const passwordRef = useRef < FormControl > ( null ) ;
41
+
42
+ const [ state , setState ] = useState < "view" | "edit" | "saving" > ( "view" ) ;
43
+ const [ password , setPassword ] = useState < string > ( "" ) ;
44
+ const [ email_address , set_email_address ] = useState < string > ( "" ) ;
45
+ const [ error , setError ] = useState < string > ( "" ) ;
39
46
40
- private start_editing ( ) : void {
41
- this . setState ( {
42
- state : "edit" ,
43
- email_address :
44
- this . props . email_address != null ? this . props . email_address : "" ,
45
- error : "" ,
46
- password : "" ,
47
- } ) ;
47
+ function start_editing ( ) : void {
48
+ setState ( "edit" ) ;
49
+ set_email_address ( props . email_address != null ? props . email_address : "" ) ;
50
+ setError ( "" ) ;
51
+ setPassword ( "" ) ;
48
52
}
49
53
50
- private cancel_editing ( ) : void {
51
- this . setState ( {
52
- state : "view" ,
53
- password : "" ,
54
- } ) ; // more secure...
54
+ function cancel_editing ( ) : void {
55
+ setState ( "view" ) ;
56
+ setPassword ( "" ) ;
55
57
}
56
58
57
- private async save_editing ( ) : Promise < void > {
58
- if ( this . state . password . length < 6 ) {
59
- this . setState ( {
60
- state : "edit" ,
61
- error : "Password must be at least 6 characters long." ,
62
- } ) ;
59
+ async function save_editing ( ) : Promise < void > {
60
+ if ( password . length < 6 ) {
61
+ setState ( "edit" ) ;
62
+ setError ( "Password must be at least 6 characters long." ) ;
63
63
return ;
64
64
}
65
- this . setState ( {
66
- state : "saving" ,
67
- } ) ;
65
+ setState ( "saving" ) ;
68
66
try {
69
- await webapp_client . account_client . change_email (
70
- this . state . email_address ,
71
- this . state . password
72
- ) ;
67
+ await webapp_client . account_client . change_email ( email_address , password ) ;
73
68
} catch ( error ) {
74
- this . setState ( {
75
- state : "edit" ,
76
- error : `Error -- ${ error } ` ,
77
- } ) ;
69
+ setState ( "edit" ) ;
70
+ setError ( `Error -- ${ error } ` ) ;
78
71
return ;
79
72
}
80
- if ( this . props . is_anonymous ) {
73
+ if ( props . is_anonymous ) {
81
74
log ( "email_sign_up" , { source : "anonymous_account" } ) ;
82
75
}
83
- this . setState ( {
84
- state : "view" ,
85
- error : "" ,
86
- password : "" ,
87
- } ) ;
76
+ setState ( "view" ) ;
77
+ setError ( "" ) ;
78
+ setPassword ( "" ) ;
88
79
// if email verification is enabled, send out a token
89
80
// in any case, send a welcome email to an anonymous user, possibly
90
81
// including an email verification link
91
- if ( ! ( this . props . verify_emails || this . props . is_anonymous ) ) {
82
+ if ( ! ( props . verify_emails || props . is_anonymous ) ) {
92
83
return ;
93
84
}
94
85
try {
95
86
// anonymouse users will get the "welcome" email
96
87
await webapp_client . account_client . send_verification_email (
97
- ! this . props . is_anonymous
88
+ ! props . is_anonymous ,
98
89
) ;
99
90
} catch ( error ) {
100
91
const err_msg = `Problem sending welcome email: ${ error } ` ;
@@ -103,141 +94,150 @@ export class EmailAddressSetting extends Component<Props, State> {
103
94
}
104
95
}
105
96
106
- private is_submittable ( ) : boolean {
107
- return ! ! (
108
- this . state . password !== "" &&
109
- this . state . email_address !== this . props . email_address
110
- ) ;
97
+ function is_submittable ( ) : boolean {
98
+ return ! ! ( password !== "" && email_address !== props . email_address ) ;
111
99
}
112
100
113
- private render_change_button ( ) : Rendered {
101
+ function render_change_button ( ) : Rendered {
114
102
return (
115
103
< Button
116
- disabled = { ! this . is_submittable ( ) }
117
- onClick = { this . save_editing . bind ( this ) }
104
+ disabled = { ! is_submittable ( ) }
105
+ onClick = { save_editing }
118
106
bsStyle = "success"
119
107
>
120
- { this . button_label ( ) }
108
+ { button_label ( ) }
121
109
</ Button >
122
110
) ;
123
111
}
124
112
125
- private render_error ( ) : Rendered {
126
- if ( this . state . error ) {
113
+ function render_error ( ) : Rendered {
114
+ if ( error ) {
127
115
return (
128
116
< ErrorDisplay
129
- error = { this . state . error }
130
- onClose = { ( ) => this . setState ( { error : "" } ) }
117
+ error = { error }
118
+ onClose = { ( ) => setError ( "" ) }
131
119
style = { { marginTop : "15px" } }
132
120
/>
133
121
) ;
134
122
}
135
123
}
136
124
137
- private render_edit ( ) : Rendered {
138
- const password_label = this . props . email_address
139
- ? "Current password"
140
- : "Choose a password" ;
125
+ function render_edit ( ) : Rendered {
126
+ const password_label = intl . formatMessage (
127
+ {
128
+ id : "account.settings.email_address.password_label" ,
129
+ defaultMessage :
130
+ "{have_email, select, true {Current password} other {Choose a password}}" ,
131
+ } ,
132
+ {
133
+ have_email : ! ! props . email_address ,
134
+ } ,
135
+ ) ;
141
136
return (
142
137
< Well style = { { marginTop : "3ex" } } >
143
138
< FormGroup >
144
- New email address
139
+ < FormattedMessage
140
+ id = "account.settings.email_address.new_email_address_label"
141
+ defaultMessage = "New email address"
142
+ />
145
143
< FormControl
146
144
autoFocus
147
145
type = "email_address"
148
- ref = "email_address"
149
- value = { this . state . email_address }
146
+ ref = { emailRef }
147
+ value = { email_address }
150
148
151
- onChange = { ( ) =>
152
- this . setState ( {
153
- email_address : ReactDOM . findDOMNode ( this . refs . email_address )
154
- . value ,
155
- } )
156
- }
149
+ onChange = { ( ) => {
150
+ const em = ReactDOM . findDOMNode ( emailRef . current ) ?. value ;
151
+ set_email_address ( em ) ;
152
+ } }
157
153
maxLength = { 254 }
158
154
/>
159
155
</ FormGroup >
160
156
{ password_label }
161
157
< form
162
158
onSubmit = { ( e ) => {
163
159
e . preventDefault ( ) ;
164
- if ( this . is_submittable ( ) ) {
165
- return this . save_editing ( ) ;
160
+ if ( is_submittable ( ) ) {
161
+ return save_editing ( ) ;
166
162
}
167
163
} }
168
164
>
169
165
< FormGroup >
170
166
< FormControl
171
167
type = "password"
172
- ref = "password"
173
- value = { this . state . password }
168
+ ref = { passwordRef }
169
+ value = { password }
174
170
placeholder = { password_label }
175
171
onChange = { ( ) => {
176
- const password = ReactDOM . findDOMNode (
177
- this . refs . password
178
- ) ?. value ;
179
- if ( password != null ) {
180
- this . setState ( {
181
- password,
182
- } ) ;
172
+ const pw = ReactDOM . findDOMNode ( passwordRef . current ) ?. value ;
173
+ if ( pw != null ) {
174
+ setPassword ( pw ) ;
183
175
}
184
176
} }
185
177
/>
186
178
</ FormGroup >
187
179
</ form >
188
180
< ButtonToolbar >
189
- { this . render_change_button ( ) }
190
- < Button onClick = { this . cancel_editing . bind ( this ) } > Cancel</ Button >
181
+ { render_change_button ( ) }
182
+ < Button onClick = { cancel_editing } > Cancel</ Button >
191
183
</ ButtonToolbar >
192
- { this . render_error ( ) }
193
- { this . render_saving ( ) }
184
+ { render_error ( ) }
185
+ { render_saving ( ) }
194
186
</ Well >
195
187
) ;
196
188
}
197
189
198
- private render_saving ( ) : Rendered {
199
- if ( this . state . state === "saving" ) {
190
+ function render_saving ( ) : Rendered {
191
+ if ( state === "saving" ) {
200
192
return < Saving /> ;
201
193
}
202
194
}
203
195
204
- private button_label ( ) : string {
205
- if ( this . props . is_anonymous ) {
206
- return "Sign up using an email address and password" ;
207
- } else if ( this . props . email_address ) {
208
- return "Change email address" ;
209
- } else {
210
- return "Set email address and password" ;
211
- }
212
- }
213
-
214
- public render ( ) : Rendered {
215
- const label = this . props . is_anonymous ? (
216
- < h5 style = { { color : "#666" } } >
217
- Sign up using an email address and password
218
- </ h5 >
219
- ) : (
220
- "Email address"
221
- ) ;
222
- return (
223
- < LabeledRow
224
- label = { label }
225
- style = { this . props . disabled ? { color : "#666" } : undefined }
226
- >
227
- < div >
228
- { this . props . email_address }
229
- { this . state . state === "view" ? (
230
- < Button
231
- disabled = { this . props . disabled }
232
- className = "pull-right"
233
- onClick = { this . start_editing . bind ( this ) }
234
- >
235
- { this . button_label ( ) } ...
236
- </ Button >
237
- ) : undefined }
238
- </ div >
239
- { this . state . state !== "view" ? this . render_edit ( ) : undefined }
240
- </ LabeledRow >
196
+ function button_label ( ) : string {
197
+ return intl . formatMessage (
198
+ {
199
+ id : "account.settings.email_address.button_label" ,
200
+ defaultMessage : `{type, select,
201
+ anonymous {Sign up using an email address and password}
202
+ have_email {Change email address}
203
+ other {Set email address and password}}` ,
204
+ } ,
205
+ {
206
+ type : props . is_anonymous
207
+ ? "anonymous"
208
+ : props . email_address
209
+ ? "have_email"
210
+ : "" ,
211
+ } ,
241
212
) ;
242
213
}
243
- }
214
+
215
+ const label = props . is_anonymous ? (
216
+ < h5 style = { { color : COLORS . GRAY_M } } >
217
+ Sign up using an email address and password
218
+ </ h5 >
219
+ ) : (
220
+ intl . formatMessage ( labels . email_address )
221
+ ) ;
222
+
223
+ return (
224
+ < LabeledRow
225
+ label = { label }
226
+ style = { props . disabled ? { color : COLORS . GRAY_M } : undefined }
227
+ >
228
+ < div >
229
+ { props . email_address }
230
+ { state === "view" ? (
231
+ < Button
232
+ disabled = { props . disabled }
233
+ className = "pull-right"
234
+ onClick = { start_editing }
235
+ >
236
+ { button_label ( ) } ...
237
+ </ Button >
238
+ ) : undefined }
239
+ </ div >
240
+ { state !== "view" ? render_edit ( ) : undefined }
241
+ </ LabeledRow >
242
+ ) ;
243
+ } ;
0 commit comments