Source: listeners/purchase.js

import Listener from "./listener";
import { AddPaymentInfoShopifyListener } from "./add-payment-info";

import { centsToDollars, createCartItem, getOrderTypeFromCartItems } from "../cart-item.js";

/**
 * 'ga4_purchase' - triggered when the customer lands on the "Thank You" page in ReCharge checkout
 * Reads `shipping_tier` and `payment_type` from `sessionStorage`.
 * These values should be stored on the last page of checkout, since they are not available on the "Thank You" page.
 * @class
 * @extends Listener
 * @param {Object} cart - pass in the rcData.cart object here
 */
export class PurchaseListener extends Listener {
    eventName = 'ga4_purchase';

    constructor({ cart, firstLoad }) {
        super();
        this.cart = new CheckoutCart(cart);
        this.isFirstLoad = firstLoad;
    }

    listen() {
        if (this.isFirstLoad) this.trigger();
    }

    createPayload() {
        const shipping_tier = sessionStorage.getItem('eventTracker.shippingTier') || 'USPS Free 3-5Day Shipping';
        const payment_type = sessionStorage.getItem('eventTracker.paymentType') || 'Credit Card';

        return {
            ecommerce: {
                ...this.cart.getEventData(),
                shipping_tier,
                payment_type,
            }
        };
    }
}

/**
 * Consumes an rcData.cart object (a global variable on the "Thank You" page of ReCharge checkout).
 * Adapts the cart object and line items so they can easily be used by {@link PurchaseListener}.
 * @class
 * @param {Object} cart - the rcData.cart object
 */
class CheckoutCart {
    constructor(cart) {
        this.cart = cart;
    }

    get discountCode() {
        return this.cart.discount_code;
    }

    get orderID() {
        return this.cart.order_id;
    }

    get totalShipping() {
        return this.cart.total_shipping;
    }

    get totalTax() {
        return this.cart.total_tax;
    }

    get totalPrice() {
        return this.cart.total_price;
    }

    get currency() {
        return this.cart.currency;
    }

    get items() {
        return this.cart.items.map(
            item => createCartItem(
                // include price in cents so it will match the CartJS cart item type
                // TODO: find a better way to adapt these interfaces
                { ...item, price: item.price * 100 },
                { currency: this.currency })
        );
    }

    get orderType() {
        return getOrderTypeFromCartItems(this.items);
    }

    /**
     * Formats the cart data so it can be used in an event payload
     * NOTE: this does not include 'shipping_tier' or 'payment_type' since these are not part of the `rcData` cart object.
     * @method getEventData
     * @returns {Object} - the event data that must be extracted from the cart
     * @memberof CheckoutCart
     */
    getEventData() {
        return {
            transaction_id: this.orderID,
            currency: this.currency,
            value: this.totalPrice,
            tax: this.totalTax,
            shipping: this.totalShipping,
            coupon: this.discountCode,
            order_type: this.orderType,
            items: this.items
        };
    }
}

export class PurchaseShopifyListener extends AddPaymentInfoShopifyListener {
    eventName = 'ga4_purchase';

    listen() {
        this.trigger();
    }

    createPayload() {
        return {
            ecommerce: {
                ...super.createPayload().ecommerce,
                payment_type: this.getPaymentType(),
                shipping: centsToDollars(this.checkout.shipping_price),
                tax: centsToDollars(this.checkout.tax_price),
                transaction_id: this.checkout.order_id,
            }
        };
    }

    getPaymentType() {
        return sessionStorage.getItem('eventTracker.paymentType') || null;
    }
}