feat: param based redirection (#993)

On welcome page CTA click redirection would be based on next query param.

VAN-1535
This commit is contained in:
Mubbshar Anwar
2023-07-25 16:03:41 +05:00
committed by GitHub
parent 72e601948c
commit f5cb7a1dbd
4 changed files with 80 additions and 52 deletions

View File

@@ -3,7 +3,10 @@ import { COMPLETE_STATE, FAILURE_STATE, PENDING_STATE } from '../../data/constan
export const defaultState = {
fieldDescriptions: {},
optionalFields: {},
optionalFields: {
fields: {},
extended_profile: [],
},
thirdPartyAuthApiStatus: null,
thirdPartyAuthContext: {
currentProvider: null,
@@ -13,6 +16,7 @@ export const defaultState = {
secondaryProviders: [],
pipelineUserDetails: null,
errorMessage: null,
welcomePageRedirectUrl: null,
},
};

View File

@@ -23,12 +23,12 @@ import PropTypes from 'prop-types';
import { Helmet } from 'react-helmet';
import { saveUserProfile } from './data/actions';
import { welcomePageContextSelector } from './data/selectors';
import messages from './messages';
import ProgressiveProfilingPageModal from './ProgressiveProfilingPageModal';
import BaseContainer from '../base-container';
import { RedirectLogistration } from '../common-components';
import { getThirdPartyAuthContext } from '../common-components/data/actions';
import { optionalFieldsSelector } from '../common-components/data/selectors';
import {
COMPLETE_STATE,
DEFAULT_REDIRECT_URL,
@@ -55,6 +55,7 @@ const ProgressiveProfiling = (props) => {
} = props;
const registrationEmbedded = isHostAvailableInQueryParams();
const queryParams = getAllPossibleQueryParams();
const authenticatedUser = getAuthenticatedUser();
const DASHBOARD_URL = getConfig().LMS_BASE_URL.concat(DEFAULT_REDIRECT_URL);
const enablePersonalizedRecommendations = getConfig().ENABLE_PERSONALIZED_RECOMMENDATIONS;
@@ -90,9 +91,9 @@ const ProgressiveProfiling = (props) => {
useEffect(() => {
if (registrationEmbedded) {
getFieldDataFromBackend({ is_welcome_page: true });
getFieldDataFromBackend({ is_welcome_page: true, next: queryParams?.next });
}
}, [registrationEmbedded, getFieldDataFromBackend]);
}, [registrationEmbedded, getFieldDataFromBackend, queryParams?.next]);
useEffect(() => {
if (registrationEmbedded && Object.keys(welcomePageContext).includes('fields')) {
@@ -100,7 +101,8 @@ const ProgressiveProfiling = (props) => {
fields: welcomePageContext.fields,
extendedProfile: welcomePageContext.extended_profile,
});
setRegistrationResult({ redirectUrl: getConfig().SEARCH_CATALOG_URL });
const nextUrl = welcomePageContext.nextUrl ? welcomePageContext.nextUrl : getConfig().SEARCH_CATALOG_URL;
setRegistrationResult({ redirectUrl: nextUrl });
}
}, [registrationEmbedded, welcomePageContext]);
@@ -142,8 +144,6 @@ const ProgressiveProfiling = (props) => {
return null;
}
const queryParams = getAllPossibleQueryParams();
const handleSubmit = (e) => {
e.preventDefault();
window.history.replaceState(location.state, null, '');
@@ -210,10 +210,10 @@ const ProgressiveProfiling = (props) => {
</title>
</Helmet>
<ProgressiveProfilingPageModal isOpen={showModal} redirectUrl={registrationResult.redirectUrl} />
{queryParams?.next && (
{(props.shouldRedirect && welcomePageContext.nextUrl) && (
<RedirectLogistration
success
redirectUrl={queryParams.next}
redirectUrl={registrationResult.redirectUrl}
/>
)}
{props.shouldRedirect && (
@@ -300,6 +300,7 @@ ProgressiveProfiling.propTypes = {
welcomePageContext: PropTypes.shape({
extended_profile: PropTypes.arrayOf(PropTypes.string),
fields: PropTypes.shape({}),
nextUrl: PropTypes.string,
}),
welcomePageContextApiStatus: PropTypes.string,
// Actions
@@ -323,7 +324,7 @@ const mapStateToProps = state => {
shouldRedirect: welcomePageStore.success,
showError: welcomePageStore.showError,
submitState: welcomePageStore.submitState,
welcomePageContext: optionalFieldsSelector(state),
welcomePageContext: welcomePageContextSelector(state),
welcomePageContextApiStatus: state.commonComponents.thirdPartyAuthApiStatus,
};
};

View File

@@ -0,0 +1,14 @@
import { createSelector } from 'reselect';
export const storeName = 'commonComponents';
export const commonComponentsSelector = state => ({ ...state[storeName] });
export const welcomePageContextSelector = createSelector(
commonComponentsSelector,
commonComponents => ({
fields: commonComponents.optionalFields.fields,
extended_profile: commonComponents.optionalFields.extended_profile,
nextUrl: commonComponents.thirdPartyAuthContext.welcomePageRedirectUrl,
}),
);

View File

@@ -70,6 +70,9 @@ describe('ProgressiveProfilingTests', () => {
commonComponents: {
thirdPartyAuthApiStatus: null,
optionalFields: {},
thirdPartyAuthContext: {
welcomePageRedirectUrl: null,
},
},
};
@@ -156,21 +159,6 @@ describe('ProgressiveProfilingTests', () => {
expect(store.dispatch).toHaveBeenCalledWith(saveUserProfile('abc123', formPayload));
});
it('should set host property value to host where iframe is embedded for on ramp experience', async () => {
getAuthenticatedUser.mockReturnValue({ userId: 3, username: 'abc123' });
const expectedEventProperties = {
isGenderSelected: false,
isYearOfBirthSelected: false,
isLevelOfEducationSelected: false,
host: 'http://example.com',
};
delete window.location;
window.location = { href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING), search: '?host=http://example.com' };
const progressiveProfilingPage = await getProgressiveProfilingPage();
progressiveProfilingPage.find('button.btn-brand').simulate('click');
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.submit.clicked', expectedEventProperties);
});
it('should set host property value empty for non-embedded experience', async () => {
getAuthenticatedUser.mockReturnValue({ userId: 3, username: 'abc123' });
const expectedEventProperties = {
@@ -186,17 +174,6 @@ describe('ProgressiveProfilingTests', () => {
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.submit.clicked', expectedEventProperties);
});
it('should set host property value embedded host for on ramp experience for skip link event', async () => {
getAuthenticatedUser.mockReturnValue({ userId: 3, username: 'abc123' });
const host = 'http://example.com';
delete window.location;
window.location = { href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING), search: `?host=${host}` };
const progressiveProfilingPage = await getProgressiveProfilingPage();
progressiveProfilingPage.find('button.btn-link').simulate('click');
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.skip.link.clicked', { host });
});
it('should open modal on pressing skip for now button', async () => {
getAuthenticatedUser.mockReturnValue({ userId: 3, username: 'abc123' });
delete window.location;
@@ -283,21 +260,9 @@ describe('ProgressiveProfilingTests', () => {
mergeConfig({
SEARCH_CATALOG_URL: 'http://localhost/search',
});
const host = 'http://example.com';
delete window.location;
window.location = {
assign: jest.fn().mockImplementation((value) => { window.location.href = value; }),
href: getConfig().BASE_URL,
search: `?variant=${EMBEDDED}`,
};
it('should render fields returned by backend API', async () => {
delete window.location;
window.location = {
assign: jest.fn().mockImplementation((value) => { window.location.href = value; }),
href: getConfig().BASE_URL,
search: `?variant=${EMBEDDED}&host=http://localhost/host-website`,
};
beforeEach(() => {
props = {};
store = mockStore({
...initialState,
@@ -307,6 +272,44 @@ describe('ProgressiveProfilingTests', () => {
optionalFields,
},
});
});
it('should set host property value embedded host for on ramp experience for skip link event', async () => {
delete window.location;
window.location = {
href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING),
search: `?host=${host}&variant=${EMBEDDED}`,
};
const progressiveProfilingPage = await getProgressiveProfilingPage();
progressiveProfilingPage.find('button.btn-link').simulate('click');
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.skip.link.clicked', { host });
});
it('should set host property value to host where iframe is embedded for on ramp experience', async () => {
const expectedEventProperties = {
isGenderSelected: false,
isYearOfBirthSelected: false,
isLevelOfEducationSelected: false,
host: 'http://example.com',
};
delete window.location;
window.location = {
href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING),
search: `?host=${host}`,
};
const progressiveProfilingPage = await getProgressiveProfilingPage();
progressiveProfilingPage.find('button.btn-brand').simulate('click');
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.submit.clicked', expectedEventProperties);
});
it('should render fields returned by backend API', async () => {
delete window.location;
window.location = {
assign: jest.fn().mockImplementation((value) => { window.location.href = value; }),
href: getConfig().BASE_URL,
search: `?variant=${EMBEDDED}&host=${host}`,
};
const progressiveProfilingPage = await getProgressiveProfilingPage();
expect(progressiveProfilingPage.find('#gender').exists()).toBeTruthy();
@@ -319,7 +322,6 @@ describe('ProgressiveProfilingTests', () => {
href: getConfig().BASE_URL,
search: `?variant=${EMBEDDED}`,
};
props = {};
store = mockStore({
...initialState,
commonComponents: {
@@ -338,7 +340,7 @@ describe('ProgressiveProfilingTests', () => {
window.location = {
assign: jest.fn().mockImplementation((value) => { window.location.href = value; }),
href: getConfig().BASE_URL,
search: `?variant=${EMBEDDED}&host=http://localhost/host-website&next=${redirectUrl}`,
search: `?variant=${EMBEDDED}&host=${host}&next=${redirectUrl}`,
};
props = {};
store = mockStore({
@@ -347,6 +349,13 @@ describe('ProgressiveProfilingTests', () => {
...initialState.commonComponents,
thirdPartyAuthApiStatus: COMPLETE_STATE,
optionalFields,
thirdPartyAuthContext: {
welcomePageRedirectUrl: redirectUrl,
},
},
welcomePage: {
...initialState.welcomePage,
success: true,
},
});