feat: allow embedded experience to open register page for authenticated users (#945)

VAN-1482
This commit is contained in:
Syed Sajjad Hussain Shah
2023-06-15 14:42:09 +05:00
committed by GitHub
parent 2a2c5abc81
commit d41c06b1fd
6 changed files with 83 additions and 20 deletions

View File

@@ -19,7 +19,7 @@ const RedirectLogistration = (props) => {
redirectToRecommendationsPage,
educationLevel,
userId,
isRegistrationEmbedded,
registrationEmbedded,
} = props;
let finalRedirectUrl = '';
@@ -39,7 +39,7 @@ const RedirectLogistration = (props) => {
// TODO: Do we still need this cookie?
setCookie('van-504-returning-user', true);
if (isRegistrationEmbedded) {
if (registrationEmbedded) {
window.parent.postMessage({ action: REDIRECT, redirectUrl: `${window.location.origin}${AUTHN_PROGRESSIVE_PROFILING}` }, DISCOVER_URL);
return null;
}
@@ -87,7 +87,7 @@ RedirectLogistration.defaultProps = {
optionalFields: {},
redirectToRecommendationsPage: false,
userId: null,
isRegistrationEmbedded: false,
registrationEmbedded: false,
};
RedirectLogistration.propTypes = {
@@ -99,7 +99,7 @@ RedirectLogistration.propTypes = {
optionalFields: PropTypes.shape({}),
redirectToRecommendationsPage: PropTypes.bool,
userId: PropTypes.number,
isRegistrationEmbedded: PropTypes.bool,
registrationEmbedded: PropTypes.bool,
};
export default RedirectLogistration;

View File

@@ -2,9 +2,13 @@ import React, { useEffect, useState } from 'react';
import { getConfig } from '@edx/frontend-platform';
import { fetchAuthenticatedUser, getAuthenticatedUser } from '@edx/frontend-platform/auth';
import PropTypes from 'prop-types';
import { Route } from 'react-router-dom';
import { DEFAULT_REDIRECT_URL } from '../data/constants';
import {
DEFAULT_REDIRECT_URL, REGISTER_PAGE,
} from '../data/constants';
import { isRegistrationEmbedded } from '../data/utils/dataUtils';
/**
* This wrapper redirects the requester to our default redirect url if they are
@@ -13,13 +17,20 @@ import { DEFAULT_REDIRECT_URL } from '../data/constants';
const UnAuthOnlyRoute = (props) => {
const [authUser, setAuthUser] = useState({});
const [isReady, setIsReady] = useState(false);
const registrationEmbedded = isRegistrationEmbedded() && props.path === REGISTER_PAGE;
useEffect(() => {
if (registrationEmbedded) { return; }
fetchAuthenticatedUser({ forceRefresh: !!getAuthenticatedUser() }).then((authenticatedUser) => {
setAuthUser(authenticatedUser);
setIsReady(true);
});
}, []);
}, [registrationEmbedded]);
// Show registration page for embedded experience even if the user is authenticated
if (registrationEmbedded) {
return <Route {...props} />;
}
if (isReady) {
if (authUser && authUser.username) {
@@ -33,4 +44,8 @@ const UnAuthOnlyRoute = (props) => {
return null;
};
UnAuthOnlyRoute.propTypes = {
path: PropTypes.string.isRequired,
};
export default UnAuthOnlyRoute;

View File

@@ -2,12 +2,13 @@
/* eslint-disable react/function-component-definition */
import React from 'react';
import { getConfig } from '@edx/frontend-platform';
import { fetchAuthenticatedUser, getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { mount } from 'enzyme';
import { act } from 'react-dom/test-utils';
import { UnAuthOnlyRoute } from '..';
import { LOGIN_PAGE } from '../../data/constants';
import { REGISTER_PAGE } from '../../data/constants';
import { MemoryRouter, BrowserRouter as Router, Switch } from 'react-router-dom';
@@ -26,7 +27,7 @@ const TestApp = () => (
<Router>
<div>
<Switch>
<UnAuthOnlyRoute path={LOGIN_PAGE} render={() => (<span>Login Page</span>)} />
<UnAuthOnlyRoute path={REGISTER_PAGE} render={() => (<span>Register Page</span>)} />
</Switch>
</div>
</Router>
@@ -34,7 +35,7 @@ const TestApp = () => (
describe('UnAuthOnlyRoute', () => {
const routerWrapper = () => (
<MemoryRouter initialEntries={[LOGIN_PAGE]}>
<MemoryRouter initialEntries={[REGISTER_PAGE]}>
<TestApp />
</MemoryRouter>
);
@@ -69,4 +70,44 @@ describe('UnAuthOnlyRoute', () => {
expect(fetchAuthenticatedUser).toBeCalledWith({ forceRefresh: false });
});
it('should not route to register page for authenticated users with non-embedded/normal experience', async () => {
const user = {
username: 'gonzo',
other: 'data',
};
getAuthenticatedUser.mockReturnValue(user);
fetchAuthenticatedUser.mockReturnValueOnce(Promise.resolve(user));
let registerPage = null;
await act(async () => {
registerPage = await mount(routerWrapper());
});
expect(registerPage.find('span').exists()).toBeFalsy();
});
it('should route to register page for authenticated users with embedded experience', async () => {
const user = {
username: 'gonzo',
other: 'data',
};
delete window.location;
window.location = { href: getConfig().BASE_URL.concat(REGISTER_PAGE), search: '?variant=embedded' };
getAuthenticatedUser.mockReturnValue(user);
fetchAuthenticatedUser.mockReturnValueOnce(Promise.resolve(user));
let registerPage = null;
await act(async () => {
registerPage = await mount(routerWrapper());
});
expect(registerPage.find('span').exists()).toBeTruthy();
expect(registerPage.find('span').text()).toBe('Register Page');
});
});

View File

@@ -1,7 +1,7 @@
// Utility functions
import * as QueryString from 'query-string';
import { AUTH_PARAMS } from '../constants';
import { AUTH_PARAMS, EMBEDDED } from '../constants';
export const getTpaProvider = (tpaHintProvider, primaryProviders, secondaryProviders) => {
let tpaProvider = null;
@@ -76,3 +76,8 @@ export const windowScrollTo = (options) => {
return window.scrollTo(options.top, options.left);
};
export const isRegistrationEmbedded = () => {
const queryParams = getAllPossibleQueryParams();
return queryParams?.variant === EMBEDDED;
};

View File

@@ -20,10 +20,11 @@ import {
tpaProvidersSelector,
} from '../common-components/data/selectors';
import messages from '../common-components/messages';
import { EMBEDDED, LOGIN_PAGE, REGISTER_PAGE } from '../data/constants';
import { LOGIN_PAGE, REGISTER_PAGE } from '../data/constants';
import {
getAllPossibleQueryParams, getTpaHint, getTpaProvider, updatePathWithQueryParams,
getTpaHint, getTpaProvider, updatePathWithQueryParams,
} from '../data/utils';
import { isRegistrationEmbedded } from '../data/utils/dataUtils';
import { LoginPage } from '../login';
import { RegistrationPage } from '../register';
import { backupRegistrationForm } from '../register/data/actions';
@@ -38,7 +39,7 @@ const Logistration = (props) => {
const [institutionLogin, setInstitutionLogin] = useState(false);
const [key, setKey] = useState('');
const disablePublicAccountCreation = getConfig().ALLOW_PUBLIC_ACCOUNT_CREATION === false;
const isRegistrationEmbedded = getAllPossibleQueryParams()?.variant === EMBEDDED && selectedPage === REGISTER_PAGE;
const registrationEmbedded = isRegistrationEmbedded() && selectedPage === REGISTER_PAGE;
useEffect(() => {
const authService = getAuthService();
@@ -109,7 +110,7 @@ const Logistration = (props) => {
<Tab title={tabTitle} eventKey={selectedPage === LOGIN_PAGE ? LOGIN_PAGE : REGISTER_PAGE} />
</Tabs>
)
: (!isRegistrationEmbedded && !isValidTpaHint() && (
: (!registrationEmbedded && !isValidTpaHint() && (
<Tabs defaultActiveKey={selectedPage} id="controlled-tab" onSelect={handleOnSelect}>
<Tab title={formatMessage(messages['logistration.register'])} eventKey={REGISTER_PAGE} />
<Tab title={formatMessage(messages['logistration.sign.in'])} eventKey={LOGIN_PAGE} />
@@ -133,7 +134,7 @@ const Logistration = (props) => {
</div>
);
return (
isRegistrationEmbedded ? (
registrationEmbedded ? (
renderLogistrationTabs()
) : (
<BaseComponent>

View File

@@ -48,11 +48,12 @@ import {
import EnterpriseSSO from '../common-components/EnterpriseSSO';
import {
COMPLETE_STATE, DEFAULT_STATE,
EMBEDDED, INVALID_NAME_REGEX, LETTER_REGEX, NUMBER_REGEX, PENDING_STATE, REGISTER_PAGE, VALID_EMAIL_REGEX,
INVALID_NAME_REGEX, LETTER_REGEX, NUMBER_REGEX, PENDING_STATE, REGISTER_PAGE, VALID_EMAIL_REGEX,
} from '../data/constants';
import {
getAllPossibleQueryParams, getTpaHint, getTpaProvider, setCookie,
} from '../data/utils';
import { isRegistrationEmbedded } from '../data/utils/dataUtils';
const emailRegex = new RegExp(VALID_EMAIL_REGEX, 'i');
const urlRegex = new RegExp(INVALID_NAME_REGEX);
@@ -87,7 +88,7 @@ const RegistrationPage = (props) => {
const { formatMessage } = useIntl();
const countryList = useMemo(() => getCountryList(getLocale()), []);
const queryParams = useMemo(() => getAllPossibleQueryParams(), []);
const isRegistrationEmbedded = queryParams?.variant === EMBEDDED;
const registrationEmbedded = isRegistrationEmbedded();
const tpaHint = useMemo(() => getTpaHint(), []);
const flags = {
showConfigurableEdxFields: getConfig().SHOW_CONFIGURABLE_EDX_FIELDS,
@@ -520,7 +521,7 @@ const RegistrationPage = (props) => {
redirectUrl={registrationResult.redirectUrl}
finishAuthUrl={finishAuthUrl}
optionalFields={optionalFields}
isRegistrationEmbedded={isRegistrationEmbedded}
registrationEmbedded={registrationEmbedded}
redirectToProgressiveProfilingPage={
getConfig().ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN && Object.keys(optionalFields).includes('fields')
}
@@ -533,7 +534,7 @@ const RegistrationPage = (props) => {
<div
className={classNames(
'mw-xs mt-3',
{ 'w-100 m-auto': isRegistrationEmbedded },
{ 'w-100 m-auto': registrationEmbedded },
)}
>
<ThirdPartyAuthAlert
@@ -619,7 +620,7 @@ const RegistrationPage = (props) => {
onClick={handleSubmit}
onMouseDown={(e) => e.preventDefault()}
/>
{!isRegistrationEmbedded && (
{!registrationEmbedded && (
<ThirdPartyAuth
currentProvider={currentProvider}
providers={providers}