department-of-veterans-affairs/vets-website

View on GitHub
src/platform/site-wide/component-library-analytics-setup.js

Summary

Maintainability
C
1 day
Test Coverage
/* eslint-disable camelcase */
/**
 * Attaches CustomEvent 'component-library-analytics' listener to document.body
 * to translate component library actions into analytics dataLayer events.
 */
import _recordEvent from 'platform/monitoring/record-event';
import { getSectionLabel } from 'applications/static-pages/subscription-creators/subscribeAccordionEvents';

const analyticsEvents = {
  Modal: [{ action: 'show', event: 'int-modal-show', prefix: 'modal' }],
  'va-accordion': [
    {
      action: 'expand',
      event: 'int-accordion-expand',
      prefix: 'accordion',
    },
    {
      action: 'collapse',
      event: 'int-accordion-collapse',
      prefix: 'accordion',
    },
  ],
  'va-additional-info': [
    {
      action: 'expand',
      event: 'int-additional-info-expand',
      prefix: 'additional-info',
    },
    {
      action: 'collapse',
      event: 'int-additional-info-collapse',
      prefix: 'additional-info',
    },
  ],
  'va-alert': [
    {
      action: 'linkClick',
      event: 'nav-alert-box-link-click',
      prefix: 'alert-box',
    },
  ],
  'va-alert-expandable': [
    {
      action: 'expand',
      event: 'int-alert-expandable-expand',
      prefix: 'alert-expandable',
    },
    {
      action: 'collapse',
      event: 'int-alert-expandable-collapse',
      prefix: 'alert-expandable',
    },
  ],
  'va-breadcrumbs': [
    {
      action: 'linkClick',
      event: 'nav-breadcrumb-link-click',
      prefix: 'breadcrumbs',
    },
  ],
  'va-banner': [
    {
      action: 'close',
      event: 'int-banner-close',
      prefix: 'banner',
    },
  ],
  'va-button': [
    {
      action: 'click',
      event: 'cta-button-click',
      prefix: 'button',
    },
  ],
  'va-button-pair': [
    {
      action: 'click',
      event: 'int-button-pair-click',
      prefix: 'button-pair',
    },
  ],
  'va-checkbox': [
    {
      action: 'change',
      event: 'int-checkbox-option-click',
      prefix: 'checkbox',
    },
  ],
  'va-checkbox-group': [
    {
      action: 'change',
      event: 'int-checkbox-group-option-click',
      prefix: 'checkbox-group',
    },
  ],
  'va-date': [
    {
      action: 'blur',
      event: 'int-date-blur',
      prefix: 'date',
    },
  ],
  'va-file-input': [
    {
      action: 'change',
      event: 'int-file-input-change',
      prefix: 'file-input',
    },
  ],
  'va-link': [
    {
      action: 'click',
      event: 'nav-link-click',
      prefix: 'link',
    },
  ],
  'va-link-action': [
    {
      action: 'click',
      event: 'nav-link-click',
      prefix: 'link-action',
    },
  ],
  'va-loading-indicator': [
    {
      action: 'displayed',
      event: 'loading-indicator-displayed',
      prefix: 'loading-indicator',
    },
  ],
  'va-maintenance-banner': [
    {
      action: 'close',
      event: 'int-maintenance-banner-close',
      prefix: 'maintenance-banner',
    },
  ],
  'va-memorable-date': [
    {
      action: 'blur',
      event: 'int-memorable-date-blur',
      prefix: 'memorable-date',
    },
  ],
  'va-modal': [
    {
      action: 'click',
      event: 'cta-modal-click',
      prefix: 'modal',
    },
    {
      action: 'show',
      event: 'int-modal-show',
      prefix: 'modal',
    },
  ],
  'va-notification': [
    {
      action: 'linkClick',
      event: 'nav-notification-link-click',
      prefix: 'notification',
    },
    {
      action: 'close',
      event: 'int-notification-close',
      prefix: 'notification',
    },
  ],
  'va-number-input': [
    {
      action: 'blur',
      event: 'int-number-input-blur',
      prefix: 'number-input',
    },
  ],
  'va-official-gov-banner': [
    {
      action: 'expand',
      event: 'int-official-gov-banner-expand',
      prefix: 'official-gov-banner',
    },
    {
      action: 'collapse',
      event: 'int-official-gov-banner-collapse',
      prefix: 'official-gov-banner',
    },
  ],
  'va-on-this-page': [
    {
      action: 'click',
      event: 'nav-jumplink-click',
    },
  ],
  'va-privacy-agreement': [
    {
      action: 'click',
      event: 'nav-privacy-agreement-checkbox-click',
      prefix: 'privacy-agreement',
    },
  ],
  'va-promo-banner': [
    {
      action: 'linkClick',
      event: 'nav-promo-banner-link-click',
      prefix: 'promo-banner',
    },
    {
      action: 'close',
      event: 'int-promo-banner-close',
      prefix: 'promo-banner',
    },
  ],
  'va-radio': [
    {
      action: 'change',
      event: 'int-radio-button-option-click',
      prefix: 'radio-button',
    },
  ],
  'va-search-input': [
    {
      action: 'click',
      event: 'int-search-input-click',
      prefix: 'search-input',
    },
    {
      action: 'blur',
      event: 'int-search-input-blur',
      prefix: 'search-input',
    },
  ],
  'va-select': [
    {
      action: 'change',
      event: 'int-select-box-option-click',
      prefix: 'select',
    },
  ],
  'va-pagination': [
    {
      action: 'linkClick',
      event: 'nav-paginate-number',
      prefix: 'pagination',
    },
    {
      action: 'linkClick',
      event: 'nav-paginate-previous',
      prefix: 'pagination',
    },
    {
      action: 'linkClick',
      event: 'nav-paginate-next',
      prefix: 'pagination',
    },
  ],
  'va-progress-bar': [
    {
      action: 'change',
      event: 'nav-progress-bar-change',
      prefix: 'progress-bar',
    },
  ],
  'va-segmented-progress-bar': [
    {
      action: 'change',
      event: 'nav-segmented-progress-bar-change',
      prefix: 'segmented-progress-bar',
    },
  ],
  'va-telephone': [
    {
      action: 'click',
      event: 'int-telephone-link-click',
      prefix: 'telephone',
    },
  ],
  'va-text-input': [
    {
      action: 'blur',
      event: 'int-text-input-blur',
      prefix: 'text-input',
    },
  ],
  'va-textarea': [
    {
      action: 'blur',
      event: 'int-textarea-blur',
      prefix: 'textarea',
    },
  ],
};

