Skip to content

Commit 84e844a

Browse files
committed
ENH Convert to functional components
1 parent 82cb034 commit 84e844a

File tree

4 files changed

+987
-984
lines changed

4 files changed

+987
-984
lines changed

client/dist/js/bundle.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/src/components/TOTP/Register.js

+103-153
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* global window */
22

3-
import React, { Component } from 'react';
3+
import React, { useState } from 'react';
44
import PropTypes from 'prop-types';
55
import { QRCodeSVG } from 'qrcode.react';
66
import { formatCode } from 'lib/formatCode';
@@ -15,222 +15,172 @@ const VIEWS = {
1515
* This component provides the user interface for registering one-time time-based passwords (TOTP)
1616
* with a user.
1717
*/
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;
3132

3233
/**
3334
* Send the user back to the "select method" screen
3435
*/
35-
handleBack() {
36-
this.props.onBack();
36+
function handleBack() {
37+
onBack();
3738
}
3839

3940
/**
4041
* Send the user back to the "scan QR code" screen
4142
*/
42-
handleBackToScan() {
43-
this.setState({
44-
view: VIEWS.SCAN,
45-
error: null,
46-
});
43+
function handleBackToScan() {
44+
setView(VIEWS.SCAN);
45+
setStateError(null);
4746
}
4847

4948
/**
5049
* After user has scanned the QR code, handle the transition to the verify screen
5150
*/
52-
handleNext() {
53-
this.setState({ view: VIEWS.VALIDATE });
51+
function handleNext() {
52+
setView(VIEWS.VALIDATE);
5453
}
5554

5655
/**
5756
* Renders an action button menu with a Next and Back button, using a different handler for
5857
* the click of each button depending on which view we're in.
59-
*
60-
* @returns {HTMLElement}
6158
*/
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>;
8780
}
8881

8982
/**
9083
* Handles rendering of errors returned from the backend API requests, e.g.
9184
* your session has timed out.
92-
*
93-
* @returns {HTMLElement}
9485
*/
95-
renderErrorScreen() {
96-
const { errors } = this.props;
97-
86+
function renderErrorScreen() {
9887
if (!errors.length) {
9988
return null;
10089
}
90+
return <div className="mfa-totp__errors">
91+
{errors.join(', ')}
92+
</div>;
93+
}
10194

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>;
107107
}
108108

109109
/**
110110
* Renders the screen to scan a QR code with an authenticator app.
111-
*
112-
* @returns {HTMLElement}
113111
*/
114-
renderScanCodeScreen() {
115-
const { uri, code, errors } = this.props;
116-
const { view } = this.state;
117-
const { ss: { i18n } } = window;
118-
112+
function renderScanCodeScreen() {
119113
if (view !== VIEWS.SCAN || errors.length) {
120114
return null;
121115
}
122-
123116
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>
151138
</div>
152139
</div>
153-
{ this.renderActionsMenu() }
154140
</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>;
177143
}
178144

179145
/**
180146
* The back button for the verification screen should send you back to the register screen
181-
*
182-
* @return HTMLElement|null
183147
*/
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>;
196156
}
197157

198158
/**
199159
* Renders the screen to input and validate the TOTP code, after having registered it via QR
200160
* code with an authenticator app.
201-
*
202-
* @returns {HTMLElement}
203161
*/
204-
renderValidateCodeScreen() {
205-
const { error, view } = this.state;
206-
const { TOTPVerifyComponent, onCompleteRegistration, errors } = this.props;
207-
162+
function renderValidateCodeScreen() {
208163
if (view !== VIEWS.VALIDATE || errors.length) {
209164
return null;
210165
}
211-
212166
const verifyProps = {
213-
...this.props,
167+
...props,
214168
// Override the error prop to come from the state instead of props
215-
error,
216-
moreOptionsControl: this.renderBackButtonForVerify(),
169+
error: stateError,
170+
moreOptionsControl: renderBackButtonForVerify(),
217171
// Renaming registration callback so it fits in the Verify context
218172
onCompleteVerification: onCompleteRegistration,
219-
onCompleteRegistration: null,
173+
onCompleteRegistration: null
220174
};
221-
222175
return <TOTPVerifyComponent {...verifyProps} />;
223176
}
224177

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>;
234184
}
235185

236186
Register.propTypes = {

0 commit comments

Comments
 (0)