diff --git a/src/common-components/data/reducers.js b/src/common-components/data/reducers.js index c2150cda80..08ee0bd734 100644 --- a/src/common-components/data/reducers.js +++ b/src/common-components/data/reducers.js @@ -1,6 +1,8 @@ import { THIRD_PARTY_AUTH_CONTEXT, THIRD_PARTY_AUTH_CONTEXT_CLEAR_ERROR_MSG } from './actions'; import { COMPLETE_STATE, FAILURE_STATE, PENDING_STATE } from '../../data/constants'; +export const storeName = 'commonComponents'; + export const defaultState = { fieldDescriptions: {}, optionalFields: { diff --git a/src/common-components/data/selectors.js b/src/common-components/data/selectors.js deleted file mode 100644 index 2faa24ce07..0000000000 --- a/src/common-components/data/selectors.js +++ /dev/null @@ -1,28 +0,0 @@ -import { createSelector } from 'reselect'; - -export const storeName = 'commonComponents'; - -export const commonComponentsSelector = state => ({ ...state[storeName] }); - -export const thirdPartyAuthContextSelector = createSelector( - commonComponentsSelector, - commonComponents => commonComponents.thirdPartyAuthContext, -); - -export const fieldDescriptionSelector = createSelector( - commonComponentsSelector, - commonComponents => commonComponents.fieldDescriptions, -); - -export const optionalFieldsSelector = createSelector( - commonComponentsSelector, - commonComponents => commonComponents.optionalFields, -); - -export const tpaProvidersSelector = createSelector( - commonComponentsSelector, - commonComponents => ({ - providers: commonComponents.thirdPartyAuthContext.providers, - secondaryProviders: commonComponents.thirdPartyAuthContext.secondaryProviders, - }), -); diff --git a/src/common-components/index.jsx b/src/common-components/index.jsx index 1334873c10..f3f16198e3 100644 --- a/src/common-components/index.jsx +++ b/src/common-components/index.jsx @@ -9,7 +9,7 @@ export { default as InstitutionLogistration } from './InstitutionLogistration'; export { RenderInstitutionButton } from './InstitutionLogistration'; export { default as reducer } from './data/reducers'; export { default as saga } from './data/sagas'; -export { storeName } from './data/selectors'; +export { storeName } from './data/reducers'; export { default as FormGroup } from './FormGroup'; export { default as PasswordField } from './PasswordField'; export { default as Zendesk } from './Zendesk'; diff --git a/src/login/LoginPage.jsx b/src/login/LoginPage.jsx index 6281572675..c523da957c 100644 --- a/src/login/LoginPage.jsx +++ b/src/login/LoginPage.jsx @@ -1,9 +1,9 @@ import React, { useEffect, useMemo, useState } from 'react'; -import { connect } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { getConfig } from '@edx/frontend-platform'; import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics'; -import { injectIntl, useIntl } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { Form, StatefulButton, } from '@openedx/paragon'; @@ -14,7 +14,7 @@ import { Link } from 'react-router-dom'; import AccountActivationMessage from './AccountActivationMessage'; import { - backupLoginFormBegin, + backupLoginFormBegin as backupFormState, dismissPasswordResetBanner, loginRequest, } from './data/actions'; @@ -28,12 +28,11 @@ import { RedirectLogistration, ThirdPartyAuthAlert, } from '../common-components'; -import { getThirdPartyAuthContext } from '../common-components/data/actions'; -import { thirdPartyAuthContextSelector } from '../common-components/data/selectors'; +import { getThirdPartyAuthContext as getTPADataFromBackend } from '../common-components/data/actions'; import EnterpriseSSO from '../common-components/EnterpriseSSO'; import ThirdPartyAuth from '../common-components/ThirdPartyAuth'; import { - DEFAULT_STATE, PENDING_STATE, RESET_PAGE, + PENDING_STATE, RESET_PAGE, } from '../data/constants'; import { getActivationStatus, @@ -45,33 +44,31 @@ import { import ResetPasswordSuccess from '../reset-password/ResetPasswordSuccess'; const LoginPage = (props) => { + const dispatch = useDispatch(); + const { formatMessage } = useIntl(); + const backedUpFormData = useSelector(state => state.login.loginFormData); + const loginErrorCode = useSelector(state => state.login.loginErrorCode); + const loginErrorContext = useSelector(state => state.login.loginErrorContext); + const loginResult = useSelector(state => state.login.loginResult); + const shouldBackupState = useSelector(state => state.login.shouldBackupState); + const showResetPasswordSuccessBanner = useSelector(state => state.login.showResetPasswordSuccessBanner); + const submitState = useSelector(state => state.login.submitState); + + const thirdPartyAuthApiStatus = useSelector(state => state.commonComponents.thirdPartyAuthApiStatus); + const providers = useSelector(state => state.commonComponents.thirdPartyAuthContext.providers); + const currentProvider = useSelector(state => state.commonComponents.thirdPartyAuthContext.currentProvider); + const secondaryProviders = useSelector(state => state.commonComponents.thirdPartyAuthContext.secondaryProviders); + const finishAuthUrl = useSelector(state => state.commonComponents.thirdPartyAuthContext.finishAuthUrl); + const platformName = useSelector(state => state.commonComponents.thirdPartyAuthContext.platformName); + const thirdPartyErrorMessage = useSelector(state => state.commonComponents.thirdPartyAuthContext.errorMessage); + const { - backedUpFormData, - loginErrorCode, - loginErrorContext, - loginResult, - shouldBackupState, - thirdPartyAuthContext: { - providers, - currentProvider, - secondaryProviders, - finishAuthUrl, - platformName, - errorMessage: thirdPartyErrorMessage, - }, - thirdPartyAuthApiStatus, institutionLogin, - showResetPasswordSuccessBanner, - submitState, - // Actions - backupFormState, handleInstitutionLogin, - getTPADataFromBackend, } = props; - const { formatMessage } = useIntl(); + const activationMsgType = getActivationStatus(); const queryParams = useMemo(() => getAllPossibleQueryParams(), []); - const [formFields, setFormFields] = useState({ ...backedUpFormData.formFields }); const [errorCode, setErrorCode] = useState({ type: '', count: 0, context: {} }); const [errors, setErrors] = useState({ ...backedUpFormData.errors }); @@ -86,19 +83,20 @@ const LoginPage = (props) => { if (tpaHint) { payload.tpa_hint = tpaHint; } - getTPADataFromBackend(payload); - }, [getTPADataFromBackend, queryParams, tpaHint]); + dispatch(getTPADataFromBackend(payload)); + }, [dispatch, queryParams, tpaHint]); + /** * Backup the login form in redux when login page is toggled. */ useEffect(() => { if (shouldBackupState) { - backupFormState({ + dispatch(backupFormState({ formFields: { ...formFields }, errors: { ...errors }, - }); + })); } - }, [shouldBackupState, formFields, errors, backupFormState]); + }, [shouldBackupState, formFields, errors, dispatch]); useEffect(() => { if (loginErrorCode) { @@ -141,7 +139,7 @@ const LoginPage = (props) => { const handleSubmit = (event) => { event.preventDefault(); if (showResetPasswordSuccessBanner) { - props.dismissPasswordResetBanner(); + dispatch(dismissPasswordResetBanner()); } const formData = { ...formFields }; @@ -158,7 +156,7 @@ const LoginPage = (props) => { password: formData.password, ...queryParams, }; - props.loginRequest(payload); + dispatch(loginRequest(payload)); }; const handleOnChange = (event) => { @@ -281,88 +279,10 @@ const LoginPage = (props) => { ); }; -const mapStateToProps = state => { - const loginPageState = state.login; - return { - backedUpFormData: loginPageState.loginFormData, - loginErrorCode: loginPageState.loginErrorCode, - loginErrorContext: loginPageState.loginErrorContext, - loginResult: loginPageState.loginResult, - shouldBackupState: loginPageState.shouldBackupState, - showResetPasswordSuccessBanner: loginPageState.showResetPasswordSuccessBanner, - submitState: loginPageState.submitState, - thirdPartyAuthContext: thirdPartyAuthContextSelector(state), - thirdPartyAuthApiStatus: state.commonComponents.thirdPartyAuthApiStatus, - }; -}; - LoginPage.propTypes = { - backedUpFormData: PropTypes.shape({ - formFields: PropTypes.shape({}), - errors: PropTypes.shape({}), - }), - loginErrorCode: PropTypes.string, - loginErrorContext: PropTypes.shape({ - email: PropTypes.string, - redirectUrl: PropTypes.string, - context: PropTypes.shape({}), - }), - loginResult: PropTypes.shape({ - redirectUrl: PropTypes.string, - success: PropTypes.bool, - }), - shouldBackupState: PropTypes.bool, - showResetPasswordSuccessBanner: PropTypes.bool, - submitState: PropTypes.string, - thirdPartyAuthApiStatus: PropTypes.string, institutionLogin: PropTypes.bool.isRequired, - thirdPartyAuthContext: PropTypes.shape({ - currentProvider: PropTypes.string, - errorMessage: PropTypes.string, - platformName: PropTypes.string, - providers: PropTypes.arrayOf(PropTypes.shape({})), - secondaryProviders: PropTypes.arrayOf(PropTypes.shape({})), - finishAuthUrl: PropTypes.string, - }), // Actions - backupFormState: PropTypes.func.isRequired, - dismissPasswordResetBanner: PropTypes.func.isRequired, - loginRequest: PropTypes.func.isRequired, - getTPADataFromBackend: PropTypes.func.isRequired, handleInstitutionLogin: PropTypes.func.isRequired, }; -LoginPage.defaultProps = { - backedUpFormData: { - formFields: { - emailOrUsername: '', password: '', - }, - errors: { - emailOrUsername: '', password: '', - }, - }, - loginErrorCode: null, - loginErrorContext: {}, - loginResult: {}, - shouldBackupState: false, - showResetPasswordSuccessBanner: false, - submitState: DEFAULT_STATE, - thirdPartyAuthApiStatus: PENDING_STATE, - thirdPartyAuthContext: { - currentProvider: null, - errorMessage: null, - finishAuthUrl: null, - providers: [], - secondaryProviders: [], - }, -}; - -export default connect( - mapStateToProps, - { - backupFormState: backupLoginFormBegin, - dismissPasswordResetBanner, - loginRequest, - getTPADataFromBackend: getThirdPartyAuthContext, - }, -)(injectIntl(LoginPage)); +export default LoginPage; diff --git a/src/login/tests/LoginPage.test.jsx b/src/login/tests/LoginPage.test.jsx index 9c337bf25e..c12aeb131f 100644 --- a/src/login/tests/LoginPage.test.jsx +++ b/src/login/tests/LoginPage.test.jsx @@ -40,8 +40,18 @@ describe('LoginPage', () => { ); + const loginFormData = { + formFields: { + emailOrUsername: '', password: '', + }, + errors: { + emailOrUsername: '', password: '', + }, + }; + const initialState = { login: { + loginFormData, loginResult: { success: false, redirectUrl: '' }, }, commonComponents: { diff --git a/src/logistration/Logistration.jsx b/src/logistration/Logistration.jsx index 9451aa2745..032a37cc61 100644 --- a/src/logistration/Logistration.jsx +++ b/src/logistration/Logistration.jsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { connect } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { getConfig } from '@edx/frontend-platform'; import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics'; @@ -16,9 +16,6 @@ import { Navigate, useNavigate } from 'react-router-dom'; import BaseContainer from '../base-container'; import { clearThirdPartyAuthContextErrorMessage } from '../common-components/data/actions'; -import { - tpaProvidersSelector, -} from '../common-components/data/selectors'; import messages from '../common-components/messages'; import { LOGIN_PAGE, REGISTER_PAGE } from '../data/constants'; import { @@ -30,11 +27,8 @@ import { RegistrationPage } from '../register'; import { backupRegistrationForm } from '../register/data/actions'; const Logistration = (props) => { - const { selectedPage, tpaProviders } = props; + const { selectedPage } = props; const tpaHint = getTpaHint(); - const { - providers, secondaryProviders, - } = tpaProviders; const { formatMessage } = useIntl(); const [institutionLogin, setInstitutionLogin] = useState(false); const [key, setKey] = useState(''); @@ -42,6 +36,10 @@ const Logistration = (props) => { const disablePublicAccountCreation = getConfig().ALLOW_PUBLIC_ACCOUNT_CREATION === false; const hideRegistrationLink = getConfig().SHOW_REGISTRATION_LINKS === false; + const dispatch = useDispatch(); + const providers = useSelector(state => state.commonComponents.thirdPartyAuthContext.providers); + const secondaryProviders = useSelector(state => state.commonComponents.thirdPartyAuthContext.secondaryProviders); + useEffect(() => { const authService = getAuthService(); if (authService) { @@ -71,11 +69,11 @@ const Logistration = (props) => { return; } sendTrackEvent(`edx.bi.${tabKey.replace('/', '')}_form.toggled`, { category: 'user-engagement' }); - props.clearThirdPartyAuthContextErrorMessage(); + dispatch(clearThirdPartyAuthContextErrorMessage()); if (tabKey === LOGIN_PAGE) { - props.backupRegistrationForm(); + dispatch(backupRegistrationForm()); } else if (tabKey === REGISTER_PAGE) { - props.backupLoginForm(); + dispatch(backupLoginForm()); } setKey(tabKey); }; @@ -156,35 +154,10 @@ const Logistration = (props) => { Logistration.propTypes = { selectedPage: PropTypes.string, - backupLoginForm: PropTypes.func.isRequired, - backupRegistrationForm: PropTypes.func.isRequired, - clearThirdPartyAuthContextErrorMessage: PropTypes.func.isRequired, - tpaProviders: PropTypes.shape({ - providers: PropTypes.arrayOf(PropTypes.shape({})), - secondaryProviders: PropTypes.arrayOf(PropTypes.shape({})), - }), -}; - -Logistration.defaultProps = { - tpaProviders: { - providers: [], - secondaryProviders: [], - }, }; Logistration.defaultProps = { selectedPage: REGISTER_PAGE, }; -const mapStateToProps = state => ({ - tpaProviders: tpaProvidersSelector(state), -}); - -export default connect( - mapStateToProps, - { - backupLoginForm, - backupRegistrationForm, - clearThirdPartyAuthContextErrorMessage, - }, -)(Logistration); +export default Logistration; diff --git a/src/logistration/Logistration.test.jsx b/src/logistration/Logistration.test.jsx index 87bf3e705e..bfbf1c1ad3 100644 --- a/src/logistration/Logistration.test.jsx +++ b/src/logistration/Logistration.test.jsx @@ -43,6 +43,15 @@ describe('Logistration', () => { ); + const loginFormData = { + formFields: { + emailOrUsername: '', password: '', + }, + errors: { + emailOrUsername: '', password: '', + }, + }; + const initialState = { register: { registrationFormData: { @@ -71,6 +80,7 @@ describe('Logistration', () => { }, }, login: { + loginFormData, loginResult: { success: false, redirectUrl: '' }, }, };