class Tracker {
  constructor(transport) {
    this.transport = transport;
  }
  track() {
    throw new Error('Track does not implemented');
  }
}

class YATracker extends Tracker {
  /**
   * Yandex analytics ecommerce tracker.
   * docs: https://yandex.ru/support/metrika/data/e-commerce.html
  **/
  constructor(transport, currencyCode) {
    super(transport);
    this.currencyCode = currencyCode;
  }
  detail(productsData) {
    this.track({detail: {products: productsData}});
  }
  add(productsData) {
    this.track({add: {products: productsData}});
  }
  remove(productsData) {
    this.track({remove: {products: productsData}});
  }
  purchase(productsData, actionData) {
    this.track({purchase: {products: productsData, actionField: actionData}});
  }
  track(data) {
    this.transport.push({
      ecommerce: Object.assign({currencyCode: this.currencyCode}, data),
    });
  }
}

class GATracker extends Tracker {
  /**
   * Google analytics ecommerce tracker.
   * docs: https://developers.google.com/analytics/devguides/collection/analyticsjs/ecommerce?hl=en
  **/
  constructor(transport, name) {
    super(transport);
    this.name = name;
  }
  purchase(productsData, txData) {
    this.track('addTransaction', txData);
    for (let data of productsData)
      this.track('addItem', data);
    this.track('send');
  }
  track(actionName, data) {
    this.transport(`${this.name}:${actionName}`, data);
  }
}


/**
 * Reliable loader of Google Analytics scripts.
 *
 * Google Analytics scripts (GA) are loading by the Google tag manager (GTM).
 * If GA is still not loaded, the function will delay execution until it is loaded.
 */
function loadGaTransport(onLoadName) {
  var state = {
    loaded: false,
    delayed: [],
  };

  let load = () => {
    ga('require', 'ecommerce');
    state.loaded = true;
  };

  try {
    load();
  } catch (e) {
    window.addEventListener(onLoadName, () => {
      load();
      // submit delayed transactions
      state.delayed.forEach((args) => ga(...args));
    });
  }

  return (...args) => {
    if (state.loaded) {
      ga(...args);
    } else {
      state.delayed.push(args);
    }
  };
}

@@ -1643,516 +1643,294 @@
 aded
-.
 %0A *
-/%0Afunction loadGaTransport(onLoadName) %7B%0A  var state = %7B%0A    loaded: false,%0A    delayed: %5B%5D,%0A  %7D;%0A%0A  let load = () =%3E %7B%0A    ga('require', 'ecommerce');%0A    state.loaded = tr
+ with GA command queue.%0A *%0A * See this for details about a command queue:%0A * http://bit.ly/rf-ga-command-que
 ue
-;
 %0A 
- %7D;%0A%0A  try %7B%0A    load();%0A  %7D catch (e
+*/%0Afunction loadGaTransport(
 ) %7B%0A  
-  
+if (!
 window
-.addEventListener(onLoadName, () =%3E %7B%0A      load();%0A      // submit delayed transactions%0A      state.delayed.forEach((args) =%3E ga(...args));%0A    %7D);%0A  %7D%0A%0A  return (...args) =%3E %7B%0A    if (state.loaded) %7B%0A      ga(...args);%0A    %7D else %7B%0A      state.delayed.push(args
+%5B'ga'%5D) %7B%0A    window.ga = (...args) =%3E %7B%0A      (ga.q = ga.q %7C%7C %5B%5D).push(args);%0A    %7D;%0A    ga.l = 1*new Date(
 );%0A  
- 
- 
 %7D%0A  
-%7D
+return ga
 ;%0A%7D%0A

Use google analytics command queue (#321)