Skip to content

Commit

Permalink
ENH Convert to functional components
Browse files Browse the repository at this point in the history
  • Loading branch information
emteknetnz committed Jan 8, 2025
1 parent 7b01f05 commit 19ab5c3
Show file tree
Hide file tree
Showing 5 changed files with 857 additions and 829 deletions.
2 changes: 1 addition & 1 deletion client/dist/js/bundle-cms.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion client/dist/js/bundle.js

Large diffs are not rendered by default.

185 changes: 62 additions & 123 deletions client/src/containers/Login.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* global window */

import React, { Component, Fragment } from 'react';
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import api from 'lib/api';
import Verify from 'components/Verify';
Expand All @@ -19,91 +19,61 @@ import { connect } from 'react-redux';
* This component will either render a verification screen or a registration screen depending on
* whether the member has previously registered methods
*/
class Login extends Component {
constructor(props) {
super(props);

this.state = {
loading: false,
verificationCompleted: false,
schema: null,
schemaLoaded: false,
};

this.handleCompleteLogin = this.handleCompleteLogin.bind(this);
this.handleCompleteVerify = this.handleCompleteVerify.bind(this);
}

componentDidMount() {
const { schemaURL, onSetAllMethods } = this.props;

function Login(props) {
const {
schemaURL,
onChooseMethod,
onSetAllMethods,
onSetAvailableMethods,
} = props;

const [loading, setLoading] = useState(false);
const [verificationCompleted, setVerificationCompleted] = useState(false);
const [schema, setSchema] = useState(null);
const [schemaLoaded, setSchemaLoaded] = useState(false);

const availableMethods = schema ? schema.availableMethods : null;
const i18n = window.ss.i18n;

useEffect(() => {
return api(schemaURL)
.then(response => {
if (response.status !== 200) {
this.setState({
schemaLoaded: true, // Triggers an error state - see render()
});
// Triggers an error state - see render
setSchemaLoaded(true);
return Promise.reject();
}
return response.json();
})
.then(schemaData => {
this.setState({
schema: schemaData
});
setSchema(schemaData);
onSetAllMethods(schemaData.allMethods);
})
.catch(() => {}); // noop
}
.catch(() => {}) // noop
, []
});

componentDidUpdate(prevProps, prevState) {
// On initialisation the schema can be blank - @see componentDidMount
if (!this.state.schema) {
useEffect(() => {
if (!availableMethods) {
return;
}
onSetAvailableMethods(availableMethods);

const { availableMethods } = this.state.schema;

// If the schema was previously unset then we're updating from new schema.
if (!prevState.schema) {
this.props.onSetAvailableMethods(availableMethods);
return;
}

// Otherwise there's some change to the schema - we need to update Redux if the available
// methods have changed
const { availableMethods: prevAvailableMethods } = prevState.schema;

const oldList = prevAvailableMethods.map(method => method.urlSegment).sort().toString();
const newList = availableMethods.map(method => method.urlSegment).sort().toString();

if (oldList !== newList) {
this.props.onSetAvailableMethods(availableMethods);
}
}
}, [availableMethods]);

/**
* Handle an event indicating the Verification is complete
*/
handleCompleteVerify() {
const { schema: {
isFullyRegistered,
backupMethod,
registeredMethods,
} } = this.state;

function handleCompleteVerify() {
const { isFullyRegistered, backupMethod, registeredMethods } = schema;
// Mark verification as being completed. The server side will validate any further request -
// this state is just for controlling flow
this.setState({
verificationCompleted: true,
});

setVerificationCompleted(true);
// Redirect if the member is marked as having fully registered MFA
if (isFullyRegistered) {
this.handleCompleteLogin();
handleCompleteLogin();
return;
}

// Check if the backup method should be chosen for the register screen and update redux
if (
registeredMethods
Expand All @@ -112,92 +82,61 @@ class Login extends Component {
method => method.urlSegment === backupMethod.urlSegment
).length === 0
) {
this.props.onChooseMethod(backupMethod);
onChooseMethod(backupMethod);
}
}

/**
* Handle completion of login in it's entirety (all verification steps and any required
* registration steps)
*/
handleCompleteLogin() {
const { complete } = this.state.schema.endpoints;

this.setState({
loading: true,
});
window.location = complete;
function handleCompleteLogin() {
setLoading(true);
window.location = schema.endpoints.complete;
}

/**
* @return {null|Register}
*/
renderRegister() {
const { schema, verificationCompleted } = this.state;

function renderRegister() {
if (!schema
|| !schema.endpoints
|| !schema.endpoints.register
|| (!verificationCompleted && schema.registeredMethods.length)
) {
return null;
}

return (
<Register
{...schema}
onCompleteRegistration={this.handleCompleteLogin}
/>
);
return <Register {...schema} onCompleteRegistration={handleCompleteLogin} />;
}

/**
* @return {null|Verify}
*/
renderVerify() {
const { schema, verificationCompleted } = this.state;

function renderVerify() {
if (!schema || verificationCompleted || !schema.registeredMethods.length) {
return null;
}

return (
<Verify {...schema} onCompleteVerification={this.handleCompleteVerify} />
);
return <Verify {...schema} onCompleteVerification={handleCompleteVerify} />;
}

render() {
const { schema, schemaLoaded, loading } = this.state;
const { ss: { i18n } } = window;

if (!schema || loading) {
if (!schema && schemaLoaded) {
return (
<LoadingError
title={i18n._t('MFALogin.SOMETHING_WENT_WRONG', 'Something went wrong!')}
controls={
<button
type="button"
onClick={() => window.location.reload()}
className="btn btn-outline-secondary"
>
{i18n._t('MFALogin.TRY_AGAIN', 'Try again')}
</button>
}
/>
);
}

return <LoadingIndicator block />;
// Render component
if (!schema || loading) {
if (!schema && schemaLoaded) {
return (
<LoadingError
title={i18n._t('MFALogin.SOMETHING_WENT_WRONG', 'Something went wrong!')}
controls={
<button
type="button"
onClick={() => window.location.reload()}
className="btn btn-outline-secondary"
>
{i18n._t('MFALogin.TRY_AGAIN', 'Try again')}
</button>
}
/>
);
}

return (
<>
{ this.renderRegister() }
{ this.renderVerify() }
</>
);
return <LoadingIndicator block />;
}
return <>
{ renderRegister() }
{ renderVerify() }
</>;
}

Login.propTypes = {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"reactstrap": "^8.9.0",
"reactstrap-confirm": "^1.3.2",
"redux": "^5.0.1",
"regenerator-runtime": "^0.13.11"
"regenerator-runtime": "^0.14.1"
},
"devDependencies": {
"@silverstripe/eslint-config": "^1.3.0",
Expand Down
Loading

0 comments on commit 19ab5c3

Please sign in to comment.