export function subscribeComponentAnalyticsEvents(
  e,
  recordEvent = _recordEvent,
) {
  // Is it a component we are tracking?
  const component = analyticsEvents[e.detail.componentName];

  if (component) {
    const action = component.find(ev => ev.action === e.detail.action);
    const { version } = e.detail;

    if (action) {
      const dataLayer = {
        event: action.event,
        'event-source': 'component-library',
        'component-library-version': version,
      };

      // If the event included additional details / context...
      if (e.detail.details) {
        for (const key of Object.keys(e.detail.details)) {
          const newKey = action.prefix ? `${action.prefix}-${key}` : key;

          dataLayer[newKey] = e.detail.details[key];
        }
      }

      if (
        ['int-accordion-expand', 'int-accordion-collapse'].includes(
          action.event,
        )
      ) {
        dataLayer['accordion-section-label'] = getSectionLabel(e.target);
      }

      recordEvent(dataLayer);

      // Reset dataLayer properties to undefined with a new push
      // so they don't bleed into other event.

      const clearedDataLayer = { ...dataLayer };

      // Remove event property
      if (Object.prototype.hasOwnProperty.call(clearedDataLayer, 'event')) {
        delete clearedDataLayer.event;
      }

      // Remove gtm.uniqueEventId property
      if (
        Object.prototype.hasOwnProperty.call(
          clearedDataLayer,
          'gtm.uniqueEventId',
        )
      ) {
        delete clearedDataLayer['gtm.uniqueEventId'];
      }

      // Set everything else to undefined
      Object.keys(clearedDataLayer).forEach(key => {
        clearedDataLayer[key] = undefined;
      });

      recordEvent(clearedDataLayer);
    }
  }
}

document.body.addEventListener(
  'component-library-analytics',
  subscribeComponentAnalyticsEvents,
);