Files
frontend-app-authn/src/progressive-profiling/ProgressiveProfiling.jsx
Syed Sajjad Hussain Shah 94151c2668 fix: pass user id as string in optimizely track event (#794)
Co-authored-by: Syed Sajjad  Hussain Shah <syed.sajjad@H7FKF7K6XD.local>
2023-03-28 15:15:38 +05:00

267 lines
9.5 KiB
JavaScript

import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { getConfig, snakeCaseObject } from '@edx/frontend-platform';
import { identifyAuthenticatedUser, sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
import {
AxiosJwtAuthService,
configure as configureAuth,
ensureAuthenticatedUser,
getAuthenticatedUser,
hydrateAuthenticatedUser,
} from '@edx/frontend-platform/auth';
import { injectIntl } from '@edx/frontend-platform/i18n';
import { getLoggingService } from '@edx/frontend-platform/logging';
import {
Alert,
Form,
Hyperlink,
StatefulButton,
} from '@edx/paragon';
import { Error } from '@edx/paragon/icons';
import PropTypes from 'prop-types';
import { Helmet } from 'react-helmet';
import BaseComponent from '../base-component';
import { RedirectLogistration } from '../common-components';
import {
DEFAULT_REDIRECT_URL, DEFAULT_STATE, FAILURE_STATE,
} from '../data/constants';
import { getAllPossibleQueryParams } from '../data/utils';
import FormFieldRenderer from '../field-renderer';
import {
activateRecommendationsExperiment, RECOMMENDATIONS_EXP_VARIATION, trackRecommendationViewedOptimizely,
} from '../recommendations/optimizelyExperiment';
import { trackRecommendationsGroup, trackRecommendationsViewed } from '../recommendations/track';
import { saveUserProfile } from './data/actions';
import { welcomePageSelector } from './data/selectors';
import messages from './messages';
import ProgressiveProfilingPageModal from './ProgressiveProfilingPageModal';
const ProgressiveProfiling = (props) => {
const {
formRenderState, intl, submitState, showError, location,
} = props;
const enablePersonalizedRecommendations = getConfig().ENABLE_PERSONALIZED_RECOMMENDATIONS;
const registrationResponse = location.state?.registrationResult;
const [ready, setReady] = useState(false);
const [registrationResult, setRegistrationResult] = useState({ redirectUrl: '' });
const [values, setValues] = useState({});
const [openDialog, setOpenDialog] = useState(false);
const [showRecommendationsPage, setShowRecommendationsPage] = useState(false);
const authenticatedUser = getAuthenticatedUser();
const DASHBOARD_URL = getConfig().LMS_BASE_URL.concat(DEFAULT_REDIRECT_URL);
useEffect(() => {
configureAuth(AxiosJwtAuthService, { loggingService: getLoggingService(), config: getConfig() });
ensureAuthenticatedUser(DASHBOARD_URL)
.then(() => {
hydrateAuthenticatedUser().then(() => {
setReady(true);
});
})
.catch(() => {});
if (registrationResponse) {
setRegistrationResult(registrationResponse);
}
}, [DASHBOARD_URL, registrationResponse]);
useEffect(() => {
if (registrationResponse && authenticatedUser?.userId) {
identifyAuthenticatedUser(authenticatedUser.userId);
sendPageEvent('login_and_registration', 'welcome');
}
}, [authenticatedUser, registrationResponse]);
useEffect(() => {
if (registrationResponse && authenticatedUser?.userId) {
const queryParams = getAllPossibleQueryParams(registrationResponse.redirectUrl);
if (enablePersonalizedRecommendations && !('enrollment_action' in queryParams)) {
const userIdStr = authenticatedUser.userId.toString();
const variation = activateRecommendationsExperiment(userIdStr);
const showRecommendations = variation === RECOMMENDATIONS_EXP_VARIATION;
trackRecommendationsGroup(variation, authenticatedUser.userId);
trackRecommendationViewedOptimizely(userIdStr);
setShowRecommendationsPage(showRecommendations);
if (!showRecommendations) {
trackRecommendationsViewed([], true, authenticatedUser.userId);
}
}
}
}, [authenticatedUser, enablePersonalizedRecommendations, registrationResponse]);
if (!location.state || !location.state.registrationResult || formRenderState === FAILURE_STATE) {
global.location.assign(DASHBOARD_URL);
return null;
}
if (!ready) {
return null;
}
const optionalFields = location.state.optionalFields.fields;
const extendedProfile = location.state.optionalFields.extended_profile;
const handleSubmit = (e) => {
e.preventDefault();
window.history.replaceState(location.state, null, '');
const payload = { ...values, extendedProfile: [] };
if (Object.keys(extendedProfile).length > 0) {
extendedProfile.forEach(fieldName => {
if (values[fieldName]) {
payload.extendedProfile.push({ fieldName, fieldValue: values[fieldName] });
}
delete payload[fieldName];
});
}
props.saveUserProfile(authenticatedUser.username, snakeCaseObject(payload));
sendTrackEvent(
'edx.bi.welcome.page.submit.clicked',
{
isGenderSelected: !!values.gender,
isYearOfBirthSelected: !!values.year_of_birth,
isLevelOfEducationSelected: !!values.level_of_education,
},
);
};
const handleSkip = (e) => {
e.preventDefault();
window.history.replaceState(props.location.state, null, '');
setOpenDialog(true);
sendTrackEvent('edx.bi.welcome.page.skip.link.clicked');
};
const onChangeHandler = (e) => {
if (e.target.type === 'checkbox') {
setValues({ ...values, [e.target.name]: e.target.checked });
} else {
setValues({ ...values, [e.target.name]: e.target.value });
}
};
const formFields = Object.keys(optionalFields).map((fieldName) => {
const fieldData = optionalFields[fieldName];
return (
<span key={fieldData.name}>
<FormFieldRenderer
fieldData={fieldData}
value={values[fieldData.name]}
onChangeHandler={onChangeHandler}
/>
</span>
);
});
return (
<>
<BaseComponent showWelcomeBanner>
<Helmet>
<title>{intl.formatMessage(messages['progressive.profiling.page.title'],
{ siteName: getConfig().SITE_NAME })}
</title>
</Helmet>
<ProgressiveProfilingPageModal isOpen={openDialog} redirectUrl={registrationResult.redirectUrl} />
{props.shouldRedirect ? (
<RedirectLogistration
success
redirectUrl={registrationResult.redirectUrl}
redirectToRecommendationsPage={showRecommendationsPage}
educationLevel={values?.level_of_education}
userId={authenticatedUser?.userId}
/>
) : null}
<div className="mw-xs pp-page-content">
<div>
<h2 className="pp-page-heading text-primary">{intl.formatMessage(messages['progressive.profiling.page.heading'])}</h2>
</div>
<hr className="border-light-700 mb-4" />
{showError ? (
<Alert id="pp-page-errors" className="mb-3" variant="danger" icon={Error}>
<Alert.Heading>{intl.formatMessage(messages['welcome.page.error.heading'])}</Alert.Heading>
<p>{intl.formatMessage(messages['welcome.page.error.message'])}</p>
</Alert>
) : null}
<Form>
{formFields}
{(getConfig().AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK) && (
<span className="progressive-profiling-support">
<Hyperlink
isInline
variant="muted"
destination={getConfig().AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK}
target="_blank"
showLaunchIcon={false}
onClick={() => (sendTrackEvent('edx.bi.welcome.page.support.link.clicked'))}
>
{intl.formatMessage(messages['optional.fields.information.link'])}
</Hyperlink>
</span>
)}
<div className="d-flex mt-4 mb-3">
<StatefulButton
type="submit"
variant="brand"
className="login-button-width"
state={submitState}
labels={{
default: showRecommendationsPage ? intl.formatMessage(messages['optional.fields.next.button']) : intl.formatMessage(messages['optional.fields.submit.button']),
pending: '',
}}
onClick={handleSubmit}
onMouseDown={(e) => e.preventDefault()}
/>
<StatefulButton
className="text-gray-700 font-weight-500"
type="submit"
variant="link"
labels={{
default: intl.formatMessage(messages['optional.fields.skip.button']),
}}
onClick={handleSkip}
onMouseDown={(e) => e.preventDefault()}
/>
</div>
</Form>
</div>
</BaseComponent>
</>
);
};
ProgressiveProfiling.propTypes = {
formRenderState: PropTypes.string.isRequired,
intl: PropTypes.objectOf(PropTypes.object).isRequired,
location: PropTypes.shape({
state: PropTypes.object,
}),
saveUserProfile: PropTypes.func.isRequired,
showError: PropTypes.bool,
shouldRedirect: PropTypes.bool,
submitState: PropTypes.string,
};
ProgressiveProfiling.defaultProps = {
location: { state: {} },
shouldRedirect: false,
showError: false,
submitState: DEFAULT_STATE,
};
const mapStateToProps = state => ({
formRenderState: welcomePageSelector(state).formRenderState,
shouldRedirect: welcomePageSelector(state).success,
submitState: welcomePageSelector(state).submitState,
showError: welcomePageSelector(state).showError,
});
export default connect(
mapStateToProps,
{
saveUserProfile,
},
)(injectIntl(ProgressiveProfiling));