tachyon-event-tracker
v32.0.0
Published
An event tracking library that models [Blueprint](https://blueprint.di.xarth.tv/#/schemas)/Spade events for dispatch from a React applications.
Downloads
3
Readme
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/
:
- Create a new file named
<newEventClass>.ts
with the necessary types and interfaces to represent the new events. - Within
index.ts
, export the entirety of the<newEventClass>.ts
and add each of the new raw/processed event interfaces to the existingRawEventData
andProcessedEventData
type unions.
Create A Tracking HOC For The New Event Class
- Create a new folder in the
src/
directory named<newEvent>Tracking
. - Create a new
index.ts
file within that directory that exports the HOC and public interfaces. - 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',
});
}