Skip to content

Commit f58f33e

Browse files
committed
feat: added cohesion events tracking
1 parent 2bfce01 commit f58f33e

File tree

11 files changed

+179
-30
lines changed

11 files changed

+179
-30
lines changed

public/index.html

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,78 @@
11
<!doctype html>
22
<html lang="en-us">
3-
<head>
4-
<title><%= (process.env.SITE_NAME && process.env.SITE_NAME != 'null') ? 'Authentication | ' + process.env.SITE_NAME : 'Authentication' %></title>
5-
<meta charset="utf-8">
6-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7-
<link rel="shortcut icon" href="<%=htmlWebpackPlugin.options.FAVICON_URL%>" type="image/x-icon"/>
8-
<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.4.4/iframeResizer.contentWindow.min.js"
9-
integrity="sha512-IWwZFBvHzN41wNI6etRLLuLrDDj/6AwJcPt7cmKJAzluYTIHHQ1PF8wh0rSy05jxEvvjflVvH2MxeV6riyEEXg=="
10-
crossorigin="anonymous"
11-
referrerpolicy="no-referrer">
12-
</script>
13-
<% if (process.env.OPTIMIZELY_URL) { %>
14-
<script
15-
src="<%= process.env.OPTIMIZELY_URL %>"
16-
></script>
17-
<% } else if (process.env.OPTIMIZELY_PROJECT_ID) { %>
18-
<script
19-
src="<%= process.env.MARKETING_SITE_BASE_URL %>/optimizelyjs/<%= process.env.OPTIMIZELY_PROJECT_ID %>.js"
20-
></script>
3+
4+
<head>
5+
<title>
6+
<%= (process.env.SITE_NAME && process.env.SITE_NAME !='null' ) ? 'Authentication | ' + process.env.SITE_NAME
7+
: 'Authentication' %>
8+
</title>
9+
<meta charset="utf-8">
10+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
11+
<link rel="shortcut icon" href="<%=htmlWebpackPlugin.options.FAVICON_URL%>" type="image/x-icon" />
12+
13+
<style type='text/css'>
14+
.preampjs [data-preamp],
15+
.fusejs [data-fuse] {
16+
opacity: 0 !important
17+
}
18+
</style>
19+
<script type="text/javascript">
20+
!function (co, h, e, s, i, o, n) {
21+
var d = 'documentElement'; var a = 'className'; h[d][a] += ' preampjs fusejs';
22+
n.k = e; co._Cohesion = n; co._Preamp = { k: s, start: new Date }; co._Fuse = { k: i }; co._Tagular = { k: o };
23+
[e, s, i, o].map(function (x) { co[x] = co[x] || function () { (co[x].q = co[x].q || []).push([].slice.call(arguments)) } });
24+
var b = function () { var u = h[d][a]; h[d][a] = u.replace(/ ?preampjs| ?fusejs/g, '') };
25+
h.addEventListener('DOMContentLoaded', function () {
26+
co.setTimeout(b, 3e3);
27+
co._Preamp.docReady = co._Fuse.docReady = !0
28+
}); var z = h.createElement('script');
29+
z.async = 1; z.src = 'https://cdn.cohesionapps.com/cohesion/cohesion-latest.min.js';
30+
z.onerror = function () { var ce = 'error', f = 'function'; for (var o of co[e].q || []) o[0] === ce && typeof o[1] == f && o[1](); co[e] = function (n, cb) { n === ce && typeof cb == f && cb() }; b() };
31+
h.head.appendChild(z);
32+
}
33+
(window, document, 'cohesion', 'preamp', 'fuse', 'tagular', {
34+
tagular: {
35+
writeKey: process.env.Cohesion_Write_Key,
36+
sourceKey: process.env.Cohesion_Source_Key,
37+
taggy: {
38+
enabled: true
39+
}
40+
}
41+
})
42+
</script>
43+
44+
45+
46+
<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.4.4/iframeResizer.contentWindow.min.js"
47+
integrity="sha512-IWwZFBvHzN41wNI6etRLLuLrDDj/6AwJcPt7cmKJAzluYTIHHQ1PF8wh0rSy05jxEvvjflVvH2MxeV6riyEEXg=="
48+
crossorigin="anonymous" referrerpolicy="no-referrer">
49+
</script>
50+
<% if (process.env.OPTIMIZELY_URL) { %>
51+
<script src="<%= process.env.OPTIMIZELY_URL %>"></script>
52+
<% } else if (process.env.OPTIMIZELY_PROJECT_ID) { %>
53+
<script
54+
src="<%= process.env.MARKETING_SITE_BASE_URL %>/optimizelyjs/<%= process.env.OPTIMIZELY_PROJECT_ID %>.js"></script>
2155
<% } %>
22-
</head>
23-
<body>
24-
<div id="root"></div>
25-
</body>
56+
57+
<script>
58+
window.tagular("beam", {
59+
"@type": "core.Identify.v1",
60+
traits: {},
61+
externalIds: [
62+
{
63+
id: window.analytics.user().anonymousId(),
64+
type: "segment_anonym_id",
65+
collection: "users",
66+
encoding: "none",
67+
},
68+
],
69+
});
70+
71+
</script>
72+
</head>
73+
74+
<body>
75+
<div id="root"></div>
76+
</body>
77+
2678
</html>

src/common-components/SocialAuthProviders.jsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,25 @@ import { Login } from '@openedx/paragon/icons';
99
import PropTypes from 'prop-types';
1010

1111
import messages from './messages';
12-
import { LOGIN_PAGE, REGISTER_PAGE, SUPPORTED_ICON_CLASSES } from '../data/constants';
12+
import {
13+
ELEMENT_TYPES, LOGIN_PAGE, REGISTER_PAGE, SUPPORTED_ICON_CLASSES,
14+
} from '../data/constants';
1315
import { setCookie } from '../data/utils';
16+
import { trackSignIn } from '../tracking/trackers/login';
17+
import { trackAccountCreationEvents } from '../tracking/trackers/register';
1418

1519
const SocialAuthProviders = (props) => {
1620
const { formatMessage } = useIntl();
1721
const { referrer, socialAuthProviders } = props;
1822
const registrationFields = useSelector(state => state.register.registrationFormData);
1923

20-
function handleSubmit(e) {
24+
function handleSubmit(e, providerName) {
2125
e.preventDefault();
26+
if (referrer === LOGIN_PAGE) {
27+
trackSignIn(ELEMENT_TYPES.BUTTON, providerName.toLowerCase(), providerName);
28+
} else {
29+
trackAccountCreationEvents(ELEMENT_TYPES.BUTTON, providerName.toLowerCase(), providerName);
30+
}
2231

2332
if (referrer === REGISTER_PAGE) {
2433
setCookie('marketingEmailsOptIn', registrationFields?.configurableFormFields?.marketingEmailsOptIn);
@@ -34,7 +43,7 @@ const SocialAuthProviders = (props) => {
3443
type="button"
3544
className={`btn-social btn-${provider.id} ${index % 2 === 0 ? 'mr-3' : ''}`}
3645
data-provider-url={referrer === LOGIN_PAGE ? provider.loginUrl : provider.registerUrl}
37-
onClick={handleSubmit}
46+
onClick={(e) => handleSubmit(e, provider.name)}
3847
>
3948
{provider.iconImage ? (
4049
<div aria-hidden="true">

src/data/cohesion/utils.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { EVENT_TYPES } from '../constants';
2+
3+
/**
4+
* Creates a web element object for cohesion tracking purposes.
5+
*
6+
* @param {string} elementType - The type of the web element (e.g., 'BUTTON', 'LINK').
7+
* @param {string} webElementText - The text content of the web element.
8+
* @param {string} webElementName - The name of the web element.
9+
* @returns {Object} An object representing the web element.
10+
*/
11+
12+
export const createWebElement = (elementType, webElementName, webElementText) => ({
13+
elementType,
14+
text: webElementText,
15+
name: webElementName,
16+
});
17+
18+
export const trackEvent = (eventType, webElement) => {
19+
window.tagular('beam', {
20+
'@type': eventType,
21+
webElement,
22+
});
23+
};
24+
25+
/**
26+
* Tracks cohesion events by setting the page type and tracking a click event.
27+
*
28+
* @param {string} pageType - The type of page where the event occurred.
29+
* @param {string} elementType - The type of the web element (e.g., 'BUTTON', 'LINK').
30+
* @param {string} webElementText - The text content of the web element.
31+
* @param {string} webElementName - The name of the web element.
32+
*/
33+
export const createCohesionEvent = (pageType, elementType, webElementName, webElementText) => {
34+
window.chsn_pageType = pageType;
35+
const webElement = createWebElement(elementType, webElementName, webElementText);
36+
trackEvent(EVENT_TYPES.ElementClicked, webElement);
37+
};

src/data/constants.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,14 @@ export const VALID_EMAIL_REGEX = '(^[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&\'*+
3838
export const AUTH_PARAMS = ['course_id', 'enrollment_action', 'course_mode', 'email_opt_in', 'purchase_workflow', 'next', 'register_for_free', 'track', 'is_account_recovery', 'variant', 'host', 'cta'];
3939
export const REDIRECT = 'redirect';
4040
export const APP_NAME = 'authn_mfe';
41+
42+
export const PAGE_TYPES = {
43+
accountCreation: 'account-creation',
44+
signIn: 'sign-in',
45+
};
46+
47+
export const ELEMENT_TYPES = {
48+
BUTTON: 'BUTTON',
49+
};
50+
51+
export const EVENT_TYPES = { ElementClicked: 'redventures.usertracking.v3.ElementClicked' };

src/login/LoginPage.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ import { thirdPartyAuthContextSelector } from '../common-components/data/selecto
3232
import EnterpriseSSO from '../common-components/EnterpriseSSO';
3333
import ThirdPartyAuth from '../common-components/ThirdPartyAuth';
3434
import {
35-
DEFAULT_STATE, PENDING_STATE, RESET_PAGE,
35+
DEFAULT_STATE, ELEMENT_TYPES, PENDING_STATE,
36+
RESET_PAGE,
3637
} from '../data/constants';
3738
import {
3839
getActivationStatus,
@@ -44,7 +45,7 @@ import {
4445
import { removeCookie } from '../data/utils/cookies';
4546
import ResetPasswordSuccess from '../reset-password/ResetPasswordSuccess';
4647
import {
47-
trackForgotPasswordLinkClick, trackLoginPageViewed, trackLoginSuccess,
48+
trackForgotPasswordLinkClick, trackLoginPageViewed, trackLoginSuccess, trackSignIn,
4849
} from '../tracking/trackers/login';
4950

5051
const LoginPage = (props) => {
@@ -151,6 +152,7 @@ const LoginPage = (props) => {
151152
};
152153

153154
const handleSubmit = (event) => {
155+
trackSignIn(ELEMENT_TYPES.BUTTON, formatMessage(messages['sign.in.button.name']), formatMessage(messages['sign.in.button']));
154156
event.preventDefault();
155157
if (showResetPasswordSuccessBanner) {
156158
props.dismissPasswordResetBanner();

src/login/messages.jsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ const messages = defineMessages({
2222
defaultMessage: 'Sign in',
2323
description: 'Sign in button label that appears on login page',
2424
},
25+
'sign.in.button.name': {
26+
id: 'sign.in.button.name',
27+
defaultMessage: 'sign-in',
28+
description: 'Sign in button label that appears on login page for tracking event',
29+
},
2530
'forgot.password': {
2631
id: 'forgot.password',
2732
defaultMessage: 'Forgot password',

src/register/RegistrationPage.jsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@ import { getThirdPartyAuthContext as getRegistrationDataFromBackend } from '../c
4343
import EnterpriseSSO from '../common-components/EnterpriseSSO';
4444
import ThirdPartyAuth from '../common-components/ThirdPartyAuth';
4545
import {
46-
APP_NAME, COMPLETE_STATE, PENDING_STATE, REGISTER_PAGE,
46+
APP_NAME, COMPLETE_STATE, ELEMENT_TYPES, PENDING_STATE,
47+
REGISTER_PAGE,
4748
} from '../data/constants';
4849
import {
4950
getAllPossibleQueryParams, getTpaHint, getTpaProvider, isHostAvailableInQueryParams, removeCookie, setCookie,
5051
} from '../data/utils';
51-
import { trackRegistrationPageViewed, trackRegistrationSuccess } from '../tracking/trackers/register';
52-
52+
import { trackAccountCreationEvents, trackRegistrationPageViewed, trackRegistrationSuccess } from '../tracking/trackers/register';
5353
/**
5454
* Main Registration Page component
5555
*/
@@ -267,6 +267,7 @@ const RegistrationPage = (props) => {
267267
};
268268

269269
const handleSubmit = (e) => {
270+
trackAccountCreationEvents(ELEMENT_TYPES.BUTTON, formatMessage(messages['create.account.for.free.button.text']), buttonLabel);
270271
e.preventDefault();
271272
registerUser();
272273
};

src/register/components/ConfigurableRegistrationForm.jsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import { getConfig } from '@edx/frontend-platform';
55
import { getCountryList, getLocale, useIntl } from '@edx/frontend-platform/i18n';
66
import PropTypes from 'prop-types';
77

8+
import { ELEMENT_TYPES } from '../../data/constants';
89
import { FormFieldRenderer } from '../../field-renderer';
10+
import { trackAccountCreationEvents } from '../../tracking/trackers/register';
911
import { backupRegistrationFormBegin } from '../data/actions';
1012
import { FIELDS } from '../data/constants';
1113
import messages from '../messages';
@@ -100,6 +102,12 @@ const ConfigurableRegistrationForm = (props) => {
100102
}
101103
// setting marketingEmailsOptIn state for SSO authentication flow for register API call
102104
if (name === 'marketingEmailsOptIn') {
105+
if (!value) {
106+
trackAccountCreationEvents(ELEMENT_TYPES.BUTTON,
107+
formatMessage(messages['registration.opt.out.label.name']),
108+
formatMessage(messages['registration.opt.in.label'],
109+
{ siteName: getConfig().SITE_NAME }));
110+
}
103111
dispatch(backupRegistrationFormBegin({
104112
...backedUpFormData,
105113
configurableFormFields: {

src/register/messages.jsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ const messages = defineMessages({
3737
defaultMessage: 'I agree that {siteName} may send me marketing messages.',
3838
description: 'Text for opt in option on register page.',
3939
},
40+
'registration.opt.out.label.name': {
41+
id: 'registration.opt.out.label.name',
42+
defaultMessage: 'opt-out',
43+
description: 'Text for opt out option on register page tracking event',
44+
},
45+
4046
// Help text
4147
'help.text.name': {
4248
id: 'help.text.name',
@@ -64,6 +70,11 @@ const messages = defineMessages({
6470
defaultMessage: 'Create an account for free',
6571
description: 'Label text for registration form submission button',
6672
},
73+
'create.account.for.free.button.text': {
74+
id: 'create.account.for.free.button.text',
75+
defaultMessage: 'create-account',
76+
description: 'Label text for registration form submission button for tracking event',
77+
},
6778
'create.account.cta.button': {
6879
id: 'create.account.cta.button',
6980
defaultMessage: '{label}',

src/tracking/trackers/login.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { createCohesionEvent } from '../../data/cohesion/utils';
2+
import { PAGE_TYPES } from '../../data/constants';
13
import { createEventTracker, createPageEventTracker } from '../../data/segment/utils';
24

35
export const eventNames = {
@@ -27,3 +29,7 @@ export const trackLoginSuccess = () => createEventTracker(
2729
eventNames.loginSuccess,
2830
{},
2931
)();
32+
33+
export const trackSignIn = (elementType, webElementText, webElementName) => {
34+
createCohesionEvent(PAGE_TYPES.signIn, elementType, webElementText, webElementName);
35+
};

0 commit comments

Comments
 (0)