From 211ff4cfaf8af58b8d6ec34facd61a2a775f0c55 Mon Sep 17 00:00:00 2001 From: jenniw Date: Mon, 12 Aug 2024 12:20:39 -0400 Subject: [PATCH] Update ga to handle ecommerce events --- frontend/public/package.json | 1 + .../src/components/NotificationContainer.js | 14 +++++++--- frontend/public/src/constants.js | 4 +++ frontend/public/src/containers/App.js | 3 ++- frontend/public/src/lib/notificationsApi.js | 26 ++++++++----------- frontend/public/src/util/gaUtils.js | 17 ++++++++++++ frontend/public/src/util/withTracker.js | 7 ++--- yarn.lock | 8 ++++++ 8 files changed, 58 insertions(+), 22 deletions(-) create mode 100644 frontend/public/src/util/gaUtils.js diff --git a/frontend/public/package.json b/frontend/public/package.json index b32e369507..61aed481ad 100644 --- a/frontend/public/package.json +++ b/frontend/public/package.json @@ -87,6 +87,7 @@ "react-document-title": "2.0.3", "react-dom": "16.14.0", "react-ga": "2.7.0", + "react-ga4": "^2.1.0", "react-google-recaptcha": "1.1.0", "react-hot-loader": "4.13.1", "react-markdown": "5.0.3", diff --git a/frontend/public/src/components/NotificationContainer.js b/frontend/public/src/components/NotificationContainer.js index d830224324..4faf6cefe6 100644 --- a/frontend/public/src/components/NotificationContainer.js +++ b/frontend/public/src/components/NotificationContainer.js @@ -5,7 +5,6 @@ import { compose } from "redux" import { partial } from "ramda" // $FlowFixMe import { Alert } from "reactstrap" -import ga from "react-ga" import { removeUserNotification } from "../actions" import { @@ -14,11 +13,13 @@ import { newSetWithout, timeoutPromise } from "../lib/util" -import { getNotificationAlertProps } from "../lib/notificationsApi" +import { determineUserActionForGoogleAnalytics, getNotificationAlertProps } from "../lib/notificationsApi" import { notificationTypeMap, TextNotification } from "./notifications" import { checkFeatureFlag } from "../lib/util" +import { sendGAEcommerceEvent } from "../util/gaUtils" import type { UserNotificationMapping } from "../reducers/notifications" +import {GOOGLE_ANALYTICS_EVENT_TYPE} from "../constants"; const DEFAULT_REMOVE_DELAY_MS = 1000 @@ -58,9 +59,16 @@ export class NotificationContainer extends React.Component { render() { const { userNotifications } = this.props + const { currentUser } = this.props const { hiddenNotifications } = this.state - const ga_feature_flag = checkFeatureFlag("", ) + const ga_feature_flag = checkFeatureFlag("mitxonline-4099-dedp-google-analytics", currentUser) + if (ga_feature_flag) { + let gaEcommerceEventType = determineUserActionForGoogleAnalytics(currentUser) + if (gaEcommerceEventType === GOOGLE_ANALYTICS_EVENT_TYPE["GA_PURCHASE"]) { + sendGAEcommerceEvent(gaEcommerceEventType, event) + } + } return (
diff --git a/frontend/public/src/constants.js b/frontend/public/src/constants.js index 6f2c80aa19..899f1182d1 100644 --- a/frontend/public/src/constants.js +++ b/frontend/public/src/constants.js @@ -173,3 +173,7 @@ export const NODETYPE_COURSE = "course" export const NODEOPER_ALL = "all_of" export const NODEOPER_MIN = "min_number_of" + +export const GOOGLE_ANALYTICS_EVENT_TYPE = { + GA_PURCHASE: "purchase", +} diff --git a/frontend/public/src/containers/App.js b/frontend/public/src/containers/App.js index 1b5496df62..1ee80bf5e6 100644 --- a/frontend/public/src/containers/App.js +++ b/frontend/public/src/containers/App.js @@ -43,8 +43,9 @@ type Props = { export class App extends React.Component { componentDidMount() { const { addUserNotification } = this.props + const { currentUser } = this.props - const userMsg = getStoredUserMessage() + const userMsg = getStoredUserMessage(currentUser) if (userMsg) { addUserNotification({ "loaded-user-msg": { diff --git a/frontend/public/src/lib/notificationsApi.js b/frontend/public/src/lib/notificationsApi.js index d1710195ec..6e65024f74 100644 --- a/frontend/public/src/lib/notificationsApi.js +++ b/frontend/public/src/lib/notificationsApi.js @@ -19,7 +19,6 @@ import { USER_MSG_TYPE_COURSE_NON_UPGRADABLE, USER_MSG_TYPE_DISCOUNT_INVALID } from "../constants" -import { checkFeatureFlag } from "../lib/util" type UserMessage = { type: string, @@ -27,29 +26,26 @@ type UserMessage = { gaObject?: Object } -export function getStoredUserMessage(): UserMessage | null { +function ingestUserMessage(): userJson | null { const userMsgValue = getCookie(USER_MSG_COOKIE_NAME) if (!userMsgValue || isEmptyText(userMsgValue)) { return null } - const userMsgObject = JSON.parse(decodeURIComponent(userMsgValue)) - const ga_purchase_feature_flag = checkFeatureFlag(ENABLE_GOOGLE_ANALYTICS_DATA_PUSH) - if (ga_purchase_feature_flag) { - const user_action = determineUserActionForGoogleAnalytics(userMsgObject) - if (user_action) { - userMsgObject.gaObject = user_action - } - } + return JSON.parse(decodeURIComponent(userMsgValue)) +} + +export function getStoredUserMessage(): UserMessage | null { + const userMsgObject = ingestUserMessage() return parseStoredUserMessage(userMsgObject) } -export function determineUserActionForGoogleAnalytics(userMsgJson: Object) { +export function determineUserActionForGoogleAnalytics() { + const userMsg = ingestUserMessage() + if (!userMsg) return null const msgType = userMsgJson.type || null - if (!msgType) { - return null - } + if (!msgType) return null if (msgType === USER_MSG_TYPE_PAYMENT_ACCEPTED) { - return userMsgJson.gaObject + return "purchase" } } diff --git a/frontend/public/src/util/gaUtils.js b/frontend/public/src/util/gaUtils.js new file mode 100644 index 0000000000..cd7b91d725 --- /dev/null +++ b/frontend/public/src/util/gaUtils.js @@ -0,0 +1,17 @@ +import ga4 from "react-ga4" + +export function sendGAEvent({ category, action, label }) { + let event = { + category: category, + action: action, + label: label, + } + if (value !== undefined) { + event.value = value + } + ga4.event(event) +} + +export function sendGAEcommerceEvent({ event_type, event_data }) { + ga4.gtag("event", event_type, event_data) +} diff --git a/frontend/public/src/util/withTracker.js b/frontend/public/src/util/withTracker.js index 8c396ad775..1d943217ba 100644 --- a/frontend/public/src/util/withTracker.js +++ b/frontend/public/src/util/withTracker.js @@ -3,19 +3,20 @@ // From https://github.com/ReactTraining/react-router/issues/4278#issuecomment-299692502 import React from "react" -import ga from "react-ga" +import ga4 from "react-ga4" const withTracker = (WrappedComponent: Class>) => { const debug = SETTINGS.reactGaDebug === "true" if (SETTINGS.gaTrackingID) { - ga.initialize(SETTINGS.gaTrackingID, { debug: debug }) + ga4.initialize(SETTINGS.gaTrackingID, {debug: debug}) } const HOC = (props: Object) => { const page = props.location.pathname + const title = props.location.title if (SETTINGS.gaTrackingID) { - ga.pageview(page) + ga4.send({hitType: "pageview", page: page, title: title}) } return } diff --git a/yarn.lock b/yarn.lock index fa3f175433..dff8419d85 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15151,6 +15151,7 @@ __metadata: react-document-title: 2.0.3 react-dom: 16.14.0 react-ga: 2.7.0 + react-ga4: ^2.1.0 react-google-recaptcha: 1.1.0 react-hot-loader: 4.13.1 react-markdown: 5.0.3 @@ -18554,6 +18555,13 @@ __metadata: languageName: node linkType: hard +"react-ga4@npm:^2.1.0": + version: 2.1.0 + resolution: "react-ga4@npm:2.1.0" + checksum: f7fb41141418d4ad14756f1126a1e9958db37d4d84ae6cd798043dc03a390b6dba74d69311af0349f0b9580a43bda8930138194ccc29c4100efe446e2d6eb057 + languageName: node + linkType: hard + "react-ga@npm:2.7.0": version: 2.7.0 resolution: "react-ga@npm:2.7.0"