All files / src/contexts/Analytics Analytics.tsx

11.76% Statements 4/34
0% Branches 0/14
0% Functions 0/11
12.5% Lines 4/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95                                  1x         1x                               1x   1x                                                                                                            
import {
  useContext,
  useCallback,
  useRef,
  createContext,
  FunctionComponent,
  useEffect,
} from "react";
import { useLocation } from "react-router-dom";
import { ClickEventConfig, PageViewConfig } from "./types";
import { clickEvent } from "./util";
 
export interface AnalyticsAPI {
  trackCustomEvent: (opts: ClickEventConfig) => void;
  trackPageView: (opts: PageViewConfig) => void;
}
 
const AnalyticsContext = createContext<AnalyticsAPI>({
  trackCustomEvent: () => {},
  trackPageView: () => {},
});
 
const dispatchAnalyticsEvent = (
  detail: PageViewConfig | ClickEventConfig,
  cb?: () => void
) => {
  window?.AWSMA?.ready?.(() => {
    if (process.env.NODE_ENV === "development") {
      console.info(detail.event.name, detail);
    }
    document.dispatchEvent(
      new CustomEvent(window.AWSMA.TRIGGER_EVENT, { detail })
    );
 
    cb?.();
  });
};
 
export const useAnalytics = () => useContext(AnalyticsContext);
 
export const AnalyticsProvider: FunctionComponent = ({ children }) => {
  const { pathname } = useLocation();
 
  const prevPath = useRef<null | string>(null);
 
  const trackPageView: AnalyticsAPI["trackPageView"] = useCallback(
    (opts) => {
      if (prevPath.current === pathname) {
        return;
      }
 
      dispatchAnalyticsEvent(opts, () => {
        prevPath.current = pathname;
      });
    },
    [pathname]
  );
 
  // Tracks click events for elements with a `data-event` attr or elements which are nested within a data-event item
  useEffect(() => {
    const listener = (e: MouseEvent) => {
      if (e.target) {
        let eventName: string | null = null;
        let target: HTMLElement | null = e.target as HTMLElement;
 
        while (target && !eventName) {
          if (target.hasAttribute?.("data-event")) {
            eventName = target.getAttribute("data-event");
          } else if (target.parentElement) {
            target = target.parentElement;
          } else {
            target = null;
          }
        }
 
        if (eventName) {
          dispatchAnalyticsEvent(clickEvent({ name: eventName }));
        }
      }
    };
 
    window.addEventListener("click", listener);
 
    return () => window.removeEventListener("click", listener);
  }, []);
 
  return (
    <AnalyticsContext.Provider
      value={{ trackPageView, trackCustomEvent: dispatchAnalyticsEvent }}
    >
      {children}
    </AnalyticsContext.Provider>
  );
};