32.0.0 • Published 1 year ago

tachyon-event-tracker v32.0.0

Weekly downloads
-
License
UNLICENSED
Repository
-
Last release
1 year ago

Event Tracker

An event tracking library that models Blueprint/Spade events for dispatch from a React applications.

  • Compatible with Webpack Tree Shaking.
  • Bring your own Spade Event Reporting implementation, works well with Event Reporter.
  • Uses React 16's Context API to make it easy to consume top-level application and routing state at any level in the component hierarchy.
  • React HOC per event class to keep things simple and minimize impact on bundle size.
  • Supports most standard Blueprint events

Note: If this package is missing something that seems generically re-usable, approach the Emerging Platforms team during the planning phase of your next feature/iteration and we'll plan inject work to add support or find a helpful compromise.

Consumer Examples

Getting Started

$ yarn add tachyon-event-tracker

At the root of your application:

import { Component } from 'react';
import { EventTrackerRoot, ProcessedEventData } from 'tachyon-event-tracker';

class AppRoot extends Component {
  public override render(): JSX.Element {
    return (
      <EventTrackerRoot
        interactionMedium="<app-name>"
        location="<map-from-current-location>"
        onEvent={this.handleTrackingEvent}
      >
        { // app components }
      </EventTrackerRoot/>
    );
  }

  private handleTrackingEvent = (trackingEvent: ProcessedEventData) => {
    // Here you would deal with sending events to Spade.
    // We recommend using "tachyon-event-reporter"
  }
}

Note: Alternatively, location can be set for all events via the declarative <Pageview /> component covered in Pageview Tracking. This approach is preferred in a react-router application. Don't use both approaches together.

Supported Tracking Event Classes

Note: If the event you need is not currently supported, follow the instructions on Adding New Events.

Pageview Tracking:

  • declaratively track pageview events via Pageview component
  • used to set "location" for all other events so render as high up the component hierarchy as possible
  • automatically consumes content, medium, email_id as set on the EventTrackerRoot
import { Pageview, PageviewDataPayload } from 'tachyon-event-tracker';

class SomePage extends Component {
  public override render(): JSX.Element {
    const data: PageviewDataPayload = { ... };

    // The event will be emitted only once when Pageview is mounted
    return <Pageview {...data} />;
  }
}

For special cases, there is an alternate usePageview hook that takes the same parameters as the Pageview component.

Interaction Tracking:

Supported tracking methods:

Extending An Interaction Medium

Clicking "Some Button" below would fire a ui_interaction with interaction_medium=my-app and a interaction_content=some-button.

import { EventTrackerRoot } from 'tachyon-event-tracker';
import { TrackableButton } from '.';

<EventTrackerRoot interactionMedium="root">
  <TrackableButton interactionContent="some-button">
    Some Button
  </TrackableButton>
</EventTrackerRoot>;

To better classify and name space clicks, utilize an ExtendInteractionMedium component. The following example would have an interaction_medium=my-app.cool-feature and a interaction_content=some-button:

import {
  EventTrackerRoot,
  ExtendInteractionMedium,
} from 'tachyon-event-tracker';
import { TrackableButton } from '.';

<EventTrackerRoot interactionMedium="my-app">
  <ExtendInteractionMedium interactionMedium="cool-feature">
    <TrackableButton interactionContent="some-button">
      Some Button
    </TrackableButton>
  </ExtendInteractionMedium>
</EventTrackerRoot>;

Custom Tracking

In situations where you want to define and build your own tracking events outside of the package, but have them handled the same way natively supported event would, you can use the withCustomTracking HOC:

import { CustomTrackingProps, withCustomTracking } from 'tachyon-event-tracker';

interface SomeComponentProps extends CustomTrackingProps {}

class SomeComponentBase extends Component<SomeComponentProps> {
  public override render() {
    return <div onMouseEnter={this.mouseEnterHandler} />;
  }

  public mouseEnterHandler = () => {
    this.props.trackEvent(…);
  }
}

export const SomeComponent = withCustomTracking(SomeComponentBase);

Or the useCustomTracking hook:

import { useCustomTracking } from 'tachyon-event-tracker';

function SomeComponent: FC = () => {
  const trackEvent = useCustomTracking();

  function mouseEnterHandler() {
    trackEvent(…);
  }
};

Adding New Events

Rule of Thumb:

  • Group related events that have the same prefix or are used to track related functionality by extending existing HOCs and type files.
  • Follow the process below if you're adding a completely new class of events.

Create Type Definitions For The New Event Class

In src/eventData/:

  1. Create a new file named <newEventClass>.ts with the necessary types and interfaces to represent the new events.
  2. Within index.ts, export the entirety of the <newEventClass>.ts and add each of the new raw/processed event interfaces to the existing RawEventData and ProcessedEventData type unions.

Create A Tracking HOC For The New Event Class

  1. Create a new folder in the src/ directory named <newEvent>Tracking.
  2. Create a new index.ts file within that directory that exports the HOC and public interfaces.
  3. Create a new file named in that directory named with<NewEvent>Tracking.tsx:

Note, the snippet shows how you'd support multiple related events for an HOC. If your use case only needs to support a single event type you can remove the type union and related logic.

// src/newEventTracking/withNewEventTracking.tsx

import type { ComponentClass, ComponentType } from 'react';
import { createWithTracking } from '../createWithTracking';
import { EventType } from '../eventData';
import { EventTrackerContext } from '../EventTrackerRoot';

interface NewEventDataPayload {
  // ...
}

interface NewEvent2DataPayload {

}

type NewEvent =
 { type: EventType.NewEvent, payload: NewEventDataPayload } |
 { type: EventType.NewEvent2, payload: NewEvent2DataPayload };

/**
 * Props for mixing into components wrapped by withNewEventTracking.
 * Includes payload as partial to allow parents to optionally pass in values.
 */
export interface NewEventTrackingProps {
  trackNewEvent: (event: NewEvent) => void;
}

/**
 * Map the event to the appropriate RawEventData type. Replaces
 * undefined values with null, but does not clobber falsy values.
 */
function trackingFunction(context: EventTrackerContext): (event: NewEvent) => void {
  return (event: NewEvent) => {
    switch (event.type) {
      case EventType.NewEvent:
        onEvent({ // ... });
      case EventType.NewEvent2:
        onEvent({ // ... });
    }
  };
}

/**
 * withNewEvent is a HOC that provides the trackNewEvent prop
 * function to the wrapped component, allowing it to report NewEvent events.
 * To use, extend the wrapped components props with NewEventProps.
 */
export function withNewEventTracking<P extends NewEventTrackingProps>(
  Comp: ComponentType<P>,
): FC<Omit<P, keyof NewEventTrackingProps>> {
   return createWithTracking({
     Comp,
     trackingFunction,
     displayName: 'NewEventTracking',
     trackingFunctionName: 'trackNewEvent',
   });
 }