From c82ecf89aae6cf1add2021e9bd677ad0923f9a14 Mon Sep 17 00:00:00 2001 From: Patrick Wolfert Date: Tue, 25 May 2021 12:37:12 -0700 Subject: [PATCH] [NO-TICKET] Put analytics behind feature flags (#1047) * Put analytics behind separate feature flags Default Alert and Dialog to OFF Default HelpDrawer to ON because I think it's lower risk * Default help drawer analytics to off as well for now * Add feature flag info to doc site * Move checking for ga feature flag further up the function * ga content formatting updates * fcode formatting specification Co-authored-by: Ni Chia Co-authored-by: line47 --- .../pages/components/Alert/_Alert.docs.scss | 22 +++++++-- .../pages/components/Dialog/_Dialog.docs.scss | 23 +++++++-- .../Dialog/_ThirdPartyLink.docs.scss | 23 +++++++-- .../HelpDrawer/_HelpDrawer.docs.scss | 24 ++++++++-- .../src/components/Alert/Alert.jsx | 41 ++++++++-------- .../src/components/Alert/Alert.test.jsx | 3 ++ .../src/components/Dialog/Dialog.jsx | 47 ++++++++++--------- .../src/components/Dialog/Dialog.test.jsx | 3 ++ .../src/components/HelpDrawer/HelpDrawer.jsx | 47 ++++++++++--------- .../components/HelpDrawer/HelpDrawer.test.jsx | 3 ++ .../design-system/src/components/flags.ts | 31 ++++++++++++ 11 files changed, 194 insertions(+), 73 deletions(-) diff --git a/packages/design-system-docs/src/pages/components/Alert/_Alert.docs.scss b/packages/design-system-docs/src/pages/components/Alert/_Alert.docs.scss index bbcb04de24..d65aa4e2d8 100644 --- a/packages/design-system-docs/src/pages/components/Alert/_Alert.docs.scss +++ b/packages/design-system-docs/src/pages/components/Alert/_Alert.docs.scss @@ -191,16 +191,32 @@ Style guide: components.alert.guidance /* Google Analytics -On application where the page has `utag` loaded, analytics event tracking is enabled by default. The data goes to Tealium which allows it to route to Google Analytics or the currently approved data analytics tools. -- To disable the automatic event tracking, pass this prop to the component +**Analytics event tracking is disabled by default.** + +### Enable event tracking + +- Import and set the `setAlertSendsAnalytics` feature flag to `true` in your application's entry file: + +```JSX +import { setAlertSendsAnalytics } from "@cmsgov/"; +setAlertSendsAnalytics(true); ``` +On applications where the page has `utag` loaded, the data goes to Tealium which allows it to route to Google Analytics or the currently approved data analytics tools. + +### Disable event tracking + +- Pass the `onComponentDidMount` prop set to `false` to the component: + +```JSX analytics={ { onComponentDidMount: {false} } } ``` -- To override the event tracking, pass changes via the analytics prop +### Override event tracking + +- Pass changes via any of the [available analytics props](#components.alert.analytics). Style guide: components.alert.guidance-analytics */ diff --git a/packages/design-system-docs/src/pages/components/Dialog/_Dialog.docs.scss b/packages/design-system-docs/src/pages/components/Dialog/_Dialog.docs.scss index f56abd848a..6ebd4edba5 100644 --- a/packages/design-system-docs/src/pages/components/Dialog/_Dialog.docs.scss +++ b/packages/design-system-docs/src/pages/components/Dialog/_Dialog.docs.scss @@ -188,9 +188,24 @@ Style guide: components.dialog.guidance /* Google Analytics -On application where the page has `utag` loaded, analytics event tracking is enabled by default. The data goes to Tealium which allows it to route to Google Analytics or the currently approved data analytics tools. -- To disable the automatic event tracking, pass this prop to the component +**Analytics event tracking is disabled by default.** + +### Enable event tracking + +- Import and set the `setDialogSendsAnalytics` feature flag to `true` in your application's entry file: + +```JSX +import { setDialogSendsAnalytics } from "@cmsgov/"; +setDialogSendsAnalytics(true); ``` +On applications where the page has `utag` loaded, the data goes to Tealium which allows it to route to Google Analytics or the currently approved data analytics tools. + +### Disable event tracking + +- Pass the `onComponentDidMount` prop set to `false` to the component: +- Pass the `onComponentWillUnmount` prop set to `false` to the component: + +```JSX analytics={ { onComponentDidMount: {false}, @@ -198,7 +213,9 @@ analytics={ } } ``` -- To override the event tracking, pass changes via the analytics prop +### Override event tracking + +- Pass changes via any of the [available analytics props](#components.alert.analytics). Style guide: components.dialog.guidance-analytics */ diff --git a/packages/design-system-docs/src/pages/components/Dialog/_ThirdPartyLink.docs.scss b/packages/design-system-docs/src/pages/components/Dialog/_ThirdPartyLink.docs.scss index 16a7a45438..682f5484c6 100644 --- a/packages/design-system-docs/src/pages/components/Dialog/_ThirdPartyLink.docs.scss +++ b/packages/design-system-docs/src/pages/components/Dialog/_ThirdPartyLink.docs.scss @@ -50,9 +50,24 @@ Style guide: patterns.external-link.guidance /* Google Analytics -On application where the page has `utag` loaded, analytics event tracking is enabled by default. The data goes to Tealium which allows it to route to Google Analytics or the currently approved data analytics tools. -- To disable the automatic event tracking, pass this prop to the component +**Analytics event tracking is disabled by default.** + +### Enable event tracking + +- Import and set the `setDialogSendsAnalytics` feature flag to `true` in your application's entry file: + +```JSX +import { setDialogSendsAnalytics } from "@cmsgov/"; +setDialogSendsAnalytics(true); ``` +On applications where the page has `utag` loaded, the data goes to Tealium which allows it to route to Google Analytics or the currently approved data analytics tools. + +### Disable event tracking + +- Pass the `onComponentDidMount` prop set to `false` to the component: +- Pass the `onComponentWillUnmount` prop set to `false` to the component: + +```JSX analytics={ { onComponentDidMount: {false}, @@ -60,7 +75,9 @@ analytics={ } } ``` -- To override the event tracking, pass changes via the analytics prop +### Override event tracking + +- Pass changes via any of the [available analytics props](#components.alert.analytics). Style guide: patterns.external-link.guidance-analytics */ diff --git a/packages/design-system-docs/src/pages/components/HelpDrawer/_HelpDrawer.docs.scss b/packages/design-system-docs/src/pages/components/HelpDrawer/_HelpDrawer.docs.scss index 0e493282a7..de29fd1f2c 100644 --- a/packages/design-system-docs/src/pages/components/HelpDrawer/_HelpDrawer.docs.scss +++ b/packages/design-system-docs/src/pages/components/HelpDrawer/_HelpDrawer.docs.scss @@ -194,9 +194,24 @@ Style guide: components.help-drawer.guidance /* Google Analytics -On application where the page has `utag` loaded, analytics event tracking is enabled by default. The data goes to Tealium which allows it to route to Google Analytics or the currently approved data analytics tools. -- To disable the automatic event tracking, pass this prop to the component +**Analytics event tracking is disabled by default.** + +### Enable event tracking + +- Import and set the `setHelpDrawerSendsAnalytics` feature flag to `true` in your application's entry file: + +```JSX +import { setHelpDrawerSendsAnalytics } from "@cmsgov/"; +setHelpDrawerSendsAnalytics(true); ``` +On application where the page has `utag` loaded, the data goes to Tealium which allows it to route to Google Analytics or the currently approved data analytics tools. + +### Disable event tracking + +- Pass the `onComponentDidMount` prop set to `false` to the component: +- Pass the `onComponentWillUnmount` prop set to `false` to the component: + +```JSX analytics={ { onComponentDidMount: {false}, @@ -204,7 +219,10 @@ analytics={ } } ``` -- To override the event tracking, pass changes via the analytics prop + +### Override event tracking + +- Pass changes via any of the [available analytics props](#components.alert.analytics). Style guide: components.help-drawer.guidance-analytics */ diff --git a/packages/design-system/src/components/Alert/Alert.jsx b/packages/design-system/src/components/Alert/Alert.jsx index ac1146685b..e12bd19375 100644 --- a/packages/design-system/src/components/Alert/Alert.jsx +++ b/packages/design-system/src/components/Alert/Alert.jsx @@ -1,6 +1,7 @@ import { EVENT_CATEGORY, MAX_LENGTH, sendAnalyticsEvent } from '../analytics/SendAnalytics'; import PropTypes from 'prop-types'; import React from 'react'; +import { alertSendsAnalytics } from '../flags'; import classNames from 'classnames'; import get from 'lodash/get'; import uniqueId from 'lodash.uniqueid'; @@ -34,27 +35,29 @@ export class Alert extends React.PureComponent { } componentDidMount() { - const eventAction = 'onComponentDidMount'; - const eventHeading = this.props.heading || this.props.children; + if (alertSendsAnalytics()) { + const eventAction = 'onComponentDidMount'; + const eventHeading = this.props.heading || this.props.children; - /* Send analytics event for `error`, `warn`, `success` alert variations */ - if (this.props.variation) { - if (typeof eventHeading === 'string') { - this.eventHeadingText = eventHeading.substring(0, MAX_LENGTH); - } else { - const eventHeadingTextElement = - (this.alertRef && this.alertRef.getElementsByClassName('ds-c-alert__heading')[0]) || - (this.alertRef && this.alertRef.getElementsByClassName('ds-c-alert__body')[0]); - this.eventHeadingText = - eventHeadingTextElement && eventHeadingTextElement.textContent - ? eventHeadingTextElement.textContent.substring(0, MAX_LENGTH) - : ''; - } + /* Send analytics event for `error`, `warn`, `success` alert variations */ + if (this.props.variation) { + if (typeof eventHeading === 'string') { + this.eventHeadingText = eventHeading.substring(0, MAX_LENGTH); + } else { + const eventHeadingTextElement = + (this.alertRef && this.alertRef.getElementsByClassName('ds-c-alert__heading')[0]) || + (this.alertRef && this.alertRef.getElementsByClassName('ds-c-alert__body')[0]); + this.eventHeadingText = + eventHeadingTextElement && eventHeadingTextElement.textContent + ? eventHeadingTextElement.textContent.substring(0, MAX_LENGTH) + : ''; + } - sendAnalyticsEvent( - get(this.props.analytics, eventAction), - get(defaultAnalytics(this.eventHeadingText, this.props.variation), eventAction) - ); + sendAnalyticsEvent( + get(this.props.analytics, eventAction), + get(defaultAnalytics(this.eventHeadingText, this.props.variation), eventAction) + ); + } } } diff --git a/packages/design-system/src/components/Alert/Alert.test.jsx b/packages/design-system/src/components/Alert/Alert.test.jsx index ad2aab1d02..286427b510 100644 --- a/packages/design-system/src/components/Alert/Alert.test.jsx +++ b/packages/design-system/src/components/Alert/Alert.test.jsx @@ -1,5 +1,6 @@ import Alert from './Alert'; import React from 'react'; +import { setAlertSendsAnalytics } from '../flags'; import { shallow } from 'enzyme'; const text = 'Ruhroh'; @@ -73,6 +74,7 @@ describe('Alert', function () { }; beforeEach(() => { + setAlertSendsAnalytics(true); tealiumMock = jest.fn(); window.utag = { link: tealiumMock, @@ -80,6 +82,7 @@ describe('Alert', function () { }); afterEach(() => { + setAlertSendsAnalytics(false); jest.resetAllMocks(); }); diff --git a/packages/design-system/src/components/Dialog/Dialog.jsx b/packages/design-system/src/components/Dialog/Dialog.jsx index bcab3d0126..222f3ba698 100644 --- a/packages/design-system/src/components/Dialog/Dialog.jsx +++ b/packages/design-system/src/components/Dialog/Dialog.jsx @@ -4,6 +4,7 @@ import Button from '../Button/Button'; import PropTypes from 'prop-types'; import React from 'react'; import classNames from 'classnames'; +import { dialogSendsAnalytics } from '../flags'; import get from 'lodash/get'; // Default analytics object @@ -52,32 +53,36 @@ export class Dialog extends React.PureComponent { } componentDidMount() { - const eventAction = 'onComponentDidMount'; - const eventHeading = this.props.title || this.props.heading; + if (dialogSendsAnalytics()) { + const eventAction = 'onComponentDidMount'; + const eventHeading = this.props.title || this.props.heading; - if (typeof eventHeading === 'string') { - this.eventHeadingText = eventHeading.substring(0, MAX_LENGTH); - } else { - this.eventHeadingText = - this.headingRef && this.headingRef.textContent - ? this.headingRef.textContent.substring(0, MAX_LENGTH) - : ''; - } + if (typeof eventHeading === 'string') { + this.eventHeadingText = eventHeading.substring(0, MAX_LENGTH); + } else { + this.eventHeadingText = + this.headingRef && this.headingRef.textContent + ? this.headingRef.textContent.substring(0, MAX_LENGTH) + : ''; + } - /* Send analytics event for dialog open */ - sendAnalyticsEvent( - get(this.props.analytics, eventAction), - get(defaultAnalytics(this.eventHeadingText), eventAction) - ); + /* Send analytics event for dialog open */ + sendAnalyticsEvent( + get(this.props.analytics, eventAction), + get(defaultAnalytics(this.eventHeadingText), eventAction) + ); + } } componentWillUnmount() { - const eventAction = 'onComponentWillUnmount'; - /* Send analytics event for dialog close */ - sendAnalyticsEvent( - get(this.props.analytics, eventAction), - get(defaultAnalytics(this.eventHeadingText), eventAction) - ); + if (dialogSendsAnalytics()) { + const eventAction = 'onComponentWillUnmount'; + /* Send analytics event for dialog close */ + sendAnalyticsEvent( + get(this.props.analytics, eventAction), + get(defaultAnalytics(this.eventHeadingText), eventAction) + ); + } } render() { diff --git a/packages/design-system/src/components/Dialog/Dialog.test.jsx b/packages/design-system/src/components/Dialog/Dialog.test.jsx index c29e1c57cf..82c51771b9 100644 --- a/packages/design-system/src/components/Dialog/Dialog.test.jsx +++ b/packages/design-system/src/components/Dialog/Dialog.test.jsx @@ -1,6 +1,7 @@ import { mount, shallow } from 'enzyme'; import Dialog from './Dialog'; import React from 'react'; +import { setDialogSendsAnalytics } from '../flags'; function render(customProps = {}, deep = false) { const props = Object.assign( @@ -76,6 +77,7 @@ describe('Dialog', function () { }; beforeEach(() => { + setDialogSendsAnalytics(true); tealiumMock = jest.fn(); window.utag = { link: tealiumMock, @@ -83,6 +85,7 @@ describe('Dialog', function () { }); afterEach(() => { + setDialogSendsAnalytics(false); jest.resetAllMocks(); }); diff --git a/packages/design-system/src/components/HelpDrawer/HelpDrawer.jsx b/packages/design-system/src/components/HelpDrawer/HelpDrawer.jsx index 41c33b5b30..4a892ed643 100644 --- a/packages/design-system/src/components/HelpDrawer/HelpDrawer.jsx +++ b/packages/design-system/src/components/HelpDrawer/HelpDrawer.jsx @@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import classNames from 'classnames'; import get from 'lodash/get'; +import { helpDrawerSendsAnalytics } from '../flags'; // Default analytics object const defaultAnalytics = (heading = '') => ({ @@ -48,32 +49,36 @@ export class HelpDrawer extends React.PureComponent { componentDidMount() { if (this.headingRef) this.headingRef.focus(); - const eventAction = 'onComponentDidMount'; - const eventHeading = this.props.title || this.props.heading; + if (helpDrawerSendsAnalytics()) { + const eventAction = 'onComponentDidMount'; + const eventHeading = this.props.title || this.props.heading; - if (typeof eventHeading === 'string') { - this.eventHeadingText = eventHeading.substring(0, MAX_LENGTH); - } else { - this.eventHeadingText = - this.headingRef && this.headingRef.textContent - ? this.headingRef.textContent.substring(0, MAX_LENGTH) - : ''; - } + if (typeof eventHeading === 'string') { + this.eventHeadingText = eventHeading.substring(0, MAX_LENGTH); + } else { + this.eventHeadingText = + this.headingRef && this.headingRef.textContent + ? this.headingRef.textContent.substring(0, MAX_LENGTH) + : ''; + } - /* Send analytics event for helpdrawer open */ - sendAnalyticsEvent( - get(this.props.analytics, eventAction), - get(defaultAnalytics(this.eventHeadingText), eventAction) - ); + /* Send analytics event for helpdrawer open */ + sendAnalyticsEvent( + get(this.props.analytics, eventAction), + get(defaultAnalytics(this.eventHeadingText), eventAction) + ); + } } componentWillUnmount() { - const eventAction = 'onComponentWillUnmount'; - /* Send analytics event for helpdrawer close */ - sendAnalyticsEvent( - get(this.props.analytics, eventAction), - get(defaultAnalytics(this.eventHeadingText), eventAction) - ); + if (helpDrawerSendsAnalytics()) { + const eventAction = 'onComponentWillUnmount'; + /* Send analytics event for helpdrawer close */ + sendAnalyticsEvent( + get(this.props.analytics, eventAction), + get(defaultAnalytics(this.eventHeadingText), eventAction) + ); + } } render() { diff --git a/packages/design-system/src/components/HelpDrawer/HelpDrawer.test.jsx b/packages/design-system/src/components/HelpDrawer/HelpDrawer.test.jsx index db25bf60ab..89f0476d38 100644 --- a/packages/design-system/src/components/HelpDrawer/HelpDrawer.test.jsx +++ b/packages/design-system/src/components/HelpDrawer/HelpDrawer.test.jsx @@ -1,6 +1,7 @@ import HelpDrawer from './HelpDrawer.jsx'; import React from 'react'; import renderer from 'react-test-renderer'; +import { setHelpDrawerSendsAnalytics } from '../flags'; import { shallow } from 'enzyme'; const defaultProps = { @@ -57,6 +58,7 @@ describe('HelpDrawer', () => { }; beforeEach(() => { + setHelpDrawerSendsAnalytics(true); tealiumMock = jest.fn(); window.utag = { link: tealiumMock, @@ -64,6 +66,7 @@ describe('HelpDrawer', () => { }); afterEach(() => { + setHelpDrawerSendsAnalytics(false); jest.resetAllMocks(); }); diff --git a/packages/design-system/src/components/flags.ts b/packages/design-system/src/components/flags.ts index 3383b5eae4..9da992549a 100644 --- a/packages/design-system/src/components/flags.ts +++ b/packages/design-system/src/components/flags.ts @@ -1,11 +1,18 @@ type errorPlacementValue = 'top' | 'bottom'; + interface flagsType { ERROR_PLACEMENT_DEFAULT: errorPlacementValue; + ALERT_SENDS_ANALYTICS: boolean; + DIALOG_SENDS_ANALYTICS: boolean; + HELP_DRAWER_SENDS_ANALYTICS: boolean; } // featureFlags.js const flags: flagsType = { ERROR_PLACEMENT_DEFAULT: 'top', + ALERT_SENDS_ANALYTICS: false, + DIALOG_SENDS_ANALYTICS: false, + HELP_DRAWER_SENDS_ANALYTICS: false, }; export function errorPlacementDefault(): errorPlacementValue { @@ -15,3 +22,27 @@ export function errorPlacementDefault(): errorPlacementValue { export function setErrorPlacementDefault(value: errorPlacementValue): void { flags.ERROR_PLACEMENT_DEFAULT = value; } + +export function alertSendsAnalytics(): boolean { + return flags.ALERT_SENDS_ANALYTICS; +} + +export function setAlertSendsAnalytics(value: boolean): void { + flags.ALERT_SENDS_ANALYTICS = value; +} + +export function dialogSendsAnalytics(): boolean { + return flags.DIALOG_SENDS_ANALYTICS; +} + +export function setDialogSendsAnalytics(value: boolean): void { + flags.DIALOG_SENDS_ANALYTICS = value; +} + +export function helpDrawerSendsAnalytics(): boolean { + return flags.HELP_DRAWER_SENDS_ANALYTICS; +} + +export function setHelpDrawerSendsAnalytics(value: boolean): void { + flags.HELP_DRAWER_SENDS_ANALYTICS = value; +}