/* * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ import { BrowserPlugin, BrowserTracker, parseAndValidateFloat, parseAndValidateInt, dispatchToTrackersInCollection, } from '@snowplow/browser-tracker-core'; import { buildSelfDescribingEvent, CommonEventProperties, SelfDescribingJson } from '@snowplow/tracker-core'; const _trackers: Record = {}; const _context: Record> = {}; /** * For tracking GA Enhanced Ecommerce events and contexts * {@link https://developers.google.com/analytics/devguides/collection/analyticsjs/enhanced-ecommerce} * * @deprecated Use @snowplow/browser-plugin-snowplow-ecommerce instead */ export function EnhancedEcommercePlugin(): BrowserPlugin { return { activateBrowserPlugin: (tracker) => { _trackers[tracker.id] = tracker; _context[tracker.id] = []; }, }; } /** * An Enhanced Ecommerce Action * Used when tracking an GA Enhanced Ecommerce Action with all stored Enhanced Ecommerce contexts */ export interface EnhancedEcommerceAction { /** Actions specify how to interpret product and promotion data */ action?: string; } /** * Track a GA Enhanced Ecommerce Action with all stored * Enhanced Ecommerce contexts * * @param event * @param trackers */ export function trackEnhancedEcommerceAction( event: EnhancedEcommerceAction & CommonEventProperties = {}, trackers: Array = Object.keys(_trackers) ) { dispatchToTrackersInCollection(trackers, _trackers, (t) => { const combinedContexts = _context[t.id].concat(event.context || []); _context[t.id].length = 0; t.core.track( buildSelfDescribingEvent({ event: { schema: 'iglu:com.google.analytics.enhanced-ecommerce/action/jsonschema/1-0-0', data: { action: event.action, }, }, }), combinedContexts, event.timestamp ); }); } /** * The Action Context * Represents information about an ecommerce related action that has taken place. */ export interface EnhanacedCommerceActionContext { /** The transaction id */ id?: string; /** The store of affiliation from which this transaction occured */ affiliation?: string; /** Specifies the total revenue or grand total associated with the transaction */ revenue?: string; /** The total tax associated with the transaction. */ tax?: number; /** The shipping cost associated with the transaction. */ shipping?: number; /** The transaction coupon redeemed with the transaction. */ coupon?: string; /** The list that the associated products belong to. */ list?: string; /** A number representing a step in the checkout process. Optional on `checkout` actions. */ step?: number; /** Additional field for checkout and checkout_option actions that can describe option information on the checkout page, like selected payment method. */ option?: string; /** The currency of the transactoin */ currency?: string; } /** * Adds a GA Enhanced Ecommerce Action Context * * @param context - The context to be stored * @param trackers - The tracker identifiers which the context will be stored against */ export function addEnhancedEcommerceActionContext( context: EnhanacedCommerceActionContext = {}, trackers: Array = Object.keys(_trackers) ) { const { id, affiliation, revenue, tax, shipping, coupon, list, step, option, currency } = context; trackers.forEach((trackerId) => { if (_context[trackerId]) { _context[trackerId].push({ schema: 'iglu:com.google.analytics.enhanced-ecommerce/actionFieldObject/jsonschema/1-0-0', data: { id: id, affiliation: affiliation, revenue: parseAndValidateFloat(revenue), tax: parseAndValidateFloat(tax), shipping: parseAndValidateFloat(shipping), coupon: coupon, list: list, step: parseAndValidateInt(step), option: option, currency: currency, }, }); } }); } /** * An enhanced ecommerce impression context */ export interface EnhancedEcommerceImpressionContext { /** The product ID or SKU */ id?: string; /** The name of the product */ name?: string; /** The list or collection to which the product belongs */ list?: string; /** The brand associated with the product */ brand?: string; /** The category to which the product belongs */ category?: string; /** The variant of the product */ variant?: string; /** The product's position in a list or collection */ position?: number; /** The price of a product */ price?: string; /** The currency of a product */ currency?: string; } /** * Adds a GA Enhanced Ecommerce Impression Context * * @param context - The context to be stored * @param trackers - The tracker identifiers which the context will be stored against */ export function addEnhancedEcommerceImpressionContext( context: EnhancedEcommerceImpressionContext = {}, trackers: Array = Object.keys(_trackers) ) { const { id, name, list, brand, category, variant, position, price, currency } = context; trackers.forEach((trackerId) => { if (_context[trackerId]) { _context[trackerId].push({ schema: 'iglu:com.google.analytics.enhanced-ecommerce/impressionFieldObject/jsonschema/1-0-0', data: { id: id, name: name, list: list, brand: brand, category: category, variant: variant, position: parseAndValidateInt(position), price: parseAndValidateFloat(price), currency: currency, }, }); } }); } /** * An enhanced ecommerce product context */ export interface EnhancedEcommerceProductContext { /** The product ID or SKU */ id?: string; /** The name of the product */ name?: string; /** The list or collection to which the product belongs */ list?: string; /** The brand associated with the product */ brand?: string; /** The category to which the product belongs */ category?: string; /** The variant of the product */ variant?: string; /** The price of a product */ price?: number; /** The quantity of a product */ quantity?: number; /** The coupon code associated with a product */ coupon?: string; /** The product's position in a list or collection */ position?: number; /** The currency of the product */ currency?: string; } /** * Adds a GA Enhanced Ecommerce Product Context * * @param context - The context to be stored * @param trackers - The tracker identifiers which the context will be stored against */ export function addEnhancedEcommerceProductContext( context: EnhancedEcommerceProductContext = {}, trackers: Array = Object.keys(_trackers) ) { const { id, name, list, brand, category, variant, price, quantity, coupon, position, currency } = context; trackers.forEach((trackerId) => { if (_context[trackerId]) { _context[trackerId].push({ schema: 'iglu:com.google.analytics.enhanced-ecommerce/productFieldObject/jsonschema/1-0-0', data: { id: id, name: name, list: list, brand: brand, category: category, variant: variant, price: parseAndValidateFloat(price), quantity: parseAndValidateInt(quantity), coupon: coupon, position: parseAndValidateInt(position), currency: currency, }, }); } }); } /** * An enhanced ecommerce promo context */ export interface EnhancedEcommercePromoContext { /** The promotion ID */ id?: string; /** The name of the promotion */ name?: string; /** The creative associated with the promotion */ creative?: string; /** The position of the creative */ position?: string; /** The currency of the product */ currency?: string; } /** * Adds a GA Enhanced Ecommerce Promo Context * * @param context - The context to be stored * @param trackers - The tracker identifiers which the context will be stored against */ export function addEnhancedEcommercePromoContext( context: EnhancedEcommercePromoContext = {}, trackers: Array = Object.keys(_trackers) ) { const { id, name, creative, position, currency } = context; trackers.forEach((trackerId) => { if (_context[trackerId]) { _context[trackerId].push({ schema: 'iglu:com.google.analytics.enhanced-ecommerce/promoFieldObject/jsonschema/1-0-0', data: { id, name, creative, position, currency, }, }); } }); }