1
1
/* global window */
2
2
3
- import React , { Component } from 'react' ;
3
+ import React , { useState } from 'react' ;
4
4
import PropTypes from 'prop-types' ;
5
5
import { QRCodeSVG } from 'qrcode.react' ;
6
6
import { formatCode } from 'lib/formatCode' ;
@@ -15,222 +15,172 @@ const VIEWS = {
15
15
* This component provides the user interface for registering one-time time-based passwords (TOTP)
16
16
* with a user.
17
17
*/
18
- class Register extends Component {
19
- constructor ( props ) {
20
- super ( props ) ;
21
-
22
- this . state = {
23
- error : props . error ,
24
- view : props . error ? VIEWS . VALIDATE : VIEWS . SCAN ,
25
- } ;
26
-
27
- this . handleBack = this . handleBack . bind ( this ) ;
28
- this . handleBackToScan = this . handleBackToScan . bind ( this ) ;
29
- this . handleNext = this . handleNext . bind ( this ) ;
30
- }
18
+ function Register ( props ) {
19
+ const {
20
+ code,
21
+ onBack,
22
+ onCompleteRegistration,
23
+ error,
24
+ errors,
25
+ method,
26
+ uri,
27
+ TOTPVerifyComponent,
28
+ } = props ;
29
+ const [ stateError , setStateError ] = useState ( error ) ;
30
+ const [ view , setView ] = useState ( error ? VIEWS . VALIDATE : VIEWS . SCAN ) ;
31
+ const i18n = window . ss . i18n ;
31
32
32
33
/**
33
34
* Send the user back to the "select method" screen
34
35
*/
35
- handleBack ( ) {
36
- this . props . onBack ( ) ;
36
+ function handleBack ( ) {
37
+ onBack ( ) ;
37
38
}
38
39
39
40
/**
40
41
* Send the user back to the "scan QR code" screen
41
42
*/
42
- handleBackToScan ( ) {
43
- this . setState ( {
44
- view : VIEWS . SCAN ,
45
- error : null ,
46
- } ) ;
43
+ function handleBackToScan ( ) {
44
+ setView ( VIEWS . SCAN ) ;
45
+ setStateError ( null ) ;
47
46
}
48
47
49
48
/**
50
49
* After user has scanned the QR code, handle the transition to the verify screen
51
50
*/
52
- handleNext ( ) {
53
- this . setState ( { view : VIEWS . VALIDATE } ) ;
51
+ function handleNext ( ) {
52
+ setView ( VIEWS . VALIDATE ) ;
54
53
}
55
54
56
55
/**
57
56
* Renders an action button menu with a Next and Back button, using a different handler for
58
57
* the click of each button depending on which view we're in.
59
- *
60
- * @returns {HTMLElement }
61
58
*/
62
- renderActionsMenu ( ) {
63
- const { ss : { i18n } } = window ;
64
-
65
- return (
66
- < ul className = "mfa-action-list" >
67
- < li className = "mfa-action-list__item" >
68
- < button
69
- type = "button"
70
- className = "btn btn-primary"
71
- onClick = { this . handleNext }
72
- >
73
- { i18n . _t ( 'TOTPRegister.NEXT' , 'Next' ) }
74
- </ button >
75
- </ li >
76
- < li className = "mfa-action-list__item" >
77
- < button
78
- type = "button"
79
- className = "btn btn-secondary"
80
- onClick = { this . handleBack }
81
- >
82
- { i18n . _t ( 'TOTPRegister.BACK' , 'Back' ) }
83
- </ button >
84
- </ li >
85
- </ ul >
86
- ) ;
59
+ function renderActionsMenu ( ) {
60
+ return < ul className = "mfa-action-list" >
61
+ < li className = "mfa-action-list__item" >
62
+ < button
63
+ type = "button"
64
+ className = "btn btn-primary"
65
+ onClick = { handleNext }
66
+ >
67
+ { i18n . _t ( 'TOTPRegister.NEXT' , 'Next' ) }
68
+ </ button >
69
+ </ li >
70
+ < li className = "mfa-action-list__item" >
71
+ < button
72
+ type = "button"
73
+ className = "btn btn-secondary"
74
+ onClick = { handleBack }
75
+ >
76
+ { i18n . _t ( 'TOTPRegister.BACK' , 'Back' ) }
77
+ </ button >
78
+ </ li >
79
+ </ ul > ;
87
80
}
88
81
89
82
/**
90
83
* Handles rendering of errors returned from the backend API requests, e.g.
91
84
* your session has timed out.
92
- *
93
- * @returns {HTMLElement }
94
85
*/
95
- renderErrorScreen ( ) {
96
- const { errors } = this . props ;
97
-
86
+ function renderErrorScreen ( ) {
98
87
if ( ! errors . length ) {
99
88
return null ;
100
89
}
90
+ return < div className = "mfa-totp__errors" >
91
+ { errors . join ( ', ' ) }
92
+ </ div > ;
93
+ }
101
94
102
- return (
103
- < div className = "mfa-totp__errors" >
104
- { errors . join ( ', ' ) }
105
- </ div >
106
- ) ;
95
+ /**
96
+ * If there is a configured support link, will render a link to the TOTP authenticator's
97
+ * support documentation (e.g. userhelp).
98
+ */
99
+ function renderSupportLink ( ) {
100
+ const { supportLink, supportText } = method ;
101
+ if ( ! supportLink ) {
102
+ return null ;
103
+ }
104
+ return < a href = { supportLink } target = "_blank" rel = "noopener noreferrer" >
105
+ { supportText || i18n . _t ( 'TOTPRegister.HOW_TO_USE' , 'How to use authenticator apps.' ) }
106
+ </ a > ;
107
107
}
108
108
109
109
/**
110
110
* Renders the screen to scan a QR code with an authenticator app.
111
- *
112
- * @returns {HTMLElement }
113
111
*/
114
- renderScanCodeScreen ( ) {
115
- const { uri, code, errors } = this . props ;
116
- const { view } = this . state ;
117
- const { ss : { i18n } } = window ;
118
-
112
+ function renderScanCodeScreen ( ) {
119
113
if ( view !== VIEWS . SCAN || errors . length ) {
120
114
return null ;
121
115
}
122
-
123
116
const formattedCode = formatCode ( code ) ;
124
-
125
- return (
126
- < div >
127
- < div className = "mfa-totp__scan" >
128
- < p > { i18n . _t (
129
- 'TOTPRegister.INTRO' ,
130
- 'Verification codes are created by an app on your phone. '
131
- ) } { this . renderSupportLink ( ) } </ p >
132
-
133
- < div className = "mfa-totp__scan-code" >
134
- < div className = "mfa-totp__scan-left" >
135
- < QRCodeSVG value = { uri } size = { 160 } />
136
- </ div >
137
-
138
- < div className = "mfa-totp__scan-middle" >
139
- { i18n . _t ( 'TOTPRegister.OR' , 'Or' ) }
140
- </ div >
141
-
142
- < div className = "mfa-totp__scan-right" >
143
- < p > { i18n . _t (
144
- 'TOTPRegister.MANUAL' ,
145
- 'Enter manually the following code into authentication app:'
146
- ) } </ p >
147
- < p className = "mfa-totp__manual-code" >
148
- { formattedCode }
149
- </ p >
150
- </ div >
117
+ return < div >
118
+ < div className = "mfa-totp__scan" >
119
+ < p > { i18n . _t (
120
+ 'TOTPRegister.INTRO' ,
121
+ 'Verification codes are created by an app on your phone. '
122
+ ) } { renderSupportLink ( ) } </ p >
123
+ < div className = "mfa-totp__scan-code" >
124
+ < div className = "mfa-totp__scan-left" >
125
+ < QRCodeSVG value = { uri } size = { 160 } />
126
+ </ div >
127
+ < div className = "mfa-totp__scan-middle" >
128
+ { i18n . _t ( 'TOTPRegister.OR' , 'Or' ) }
129
+ </ div >
130
+ < div className = "mfa-totp__scan-right" >
131
+ < p > { i18n . _t (
132
+ 'TOTPRegister.MANUAL' ,
133
+ 'Enter manually the following code into authentication app:'
134
+ ) } </ p >
135
+ < p className = "mfa-totp__manual-code" >
136
+ { formattedCode }
137
+ </ p >
151
138
</ div >
152
139
</ div >
153
- { this . renderActionsMenu ( ) }
154
140
</ div >
155
- ) ;
156
- }
157
-
158
- /**
159
- * If there is a configured support link, will render a link to the TOTP authenticator's
160
- * support documentation (e.g. userhelp).
161
- *
162
- * @returns {HTMLElement }
163
- */
164
- renderSupportLink ( ) {
165
- const { method : { supportLink, supportText } } = this . props ;
166
- const { ss : { i18n } } = window ;
167
-
168
- if ( ! supportLink ) {
169
- return null ;
170
- }
171
-
172
- return (
173
- < a href = { supportLink } target = "_blank" rel = "noopener noreferrer" >
174
- { supportText || i18n . _t ( 'TOTPRegister.HOW_TO_USE' , 'How to use authenticator apps.' ) }
175
- </ a >
176
- ) ;
141
+ { renderActionsMenu ( ) }
142
+ </ div > ;
177
143
}
178
144
179
145
/**
180
146
* The back button for the verification screen should send you back to the register screen
181
- *
182
- * @return HTMLElement|null
183
147
*/
184
- renderBackButtonForVerify ( ) {
185
- const { ss : { i18n } } = window ;
186
-
187
- return (
188
- < button
189
- type = "button"
190
- className = "mfa-actions__action mfa-actions__action--back btn btn-secondary"
191
- onClick = { this . handleBackToScan }
192
- >
193
- { i18n . _t ( 'TOTPRegister.BACK' , 'Back' ) }
194
- </ button >
195
- ) ;
148
+ function renderBackButtonForVerify ( ) {
149
+ return < button
150
+ type = "button"
151
+ className = "mfa-actions__action mfa-actions__action--back btn btn-secondary"
152
+ onClick = { handleBackToScan }
153
+ >
154
+ { i18n . _t ( 'TOTPRegister.BACK' , 'Back' ) }
155
+ </ button > ;
196
156
}
197
157
198
158
/**
199
159
* Renders the screen to input and validate the TOTP code, after having registered it via QR
200
160
* code with an authenticator app.
201
- *
202
- * @returns {HTMLElement }
203
161
*/
204
- renderValidateCodeScreen ( ) {
205
- const { error, view } = this . state ;
206
- const { TOTPVerifyComponent, onCompleteRegistration, errors } = this . props ;
207
-
162
+ function renderValidateCodeScreen ( ) {
208
163
if ( view !== VIEWS . VALIDATE || errors . length ) {
209
164
return null ;
210
165
}
211
-
212
166
const verifyProps = {
213
- ...this . props ,
167
+ ...props ,
214
168
// Override the error prop to come from the state instead of props
215
- error,
216
- moreOptionsControl : this . renderBackButtonForVerify ( ) ,
169
+ error : stateError ,
170
+ moreOptionsControl : renderBackButtonForVerify ( ) ,
217
171
// Renaming registration callback so it fits in the Verify context
218
172
onCompleteVerification : onCompleteRegistration ,
219
- onCompleteRegistration : null ,
173
+ onCompleteRegistration : null
220
174
} ;
221
-
222
175
return < TOTPVerifyComponent { ...verifyProps } /> ;
223
176
}
224
177
225
- render ( ) {
226
- return (
227
- < div className = "mfa-totp__container mfa-totp__container--register" >
228
- { this . renderErrorScreen ( ) }
229
- { this . renderScanCodeScreen ( ) }
230
- { this . renderValidateCodeScreen ( ) }
231
- </ div >
232
- ) ;
233
- }
178
+ // Render the component
179
+ return < div className = "mfa-totp__container mfa-totp__container--register" >
180
+ { renderErrorScreen ( ) }
181
+ { renderScanCodeScreen ( ) }
182
+ { renderValidateCodeScreen ( ) }
183
+ </ div > ;
234
184
}
235
185
236
186
Register . propTypes = {
0 commit comments