import { History, Location } from 'history' import { debounce, inIframe } from './utils' declare global { interface Window { _paq: any } } type MatomoAction = | 'trackPageView' | 'trackEvent' | 'setReferrerUrl' | 'setCustomUrl' | 'setCustomVariable' type PushArgs = [MatomoAction, ...Array<string | number>] type PushType = (args: PushArgs) => void const ua = window.navigator.userAgent // https://chromium.googlesource.com/chromium/src.git/+/master/docs/ios/user_agent.md const iOSSafari = (!!/iPad/i.exec(ua) || !!/iPhone/i.exec(ua)) && !!/WebKit/i.exec(ua) && !/CriOS/i.exec(ua) export default class Tracker { push: PushType debouncedPush: PushType unlistenFromHistory: (() => void) | undefined previousPath: string | undefined constructor( pushFunction: PushType = (args) => { // There is an issue with the way Safari handle cookies in iframe, cf. // https://gist.github.com/iansltx/18caf551baaa60b79206. We could probably // do better but for now we don't track action of iOs Safari user in // iFrame -- to avoid errors in the number of visitors in our stats. if (!(iOSSafari && inIframe)) { window._paq.push(args) } } ) { if (typeof window !== 'undefined') window._paq = window._paq || [] this.push = pushFunction this.debouncedPush = debounce(200, pushFunction) } connectToHistory(history: History) { this.unlistenFromHistory = history.listen((loc) => { this.track(loc) }) return history } disconnectFromHistory() { if (this.unlistenFromHistory) { this.unlistenFromHistory() return true } return false } track(loc: Location) { const currentPath = loc.pathname + loc.search if (this.previousPath === currentPath) { return } if (this.previousPath) { this.push(['setReferrerUrl', this.previousPath]) } this.push(['setCustomUrl', currentPath]) // TODO: We should also call 'setDocumentTitle' but at this point the // document.title isn't updated yet. this.push(['trackPageView']) this.previousPath = currentPath } } export const devTracker = new Tracker( console?.debug?.bind(console) ?? (() => {}) // eslint-disable-line no-console )