PageSourceSearch

https://www.safeway.com/etc.clientlibs/wcax-core/clientlibs/clientlib-datalayer-eddl.min.js

js safeway.com collected 2026-09-24 08:38:56 UTC 961,585 bytes, 18,499 lines download raw bytes

1window.AB = window.AB || {};
2window.AB.DATALAYER = {};
3window.appEventData = window.appEventData || [];
4window.digitalData = window.digitalData || {};
5
6'use strict';
7
8// Comments in this file are of pure consistency reasons and offer no description externally
9(function () {
10    this.pathSections = [];
11    this.oneTagEnabledBanners = ['safeway', 'albertsons', 'randalls', 'vons', 'shaws', 'starmarket', 'jewelosco', 'tomthumb', 'acmemarkets', 'pavilions', 'shopamigos', 'shopalbertsonsmarket', 'shopmarketstreet', 'shopunitedsupermarkets', 'unitedsupermarkets', 'albertsonsmarket', 'amigos', 'marketstreet'];
12
13    this.initPathSections = function (getExistingPathSections) {
14        const pageUrl = window.location.pathname.startsWith('/orderahead') ? document.location.pathname.replace(/\/(orderahead|store\/\d+)/gi, '') : window.location.pathname;
15        if (getExistingPathSections) {
16            return [digitalData?.pageDetails?.subSection1, digitalData?.pageDetails?.subSection2, digitalData?.pageDetails?.subSection3, digitalData?.pageDetails?.subSection4].filter((x) => { return x && x !== '' });
17        } else {
18            this.pathSections = (pageUrl.indexOf('.') > -1 ? pageUrl.substring(0, pageUrl.indexOf('.')) : pageUrl).split('/').filter(x => { return x && x !== 'shop' && x !== 'mf' && x !== 'vineandcellar' && x != '' && x?.toLowerCase()?.indexOf('chat_') == -1 });
19        }
20    }
21
22    this.initPathSections();
23    this.pathSections[0] = this.pathSections[0] ? (this.pathSections[0] === 'weeklyad' ? 'weekly-ad' : this.pathSections[0]) : 'home';
24
25    this.DEFAULT_DELIVERY_BANNER = 'same banner delivery';
26
27    this.p13nData = '';
28    this.pfmSourceMktpCategories = '';
29
30    this.selectedSearchFacets = [];
31    this.selectedSearchSelections = [];
32    this.pastPurchasedProducts = 0;
33
34    this.LoginStatus = {
35        GUEST: 'guest',
36        REGISTERED: 'registered'
37    };
38
39    this.Flag = {
40        SIGN_IN: 1,                // 00000001
41        COUPON_CLIPPED: 2,         // 00000010
42        PRODUCT_ADDED: 4           // 00000100
43    };
44
45    this.KmsiStatus = {
46        'true': 'kmsi',
47        'false': 'nonkmsi',
48        'logout': 'nonkmsi',
49        'error': 'errorkmsi'
50    };
51
52    this.KmsiStatusReSignIn = {
53        'true': 'kmsi-reSignIn',
54        'false': 'nonkmsi-reSignIn',
55    };
56
57    this.cookieNames = {
58        MODAL_LINK: 'SAFEWAY_MODAL_LINK',
59        PASSWORD_RESET: 'PasswordReset',
60        KMSI: 'SAFEWAY_KMSI',
61        RE_SIGN_IN: 'SAFEWAY_RE_SIGN_IN'
62    };
63
64    this.JourneyStatusCode = {
65        EMPTY: 0,                                                                                  // 00000000
66        NO_ACTION: this.Flag.SIGN_IN,                                                                   // 00000001
67        COUPON_CLIPPED: this.Flag.SIGN_IN | this.Flag.COUPON_CLIPPED,                                        // 00000011
68        PRODUCT_ADDED: this.Flag.SIGN_IN | this.Flag.PRODUCT_ADDED,                                          // 00000101
69        COUPONS_CLIPPED_PRODUCTS_ADDED: this.Flag.SIGN_IN | this.Flag.COUPON_CLIPPED | this.Flag.PRODUCT_ADDED    // 00000111
70    };
71
72    this.JOURNEY_STATUSES = [];
73
74    this.JOURNEY_STATUSES[this.JourneyStatusCode.EMPTY] = '';
75    this.JOURNEY_STATUSES[this.JourneyStatusCode.NO_ACTION] = 'no_action';
76    this.JOURNEY_STATUSES[this.JourneyStatusCode.COUPON_CLIPPED] = 'clipped_coupon';
77    this.JOURNEY_STATUSES[this.JourneyStatusCode.PRODUCT_ADDED] = 'add_products';
78    this.JOURNEY_STATUSES[this.JourneyStatusCode.COUPONS_CLIPPED_PRODUCTS_ADDED] = 'coupon_products_added';
79
80    this.arrThirParty = ['instacart'];
81
82
83    this.EVENTS = {
84        ERROR: 'error',
85        PAGE_LOADED: 'pageLoaded',
86        ACTION_LINK: 'actionLink',
87        MODAL_VIEW: 'modalView',
88        ACCORDION_CLICKED: 'accordion_header_clicked',
89        REGISTRATION: 'registration',
90        SEARCH: 'search_results_page',
91        SEARCH_IMPRESSIONS: 'search_results_impressions',
92        CATEGORY_IMPRESSIONS: 'category_impressions',
93        DEALS_IMPRESSIONS: 'deals_impressions',
94        ZERO_SEARCH_RESULTS: 'zero_search_results',
95        UNCLIP: 'remove_coupon',
96        REWARDS: 'reward_redeemed',
97        REWARD_UNCLIPPED: 'reward_unclipped',
98        PRODUCT_LOADED: 'pdp_page',
99        MINICART: 'mini_cart',
100        MODAL_CLICK: 'modalClick',
101        MODAL_MESSAGE: 'userMessage',
102        LINK_CLICK: 'linkClick',
103        CRS_CLICK: 'crs-click',
104        COUPONNR: 'num_coupons',
105        COUPONCLIPPED: 'coupon_clipped',
106        BATCHCOUPONCLIPPED: 'batch_coupon_clipped',
107        SIGNIN: 'sign-in',
108        CREATEACC: 'create-account-success',
109        SIGN_OUT: 'ecom_logout',
110        SIGN_OUT_USER: 'ecom_logout_user',
111        PATHWAY_WIDGET_VIEW: 'br_pathway_view',
112        ADA: 'ada_user_input',
113        DS_CONFIRMATION: 'delivery_subscription_confirmation',
114        FULL_CART: 'full_cart',
115        TRANSACTION_COMPLETE: 'transaction_complete',
116        EDIT_CART: 'edit_cart',
117        SELECTIVE_CART: 'selective_view_cart'
118    };
119
120    this.timeLimitedFeatures = {
121        /**
122         * used for setting expiration date for features
123         * to use, add feature name here with timeLimit populated with date, eg.:
124         * featureName: { timeLimit: new Date('September 21, 2024').getTime() }
125         * then send isTrackingExpired flag in feature you want to timebox based on value under featureName.timeLimit
126         */
127    };
128
129    this.isB2BPage = function () {
130        return window.location.hostname.indexOf('business') !== -1;
131    }
132
133    /**
134    * Returns banner name
135    */
136    this.getBanner = function (shouldNotReturnB2B) {
137        let banner = '';
138        if (document.getElementById('banner')?.dataset?.banner) {
139            banner = document.getElementById('banner').dataset.banner;
140        } else if (typeof (window.SWY?.CONFIGSERVICE?.getResolvedBanner) === 'function' && window.SWY?.CONFIGSERVICE?.getResolvedBanner() && window.SWY?.CONFIGSERVICE?.getResolvedBanner() !== undefined) {
141            banner = window.SWY.CONFIGSERVICE.getResolvedBanner();
142        } else {
143            try {
144                banner = window.location.hostname.split('.')?.filter(x => { return x !== 'com' && x.search('www') === -1 && x.search('business') === -1 })[0]
145            } catch (e) {
146                console.log(`@AnalyticsTeam - Banner resolve error: ${e}`);
147            };
148        }
149        banner = `${AB.DATALAYER.isB2BPage() && !shouldNotReturnB2B ? 'business-' : ''}${banner}`;
150        return banner;
151    }
152
153    this.isPageLoadEvent = function (event) {
154        const pageLoadEvents = ['pageLoaded', 'pdp_page', 'search_results_page', 'search_results_impressions', 'checkout', 'checkout_step1', 'checkout_step2', 'checkout_step3', 'checkout_step4'];
155        return pageLoadEvents.indexOf(event) !== -1;
156    }
157
158    this.isProductActionEvent = function (event) {
159        const productActions = ['cart_add', 'add_quantity', 'remove_cart', 'remove_quantity'];
160        return productActions.indexOf(event) !== -1;
161    }
162
163    this.isOneTagCartEvent = function (event) {
164        const cartEvents = ['cart_add', 'mini_cart', 'add_quantity', 'remove_cart', 'remove_quantity'];
165        return cartEvents.indexOf(event) !== -1;
166    }
167
168    this.isOneTagCheckoutEvent = function (event) {
169        const checkoutSteps = ['checkout', 'checkout_step1', 'checkout_step2', 'checkout_step3', 'transaction_complete'];
170        return checkoutSteps.indexOf(event) !== -1;
171    }
172
173    this.shouldDelayEvent = function (event) {
174        const delayedEventsArray = ['search_results_page', 'zero_search_results', 'pageLoaded', 'pdp_page', 'search_results_impressions', 'category_impressions'];
175        return delayedEventsArray.indexOf(event) !== -1;
176    }
177
178    this.isCRSClickEvent = function (event, data) {
179        const crsLinkNames = ['product-click', 'coupon-clip-click', 'offer-details-click', 'add-to-list-click', 'pause-click', 'play-click', 'item-click', 'swipe-left-click', 'swipe-right-click'];
180        const isUniversalCRSClickEvent = event === 'crs-click'
181            && data?.link
182            && data.link.isCRSClick === true
183            && !!data?.absPlacement;
184        return AB.DATALAYER.isHomePage()
185            && !AB.DATALAYER.isB2BPage()
186            && (isUniversalCRSClickEvent
187                || (event === 'linkClick'
188                    && data?.link
189                    && (data.link.isCRSClick === true || crsLinkNames.indexOf(data.link.linkName) !== -1)
190                    && !!data?.absPlacement));
191    }
192
193    this.isOneTagTrackedLink = function (event, data) {
194        const oneTagEnabledLinkClicks = [`${digitalData?.pageDetails?.subSection1}-product-click`, 'flex-impressions', 'flex-experiment-exposure-loaded', 'bundle-impressions', 'image-impressions', 'text-impressions', 'recipe-impressions', 'deals-impressions', 'experiment-exposure-loaded-deals'];
195        const stickyLinkName = data?.link?.linkName || '';
196        const isStickyBannerClick = stickyLinkName.indexOf('bannerClicked|sticky-banner:') === 0
197            || stickyLinkName.indexOf('sticky-banner|link|') === 0
198            || stickyLinkName.indexOf('cta|sticky-banner-dismiss-') === 0
199            || stickyLinkName.indexOf('cta|sticky-promo-ad-banner-dismiss-') === 0;
200        const oneTagSpecificLinkNames = ['offer-details|coupon', 'banner-clicked', 'deals-carousel-right', 'deals-carousel-left', 'product-carousel-right', 'product-carousel-left', 'flex-impressions', 'flex-experiment-exposure-loaded', 'bundle-impressions'];
201        return (!AB.DATALAYER.isB2BPage()
202            && event === 'linkClick'
203            && data?.link
204            && (oneTagEnabledLinkClicks.indexOf(data.link.linkName) !== -1 || oneTagSpecificLinkNames.indexOf(data.link.oneTagLinkName) !== -1 || isStickyBannerClick))
205            || AB.DATALAYER.isCRSClickEvent(event, data);
206    }
207
208    this.isOneTagImpressionLink = function (event, data) {
209        const linksList = ['experiment-exposure-loaded', 'experiment-exposure-loaded-splash-screen', 'experiment-exposure-loaded-deals', 'experiment-exposure-loaded-banner', 'experiment-exposure-loaded-bundle', 'experiment-exposure', 'flex-experiment-exposure-loaded', 'banner-impressions-engagement-ladder', 'banner-impressions', 'headline-impressions', 'headline-standard-impressions', 'headline-hero-impressions', 'flex-impressions', 'bundle-impressions', 'image-impressions', 'text-impressions', 'recipe-impressions'];
210        const oneTagSpecificLinkNames = ['banner-clicked'];
211        return event === 'linkClick' && data?.link && (
212            linksList.indexOf(data.link.linkName) !== -1
213            || oneTagSpecificLinkNames.indexOf(data.link.oneTagLinkName) !== -1
214            || (data.link.linkName === 'deals-impressions' && data?.pageFilter?.mediaType === 'deals-carousel-mktng-card')
215        );
216    }
217
218    this.isOneTagGamOrAmcEvent = function (event, data) {
219        const linksList = ['gam-banner-impressions', 'gam-banner-exposure'];
220        const oneTagSpecificLinkNames = [];
221        return event === 'linkClick' && data?.link && (linksList.indexOf(data.link.linkName) !== -1 || oneTagSpecificLinkNames.indexOf(data.link.oneTagLinkName) !== -1);
222    }
223
224    this.isOneTagMiscEvent = function (event) {
225        const miscEvents = ['reward_redeemed', 'reward_unclipped'];
226        return miscEvents.indexOf(event) !== -1;
227    }
228
229    this.isOneTagMiscLinkClick = function (data) {
230        const oneTagLinkName = data?.link?.oneTagLinkName
231        const miscEvents = ['offer-details|coupon', 'deals-carousel-right', 'deals-carousel-left', 'product-carousel-right', 'product-carousel-left'];
232        return miscEvents.indexOf(oneTagLinkName) !== -1;
233    }
234
235    this.shouldSendOneTagLinkClick = function (event) {
236        const eventsToBeSentAsLC = ['reward_redeemed', 'reward_unclipped'];
237        return eventsToBeSentAsLC.indexOf(event) !== -1;
238    }
239
240    this.shouldSendDatatoOneTag = function (event, data) {
241        const oneTagEnabledEventsB2B = ['search_results_impressions', 'pdp_page', 'cart_add', 'category_impressions', 'transaction_complete','target-experiment-exposure'];
242        const oneTagEnabledEvents = ['product-exposed', 'product-impressions', 'banner-impressions', 'reward_redeemed', 'reward_unclipped', 'search_results_page', 'zero_search_results', 'target-experiment-exposure', 'custom-cake-exposed'];
243        return (oneTagEnabledEventsB2B.indexOf(event) !== -1 && AB.DATALAYER.isB2BPage() && AB.DATALAYER.oneTagEnabledBanners.indexOf(AB.DATALAYER.getBanner(true)) !== -1) || (oneTagEnabledEvents.indexOf(event) !== -1 && !AB.DATALAYER.isB2BPage()) || AB.DATALAYER.isOneTagTrackedLink(event, data);
244    }
245
246    /**
247     * Rounds up the passed value to specified number of decimals
248     * @param value - full value passed to be processed
249     * @param decimals - number of decimals that should be kept when value is rounded up
250     */
251    this.roundUpValue = function (value, decimals) {
252        return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
253    };
254
255    this.getLSItem = function (item) {
256        if (typeof (Storage) !== 'undefined') {
257            let LSValue = localStorage.getItem(item) ? localStorage.getItem(item) : '';
258            return LSValue;
259        }
260    }
261
262    this.setLSItem = async function (item, value) {
263        if (typeof (Storage) !== 'undefined') {
264            localStorage.setItem(item, value);
265        }
266    }
267
268    this.removeLSItem = async function (item) {
269        if (typeof (Storage) !== 'undefined') {
270            localStorage.removeItem(item);
271        }
272    }
273
274    this.handleGetLSValue = function (item) {
275        let value = AB.DATALAYER.getLSItem(item);
276        AB.DATALAYER.removeLSItem(item);
277        return value;
278    }
279
280    this.getSSItem = function (item) {
281        if (typeof (Storage) !== 'undefined') {
282            let SSValue = sessionStorage.getItem(item) ? sessionStorage.getItem(item) : '';
283            return SSValue;
284        }
285    }
286
287    this.removeSSItem = async function (item) {
288        if (typeof (Storage) !== 'undefined') {
289            sessionStorage.removeItem(item);
290        }
291    }
292
293    this.safeJSONParse = function (valueToBeParsed) {
294        if (valueToBeParsed && valueToBeParsed !== '' && valueToBeParsed !== 'undefined') {
295            try {
296                return JSON.parse(valueToBeParsed);
297            } catch (error) {
298                console.error(`@AnalyticsTeam - Failed to parse JSON: ${error}`);
299            }
300        }
301        return {};
302    }
303
304    /**
305     * Find the visible html element - equivalent of checking :visible in jquery
306     * @param queryElements html querySelectorAll value to find the visible status
307     * @returns Filtered Visible element array
308     */
309    this.findVisibleElement = function (queryElements) {
310        if (queryElements) {
311            const visibleElems = [];
312            for (let i = 0; i < queryElements.length; ++i) {
313                if ((window.getComputedStyle(queryElements[i])).display !== 'none' && queryElements[i].offsetParent) {
314                    visibleElems.push((queryElements[i]));
315                }
316            }
317            return visibleElems;
318        } else {
319            return [];
320        }
321    }
322
323    this.areCookiesEnabled = function () {
324        let isEnabled = navigator?.cookieEnabled ? true : false;
325        // return if cookies are enabled from browser
326        return isEnabled;
327    }
328
329    this.getResolvedCookieName = function (cname) {
330        let isB2B = false,
331            siteType = window.location.hostname && window.location.hostname.startsWith('business'),
332            cookieName = cname;
333        const sessionCookiePrefixes = ['SWY_', 'EComm', 'USED_', 'SAFEWAY_', 'abs_', 'absV'];
334        // check if cookie name does not start with B_ and on B2B site
335        if (cname && !cname.startsWith('B_') && siteType) {
336            for (let i = 0; i < sessionCookiePrefixes.length; i++) {
337                if (cname.startsWith(sessionCookiePrefixes[i])) {
338                    isB2B = true;
339                }
340            }
341        }
342
343        isB2B && (cookieName = 'B_' + cname)
344
345        return cookieName;
346    }
347
348    /**
349     * Function created to set the carouselName
350     * @param {*} elementReference name of the attribute that we want to reset 
351     */
352    this.getAnalyticsCarouselTitle = function (elementReference) {
353        let analyticsCarouselTitle = '';
354        if (elementReference && elementReference instanceof Element) {
355            const isBIACrossSell = elementReference.closest('.slick-product-carousel')?.querySelectorAll('[data-carousel-behaviour="bia-crossSell"]')?.length;
356            const isBIASpaCarousel = elementReference.closest('.slick-product-carousel')?.querySelectorAll('[data-carousel-behaviour="bia-spaCarousel"]')?.length;
357            if (isBIACrossSell) {
358                analyticsCarouselTitle = elementReference.closest('cross-sell')?.querySelector('.cross-sell__header .cross-sell__title')?.textContent;
359            } else if (isBIASpaCarousel) {
360                analyticsCarouselTitle = elementReference.closest('.bia-spa-carousel-container')?.querySelector('.bia-spa-carousel-container-header')?.textContent?.trim();
361            } else if (elementReference.closest('.master-product-carousel')) {
362                analyticsCarouselTitle = elementReference.closest('.master-product-carousel')?.querySelector('[data-carousel-title]')?.getAttribute('data-carousel-title');
363            } else {
364                analyticsCarouselTitle = elementReference.closest('.slick-product-carousel, .slick-coupon-carousel')?.querySelector('lazy-wrapper')?.getAttribute('data-carousel-title') ||
365                    elementReference.closest('.slick-product-carousel, .slick-coupon-carousel')?.querySelector('.carousel-header-text, .carousel-nav__header-title')?.textContent?.trim() || elementReference.closest('.cms-coupon-grid')?.querySelector('.grid-title')?.textContent?.trim();
366            }
367        }
368        return analyticsCarouselTitle;
369    }
370
371    // Retrieves a cookie based on name, returns its value as string
372    this.getCookie = function (cname) {
373        // resolve cookie name based on which site a user is on
374        if (window?.AB?.COMMON && window?.SWY?.CONFIGSERVICE) {
375            if (cname === 'SAFEWAY_KMSI' && !AB.COMMON.isB2BSite()) {
376                cvalue = SWY.CONFIGSERVICE.getKmsiValue('SAFEWAY_KMSI');
377                if (cvalue === null) {
378                    cvalue = SWY.CONFIGSERVICE.getKmsiValue('ACI_S_SAFEWAY_KMSI');
379                }
380                return cvalue;
381            } else if (cname === 'B_SAFEWAY_KMSI' && AB.COMMON.isB2BSite()) {
382                cvalue = SWY.CONFIGSERVICE.getKmsiValue('B_SAFEWAY_KMSI');
383                if (cvalue === null) {
384                    cvalue = SWY.CONFIGSERVICE.getKmsiValue('ACI_S_B_SAFEWAY_KMSI');
385                }
386                return cvalue;
387            }
388        }
389
390        const name = cname === 'absVisitorId' ? 'absVisitorId=' : this.getResolvedCookieName(cname) + '=';
391        const decodedCookie = decodeURIComponent(document.cookie);
392        const ca = decodedCookie.split(';');
393        for (let i = 0; i < ca.length; i++) {
394            let c = ca[i];
395            while (c.charAt(0) === ' ') {
396                c = c.substring(1);
397            }
398            if (c.indexOf(name) === 0) {
399                return c.substring(name.length, c.length);
400            }
401        }
402        return '';
403    };
404
405    this.deleteCookie = function (name, domain) {
406        let domainStr = domain ? 'domain=' + domain : '';
407        if (Array.isArray(name)) {
408            name.forEach(cookieName => {
409                document.cookie = cookieName + '=; expires=Thu, 05-Mar-1992 00:00:01 GMT; path=/;' + domainStr;
410            });
411        } else {
412            document.cookie = name + '=; expires=Thu, 05-Mar-1992 00:00:01 GMT; path=/;' + domainStr;
413        }
414    }
415
416    this.getUserChannel = function () {
417        const deliveryPreference = digitalData?.user?.deliveryPreference?.toLowerCase() || '';
418        return deliveryPreference === 'dug' ? 'pickup' : deliveryPreference;
419    }
420
421    this.analyticsGetURLParameterByName = function (name, doDecode) {
422        let match = RegExp('[?&]' + name + '=([^&]*)', 'i').exec(window.location.search);
423
424        if (doDecode == false) {
425            return match ? match[1].replace(/\+/g, ' ') : null;
426        } else {
427            return match ? decodeURIComponent(match[1].replace(/\+/g, ' ')) : null;
428        }
429    };
430
431    this.checkAuthorization = function () {
432        return (typeof AB?.userInfo?.userType != 'undefined' && (String(AB?.userInfo?.userType).toLowerCase() == null ||
433            String(AB?.userInfo?.userType).toLowerCase() == '' || String(AB?.userInfo?.userType).toLowerCase() == 'g'
434            || String(AB?.userInfo?.userType).toLowerCase() == 'a')) ? false : true;
435    };
436
437    this.sanitizeAnalyticsText = function (text) {
438        if (text && (typeof (text) === 'string' || text instanceof String)) {
439            return text.toLowerCase()?.replace(',', '-')?.replace('&', 'and')?.split(' ')?.join('-')?.replace(/[^\w-,|#:]/gi, '')?.replace('--', '-')?.split('-')?.filter(x => { return x })?.join('-');
440        } else {
441            return '';
442        }
443    }
444
445    this.cleanPrice = function (amt) {
446        return Math.round(amt * 100) / 100;
447    }
448
449    this.toStringAll = function (o) {
450        Object.keys(o).forEach(k => {
451            if (typeof o[k] === 'object') {
452                return this.toStringAll(o[k]);
453            }
454            if ((o[k] === 0) || o[k]) {
455                o[k] = o[k].toString();
456            };
457        });
458        return o;
459    }
460
461    this.getLocalISOTime = function (time) {
462        const timezoneOffset = time.getTimezoneOffset();
463        const convertedTimezone = Math.abs(timezoneOffset);
464        const isoFormatted = new Date(time.getTime() - timezoneOffset * 60 * 1000).toISOString();
465        return `${isoFormatted.slice(0, -1)}${timezoneOffset > 0 ? '-' : '+'}${String(Math.floor(convertedTimezone / 60)).padStart(2, '0')}:${String(convertedTimezone % 60).padStart(2, '0')}`
466    }
467
468    this.getBannerEnvironment = function () {
469        let sub = location.hostname.split('.')[0];
470
471        function bannerEnv(subDomain) {
472            let subDomainEnv = '';
473            switch (true) {
474                case subDomain.includes('dev1'):
475                    subDomainEnv = 'dev1';
476                    break;
477                case subDomain.includes('dev2'):
478                    subDomainEnv = 'dev2';
479                    break;
480                case subDomain.includes('dev3'):
481                    subDomainEnv = 'dev3';
482                    break;
483                case subDomain.includes('qa1'):
484                    subDomainEnv = 'qa1';
485                    break;
486                case subDomain.includes('qa2'):
487                    subDomainEnv = 'qa2';
488                    break;
489                case subDomain.includes('qa3'):
490                    subDomainEnv = 'qa3';
491                    break;
492                case subDomain.includes('stage'):
493                    subDomainEnv = 'stage';
494                    break;
495                case subDomain.includes('beta'):
496                    subDomainEnv = 'beta';
497                    break;
498                default:
499                    break;
500            }
501            return subDomainEnv;
502        }
503
504        return (/-/).test(sub) ? bannerEnv(sub.replace(/[^-]*-/, '')) : 'prod';
505    }
506
507    this.getAPIInfo = function () {
508        let APIInfo = {
509            subscriptionKey: '',
510            serverEnv: '',
511            impressionsSubKey: '',
512            searchSubKey: ''
513        };
514        switch (this.getBannerEnvironment()) {
515            case 'dev1':
516            case 'dev2':
517            case 'dev3':
518                APIInfo.subscriptionKey = '9d4e44621ea0402ab85b74707d88d726';
519                APIInfo.serverEnv = 'devint';
520                break;
521            case 'qa1':
522                APIInfo.subscriptionKey = '319576f956fa4a0d8de8588c95a83d43';
523                APIInfo.serverEnv = 'qa1int';
524                break;
525            case 'qa2':
526                APIInfo.subscriptionKey = 'ee45b60e76f846d7a7121895c6ce3e1d';
527                APIInfo.serverEnv = 'qa2int';
528                break;
529            case 'qa3':
530                APIInfo.subscriptionKey = '16aef1f2843741b097417cebcf4f8afc';
531                APIInfo.serverEnv = 'perfint';
532                break;
533            case 'stage':
534                APIInfo.subscriptionKey = '47223223fb8e450189a5bb98314617cc';
535                APIInfo.serverEnv = 'stageint';
536                break;
537            case 'prod':
538                APIInfo.subscriptionKey = '64713b635f004b0b81d6e4531b8c966d';
539                APIInfo.serverEnv = 'int';
540                break;
541            default:
542                break;
543        }
544        return APIInfo;
545    }
546
547    this.setDataInteger = function (value) {
548        return isNaN(parseFloat(value)) ? undefined : parseFloat(value);
549    }
550
551    this.setDataBoolean = function (value) {
552        if (typeof value === 'boolean') {
553            return value;
554        } else if (typeof value === 'string') {
555            let booleanStr = value.toLowerCase();
556            booleanStr = booleanStr === 'true' ? true : booleanStr === 'false' ? false : undefined;
557            return booleanStr;
558        } else {
559            return undefined;
560        }
561    }
562
563    this.safeReducer = function (a, b) {
564        a = isNaN(parseFloat(a)) ? 0 : parseFloat(a);
565        b = isNaN(parseFloat(b)) ? 0 : parseFloat(b);
566        return a + b;
567    };
568
569    this.getSearchImpressionProducts = function (impressions, isProductClick) {
570        return impressions.map(impression => {
571            const item = isProductClick ? impression : impression?.product;
572            return {
573                pId: item?.id,
574                bia: item?.bia,
575                oos: item?.oos,
576                sponsored: item?.sponsored,
577                mp: item?.mp,
578                display: item?.display,
579                placement: isProductClick ? impression?.placement : undefined,
580                pName: item?.name
581            }
582        });
583    }
584
585    /**
586    * Function to return date time in below format
587    * 'Wednesday, April 17, 2024 1:00 PM'
588    * @param {*} dateTimeString example value for dateTimeString 2024-04-17T13:00:00
589    */
590    this.getFullDateWithTime = function (dateTimeString) {
591        const curruntDate = new Date(dateTimeString);
592        const day = curruntDate.toLocaleDateString('en-US', { weekday: 'long' });
593        const month = curruntDate.toLocaleDateString('en-US', { month: 'long' });
594        const date = curruntDate.toLocaleDateString('en-US', { day: '2-digit' });
595        const year = curruntDate.toLocaleDateString('en-US', { year: 'numeric' });
596        const time = curruntDate.toLocaleString('en-US', { hour: '2-digit', minute: 'numeric', hour12: true });
597        return `${day}, ${month} ${date}, ${year} ${time},`;
598    }
599
600    this.generateEventId = function () {
601        const currentDate = new Date();
602        const currentTime = currentDate.getTime();
603        const eventId = `${currentTime}${Math.floor(Math.random() * 10000000000)}${window.crypto && window.crypto.randomUUID ? window.crypto.randomUUID() : ''}`;
604        return eventId;
605    };
606
607    this.generateCurrentTime = function () {
608        const currentDate = new Date();
609        const eventTime = AB.DATALAYER.getLocalISOTime(currentDate);
610        return eventTime;
611    };
612
613    this.getDeviceInfo = function () {
614        let deviceOS = ''
615        if (window?.navigator?.userAgent?.toLowerCase()?.includes('windows')) {
616            deviceOS = window?.navigator?.userAgent?.match(/\(.*?\)/g)?.map(x => x?.replace(/[()]/g, ''))[0]?.split(';')[0]?.trim()?.toLowerCase()?.replace(/\s/g, '-')?.replace(/undefined/gi, '-') || 'not-defined';
617        } else {
618            deviceOS = window?.navigator?.userAgent?.match(/\(.*?\)/g)?.map(x => x?.replace(/[()]/g, ''))[0]?.split(';')[1]?.trim()?.toLowerCase()?.replace(/\s/g, '-')?.replace(/undefined/gi, '-') || 'not-defined';
619        }
620        return deviceOS;
621    }
622
623    this.getBrowserType = function () {
624        function isMobile() {
625            const regex = /Mobi|Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
626            return (regex.test(window.navigator.userAgent)) && ('ontouchstart' in window || navigator.maxTouchPoints > 0);
627        }
628
629        return `${isMobile() ? 'mobile' : ''}web`;
630    }
631
632    this.throttleEvent = function (func, delay) {
633        // Capture the current time 
634        let time = Date.now();
635
636        return () => {
637            if ((time + delay - Date.now()) <= 0) {
638                func();
639                time = Date.now();
640            }
641        }
642    }
643
644    this.isEditOrderMode = function () {
645        let result = false;
646        // check for edit order cookies set by ERUMS
647        if (AB.DATALAYER.getCookie('SlotInfo') !== 'undefined' && AB.DATALAYER.getCookie('OrderStoreId') !== 'undefined' && AB.DATALAYER.getCookie('SlotInfo') !== '' && AB.DATALAYER.getCookie('OrderStoreId') !== '') {
648            result = true;
649        }
650        return result;
651    };
652
653    // Function to get zone & slot information for v218
654    this.getZoneInfo = function (element) {
655        const sectionInfo = {
656            section: '0',
657            row: '0',
658            zone: '0'
659        };
660        //find zone
661        if (element) {
662            let rowComponents = [];
663            const closestMarkerComponent = element?.closest('.marker-component');
664
665            const zoneElement = element?.closest('.zone')?.querySelector('.zone-component');
666            const zoneId = zoneElement?.dataset?.zoneType?.split('zone') && zoneElement?.dataset?.zoneType?.split('zone')?.length > 0 ? zoneElement?.dataset?.zoneType?.split('zone')[1] : '0';
667            sectionInfo.zone = zoneId || '0';
668            //find section Id
669            if (closestMarkerComponent) {
670                rowComponents = this.getRowComponents(closestMarkerComponent);
671                const sectionId = closestMarkerComponent.getAttribute('data-section-id');
672                sectionInfo.section = sectionId ? `${sectionId}` : '0';
673            }
674            //find row
675            if (rowComponents.length > 0) {
676                for (let i = 0; i < rowComponents.length; i++) {
677                    if (rowComponents[i].contains(element) || rowComponents[i] === element) {
678                        sectionInfo.row = i + 1;
679                        break;
680                    }
681                }
682            }
683        }
684        return sectionInfo;
685    }
686
687    // Helper function for zone function
688    this.getRowComponents = function (markerComponent) {
689        let rowComponents = [];
690        const rowComponentClassList = ['nextgen-banner-unit_HeroBanner', 'google-adManager--HeroBanner'];
691        const classList = [
692            'hero-intro',
693            'standard-intro',
694            'flex-card',
695            'master-product-carousel',
696            'title-header',
697            'shopbycategory',
698            'coupon-carousel',
699            'meal-carousel',
700            'raw-html',
701            'nextgen-banner-unit-proxy',
702            'web-stories',
703            'product-carousel-v2',
704            'multi-columns-control',
705            'nextgen-banner-unit',
706            'slick-meal-carousel',
707            'banner-headline',
708            'slick-product-carousel',
709            'image.section',
710            'button.section',
711            'bundles-box',
712            'meals-bundles-carousel'
713        ];
714        const containerClassList = [
715            'flex-container',
716            'nextgen-abs-carousel-proxy',
717            'nextgen-banner-carousel', 
718            'nextgen-abs-carousel-wrapper',
719        ];
720        const classSelector = '.' + classList.join(',.');
721        const containerClassSelector = '.' + containerClassList.join(',.');
722        const rowComponentClassListSelector = '.' + rowComponentClassList.join(',.');
723        const markerElements = markerComponent.querySelectorAll(classSelector);
724        for (let i = 0; i < markerElements.length; i++) {
725            //Check if component is empty or hidden
726            if (markerElements[i].offsetHeight <= 0 || markerElements[i].offsetWidth <= 0) {
727                //Skip the component as its empty or hidden
728                //Move to next component
729                continue;
730            }
731            //Check if element is already child of one of the row components
732            if (rowComponents.some(t => t.contains(markerElements[i]) || t === markerElements[i])) {
733                //Skip the component as its part of the container already or it is itself is row component
734                //Move to next component
735                continue;
736            }
737            //Check if the component is marked as row component
738            if (markerElements[i].querySelector(rowComponentClassListSelector) || rowComponentClassList.some(c => markerElements[i].classList.contains(c))) {
739                //Skip the row component if it is a cloned component
740                if (!markerElements[i]?.closest('.slick-cloned')) {
741                    rowComponents.push(markerElements[i]);
742                }
743                continue;
744            }
745            //Check if the component is inside the ROW component by finding closest container is either of Container classes
746            const rowComponent = markerElements[i].closest(containerClassSelector);
747            if (rowComponent) {
748                rowComponents.push(rowComponent);
749                continue;
750            }
751            //if component is not in either of the container classes then it is ROW component itself as previous condition would have skipped it
752            rowComponents.push(markerElements[i]);
753        }
754        return rowComponents;
755    }
756
757}).call(AB.DATALAYER);
758
759'use strict';
760// Serverside tracking setup - OneTag Platform
761(function () {
762    this.getBannerSubTotal = function (event, data) {
763        let subtotal = data?.cart?.transaction?.subTotal;
764        const marketPlaceCarts = data?.cart?.transaction?.subTotalMarketplaceCarts;
765
766        if (AB.DATALAYER.isOneTagCartEvent(event)) {
767            return AB.DATALAYER.setDataInteger(subtotal) || 0;
768        } else if (AB.DATALAYER.isOneTagCheckoutEvent(event)) {
769            if ((!marketPlaceCarts || marketPlaceCarts === 'undefined') && (!data?.cart?.transaction?.subTotalWineCart)) {
770                return AB.DATALAYER.setDataInteger(subtotal)
771            } else {
772                return 0
773            }
774        } else {
775            return undefined;
776        }
777    }
778
779    this.getMpSubTtl = function (event, data) {
780        let subTtlMpCarts = [];
781        const marketPlaceCarts = data?.cart?.transaction?.subTotalMarketplaceCarts;
782
783        if ((AB.DATALAYER.isOneTagCartEvent(event) || event === 'full_cart' || AB.DATALAYER.isOneTagCheckoutEvent(event)) && marketPlaceCarts && marketPlaceCarts !== 'undefined') {
784            let mpCartsArr = marketPlaceCarts.split('#');
785            subTtlMpCarts = mpCartsArr.map(cart => {
786                let sellerCartArr = cart.split(':');
787                let sellerCartId = sellerCartArr[0];
788                let sellerCartSubTtl = sellerCartArr[1];
789                return {
790                    sellerId: sellerCartId,
791                    subTotal: sellerCartSubTtl && AB.DATALAYER.setDataInteger(sellerCartSubTtl)
792                };
793            });
794
795            if (AB.DATALAYER.isOneTagCheckoutEvent(event)) {
796                let sellerId = data?.page?.sellerId;
797                subTtlMpCarts = subTtlMpCarts.filter(item => item.sellerId === sellerId);
798            }
799            return subTtlMpCarts.length > 0 ? subTtlMpCarts : undefined;
800        } else {
801            return undefined;
802        }
803    }
804
805    this.getWineSubTtl = function (wineCart) {
806        if (wineCart) {
807            return {
808                sellerId: wineCart.sellerId,
809                subTotal: wineCart.subTotal
810            }
811        }
812        else {
813            return undefined;
814        }
815    }
816
817    this.getAnalyticsCartItems = function (item) {
818        let tempCartItems = item && Array.isArray(item) ? item : [];
819        let mappedCartItems = [];
820        for (let i = 0; i < tempCartItems.length; i++) {
821            const itemId = tempCartItems[i] && tempCartItems[i].productID && tempCartItems[i].productID.toString();
822            let item = {
823                prdID: itemId,
824                prdNam: tempCartItems[i].productName,
825                units: tempCartItems[i].units,
826                lp: tempCartItems[i].listPrice,
827                bp: tempCartItems[i].basePrice,
828                ppUnit: tempCartItems[i].pricePerUnit,
829                uTyp: tempCartItems[i].unitType,
830                totp: tempCartItems[i].totalPrice,
831                itemP: tempCartItems[i].itemPrice,
832                inv: tempCartItems[i].inventory,
833                cpnClpd: tempCartItems[i].couponClipped,
834                cpnApld: tempCartItems[i].couponApplied,
835                ccSav: tempCartItems[i].clubcardItemSavings,
836                j4uSav: tempCartItems[i].j4uItemSavings,
837                rSav: tempCartItems[i].rewardsItemSavings,
838                eSav: tempCartItems[i].employeeItemSavings,
839                tSav: tempCartItems[i].totalItemSavings,
840                oTyp: tempCartItems[i].offerType,
841                oText: tempCartItems[i].offerText,
842                isFound: tempCartItems[i]?.isFound && AB.DATALAYER.setDataBoolean(tempCartItems[i]?.isFound),
843                sId: tempCartItems[i]?.productSellerId,
844                cId: tempCartItems[i]?.productCartId?.toString()
845            };
846            mappedCartItems.push(item);
847        }
848        return mappedCartItems;
849    }
850
851    this.getCookiePref = function () {
852        if (window.OptanonActiveGroups) {
853            return window.OptanonActiveGroups;
854        } else {
855            let cookie = AB.DATALAYER.getCookie('OptanonConsent');
856            if (cookie) {
857                cookie = cookie.split(/[=&]/);
858                cookie = cookie.find(e =>
858 e.includes('C000'));
859                if (cookie) {
860                    cookie = cookie.split(',');
861                    cookie = cookie.filter(e => e.includes(':1'));
862                    //assuming the [necessary only cookies] are always included
863                    cookie = cookie.join(',').replaceAll(':1', '');
864                    return cookie;
865                }
866                //if this is reached then the cookie is malformed
867                else return
868            }
869            //we have no valid cookie or window.OptanonActiveGroups
870            else return
871        }
872    }
873
874    this.getSubEvent = function (event, data) {
875        if (event === 'linkClick' && data?.link?.linkName === 'flex-impressions') {
876            return 'flex-impressions';
877        }
878
879        if (event === 'linkClick' && data?.link?.linkName === 'bundle-impressions') {
880            return 'bundle-impressions';
881        }
882
883        if (event === 'linkClick'
884            && typeof data?.link?.linkName === 'string'
885            && /^(image|text|recipe)-impressions$/.test(data.link.linkName)) {
886            return data.link.linkName;
887        }
888
889        if (event === 'linkClick' && data?.link?.linkName === 'deals-impressions') {
890            return 'deals-impressions';
891        }
892
893        if (AB.DATALAYER.isCRSClickEvent(event, data)) {
894            return 'crs:clicks';
895        }
896
897        if (event === 'linkClick' && data?.link?.linkName === 'experiment-exposure-loaded') {
898            return 'experiment-exposure';
899        }
900
901        if (event === 'linkClick' && data?.link?.linkName === 'flex-experiment-exposure-loaded') {
902            return 'experiment-exposure';
903        }
904
905        if (event === 'linkClick' && typeof data?.link?.linkName === 'string' && data.link.linkName.startsWith('experiment-exposure-loaded-')) {
906            return 'experiment-exposure';
907        }
908
909        switch (event) {
910            case 'experiment-exposure-loaded':
911            case 'experiment-exposure-loaded-splash-screen':
912            case 'experiment-exposure-loaded-deals':
913            case 'experiment-exposure-loaded-banner':
914            case 'gam-banner-exposure':
915            case 'experiment-exposure-loaded-bundle':
916                return 'experiment-exposure';
917            case 'banner-impressions':
918            case 'banner-impressions-engagement-ladder':
919            case 'gam-banner-impressions':
920                return 'banner-impressions';
921            case 'headline-impressions':
922            case 'headline-standard-impressions':
923            case 'headline-hero-impressions':
924                return 'headline-impressions';
925            case 'reward_redeemed':
926            case 'reward_unclipped':
927                return 'linkClick';
928            case 'target-experiment-exposure':
929                return 'target-experiment-exposure';
930            default:
931                if (event === 'pageLoaded' && data?.page?.subSection1 === 'aisles') {
932                    return 'category_page';
933                }
934                if (event.includes('experiment-exposure')) {
935                    return 'experiment-exposure';
936                }
937                return event;
938        }
939    }
940
941    this.getSubscriptionKey = function () {
942        return AB.DATALAYER.getAPIInfo()?.subscriptionKey;
943    }
944
945    this.getSubEventEndpoint = function (event, data) {
946        switch (true) {
947            case AB.DATALAYER.isB2BPage():
948                return '/b2b';
949            case AB.DATALAYER.isCRSClickEvent(event, data):
950                return '/ces';
951            case event === 'product-impressions' && data?.pageFilter?.mediaType === 'product-carousel-mktng-card':
952                return '/impression';
953            case event === 'search_results_impressions'
954                || event === 'product-exposed'
955                || (event === 'product-impressions' && data.link?.linkName === `${digitalData?.pageDetails?.subSection1}-product-impressions`)
956                || (event === 'linkClick' && data.link?.linkName === `${digitalData?.pageDetails?.subSection1}-product-click`)
957                || event === 'search_results_page'
958                || event === 'zero_search_results':
959                return '/search';
960            case AB.DATALAYER.isOneTagImpressionLink(event, data):
961                return '/impression';
962            case event === 'batch_coupon_clipped':
963                return '/coupon';
964            case AB.DATALAYER.isOneTagMiscEvent(event) || AB.DATALAYER.isOneTagMiscLinkClick(data):
965                return '/misc';
966            case AB.DATALAYER.isOneTagGamOrAmcEvent(event, data):
967                return '/amc';
968            case event === 'target-experiment-exposure':
969                return '/experimentation';
970            default:
971                return '';
972        }
973    }
974
975    this.updateOneTagMapping = function (event, data) {
976        let serverSideData = {};
977        serverSideData.event = {
978            name: AB.DATALAYER.isPageLoadEvent(event) ? 'pageLoaded' : 'pageAction',
979            subEvent: AB.DATALAYER.getSubEvent(event, data),
980            id: data?.serverData?.eventId,
981            time: data?.serverData?.currentTime
982        };
983        serverSideData.page = {
984            pgName: data?.page?.pageName,
985            channel: data?.page?.channel,
986            bnr: data?.page?.banner,
987            ss1: data?.page?.subSection1,
988            ss2: data?.page?.subSection2,
989            ss3: data?.page?.subSection3,
990            ss4: data?.page?.subSection4,
991            siteTP: data?.page?.siteTypePath,
992            pURL: data?.page?.pageUrl,
993            platform: data?.page?.platform,
994            rURL: data?.page?.referringURL,
995            tp: data?.page?.thirdParty,
996            sId: data?.page?.sellerId,
997            pt: data?.page?.pageType,
998            params: data?.page?.parameters?.toLowerCase(),
999            msgDetail: data?.page?.msgDetail || data?.page?.abTestDetails,
1000            bnrName: data?.page?.bnrName,
1001            dlsCpnIds: data?.page?.dlsCpnIds,
1002            expVariant: data?.page?.expVariant,
1003            deviceType: data?.page?.deviceType,
1004            prevPgname: data?.page?.previousPageName,
1005            icmpId: digitalData?.crossPageData?.analyticsQueryParamIcmpid?.data
1006        };
1007        // When the sponsored-impressions fix is disabled (killswitch ON), retain the
1008        // legacy rTyp fallback derived from the pfm string (eVar14 = 4th '#' segment).
1009        // pfm layout: "<pfmPath>#<section/mediaType>#<search|non-search>
1009#<recType>#<placement>[#<badge>]"
1010        let rTypFromPfm;
1011        if (window?.SWY?.CONFIGSERVICE?.featureToggleConfig?.isSponsoredImpressionFixDisabled) {
1012            const carouselPfm = Array.isArray(data?.carousel)
1013                ? data.carousel.find(c => c?.pfm)?.pfm
1014                : undefined;
1015            const pfmStr = carouselPfm || data?.productInfo?.pfmDetail;
1016            const pfmParts = typeof pfmStr === 'string' ? pfmStr.split('#') : [];
1017            rTypFromPfm = pfmParts.length >= 5 ? pfmParts[3] : undefined;
1018        }
1019
1020        serverSideData.pageFilter = {
1021            filTyp: data?.pageFilter?.filterType,
1022            filSel: (event === 'linkClick' && data.link?.linkName === `${digitalData?.pageDetails?.subSection1}-product-click`) ? data?.pageFilter?.pdpID : data?.pageFilter?.filterSelection,
1023            sortSel: data?.pageFilter?.sortSelection,
1024            topNav: data?.pageFilter?.topNav,
1025            carousel: data?.pageFilter?.carousel,
1026            adaFlg: data?.pageFilter?.adaFlag,
1027            rTyp: data?.pageFilter?.recommendationType || rTypFromPfm,
1028            placement: data?.pageFilter?.placement,
1029            fpDisMon: data?.pageFilter?.freshPassDiscountedMonths?.toString(),
1030            premSlots: data?.pageFilter?.premiumSlots,
1031            promoCode: data?.pageFilter?.promoCode,
1032            mTyp: data?.pageFilter?.mediaType,
1033            subsFunnel: data?.pageFilter?.subscriptionFunnel,
1034            fpPlanPrice: data?.pageFilter?.freshPassPlanPrice ? Number(data.pageFilter.freshPassPlanPrice) : undefined,
1035            bnrLoc: data?.pageFilter?.bannerCardCarousel
1036        };
1037        serverSideData.user = {
1038            shopZC: data?.user?.shopZipCode,
1039            ssId: data?.user?.shopStoreId,
1040            loginSts: data?.user?.loginStatus,
1041            ccn: data?.user?.clubCardNumber,
1042            hhId: data?.user?.houseHoldId,
1043            uType: data?.user?.userType,
1044            custId: data?.user?.customerId,
1045            subSts: data?.user?.subscriptionStatus,
1046            subDate: data?.user?.subscriptionDate,
1047            dataLC: data?.user?.dataLoadComplete,
1048            jrnSts: data?.user?.journeyStatus,
1049            addType: data?.user?.addressType,
1050            type: data?.user?.type,
1051            dlvPre: data?.user?.deliveryPreference,
1052            uuid: data?.user?.uuid,
1053            odrSts: data?.user?.orderStatus,
1054            ordCnt: data?.user?.orderCount?.toString() || data?.user?.orderStatus,
1055            custSts: data?.user?.customerStatus,
1056            dlvBnr: data?.user?.deliveryBanner,
1057            picLoc: data?.user?.pickupLocation,
1058            dlvComb: data?.user?.deliveryCombo,
1059            locTck: data?.user?.shopZipCode || data?.user?.locationTracking, // currently duplicate of shopZC, as per Raju; keeping the alternate mapping to locationTracking as well just in case
1060            absVisitorId: data?.user?.absVisitorId || AB.DATALAYER.getCookie('absVisitorId'),
1061            sessionId: data?.user?.sessionId,
1062            cookiePref: AB.DATALAYER.getCookiePref(),
1063            clientUA: window.navigator?.userAgent,
1064            osType: data?.user?.deviceInfo,
1065            adobeVisitorId: window['Visitor'] && window['Visitor'].getInstance('A7BF3BC75245ADF20A490D4D@AdobeOrg')?.getMarketingCloudVisitorID(),
1066            vendor: [
1067                {
1068                    name: 'fb',
1069                    vars: [
1070                        {
1071                            key: 'fbp',
1072                            value: AB.DATALAYER.getCookie('_fbp')
1073                        },
1074                        {
1075                            key: 'fbc',
1076                            value: ''
1077                        }
1078                    ]
1079                }
1080            ]
1081        };
1082
1083        if (data?.link?.linkName === 'gam-banner-impressions' || data?.link?.linkName === 'gam-banner-exposure') {
1084            const gamData = {
1085                name: 'gamadData',
1086                vars: [
1087                    {
1088                        key: 'adUnitPath',
1089                        value: data?.user?.gamAdData?.adUnitPath || 'no-value'
1090                    },
1091                    {
1092                        key: 'lineItemId',
1093                        value: data?.user?.gamAdData?.lineItemId || 'no-value'
1094                    },
1095                    {
1096                        key: 'creativeId',
1097                        value: data?.user?.gamAdData?.creativeId || 'no-value'
1098                    },
1099                    {
1100                        key: 'creativeTemplateId',
1101                        value: data?.user?.gamAdData?.creativeTemplateId || 'no-value'
1102                    },
1103                    {
1104                        key: 'responseStatus',
1105                        value: data?.user?.gamAdData?.responseStatus || 'no-value'
1106                    },
1107                    {
1108                        key: 'uniqueID',
1109                        value: data?.user?.gamAdData?.uniqueID || 'no-value'
1110                    },
1111                    {
1112                        key: 'responseTime',
1113                        value: data?.user?.gamAdData?.responseTime || 'no-value'
1114                    },
1115                    {
1116                        key: 'targetingMap',
1117                        value: data?.user?.gamAdData?.targetingMap || 'no-value'
1118                    }
1119                ]
1120            };
1121            serverSideData.user.vendor = serverSideData.user.vendor || [];
1122            serverSideData.user.vendor.push(gamData);
1123        }
1124        serverSideData.global = {
1125            expIds: data?.serverData?.experimentIds,
1126            attrToken: data?.serverData?.attributionToken
1127        };
1128
1129        serverSideData.productInfo = {};
1130
1131        serverSideData.search = {
1132            asf: data?.search?.autoSearchFlag?.toString() || 'false',
1133            ist: data?.search?.internalSearchTerm,
1134            resCnt: data?.search?.searchResults?.toString(),
1135            type: data?.search?.searchType,
1136            tfc: data?.search?.typedSearchCount,
1137            tst: data?.search?.typedSearchTerm,
1138            filter: data?.search?.filter,
1139            orderBy: data?.search?.orderBy,
1140            offset: data?.search?.offset && AB.DATALAYER.setDataInteger(data?.search?.offset),
1141            completionAttrToken: data?.search?.completionAttrToken,
1142            selPosition: data?.search?.selectedPosition ? Number(data?.search?.selectedPosition) : undefined,
1143            apiSearchTerm: data?.search?.apiSearchTerm,
1144            pageCategories: event !== 'search_results_impressions' && data?.search?.pageCategories ? data?.search?.pageCategories : undefined,
1145            impressions: (event === 'search_results_impressions' || event === 'category_impressions' || (event === 'linkClick' && data.link?.linkName === `${digitalData?.pageDetails?.subSection1}-product-click`)) && data?.search?.impressions ? AB.DATALAYER.getSearchImpressionProducts(data?.search?.impressions, event === 'linkClick') : undefined
1146        };
1147        serverSideData.cart = {
1148            cartInfo: {
1149                cId: data?.cart?.cartInfo?.currentCartId,
1150                sId: data?.productInfo?.sellerId,
1151                actvCarts: data?.cart?.cartInfo?.activeCarts,
1152                cType: data?.cart?.cartInfo?.cartType,
1153                isMFC: data?.cart?.cartInfo?.isMFC,
1154                mfcUnavCnt: data?.cart?.cartInfo?.mfcUnavailableCount,
1155                totUnits: data?.cart?.cartInfo?.totalUnits,
1156                uniqueSKUCnt: data?.cart?.cartInfo?.uniqueSKUCnt && AB.DATALAYER.setDataInteger(data?.cart?.cartInfo?.uniqueSKUCnt),
1157            },
1158            transaction: {
1159                dlvTime: data?.cart?.transaction?.deliveryTime,
1160                dlvWin: data?.cart?.transaction?.deliveryWindow,
1161                dlvST: data?.cart?.transaction?.deliverySlotType,
1162                ordId: data?.cart?.transaction?.orderID,
1163                payMthd: data?.cart?.transaction?.paymentMethod,
1164                rev: data?.cart?.transaction?.revenue,
1165                shipFee: data?.cart?.transaction?.shippingFee?.toString(),
1166                fuelSur: data?.cart?.transaction?.fuelSurcharge,
1167                servcFee: data?.cart?.transaction?.serviceFee?.toString(),
1168                tRev: data?.cart?.transaction?.tippingRevenue,
1169                tMode: data?.cart?.transaction?.tippingMode,
1170                uniqueOrderFlag: data?.cart?.transaction?.uniqueOrderFlag && AB?.DATALAYER?.setDataInteger(data?.cart?.transaction?.uniqueOrderFlag),
1171                icmpId: data?.cart?.transaction?.icmpId,
1172                emailClipCpn: data?.cart?.transaction?.emailClipAllCoupon,
1173                promoExist: data?.cart?.transaction?.isPromoApplied,
1174                rewardsExist: data?.cart?.transaction?.isRewardsApplied,
1175                subTtl: AB?.DATALAYER?.getBannerSubTotal(event, data),
1176                subTtlMpCarts: AB?.DATALAYER?.getMpSubTtl(event, data),
1177                subTtlWineCart: data?.cart?.transaction?.subTotalWineCart && AB.DATALAYER.getWineSubTtl(data?.cart?.transaction?.subTotalWineCart),
1178            },
1179            item: data?.cart?.item && AB.DATALAYER.getAnalyticsCartItems(data?.cart?.item),
1180            savings: {
1181                ccSav: data?.cart?.savings?.clubcardSavings,
1182                j4uSav: data?.cart?.savings?.j4uSavings,
1183                rwdSav: data?.cart?.savings?.rewardsSavings,
1184                empSav: data?.cart?.savings?.employeeSavings,
1185                pcSav: data?.cart?.savings?.promocodeSavings,
1186                catInvalidId: data?.cart?.savings?.categoryInvali
1186dId,
1187                catInvalidName: data?.cart?.savings?.categoryInvalidName,
1188                catInvalidNone: data?.cart?.savings?.categoryInvalidNone,
1189                ttlSav: data?.cart?.savings?.totalSavings ? data?.cart?.savings?.totalSavings.toString() : '0',
1190
1191            }
1192        };
1193
1194        // Populate productInfo values if they exist
1195        if ((AB.DATALAYER.isPdp()
1196            && (event === 'product-exposed'
1197                || event === 'product-impressions' || event === 'custom-cake-exposed'))
1198            || (event !== 'search_results_impressions'
1199                && event !== 'product-exposed'
1200                && event !== 'product-impressions') || (event === 'linkClick'
1201                    && data.link?.linkName === `${digitalData?.pageDetails?.subSection1}-product-click`)) {
1202            serverSideData.productInfo.pId = data?.productInfo?.productID;
1203            serverSideData.productInfo.pName = data?.productInfo?.productName  + (data?.productInfo?.isCustomCake && event === 'custom-cake-exposed' ? '|event424=1' : '');
1204            serverSideData.productInfo.fName = data?.productInfo?.fullName;
1205            serverSideData.productInfo.units = data?.productInfo?.units && AB.DATALAYER.setDataInteger(data?.productInfo?.units);
1206            serverSideData.productInfo.uTyp = data?.productInfo?.unitType;
1207            serverSideData.productInfo.ppunit = data?.productInfo?.pricePerUnit;
1208            serverSideData.productInfo.lp = data?.productInfo?.listPrice;
1209            serverSideData.productInfo.carouselSec = data?.productInfo?.carouselSection;
1210            serverSideData.productInfo.bp = data?.productInfo?.basePrice?.toString();
1211            serverSideData.productInfo.pType = data?.productInfo?.pricingType;
1212            serverSideData.productInfo.cpnFlg = data?.productInfo?.couponFlag;
1213            serverSideData.productInfo.cpnClpd = data?.productInfo?.couponClipped;
1214            serverSideData.productInfo.cpnId = data?.productInfo?.couponID;
1215            serverSideData.productInfo.aId = data?.productInfo?.aisleId ? data.productInfo.aisleId : '';
1216            serverSideData.productInfo.upc = data?.productInfo?.upc;
1217            serverSideData.productInfo.pfmDtl = data?.productInfo?.pfmDetail;
1218            serverSideData.productInfo.ics = data?.productInfo?.isCrossSell;
1219            serverSideData.productInfo.mto = data?.productInfo?.mto;
1220            serverSideData.productInfo.deptNam = data?.productInfo?.departmentName;
1221            serverSideData.productInfo.lbs = data?.productInfo?.lbs?.toString();
1222            serverSideData.productInfo.each = data?.productInfo?.each;
1223            serverSideData.productInfo.aisle = data?.productInfo?.aisleName;
1224            serverSideData.productInfo.shelf = data?.productInfo?.shelfName;
1225            serverSideData.productInfo.offTyp = data?.productInfo?.offerType;
1226            serverSideData.productInfo.offText = data?.productInfo?.offerText;
1227            serverSideData.productInfo.carouselSz = data?.productInfo?.carouselSize && AB.DATALAYER.setDataInteger(data?.productInfo?.carouselSize);
1228            serverSideData.productInfo.isRcmnd = data?.productInfo?.isRecommended;
1229            serverSideData.productInfo.iQn = data.link?.linkName === `${digitalData?.pageDetails?.subSection1}-product-click` ? undefined : data?.productInfo?.units ? data?.productInfo.units.toString() : '0';
1230            serverSideData.productInfo.iv = data?.productInfo?.listPrice?.toString();
1231            serverSideData.productInfo.sellerId = data?.productInfo?.sellerId;
1232            serverSideData.productInfo.sellerNam = data?.productInfo?.sellerName;
1233            serverSideData.productInfo.isMHMD = data?.productInfo?.isProductTrackingDisabled;
1234            serverSideData.productInfo.bia = data?.productInfo?.bia;
1235            serverSideData.productInfo.oos = data?.productInfo?.oos;
1236            serverSideData.productInfo.sponsored = data?.productInfo?.sponsored;
1237            serverSideData.productInfo.mp = data?.productInfo?.mp;
1238            serverSideData.productInfo.display = data?.productInfo?.display;
1239            serverSideData.productInfo.placement = data?.productInfo?.placement;
1240            serverSideData.productInfo.isCustomCake = data?.productInfo?.isCustomCake ? "Yes" : "No";
1241        }
1242
1243        if ((event === 'transaction_complete' || event === 'delivery_subscription_confirmation') && AB.DATALAYER.getCookie('cje')) {
1244            serverSideData.user.vendor.push({
1245                name: 'cj',
1246                vars: [{
1247                    key: 'cje',
1248                    value: AB.DATALAYER.getCookie('cje')
1249                }
1250                ]
1251            })
1252        }
1253
1254        if (AB.DATALAYER.isPageLoadEvent() || AB.DATALAYER.isOneTagCheckoutEvent()) {
1255            const gclid = AB?.DATALAYER?.analyticsGetURLParameterByName && AB.DATALAYER.analyticsGetURLParameterByName('gclid');
1256            const isCmpidFromGclid = ['search_', 'kw_', 'ps_', 'PS_', 'co_kw'].some((value) => serverSideData?.page?.params?.startsWith(value));
1257            if (gclid || isCmpidFromGclid) {
1258                serverSideData.user.vendor.push({
1259                    name: 'google',
1260                    vars: [{
1261                        key: 'gclid',
1262                        value: gclid || 'no-value'
1263                    }
1264                    ]
1265                })
1266            }
1267        }
1268
1269        if (AB.DATALAYER.isProductActionEvent(event)) {
1270            serverSideData.cart.updateTime = data?.serverData?.currentTime;
1271        }
1272
1273        if (data?.batchCouponsClipped && Array.isArray(data?.batchCouponsClipped) && (event === 'batch_coupon_clipped')) {
1274            serverSideData.batchCpnsClp = data?.batchCouponsClipped.map(coupon => ({
1275                type: coupon.couponType,
1276                name: coupon.couponName,
1277                id: coupon.couponId,
1278                clipMthd: coupon.couponclipmethod,
1279                clipCnt: coupon.numberofcouponsclipped,
1280                savings: coupon.couponSavings || '0',
1281                sku: coupon.productSKU?.toString(),
1282                carouselSec: coupon.carouselSection
1283            }));
1284
1285        }
1286        serverSideData.rewards = {
1287            id: data?.rewards?.rewardsID,
1288            redeemed: data?.rewards?.rewardsRedeemed
1289        };
1290
1291        if (event === 'target-experiment-exposure') {
1292            serverSideData.experiment = { ...data?.experiment };
1293            serverSideData.xerargs = { ...data?.xerargs };
1294            serverSideData.misc = { ...data?.misc };
1295            serverSideData.compMetaData = { ...data?.compMetaData };
1296            serverSideData.page = { ...serverSideData.page,                 
1297                mktChannel: data?.page.mktChannel,
1298                slot: data?.page?.slot,
1299                subSlot: data?.page?.subSlot,
1300                zone: data?.page?.zone,
1301                deviceType:data?.page?.deviceType
1302            };
1303        }
1304
1305        // Handles linkClick setup
1306        serverSideData.link = {
1307            name: AB.DATALAYER.shouldSendOneTagLinkClick(event) ? event : data?.link?.linkName,
1308            c14: data?.link?.c14
1309        };
1310        if (!window?.SWY?.CONFIGSERVICE?.featureToggleConfig?.isSponsoredImpressionFixDisabled && Array.isArray(data?.carousel)) {
1311            serverSideData.carousel = data.carousel.map(item => {
1312                const mapped = { ...item };
1313                // Ensure `detail` is set. Prefer explicit detail, then the raw
1314                // impression detail field used by some flows (adobeMetrics.metricA).
1315                if (!mapped.detail) {
1316                    mapped.detail = item?.impressionAdditionalDetail
1317                        || item?.adobeMetrics?.metricA
1318                        || undefined;
1319                }
1320                // Remove the raw intermediate field to keep payload clean
1321                delete mapped.impressionAdditionalDetail;
1322                return mapped;
1323            });
1324        } else {
1325            serverSideData.carousel = data?.carousel;
1326        }
1327        serverSideData.component = data?.component;
1328        serverSideData.absPlacement = data?.absPlacement;
1329        serverSideData.crs = data?.crs;
1330
1331        if (AB.DATALAYER.isCRSClickEvent(event, data)) {
1332            delete serverSideData.cart;
1333            delete serverSideData.global;
1334            delete serverSideData.productInfo;
1335            delete serverSideData.search;
1336
1337            if (data?.product) {
1338                serverSideData.product = data.product;
1339            }
1340            if (Array.isArray(data?.batchCouponsClipped)) {
1341                serverSideData.batchCouponsClipped = data.batchCouponsClipped;
1342            }
1343        }
1344
1345        // Story-aligned banner impression payload should exclude unrelated sections.
1346        if (serverSideData?.event?.subEvent === 'banner-impressions') {
1347            delete serverSideData.cart;
1348            delete serverSideData.global;
1349            delete serverSideData.productInfo;
1350            delete serverSideData.search;
1351        }
1352
1353        // Story-aligned flex impression payload should exclude unrelated sections.
1354        if (serverSideData?.event?.subEvent === 'flex-impressions') {
1355            delete serverSideData.cart;
1356            delete serverSideData.global;
1357            delete serverSideData.productInfo;
1358            delete serverSideData.search;
1359
1360            serverSideData.page = {
1361                ...serverSideData.page,
1362                rURL: serverSideData?.page?.rURL || data?.page?.referringURL || AB.DATALAYER.getReferringUrl(),
1363                deviceType: serverSideData?.page?.deviceType || data?.page?.deviceType || digitalData?.pageDetails?.deviceType
1364            };
1365
1366            if (serverSideData.page) {
1367                delete serverSideData.page.prevPgname;
1368            }
1369        }
1370
1371        // Story-aligned flex experiment exposure payload should exclude unrelated sections.
1372        if (serverSideData?.event?.subEvent === 'experiment-exposure' && serverSideData?.link?.name === 'flex-experiment-exposure-loaded') {
1373            delete serverSideData.cart;
1374            delete serverSideData.global;
1375            delete serverSideData.productInfo;
1376            delete serverSideData.search;
1377
1378            serverSideData.page = {
1379                ...serverSideData.page,
1380                abTestDetails: serverSideData?.page?.msgDetail || data?.page?.abTestDetails || data?.component?.[0]?.detail,
1381                rURL: serverSideData?.page?.rURL || data?.page?.referringURL || AB.DATALAYER.getReferringUrl(),
1382                deviceType: serverSideData?.page?.deviceType || data?.page?.deviceType || digitalData?.pageDetails?.deviceType
1383            };
1384
1385            if (serverSideData.page) {
1386                delete serverSideData.page.prevPgname;
1387            }
1388        }
1389
1390        const isCRSEvent = AB.DATALAYER.isCRSClickEvent(event, data);
1391
1392        Object.keys(serverSideData).forEach(key => {
1393            if (typeof serverSideData[key] == 'object' && serverSideData[key]) {
1394                Object.keys(serverSideData[key]).forEach(subKey => {
1395                    if (typeof serverSideData[key][subKey] == 'object' && serverSideData[key][subKey]) {
1396                        Object.keys(serverSideData[key][subKey]).forEach(subChildKey => {
1397                            if (serverSideData[key][subKey][subChildKey] === '' || serverSideData[key][subKey][subChildKey] === undefined || serverSideData[key][subKey][subChildKey] === 'no-value' || serverSideData[key][subKey][subChildKey] === 'undefined' || serverSideData[key][subKey][subChildKey] === null) {
1398                                delete serverSideData[key][subKey][subChildKey];
1399                            }
1400                        });
1401                    }
1402                    if (serverSideData[key][subKey] === undefined || serverSideData[key][subKey] === 'no-value' || serverSideData[key][subKey] === 'undefined' || serverSideData[key][subKey] === null) {
1403                        delete serverSideData[key][subKey];
1404                    } else if (serverSideData[key][subKey] === '' && !(isCRSEvent && key === 'pageFilter' && subKey === 'mTyp')) {
1405                        delete serverSideData[key][subKey];
1406                    }
1407                });
1408            }
1409        });
1410
1411        Object.keys(serverSideData).forEach(key => {
1412            if (typeof serverSideData[key] == 'object' && serverSideData[key]) {
1413                if (Object.entries(serverSideData[key]).length <= 0) {
1414                    delete serverSideData[key]
1415                } else if (Object.entries(serverSideData[key]).length > 0) {
1416                    Object.keys(serverSideData[key]).forEach(subKey => {
1417                        if (typeof serverSideData[key][subKey] == 'object' && serverSideData[key][subKey] && Object.entries(serverSideData[key][subKey]).length <= 0) {
1418                            delete serverSideData[key][subKey]
1419                        } else if (serverSideData[key][subKey] && typeof serverSideData[key][subKey] == 'object' && Object.entries(serverSideData[key][subKey]).length > 0) {
1420                            Object.keys(serverSideData[key][subKey]).forEach(subChildKey => {
1421                                if (serverSideData[key][subKey][subChildKey] && typeof serverSideData[key][subKey][subChildKey] == 'object' && Object.entries(serverSideData[key][subKey][subChildKey]).length <= 0) {
1422                                    delete serverSideData[key][subKey][subChildKey];
1423                                }
1424                            });
1425                        }
1426                        if (typeof serverSideData[key][subKey] == 'object' && serverSideData[key][subKey] && Object.entries(serverSideData[key][subKey]).length <= 0) {
1427                            delete serverSideData[key][subKey]
1428                        }
1429                    });
1430                    if (Object.entries(serverSideData[key]).length <= 0) {
1431                        delete serverSideData[key]
1432                    }
1433                }
1434
1435            }
1436        });
1437
1438        return serverSideData;
1439    };
1440
1441    this.sendDataToOneTag = function (eventName, data) {
1442        const absVisitorId = data?.user?.absVisitorId || '';
1443        const urlFormat = `${AB.DATALAYER.isB2BPage() ? 'business' : 'www'}${AB.DATALAYER.getBannerEnvironment() !== 'prod' ? `-${AB.DATALAYER.getBannerEnvironment()}` : ''}`;
1444        const subEventEndpoint = AB.DATALAYER.getSubEventEndpoint(eventName, data);
1445        const subscriptionKey = AB.DATALAYER.getSubscriptionKey(eventName, data);
1446        const URL = `https://${urlFormat}.${AB.DATALAYER.getBanner(true)}.com/abs/${AB.DATALAYER.getAPIInfo()?.serverEnv}/ocat${subEventEndpoint}/serversidetag/event/`;
1447        const serverSideData = AB.DATALAYER.updateOneTagMapping(eventName, data);
1448        let resendAttempted = false;
1449
1450        const fetchPromise = fetch && fetch(URL, {
1451            method: 'POST',
1452            headers: {
1453                'Content-Type': 'text/plain',
1454                absVisitorId: `${absVisitorId}`,
1455                'Ocp-Apim-Subscription-Key': subscriptionKey,
1456                cookiePref: `${AB.DATALAYER.getCookiePref()}`,
1457            },
1458            body: JSON.stringify(serverSideData),
1459        });
1460
1461        // If returnPromise is true, return the promise with error handling
1462        if (data?.experimentationReturnPromise && eventName === 'target-experiment-exposure') {
1463            return fetchPromise
1464                .then(result => {
1465                    if (result?.status !== 200) {
1466                        throw new Error(`HTTP ${result.status}`);
1467                    }
1468                    return result;
1469                })
1470                .catch(error => {
1471                    console.error(`[DATALAYER] ${eventName} tracking failed:`, error);
1472                    throw error;
1473                });
1474        }
1475
1476        // Otherwise, fire and forget with retry logic for transaction_complete
1477        fetchPromise.catch(() => {
1478            if (!resendAttempted && eventName === 'transaction_complete') {
1479                setTimeout(() => {
1480                    fetch(URL, {
1481                        method: 'POST',
1482                        headers: {
1483                            'Content-Type': 'text/plain',
1484                            absVisitorId: `${absVisitorId}`,
1485                            'Ocp-Apim-Subscription-Key': subscriptionKey,
1486                            cookiePref: `${AB.DATALAYER.getCookiePref()}`,
1487                        },
1488                        body: JSON.stringify(serverSideData),
1489                    })
1490                    resendAttempted = true;
1491                }, 5000);
1492            }
1493        });
1494    }
1495
1496    this.sendExperimentDataToOneTag = function (experimentData) {
1497        const hasValidHouseholdId = digitalData?.user?.houseHoldId && digitalData.user.houseHoldId !== 'ID not found';
1498        const isGuestUser = digitalData?.user?.type === 'A' || digitalData?.user?.type === 'G';
1499        const isDataReady = isGuestUser 
1500            ? !!(digitalData?.user?.shopStoreId && digitalData?.user?.shopZipCode)
1501            : !!hasValidHouseholdId;
1502        const waitForDigitalData = () => {
1503            return new Promise((resolve) => {
1504                if (isDataReady) {
1505                    resolve();
1506                } else {
1507                    const handler = () => resolve();
1508                    window.addEventListener('digitalDataReady', handler, { once: true });
1509                }
1510            });
1511        };
1512
1513        const sendExperimentPayload = () => {
1514            const { pageDetails, user, pageFilter } = digitalData || {};
1515
1516            const experimentPayload = {
1517                compMetaData: {
1518                    type: experimentData?.compMetaData?.type,
1519                    name: experimentData?.compMetaData?.name
1520                },
1521                experiment: {
1522                    id: experimentData?.experiment?.id,
1523                    group: experimentData?.experiment?.group,
1524                    eligible: experimentData?.experiment?.eligible.toString(),
1525                    featureId: experimentData?.experiment?.featureId
1526                },
1527                misc: { ...experimentData?.misc },
1528                page: {
1529                    ...pageDetails,
1530                    mktChannel: experimentData?.mktChannel,
1531                    slot: experimentData?.slot,
1532                    subSlot: experimentData?.subSlot,
1533                    zone: experimentData?.zone
1534                },
1535                pageFilter: { ...pageFilter },
1536                user: { ...user },
1537                experimentationReturnPromise: true
1538            };
1539
1540            return this.pushEvent('target-experiment-exposure', experimentPayload)
1541                .then(result => result.json())
1542                .then(body => {
1543                    if (!body || Object.keys(body).length === 0 || body?.response === false) {
1544                        throw new Error('API returned failure status');
1545                    }
1546                    
1547                    if (body.response && typeof body.response === 'string' && body.response.toLowerCase() !== 'success') {
1548                        throw new Error(`API returned non-success response: ${body.response}`);
1549                    }
1550                    
1551                    return body;
1552                });
1553        };
1554
1555        if (isDataReady) {
1556            return sendExperimentPayload();
1557            
1558        } else {
1559            return waitForDigitalData().then(() => sendExperimentPayload());
1560        }
1561    };
1562
1563}).call(AB.DATALAYER);
1564
1565'use strict';
1566
1567// Comments in this file are of pure consistency reasons and offer no description externally
1568(function () {
1569    /**
1570     * Checks if current page is the homepage
1571     */
1572    this.isHomePage = function () {
1573        if (digitalData?.pageDetails) {
1574            return digitalData.pageDetails.subSection1 === 'home'
1575                && digitalData.pageDetails.subSection2 === ''
1576                && digitalData.pageDetails.subSection3 === ''
1577                && digitalData.pageDetails.subSection4 === '';
1578        } else {
1579            return false;
1580        }
1581    }
1582
1583    this.isShopPage = function () {
1584        return window.location.pathname.search('shop') !== -1;
1585    }
1586
1587    /**
1588     * Checks if the current page is a landing page
1589     */
1590    this.isLpPage = function () {
1591        if (digitalData?.pageDetails) {
1592            return window.digitalData.pageDetails.pageUrl.indexOf('/lp') !== -1 || window.digitalData.pageDetails.pageUrl.indexOf('/subscribe') !== -1;
1593        } else {
1594            return false;
1595        }
1596    }
1597
1598    /**
1599     * Checks if the current page is Subscription Delivery landing page
1600     */
1601    this.isSubscriptionDeliveryPage = function () {
1602        if (digitalData?.pageDetails) {
1603            return ((window.digitalData.pageDetails.subSection1 === 'lp' || window.digitalData.pageDetails.subSection1 === 'freshpass') && (window.digitalData.pageDetails.subSection2 === 'subscriptions-delivery' || window.digitalData.pageDetails.subSection3 === 'subscribe'));
1604        } else {
1605            return false;
1606        }
1607    }
1608
1609    /**
1610     * Checks if the current page is a L4 aisle page (e.g. https://www-qa2.vons.com/shop/aisles/beverages/coffee/coffee-ground.2053.html)
1611     */
1612    this.isAislesL4Page = function () {
1613        if (digitalData?.pageDetails) {
1614            return !!(window.digitalData.pageDetails.subSection1 === 'aisles'
1615                && window.digitalData.pageDetails.subSection2
1616                && window.digitalData.pageDetails.subSection3
1617                && window.digitalData.pageDetails.subSection4);
1618        } else {
1619            return false;
1620        }
1621    }
1622
1623    /**
1624     * Checks if the current page is a L3 aisle page (e.g. https://shop-qa2.tomthumb.com/aisles/beverages/energy-drinks-shots.2053.html)
1625     */
1626    this.isAislesL3Page = function () {
1627        if (digitalData?.pageDetails) {
1628            return window.digitalData.pageDetails.subSection1 === 'aisles'
1629                && window.digitalData.pageDetails.subSection2
1630                && window.digitalData.pageDetails.subSection3
1631                && !window.digitalData.pageDetails.subSection4;
1632        } else {
1633            return false;
1634        }
1635    }
1636
1637    /**
1638     * Checks if the current page is a L2 aisle page (e.g. https://shop-qa2.tomthumb.com/aisles/beverages.2574.html)
1639     */
1640    this.isAislesL2Page = function () {
1641        if (digitalData?.pageDetails) {
1642            return window.digitalData.pageDetails.subSection1 === 'aisles'
1643                && window.digitalData.pageDetails.subSection2
1644                && !window.digitalData.pageDetails.subSection3
1645                && !window.digitalData.pageDetails.subSection4;
1646        } else {
1647            return false;
1648        }
1649    }
1650
1651    /**
1652     * Checks if the current page is a L2, L3 or L4 aisle page
1653     */
1654    this.isAislesPage = function () {
1655        return this.isAislesL2Page() || this.isAislesL3Page() || this.isAislesL4Page();
1656    }
1657
1658    /**
1659     * Checks if the current page is the j4u page
1660     */
1661    this.isJ4UPage = function () {
1662        if (digitalData?.pageDetails) {
1663            return window.digitalData.pageDetails.subSection1 === 'justforu' &&
1664                window.digitalData.pageDetails.subSection2 &&
1665                !window.digitalData.pageDetails.subSection3 &&
1666                !window.digitalData.pageDetails.subSection4;
1667        } else {
1668            return false;
1669        }
1670    }
1671
1672    /**
1673     * Checks if the current page is a re-sign-in page
1674     */
1675    this.isReSignInPage = function () {
1676        if (digitalData?.pageDetails) {
1677            return (window.digitalData.pageDetails.subSection1 === 'account' || window.digitalData.pageDetails.subSection1 === 'welcome') && window.digitalData.pageDetails.subSection2 === 're-sign-in';
1678        } else {
1679            return false;
1680        }
1681    }
1682
1683    this.isAuthSignInPage = function () {
1684        return window.location.pathname.indexOf('/account/auth/service/sign-in') != -1;
1685    }
1686
1687    /**
1688     * Checks if the current page is displaying search results
1689     */
1690    this.isSearchResultsPage = function () {
1691        return digitalData?.pageDetails?.subSection1 === 'search-results' || digitalData?.pageDetails?.subSection1 === 'zero-search-results' || (this.isWineShopPage() && digitalData?.pageDetails?.subSection1 === 'search-results') || (window.location.pathname.startsWith('/foru/coupons-deals') && window.location.search.includes('?q='));
1692    }
1693
1694    /**
1695     * Checks if the current page is a product detail page
1696     */
1697    this.isPdp = function () {
1698        if (digitalData?.pageDetails) {
1699            return window.digitalData.pageDetails.subSection1 === 'product-details' || window.digitalData.pageDetails.subSection1 === 'pd' ||
1700                (window.digitalData.pageDetails.subSection1 === 'product' && window.digitalData.pageDetails.subSection2 === 'details') ||
1701                (window.digitalData.pageDetails.subSection1 === 'vineandcellar' && window.digitalData.pageDetails.subSection2 === 'product-details') ||
1702                (window.digitalData.pageDetails.subSection1 === 'marketplace' && window.digitalData.pageDetails.subSection2 === 'product-details')
1703        } else {
1704            return false;
1705        }
1706    }
1707
1708    this.isNewPdp = function () {
1709        return window.location.pathname.startsWith('/product/details');
1710    }
1711
1712    /**
1713     * Checks if the current page is part of the Auto Replenishment flow
1714     */
1715    this.isARPage = function () {
1716        return window.location.pathname.startsWith('/schedule-and-save');
1717    }
1718
1719    /**
1720     * Checks if the current page is part of the Manage Schedule & Save SPA flow
1721     */
1722    this.isARManagePage = function () {
1723        return window.location.pathname.startsWith('/schedule-and-save/manage');
1724    }
1725
1726    /**
1727     * Checks if the current page is part of the Manage Schedule & Save SPA flow
1728     */
1729    this.isARTestManagePage = function () {
1730        return window.location.pathname.startsWith('/hey-sirius/manage');
1731    }
1732
1733    /**
1734     * Checks if the current page is part of the Freshpass SPA flow
1735     */
1736    this.isFreshpassManagePage = function () {
1737        return window.location.pathname.startsWith('/freshpass/manage');
1738    }
1739
1740    this.isFreshpassConfirmationPage = function () {
1741        return window.location.pathname.startsWith('/delivery-subscription/dsconfirmation') || window.location.pathname.startsWith('/freshpass/manage/confirmation');
1742    }
1743
1744    /**
1745     * Checks if current page is part of the Drive Up and Go notification flow for pickup
1746     */
1747    this.isDUGNotification = function () {
1748        if (digitalData?.pageDetails) {
1749            return window.digitalData.pageDetails.subSection1 === 'mobile-pickup';
1750        } else {
1751            return false;
1752        }
1753    }
1754
1755    /**
1756     * Checks if current page is the Deals page
1757     */
1758    this.isDealsPage = function () {
1759        return window.digitalData?.pageDetails?.subSection1 === 'deals';
1760    }
1761
1762    this.isCouponsAndDealsPage = function () {
1763        return window.location.pathname.indexOf('coupons-deals') !== -1;
1764    }
1765
1766    this.isB4USPA = function () {
1767        return window.location.pathname.indexOf('loyalty/coupons-deals') !== -1
1768            || window.location.pathname.indexOf('loyalty/deals') !== -1
1769            || window.location.pathname.indexOf('loyalty/mylist') !== -1
1770            || window.location.pathname.indexOf('loyalty/guest') !== -1
1771            || window.location.pathname.indexOf('loyalty/foru-guest') !== -1
1772            || window.location.pathname.indexOf('loyalty/offer-details') !== -1;
1773    }
1774
1775    /**
1776     * Checks if the current page belongs to the eRums project
1777     * It is used to exclude the AEM init functions from running on these pages
1778     */
1779    this.isErumsPage = function () {
1780        return window.location.pathname.startsWith('/erums');
1781    };
1782
1783    /**
1784     * Checks if current page is Don't forget to add page
1785     */
1786    this.isDFTAPage = function () {
1787        return window.location.pathname.startsWith('/erums/cart/dnf');
1788    }
1789
1790
1791    /**
1792     * Checks if the current page belongs to the IAUC UCA React project
1793     */
1794    this.isAccountPage = function () {
1795        return window.location.pathname.startsWith('/customer-account');
1796    }
1797
1798    /**
1799     * Checks if the current page is the Payment Methods page
1800     */
1801    this.isPaymentPage = function () {
1802        return window.location.pathname.startsWith('/customer-account/payment');
1803    }
1804
1805    /**
1806     * Checks if the current page is the Unsubscribe page
1807     */
1808    this.isUnsubscribePage = function () {
1809        return window.location.pathname.startsWith('/customer-account/unsubscribe');
1810    }
1811
1812    this.isResetPasswordPage = function () {
1813        return window.digitalData?.pageDetails?.subSection2 === 'reset-password';
1814    }
1815
1816    /**
1817     * Check if the current page is forgot password/reset password page
1818     */
1819    this.isAccountResetPage = function () {
1820        return window.location.pathname.startsWith('/account-reset');
1821    }
1822
1823    /**
1824     * Checks if the current page is the Students page
1825     */
1826    this.isStudentsPage = function () {
1827        return window.location.pathname.startsWith('/customer-account/students');
1828    }
1829
1830    /**
1831     * Checks if the current page belongs to the SVSS Orders React project
1832     */
1833    this.isOrdersPage = function () {
1834        return window.location.pathname.startsWith('/order-account');
1835    }
1836
1837    /**
1838     * Checks if the current page is part of the Recipes section of the website
1839     */
1840    this.isRecipesPage = function () {
1841        if (digitalData?.pageDetails) {
1842            return window.digitalData.pageDetails.subSection1 === 'recipes';
1843        }
1844    }
1845
1846    /**
1847     * Checks if the current page is OHC page
1848     */
1849    this.isHelpCenterPage = function () {
1850        return window.location.pathname.startsWith('/help');
1851    }
1852
1853    /**
1854     * Checks if the current page is Customer Care page
1855     */
1856    this.isCustomerCarePage = function () {
1857        return window.location.pathname.startsWith('/customer-care');
1858    }
1859
1860    /**
1861     * Checks if the current page is Spotlight page
1862     */
1863    this.isSpotlightPage = function () {
1864        return document?.title?.toLowerCase() === 'spotlight';
1865    }
1866
1867    /**
1868     * Checks if the current page is the new design for the BIA page
1869     */
1870    this.isBIAPage = function () {
1871        return window.location.pathname.startsWith('/shop/purchases/buy-it-again');
1872    }
1873
1874    /**
1875     * Checks if the current page is a games page
1876     */
1877    this.isGamesPage = function () {
1878        return window.location.pathname.startsWith('/foru/games') || window.location.pathname.startsWith('/flavoradventure/start');
1879    }
1880
1881    this.isGamesSPAPage = function () {
1882        return window.location.pathname.startsWith('/games');
1883    }
1884
1885    this.setMarketplacePage = function () {
1886        if (window.digitalData && window.digitalData.pageDetails) {
1887            window.isAnalyticsMarketplacePage = digitalData.pageDetails.subSection1 === 'marketplace' || digitalData.pageDetails.subSection1 === 'm' || (window.location.pathname.startsWith('/shop/m') && !window.location.pathname.startsWith('/shop/mf')) || window.location.pathname.startsWith('/shop/marketplace');
1888        }
1889    }
1890
1891    this.isMarketplaceCategoryPage = function () {
1892        return window.isAnalyticsMarketplacePage && window.location.pathname.indexOf('aisles') != -1;
1893    }
1894
1895    this.isWineShopCategoryPage = function () {
1896        return window.location.pathname.indexOf('vineandcellar/aisles') !== -1;
1897    }
1898
1899    this.isWineShopL2Page = function () {
1900        return this.isWineShopCategoryPage() && this.pathSections?.length === 2;
1901    }
1902
1903    this.isWineShopL3Page = function () {
1904        return this.isWineShopCategoryPage() && this.pathSections?.length === 3;
1905    }
1906
1907    this.isWineShopL4Page = function () {
1908        return this.isWineShopCategoryPage() && this.pathSections?.length === 4;
1909    }
1910
1911    this.isWineShopPage = function () {
1912        return window.location.pathname.indexOf('vineandcellar') !== -1;
1913    }
1914
1915    this.isMarketplaceSearchPage = function () {
1916        return window.isAnalyticsMarketplacePage && (window.location.pathname.indexOf('search-results') != -1 || window.location.pathname.indexOf('seller-search') !== -1);
1917    }
1918
1919    this.isWineShopSearchPage = function () {
1920        return window.location.pathname.indexOf('vineandcellar/search-results') !== -1;
1921    }
1922
1923    this.isPharmacyRxPage = function () {
1924        return window.location.pathname.startsWith('/pharmacy/create-account');
1925    }
1926
1927    this.isCategoriesPage = function () {
1928        return window.digitalData?.pageDetails?.subSection1 === 'aisles' && !window.digitalData?.pageDetails?.subSection2;
1929    }
1930
1931    /**
1932    * Checks if the current page is weekly-ad page
1933    */
1934    this.isWeeklyAdPage = function () {
1935        return window.location.pathname.startsWith('/weeklyad') || window.location.pathname.startsWith('/emju-weeklyad');
1936    }
1937
1938    this.isWeeklyAdDealsPage = function () {
1939        return window.location.pathname.startsWith('/weeklyad/yourdeals') || window.location.pathname.startsWith('/emju-weeklyad/yourdeals');
1940    }
1941
1942    this.getBannerSellerId = function () {
1943        return `${AB.DATALAYER.isB2BPage() ? '00000000' : '11111111'}`;
1944    }
1945
1946    /**
1947    * Checks if the current page is one of the Cart and checkout pages
1948    */
1949    this.isCartAndCheckoutPage = function (page, isEditPage) {
1950        return !this.isDFTAPage() && window.location.pathname.startsWith(`/erums/${isEditPage ? 'order/edit' : ''}`) && window.location.pathname.includes(`${page ? page : ''}`);
1951    }
1952
1953    /**
1954    * Checks if the current page is weekly-ad page
1955    */
1956    this.isOrderAheadPage = function () {
1957        return window.location.pathname.startsWith('/orderahead');
1958    }
1959
1960    this.isRecipesAndMealsPage = function (page, type) {
1961        if (type) {
1962            return window.location.pathname.startsWith(type === 'recipes' ? 'recipes' : type === 'meals' ? '/meal-plans-recipes' : '')
1963                && window.location.pathname.includes(`${page ? page : ''}`);
1964        } else {
1965            return (window.location.pathname.startsWith('/meal-plans-recipes') || window.location.pathname.startsWith('/recipes'))
1966                && window.location.pathname.includes(`${page ? page : ''}`);
1967        }
1968
1969    }
1970
1971    this.isMealsPlansPage = function () {
1972        return window.location.pathname.startsWith('/meal-plans-recipes');
1973    }
1974
1975    this.isBundlesLP = function () {
1976        return window.location.pathname.startsWith('/bundles') || window.location.pathname.startsWith('/meal-plans-recipes/bundles');
1977    }
1978
1979    this.isAssistantPage = function () {
1980        return window.location.pathname.startsWith('/assistant/chat');
1981    }
1982
1983    this.isReviewsPage = function () {
1984        return window.location.pathname.startsWith('/product/reviews');
1985    }
1986
1987    this.isRewardsPage = function () {
1988        return window.location.pathname.startsWith('/rewards');
1989    }
1990
1991    this.isSelfMergeAccountsPage = function () {
1992        return window.location.pathname.startsWith('/customer-account/account-settings/merge');
1993    }
1994
1995    this.isExpediaPageSource = function () {
1996        return window.location.search?.indexOf('webSource=WEB-EXPEDIA') != -1;
1997    }
1998
1999    this.isSelectiveCartPage = function () {
2000        return AB.DATALAYER.analyticsGetURLParameterByName('selective') == 'true';
2001    }
2002
2003    this.getExperimentIds = function () {
2004        const targetFlagsValues = window.analyticsSwy?.testFlags
2005            && typeof window.analyticsSwy?.testFlags === 'object'
2006            && Object.keys(window.analyticsSwy.testFlags).filter((key) => key.toLowerCase().includes('acip')).map((key) => `${key}_${window.analyticsSwy.testFlags[key]}`);
2007        const searchVariant = targetFlagsValues && targetFlagsValues.length > 0 ? targetFlagsValues
2008            : localStorage ? Object.keys(localStorage).filter((key) => key.toLowerCase().includes('acip')).map((key) => `${key.replace('ab', '')}_${localStorage[key]}`) : [];
2009        return searchVariant ? searchVariant : []
2010    }
2011
2012    this.setEventOncePerPage = function (eventName, event, productID) {
2013        try {
2014            let eventSent = false;
2015            // Find the index of the last untilNextEvent in appEventData
2016            let eventIndex = -1;
2017            const listOfPageLoadEvents = [
2018                'pageLoaded',
2019                'search_results_page',
2020                'zero_search_results',
2021                'pdp_page',
2022                'full_cart',
2023                'checkout_step1',
2024                'checkout_step2',
2025                'checkout_step3',
2026                'transaction_complete',
2027                'pageLoaded_mediacollective',
2028                'selective_view_cart',
2029                'edit_cart',
2030                'pageLoaded_fc',
2031                'pageLoaded_spotlight',
2032                'pageLoaded_albspartner'
2033            ];
2034
2035            eventIndex = appEventData.findLastIndex((eventObj) => listOfPageLoadEvents.includes(eventObj?.event));
2036
2037            if (eventIndex !== -1) {
2038                eventSent = appEventData.slice(eventIndex).some((eventObj) =>
2039                    eventObj?.[`${event.includes('modal') ? 'modal' : event.includes('link') ? 'link' : event.includes('hover') ? 'hover' : ''}`]?.[`${event.includes('modal') ? 'modalAction' : 'linkName'}`] === eventName && (!productID || eventObj?.productInfo?.productID === productID));
2040            }
2041            return eventSent;
2042        } catch (e) {
2043            console.error('@AnalyticsTeam - Failed to send setEventOncePerPage value due to following error: ', e);
2044        }
2045    }
2046
2047    this.getFullDeliveryTime = function (reservedSlot) {
2048        function getDeliveryHours(dataTime) {
2049            const time = new Date(dataTime);
2050            let dHours = time.getHours();
2051            const amPm = dHours >= 12 ? 'PM' : 'AM';
2052            dHours = (dHours % 12) ? (dHours % 12) : 12;
2053            return `${dHours}:00 ${amPm}`;
2054        }
2055
2056        function getDeliveryDate(dataTime) {
2057            if (!dataTime) {
2058                return '';
2059            }
2060            const tempDate = (new Date(dataTime)).toString().split(' ');
2061            return `${tempDate[0]} ${tempDate[1]} ${tempDate[2]}`;
2062        }
2063
2064        const fullDeliveryTime = `${getDeliveryDate(reservedSlot.displayStartTS)} ${getDeliveryHours(reservedSlot.displayStartTS)} - ${getDeliveryHours(reservedSlot.displayEndTS)}`;
2065        return fullDeliveryTime;
2066    }
2067
2068    this.setDeliveryWindow = function (reservedSlot) {
2069        const slotStartTS = reservedSlot.displayStartTS ? reservedSlot.displayStartTS : reservedSlot.slotStartTS;
2070        const slotEndTS = reservedSlot.displayEndTS ? reservedSlot.displayEndTS : reservedSlot.lastPickupTS ? reservedSlot.lastPickupTS : reservedSlot.slotEndTS;
2071
2072        function toLocal(timestamp) {
2073            const ds = timestamp.replace(/-|:|T/gi, ',').split(',');
2074            return new Date(Date.UTC(ds[0], ds[1] - 1, ds[2], ds[3], ds[4], ds[5]))
2075        }
2076
2077        function getDayDelta(endDate) {
2078            const current = new Date();
2079            const final = toLocal(endDate);
2080            const deltaT = (final.getTime() - current.getTime()) / 1000 / 60 / 60, eot = 24 - current.getHours();
2081            return (eot < deltaT ? (Math.ceil((deltaT - eot) / 24)) : 0) + 1;
2082        }
2083
2084        let day_time = {
2085            day: getDayDelta(slotStartTS),
2086            time: Math.ceil(new Date(slotEndTS).getTime() / 1000 / 60 / 60 - new Date(slotStartTS).getTime() / 1000 / 60 / 60),
2087            value: ''
2088        }
2089        day_time.value = `${day_time.day}|${day_time.time}-hour${day_time.time > 1 ? 's' : ''}`;
2090
2091        let elite_tag_value = '';
2092        if (this.isCartAndCheckoutPage('prebook') || this.isCartAndCheckoutPage('erums/checkout')) {
2093            let elite_tag = document.querySelector('app-delivery-window-type .card[aria-checked="true"] #elite-slot-body');
2094            let non_elite = document.querySelector('#timesForTheDay input:checked');
2095            non_elite = non_elite ? non_elite.parentElement.querySelector('.badge-style') : null;
2096
2097            let non_elite_value = non_elite ? non_elite.textContent.toLowerCase().replace(/\s/g, '-') : 'more-delivery-times';
2098            let eliteValue = elite_tag?.textContent?.toLowerCase()?.replace(/^\s|\s$/g, '')?.replace(/slot type|\s{2,}/g, '')?.replace(/\s/g, '-') || '';
2099            elite_tag_value = elite_tag && eliteValue ? eliteValue : non_elite_value;
2100
2101            switch (true) {
2102                case elite_tag_value.indexOf('flash') !== -1:
2103                    elite_tag_value = 'flash';
2104                    break;
2105                case elite_tag_value.indexOf('premium') !== -1:
2106                    elite_tag_value = 'premium';
2107                    break;
2108                case elite_tag_value.indexOf('best-value') !== -1:
2109                    elite_tag_value = 'best-value';
2110                    break;
2111                case elite_tag_value.indexOf('fastest') !== -1:
2112                    elite_tag_value = 'fastest';
2113                    break;
2114                default:
2115                    break;
2116            }
2117        }
2118        !this.isCartAndCheckoutPage('order/confirmation') && this.setLSItem('elite_tag', elite_tag_value);
2119
2120        digitalData.cart.transaction.deliveryTime = AB.DATALAYER.getFullDeliveryTime(reservedSlot);
2121        digitalData.cart.transaction.deliveryWindow = day_time.value;
2122        digitalData.cart.transaction.deliverySlotType = elite_tag_value;
2123    }
2124
2125    this.getPaymentMethod = function (payments) {
2126        let types = {
2127            'CREDITCARD': 'cc',
2128            'EBT': 'ebt',
2129            'EBT-CARD': 'snap_ebt_card',
2130            'EBT-CASH': 'snap_ebt_cash',
2131            'CREDITONACCOUNT': 'coa',
2132            'EWALLET': 'ewallet'
2133        },
2134            subTypes = {
2135                'PAYPAL': 'paypal'
2136            },
2137            ret = {
2138                methods: [],
2139                type: {},
2140                method: ''
2141            };
2142
2143        if (payments && (payments.length > 0)) {
2144            payments.forEach((payment) => {
2145                const paymentType = payment.type !== undefined ? payment.type : payment.paymentType;
2146                const paymentSubtype = payment.subType !== undefined ? payment.subType : payment.paymentSubType;
2147                if (types[paymentType] === 'ewallet')
2148                    ret.methods.push(subTypes[paymentSubtype]);
2149                else {
2150                    ret.methods.push(types[paymentType]);
2151                }
2152                ret.type[types[payment.type]] = payment.originalTransactionAmount;
2153            });
2154        }
2155        ret.method = ret.methods.join('|');
2156        return ret;
2157    }
2158
2159    /**
2160    * Checks if GRS search_results_impressions event should be triggered
2161    */
2162    this.shouldSetGRSSearchImpression = function () {
2163        return this.isSearchResultsPage() && !this.isMarketplaceSearchPage() && !this.isMarketplaceCategoryPage() && !this.isWineShopPage();
2164    }
2165
2166    /**
2167     * Sets a cookie to track modal link clicks
2168     * @param value - the dynamic value stored in the cookie
2169     */
2170    this.setModalLinkCookie = function (value) {
2171        SWY.CONFIGSERVICE.setDomainCookie(this.cookieNames.MODAL_LINK, value, `${SWY.CONFIGSERVICE.resolvedBanner}.com`, 0);
2172    }
2173
2174    /**
2175     * Sets a cookie for tracking the forgot password/password recovery flow
2176     */
2177    this.setForgotPasswordCookie = function () {
2178        // SWY.CONFIGSERVICE.setDomainCookie(this.cookieNames.PASSWORD_RESET, 'forgotpassword', `${SWY.CONFIGSERVICE.resolvedBanner}.com`, 0 );
2179        this.setLinkClickEvents('passwordReset');
2180    }
2181
2182    /**
2183     * Sets a local storage item to track the creation of the a new account
2184     */
2185    this.setCreateAccountClicked = function () {
2186        localStorage.setItem('create_account_clicked', true);
2187    }
2188
2189    /**
2190     * Checks if the user is authorized to add/remove products to/from cart
2191     */
2192    this.isUserAuthorized = function () {
2193        let isErumStore = false;
2194        if (AB?.userInfo?.hasOwnProperty('isErumStore')) {
2195            isErumStore = AB?.userInfo?.isErumStore;
2196        }
2197        let isRegistered = AB.DATALAYER.checkAuthorization();
2198        return !isRegistered && ((isErumStore && AB?.userInfo?.erumsGuestEnabled === false) || !isErumStore) ? false : true;
2199    }
2200
2201    /**
2202     * Updates the datalayer with information about the coupon that is clipped
2203     * @param coupon - information about the coupon that is clipped
2204     * TO DO: remove after 2024 7.1 release, as all references to this function have been removed
2205     */
2206    this.analyticsCouponUpdate = function (coupon, analyticsData) {
2207        if (window.AB && window.AB.DATALAYER) {
2208            window.AB.DATALAYER.clipCoupon(coupon, analyticsData);
2209        } else {
2210            console.warn('AB.DATALAYER is not defined on this page');
2211        }
2212    }
2213
2214    /**
2215     * Sets modal click events
2216     * @param modalClicked - name of the modal that is clicked
2217     */
2218    this.setModalClickEvents = function (modalClicked, modalMessage, oncePerPageView) {
2219        try {
2220            const updatedModalMessage = modalMessage && ['sendMealsData', 'sendRecipesData'].indexOf(modalMessage) === -1 ? modalMessage : digitalData?.modal?.modalMessage;
2221            if (window.digitalData?.modal) {
2222                window.digitalData.modal.modalAction = modalClicked;
2223                window.digitalData.modal.modalMessage = updatedModalMessage;
2224            }
2225            if (modalClicked === 'pdp:guaranteed-fresh-link|terms-of-service') {
2226                digitalData.productInfo = digitalData?.productInfo || {};
2227                digitalData.productInfo.productID = modalMessage;
2228            }
2229
2230            if (modalClicked.indexOf('createAccount Modal|continue-with-') !== -1) {
2231                const smsCheckbox = document.querySelector('#textSubscribe')?.checked;
2232                const emailCheckbox = document.querySelector('#emailSubscribe')?.checked;
2233                digitalData.pageFilter.isSocialSmsCheckedOut = !smsCheckbox;
2234                digitalData.pageFilter.isSocialEmailCheckedOut = !emailCheckbox;
2235            }
2236
2237            const eventTrigger = oncePerPageView ? this.setEventOncePerPage(modalClicked, 'modalView') : false;
2238            let payload = {
2239                modal: {
2240                    modalAction: modalClicked,
2241                    modalMessage: updatedModalMessage
2242                },
2243                page: digitalData?.pageDetails,
2244                pageFilter: digitalData?.pageFilter,
2245                user: digitalData?.user,
2246                productInfo: digitalData?.productInfo
2247            };
2248
2249            if (modalMessage === 'sendMealsData') {
2250                payload.meals = digitalData.meals;
2251            } else if (modalMessage === 'sendRecipesData') {
2252                payload.recipes = digitalData.recipes;
2253            }
2254
2255            !eventTrigger && this.pushEvent(
2256                this.EVENTS.MODAL_CLICK, payload
2257            );
2258            const clearTopNavActions = ['otp:lets-find-your-account|close', 'signin modal|close', 'createaccount modal|close'];
2259            if (clearTopNavActions.indexOf(modalClicked) !== -1) {
2260                AB.DATALAYER.removeLSItem('topNavPreviousPage');
2261            }
2262            if (window.digitalData?.modal?.modalMessage) {
2263                window.digitalData.modal.modalMessage = '';
2264            }
2265            this.setAnalyticsCrossPageData({ action: 'remove', name: 'acip371626Checkbox' });
2266            if (modalClicked.indexOf('|start-shopping') != -1) {
2267                this.setAnalyticsCrossPageData({ action: 'remove', name: 'acip371626Verified' });
2268            }
2269            if (modalClicked?.indexOf('account-social-verify') != -1) {
2270                this.setAnalyticsCrossPageData({ action: 'remove', name: 'acip371626Social' });
2271            }
2272        } catch (e) {
2273            console.error('@AnalyticsTeam - Failed to send ModalClicked value due to following error: ', e);
2274        }
2275    }
2276
2277    this.setB2BModalEvent = function (modalEvent, modalAction) {
2278        if (AB.DATALAYER.isB2BPage()) {
2279            this.pushEvent(
2280                modalEvent, {
2281                modal: {
2282                    modalAction: modalAction,
2283                }
2284            }
2285            );
2286        }
2287    }
2288
2289    this.trackShopFlyout = function (classes) {
2290        const isShopButton = classes && Array.from(classes)?.length > 0 && Array.from(classes).indexOf('shop-class') !== -1;
2291        if (isShopButton && AB.DATALAYER.isB2BPage()) {
2292            const targetNode = document.querySelector('.menu-nav__list-item.shop-class');
2293            const config = { attributes: false, childList: true, subtree: true };
2294            let isModalEventSet = false;
2295            const callback = function (mutations, observer) {
2296                if (window.jQuery && !isModalEventSet) {
2297                    const shopModal = jQuery('#flyoutContainer #shopFlyOutModal');
2298                    isModalEventSet = true;
2299                    if (shopModal) {
2300                        shopModal.on('shown.bs.modal', () => {
2301                            AB.DATALAYER.setB2BModalEvent('modalView', 'shop_leftnavigation|view');
2302                            shopModal.off('shown.bs.modal');
2303                            observer.disconnect();
2304                        })
2305                    }
2306                }
2307
2308            };
2309            const observer = new MutationObserver(callback);
2310            observer.observe(targetNode, config);
2311        }
2312    }
2313
2314    this.trackAccFlyout = function () {
2315        if (AB.DATALAYER.isB2BPage()) {
2316            let elem = document.querySelector('.menu-nav__profile-button[aria-label="Account menu"]');
2317            if (elem?.getAttribute('aria-expanded') === 'false') {
2318                AB.DATALAYER.setB2BModalEvent('modalView', 'account_rightnavigation|view');
2319            }
2320        }
2321    }
2322
2323    // Sets the Add to Cart Clicked flag, used for sign in modal tracking when this modal is triggered from ATC button
2324    this.setATCFlag = function (flag) {
2325        digitalData.modal.isATCClicked = flag;
2326    }
2327
2328    // return the node(s) if visible
2329    this.isVisible = function (node) {
2330        let filteredArray;
2331        if (typeof (node?.[Symbol.iterator]) === 'function') {
2332            filteredArray = Array.from(node).filter((element) => {
2333                return (
2334                    element?.offsetWidth !== 0 &&
2335                    element?.offsetHeight !== 0 &&
2336                    element?.getClientRects().length &&
2337                    !element?.classList?.contains('d-none') &&
2338                    !element?.classList?.value?.includes('d-none') &&
2339                    !element?.className?.includes('d-none')
2340                );
2341            });
2342        } else {
2343            if (node?.offsetWidth !== 0 &&
2344                node?.offsetHeight !== 0 &&
2345                node?.getClientRects().length &&
2346                !node?.classList?.contains('d-none') &&
2347                !node?.classList?.value?.includes('d-none') &&
2348                !node?.className?.includes('d-none')) {
2349                filteredArray = node;
2350            }
2351        }
2352        return filteredArray;
2353    }
2354
2355    // check if element is within viewport; used for AMC impressions, Rokt impressions
2356    this.isElementVisible = function (element) {
2357        const noHiddenClass = !element?.classList?.contains('d-none') &&
2358            !element?.classList?.value?.includes('d-none') &&
2359            !element?.className?.includes('d-none');
2360        const elHeightPosition = element?.getBoundingClientRect()?.bottom;
2361        const elWidth = element?.getBoundingClientRect()?.width || 0;
2362        const variableWidthReduction = (25 * elWidth) / 100;
2363        const elWidthPosition = element?.getBoundingClientRect()?.right - variableWidthReduction;
2364        const screenHeight = screen?.height;
2365        const windowWidth = window.innerWidth;
2366        const elHeight = element?.getBoundingClientRect()?.height;
2367        return elHeightPosition && screenHeight >= elHeightPosition && windowWidth >= elWidthPosition && elHeightPosition >= elHeight && noHiddenClass;
2368    }
2369
2370    /**
2371     * Sets modal view events
2372     * @param modalViewed - - name of the modal that has been opened and is viewed
2373     * @param oncePerPageView - true or false value, if the event should trigger once per pageView
2374     */
2375    this.setModalViewEvents = function (modalViewed, oncePerPageView, productID) {
2376        try {
2377            if (window.digitalData?.modal) {
2378                window.digitalData.modal.modalAction = modalViewed;
2379            }
2380            if (productID && ['sendMealsData', 'sendRecipesData'].indexOf(productID) === -1) {
2381                digitalData.productInfo.productID = productID;
2382                digitalData.productInfo.isProductTrackingDisabled = digitalData.pageFlags?.isProductTrackingDisabled;
2383            }
2384            digitalData.modal.modalMessage = digitalData?.modal?.isATCClicked ? 'sign-in-to-add' : digitalData.modal.modalMessage === 'sign-in-to-add' ? '' : digitalData.modal.modalMessage;
2385
2386            if (this.getLSItem('analyticsCTAValue')?.indexOf('cta:customer-account:account-dashboard:account-security|link') != -1) {
2387                digitalData.pageFilter.topNav = this.initTopNav();
2388            }
2389
2390            const eventTrigger = oncePerPageView ? this.setEventOncePerPage(modalViewed, 'modalView') : false;
2391
2392            let payload = {
2393                modal: digitalData?.modal,
2394                page: digitalData?.pageDetails,
2395                pageFilter: digitalData?.pageFilter,
2396                user: digitalData?.user,
2397                productInfo: digitalData?.productInfo
2398            };
2399
2400            if (productID === 'sendMealsData') {
2401                payload.meals = digitalData.meals;
2402            } else if (productID === 'sendRecipesData') {
2403                payload.recipes = digitalData.recipes;
2404            } else if (productID === 'name-exists' || productID === 'name-doesnt-exist') {
2405                payload.modal.modalMessage = productID;
2406            } else if(productID === 'customCakeData' && digitalData?.pageFilter?.topNav) {
2407                digitalData.pageFilter.topNav = `cta:${digitalData?.page?.previousPageName}|link|customise`;
2408            }
2409            
2410            const eventName = productID === 'custom-cake-view' ? 'custom-cake-exposed' : this.EVENTS.MODAL_VIEW;
2411
2412            !eventTrigger && this.pushEvent(
2413                eventName, payload,
2414                oncePerPageView
2415            );
2416            AB.DATALAYER.setATCFlag(false);
2417        } catch (e) {
2418            console.error('@AnalyticsTeam - Failed to send ModalView value due to following error: ', e);
2419        }
2420    }
2421
2422    /**
2423     * Fire the requested event with the apropriate params
2424     *
2425     */
2426    this.handleModalAndLinkEvents = function ({ eventType, modalAndLinkData, modalMessage, topNav, oncePerPageView } = {}) {
2427        try {
2428            switch (eventType) {
2429                case 'modalView':
2430                    this.setModalViewEvents(modalAndLinkData, oncePerPageView, modalMessage);
2431                    break;
2432                case 'goToAccount':
2433                    this.setSignInModalEvents(eventType, modalAndLinkData, modalMessage, topNav);
2434                    break;
2435                case 'modalClick':
2436                    this.setModalClickEvents(modalAndLinkData, modalMessage, oncePerPageView);
2437                    break;
2438                case 'linkClick':
2439                    this.setLinkClickEvents(modalAndLinkData, oncePerPageView);
2440                    break;
2441                case 'topNav':
2442                    this.analyticsCTATracking(modalAndLinkData);
2443                    break;
2444                case 'crossPageData':
2445                    this.setAnalyticsCrossPageData({ action: 'set', name: modalAndLinkData, data: modalMessage, isAcrossPages: false });
2446                    break;
2447                default:
2448                    break;
2449            }
2450        } catch (error) {
2451            console.error('@AnalyticsTeam error:', error);
2452        }
2453    }
2454
2455    /**
2456     * Sets localStorage item for SBC items link
2457     * Used for pageFilter.topNav setting on the next page
2458     * @param element - DOM element of the image
2459     */
2460    this.setSBCLinkClickEvents = function (element) {
2461        if (element) {
2462            const currentPill = element.closest('.categories-item');
2463            const elementTitle = element.closest('.c-shop-by-category__view') && element.closest('.c-shop-by-category__view').querySelector('.shop-by-category-heading__title') ? element.closest('.c-shop-by-category__view').querySelector('.shop-by-category-heading__title').textContent : 'no-value';
2464            const componentTitle = element.closest('.c-shop-by-category__main-wrapper') ? element.closest('.c-shop-by-category__main-wrapper').getAttribute('component-title') : '';
2465            const allSBCs = document.querySelectorAll('.shopbycategory');
2466            const currentSBC = element.closest('.shopbycategory');
2467            const SBCindex = allSBCs && currentSBC ? Array?.prototype?.indexOf?.call(allSBCs, currentSBC) + 1 : 0;
2468
2469            const currentPillMktpTitle = currentPill?.querySelector('.aisle-category') ? currentPill.querySelector('.aisle-category').textContent?.toLowerCase().replace(' - ', ' ').replace(/\s/g, '-') : 'no-value';
2470            const allCurrentSBCPills = currentSBC?.querySelectorAll('.categories-item');
2471            const currentZoneSlot = SBCindex > 0 ? `z${SBCindex < 10 ? '0' : ''}${SBCindex}` : 'z00';
2472            const currentPillSlotValue = allCurrentSBCPills && currentPill ? Array?.prototype?.indexOf?.call(allCurrentSBCPills, currentPill) + 1 : 0;
2473            const currentPillSlot = currentPillSlotValue > 0 ? `sp${currentPillSlotValue < 10 ? '0' : ''}${currentPillSlotValue}` : `sp00`;
2474
2475            const aisleName = element.dataset['aisleName'];
2476            let aislesPreviousPage = `aisles-${aisleName}`;
2477            let categoryPill = `${currentZoneSlot}|click|category-pill:${currentPillMktpTitle}|${currentPillSlot}`;
2478
2479            if (!elementTitle && SBCindex === 1 && !componentTitle) {
2480                if (this.isHomePage()) {
2481                    aislesPreviousPage += '-home';
2482                } else if (this.isPdp()) {
2483                    aislesPreviousPage += '-pdp';
2484                }
2485            }
2486            if (this.isMarketplaceCategoryPage()) {
2487                if (window.digitalData.pageDetails && !window.digitalData.pageDetails.subSection3 && !window.digitalData.pageDetails.subSection4) {
2488                    aislesPreviousPage += '-l1';
2489                }
2490            }
2491            localStorage.setItem('aislesPreviousPage', aislesPreviousPage);
2492            if (window.isAnalyticsMarketplacePage) {
2493                localStorage.setItem('mktpCategoryPillClicked', categoryPill);
2494            }
2495        }
2496    }
2497
2498    /**
2499     * Sets the default link click event
2500     * @param linkClicked - name of the link that is clicked
2501     * @param oncePerPageView - boolean type, if the event should trigger once per pageView
2502     */
2503    this.setLinkClickEvents = function (linkClicked, oncePerPageView, modalMessage, isSendToSS) {
2504        try {
2505            let productId;
2506            const isStickyBannerDismissLink = linkClicked?.indexOf('cta|sticky-banner-dismiss-') === 0
2507                || linkClicked?.indexOf('cta|sticky-promo-ad-banner-dismiss-') === 0;
2508            if (window.digitalData && window.digitalData.link) {
2509                window.digitalData.link.linkName = linkClicked;
2510            }
2511
2512            if (modalMessage && ['sendMealsData', 'sendRecipesData'].indexOf(modalMessage) === -1) {
2513                digitalData.modal.modalMessage = modalMessage;
2514            }
2515
2516            let payload = {
2517                link: {
2518                    linkName: linkClicked
2519                },
2520                page: digitalData?.pageDetails,
2521                pageFilter: digitalData?.pageFilter,
2522                user: digitalData?.user,
2523                productInfo: digitalData?.productInfo || {},
2524                modal: digitalData?.modal,
2525                cart: digitalData?.cart
2526            };
2527            if (isSendToSS !== undefined) {
2528                payload.link.isSendToSS = isSendToSS;
2529            }
2530            if (isStickyBannerDismissLink) {
2531                payload.link.c14 = 'sticky-banner|shop-ex|564521|538994';
2532            }
2533            if (linkClicked === 'selective-cart|check' || linkClicked === 'selective-cart|uncheck') {
2534                productId = modalMessage;
2535                payload.link.selectiveCartProductId = productId;
2536                payload.productInfo.productID = productId;
2537            }
2538            const eventTrigger = oncePerPageView ? this.setEventOncePerPage(linkClicked, 'linkClick', productId) : false;
2539            if (modalMessage === 'sendMealsData') {
2540                payload.meals = digitalData.meals;
2541            } else if (modalMessage === 'sendRecipesData') {
2542                payload.recipes = digitalData.recipes;
2543            } else if ((['grid-product-clicks-oneTag', 'top-nav-oneTag'].indexOf(modalMessage) != -1) || (linkClicked === 'full-cart|add-note')) {
2544                payload.link.feature = modalMessage;
2545            }
2546
2547            !eventTrigger && this.pushEvent(
2548                this.EVENTS.LINK_CLICK, payload
2549            );
2550        } catch (e) {
2551            console.error('@AnalyticsTeam - Failed to send LinkClicked value due to following error: ', e);
2552        }
2553    }
2554
2555    /**
2556     * Sets the link click events for the offer drawer
2557     * @param linkClicked - default link click name
2558     * @param offerName - the name of the offer drawer that has been opened
2559     */
2560    this.setLinkClickOfferDrawer = function (linkClicked, offerName, element) {
2561        if (AB?.DATALAYER && digitalData) {
2562            let carouselTitle;
2563            const payload = {
2564                link: {
2565                    linkName: linkClicked,
2566                    linkDetail: offerName,
2567                    oneTagLinkName: 'offer-details|coupon'
2568                },
2569                page: structuredClone(digitalData?.pageDetails),
2570                pageFilter: structuredClone(digitalData?.pageFilter)
2571            };
2572            if (element && element instanceof Element) {
2573                const modelId = element.closest('lazy-wrapper')?.getAttribute('data-model-configuration-id');
2574                if (modelId) {
2575                    payload.page.abTestDetails = digitalData.couponTrackingInfo && digitalData.couponTrackingInfo[modelId] && digitalData.couponTrackingInfo[modelId].msgExperiment;
2576                }
2577                carouselTitle = this.getAnalyticsCarouselTitle(element);
2578                this.trackAEMZone('offer-drawer', element, `${carouselTitle}:drawer`);
2579            }
2580            if (AB.DATALAYER.isWeeklyAdDealsPage()) {
2581                linkClicked = `weekly-ad:${carouselTitle ? AB.DATALAYER.sanitizeAnalyticsText(carouselTitle) : ''}|offer-details`;
2582            }
2583            payload.pageFilter.placement = AB.DATALAYER.setCouponPlacement({}, element, 'offer-drawer');
2584
2585            AB.DATALAYER.pushEvent(
2586                this.EVENTS.LINK_CLICK, payload
2587            );
2588            if (AB.DATALAYER.isHomePage()) {
2589                const placement = payload.pageFilter?.placement;
2590                const mTyp = element?.closest('.slick-product-carousel, .master-product-carousel') ? 'product-carousel' : 'deals-carousel';
2591                AB.DATALAYER.setCRSClickEvent({
2592                    linkName: 'offer-details-click',
2593                    mTyp: mTyp,
2594                    element: element,
2595                    placement: placement,
2596                    component: AB.DATALAYER.getCRSComponent({
2597                        element: element,
2598                        section: carouselTitle,
2599                        detail: payload.page?.abTestDetails,
2600                        placement: placement
2601                    })
2602                });
2603            }
2604            digitalData.pageFilter.bannerCardCarousel = '';
2605        } else {
2606            console.warn('AB.DATALAYER is not defined on this page');
2607        }
2608    }
2609
2610    /**
2611     * Sets the modal message event
2612     * @param userMessage - message that is displayed to the user
2613     */
2614    this.setUserMessageEvents = function (userMessage) {
2615        if (window.digitalData && window.digitalData.modal) {
2616            window.digitalData.modal.modalMessage = userMessage;
2617        }
2618        if (window.AB && window.AB.DATALAYER) {
2619            AB.DATALAYER.pushEvent(
2620                this.EVENTS.MODAL_MESSAGE, {
2621                modal: {
2622                    modalMessage: userMessage
2623                },
2624                page: digitalData?.pageDetails,
2625                pageFilter: digitalData?.pageFilter
2626            }
2627            );
2628        } else {
2629            console.warn('AB.DATALAYER is not defined on this page');
2630        }
2631    }
2632
2633    /**
2634     * Updates datalayer when location tracking is enabled
2635     */
2636    this.geoEnabled = function () {
2637        if (window.digitalData && window.digitalData.user) {
2638            window.digitalData.user.locationTracking = 'enabled';
2639        }
2640    }
2641
2642    /**
2643     * Updates datalayer when location tracking is disabled or throws errors
2644     */
2645    this.geoBlocked = function () {
2646        if (window.digitalData && window.digitalData.user) {
2647            window.digitalData.user.locationTracking = 'blocked';
2648        }
2649    }
2650
2651    /**
2652     * Returns cart savings types and values
2653     * @param savings - the savings object from the API response, either cart savings or item savings
2654     * @param calledBy - component that is calling the method, can be called on minicart open or on product action
2655     */
2656    this.calculateCartSavings = function (savings, calledBy) {
2657        const clubcardSavings = [];
2658        const j4uSavings = [];
2659        const employeeSavings = [];
2660        const rewardsSavings = [];
2661        const promoCodeSavings = [];
2662        const totalSavings = {};
2663        if (savings && Array.isArray(savings) && savings.length > 0) {
2664            if (calledBy === 'cart') {
2665                // Separating cart savings into multiple sections
2666                savings.forEach(x => {
2667                    if (x.savingsCategoryName === 'Club Card Savings') {
2668                        clubcardSavings.push(x?.savingsAmount && !isNaN(parseFloat(x.savingsAmount)) ? parseFloat(x.savingsAmount) : 0);
2669                    } else if (x.savingsCategoryName === 'J4U Savings' || x.savingsCategoryName === 'Just for U Savings') {
2670                        j4uSavings.push(x?.savingsAmount && !isNaN(parseFloat(x.savingsAmount)) ? parseFloat(x.savingsAmount) : 0);
2671                    } else if (x.savingsCategoryName === 'Employee Savings') {
2672                        employeeSavings.push(x?.savingsAmount && !isNaN(parseFloat(x.savingsAmount)) ? parseFloat(x.savingsAmount) : 0);
2673                    } else if (x.savingsCategoryName === 'Rewards Savings') {
2674                        rewardsSavings.push(x?.savingsAmount && !isNaN(parseFloat(x.savingsAmount)) ? parseFloat(x.savingsAmount) : 0);
2675                    } else if (x.savingsCategoryName === 'Rewards and CashOff') {
2676                        rewardsSavings.push(x?.savingsAmount && !isNaN(parseFloat(x.savingsAmount)) ? parseFloat(x.savingsAmount) : 0);
2677                    }
2678                });
2679            } else if (calledBy === 'item') {
2680                // Separating item savings into multiple sections
2681                const savingsCategories = {
2682                    'Club Card Savings': 'clubcardSavings',
2683                    'Just for U Savings': 'j4uSavings',
2684                    'Employee Savings': 'employeeSavings',
2685                    'Rewards Savings': 'rewardsSavings',
2686                    'Rewards and CashOff': 'rewardsSavings',
2687                    18: 'clubcardSavings',
2688                    42: 'j4uSavings',
2689                    67: 'clubcardSavings',
2690                    68: 'clubcardSavings',
2691                    69: 'j4uSavings',
2692                    70: 'j4uSavings',
2693                    72: 'employeeSavings',
2694                    75: 'j4uSavings',
2695                    76: 'j4uSavings',
2696                    77: 'clubcardSavings',
2697                    80: 'clubcardSavings',
2698                    85: 'clubcardSavings',
2699                    89: 'rewardsSavings'
2700                };
2701                savings.forEach(x => {
2702                    if (savingsCategories[x.categoryId] === 'j4uSavings') {
2703                        j4uSavings.push(x?.discountAmount && !isNaN(parseFloat(x.discountAmount)) ? parseFloat(x.discountAmount) : 0);
2704                    } else if (savingsCategories[x.categoryId] === 'employeeSavings') {
2705                        employeeSavings.push(x?.discountAmount && !isNaN(parseFloat(x.discountAmount)) ? parseFloat(x.discountAmount) : 0);
2706                    } else if (savingsCategories[x.categoryId] === 'rewardsSavings') {
2707                        rewardsSavings.push(x?.discountAmount && !isNaN(parseFloat(x.discountAmount)) ? parseFloat(x.discountAmount) : 0);
2708                    } else if (savingsCategories[x.categoryId] === 'clubcardSavings') {
2709                        clubcardSavings.push(x?.discountAmount && !isNaN(parseFloat(x.discountAmount)) ? parseFloat(x.discountAmount) : 0);
2710                    }
2711                })
2712            }
2713        }
2714
2715        const clubcardSavingsValue = clubcardSavings.reduce(AB.DATALAYER.safeReducer, 0);
2716        const j4uSavingsValue = j4uSavings.reduce(AB.DATALAYER.safeReducer, 0);
2717        const employeeSavingsValue = employeeSavings.reduce(AB.DATALAYER.safeReducer, 0);
2718        const rewardsSavingsValue = rewardsSavings.reduce(AB.DATALAYER.safeReducer, 0);
2719        const promoCodeSavingsValue = promoCodeSavings.reduce(AB.DATALAYER.safeReducer, 0);
2720
2721        totalSavings.clubcardSavings = clubcardSavingsValue.toString();
2722        totalSavings.j4uSavings = j4uSavingsValue.toString();
2723        totalSavings.employeeSavings = employeeSavingsValue.toString();
2724        totalSavings.rewardsSavings = rewardsSavingsValue.toString();
2725        totalSavings.promocodeSavings = promoCodeSavingsValue.toString();
2726
2727        totalSavings.total = [clubcardSavingsValue, j4uSavingsValue, employeeSavingsValue, rewardsSavingsValue, promoCodeSavingsValue].reduce(AB.DATALAYER.safeReducer, 0);
2728
2729        return totalSavings;
2730    }
2731
2732    /**
2733     * Returns the offer drawer status - open or closed
2734     * @param productID  - the ID of the product that the offer drawer open has been triggered from
2735     */
2736    this.getDrawerStatus = function (productID) {
2737        const currentProduct = document.querySelector(`.product-item-${productID}`);
2738        return currentProduct?.closest('.sidebar__right-drawer[aria-label="offer details"]');
2739    }
2740
2741    /**
2742     * Returns the type of the offer drawer - basic offer drawer, BOGO or j4u (coupons drawer)
2743     * @param productID - the ID of the product that the offer drawer open has been triggered from
2744     */
2745    this.getDrawerType = function (productID) {
2746        const currentProduct = document.querySelector(`.product-item-${productID}`);
2747        let drawerType = 'drawer';
2748        if (currentProduct?.closest('right-drawer product-generic-grid')?.getAttribute('data-api-type') === 's-bogo') {
2749            drawerType = 'BOGO-drawer';
2750        } else if (currentProduct?.closest('right-drawer product-generic-grid')?.getAttribute('data-api-type') === 'c-products-by-upc-drawer') {
2751            drawerType = 'J4U-drawer';
2752        }
2753        return drawerType;
2754    }
2755
2756    /**
2757     * Returns the minicart drawer status
2758     */
2759    this.getMinicartStatus = function () {
2760        return document.querySelector('.sidebar__right-drawer') && document.querySelector('.sidebar__right-drawer')?.ariaLabel === 'Shopping cart';
2761    }
2762
2763    /**
2764     * Separates pages into sections and types based on subSection values
2765     */
2766    this.sortSiteSections = function () {
2767        let siteSection = 'not-available';
2768        let pageType = 'not-available';
2769        if (digitalData?.pageDetails) {
2770            let subSection1 = digitalData.pageDetails.subSection1 === 'loyalty' ? digitalData.pageDetails.subSection2 : digitalData.pageDetails.subSection1;
2771            let subSection2 = digitalData.pageDetails.subSection2;
2772            if (this.isWineShopPage()) {
2773                subSection1 = 'vineandcellar';
2774            }
2775
2776            switch (subSection1) {
2777                case 'home':
2778                    siteSection = 'Home';
2779                    pageType = 'Home';
2780                    break;
2781                case 'search-results':
2782                    siteSection = 'Shop';
2783                    pageType = 'Search Results';
2784                    break;
2785                case 'product-details':
2786                case 'product':
2787                    siteSection = 'Shop';
2788                    pageType = 'PDP';
2789                    break;
2790                case 'aisles':
2791                    siteSection = 'Shop';
2792                    if (AB.DATALAYER.isAislesL2Page()) {
2793                        pageType = 'Aisles L2';
2794                    } else if (AB.DATALAYER.isAislesL3Page()) {
2795                        pageType = 'Aisles L3';
2796                    } else if (AB.DATALAYER.isAislesL4Page()) {
2797                        pageType = 'Aisles L4';
2798                    } else {
2799                        pageType = 'Aisles';
2800                    }
2801                    break;
2802                case 'deals':
2803                    siteSection = 'Shop';
2804                    pageType = 'Deals';
2805                    break;
2806                case 'product-review':
2807                    siteSection = 'Shop';
2808                    pageType = 'Product Review';
2809                    break;
2810                case 'justforu':
2811                case 'offer-details':
2812                    siteSection = 'Banners for you';
2813                    subSection2 === 'coupons-deals' ? pageType = 'Coupons Page' : pageType = 'Banners for you';
2814                    break;
2815                case 'justforu-guest':
2816                case 'foru-guest':
2817                case 'guest':
2818                    siteSection = 'Banners for you';
2819                    pageType = 'Banners for you';
2820                    break;
2821                case 'account':
2822                    siteSection = 'Account';
2823                    if (subSection2 === 'sign-in') {
2824                        pageType = 'Sign-In';
2825                    } else if (subSection2 === 'short-registration') {
2826                        pageType = 'Registration';
2827                    }
2828                    break;
2829                case 'customer-account':
2830                    siteSection = 'Account';
2831                    if (subSection2 === 'rewards') {
2832                        pageType = 'Rewards';
2833                    } else {
2834                        pageType = 'My Account';
2835                    }
2836                    break;
2837                case 'order-account':
2838                    siteSection = 'Account';
2839                    pageType = 'Orders';
2840                    break;
2841                case 'pet-program':
2842                    siteSection = 'Account';
2843                    pageType = 'Pet Program';
2844                    break;
2845                case 'freshpass':
2846                case 'delivery-subscription':
2847                    siteSection = 'Account';
2848                    pageType = 'Delivery Subscription';
2849                    break;
2850                case 'schedule-and-save':
2851                    siteSection = 'Account';
2852                    pageType = 'Schedule and Save';
2853                    break;
2854                case 'recipes':
2855                    siteSection = 'Recipes';
2856                    pageType = 'Recipes';
2857                    break;
2858                case 'pharmacy':
2859                    siteSection = subSection2 === 'create-account' ? 'Shop' : 'Pharmacy';
2860                    pageType = 'Pharmacy';
2861                    break;
2862                case 'vaccinations':
2863                    siteSection = 'Pharmacy';
2864                    pageType = 'Pharmacy';
2865                    break;
2866                case 'sp':
2867                case 'vs':
2868                case 'lp':
2869                    siteSection = this.isFreshpassManagePage() ? 'Account' : 'Landing Page';
2870                    pageType = 'Landing Page';
2871                    break;
2872                case 'mylist':
2873                    siteSection = 'My List';
2874                    pageType = 'My List';
2875                    break;
2876                case 'foru':
2877                case 'rewards':
2878                case 'coupons-deals':
2879                    siteSection = 'Banners for you';
2880                    subSection2 === 'coupons-deals' ? pageType = 'Coupons Page' : pageType = 'Banners for you';
2881                    break;
2882                case 'foru-guest':
2883                    siteSection = 'Banners for you';
2884                    pageType = 'Banners for you';
2885                    break;
2886                case 'flavoradventure':
2887                    siteSection = 'Banners for you';
2888                    pageType = 'Flavor Adventure';
2889                    break;
2890                case 'm':
2891                case 'marketplace':
2892                    siteSection = 'marketplace';
2893                    pageType = 'marketplace';
2894                    break;
2895                case 'household':
2896                    siteSection = 'Shop';
2897                    pageType = 'Pharmacy';
2898                    break;
2899                case 'vineandcellar':
2900                    siteSection = 'wine-shop';
2901                    pageType = 'wine-shop';
2902                    break;
2903                case 'weekly-ad':
2904                    siteSection = 'weekly-ad';
2905                    pageType = 'weekly-ad';
2906                    break;
2907                case 'erums':
2908                case 'Full Cart':
2909                case 'Checkout':
2910                case 'reserve time':
2911                    siteSection = 'Checkout';
2912                    pageType = 'Checkout';
2913                    break;
2914                case 'purchases':
2915                    siteSection = 'shop';
2916                    pageType = 'buy-it-again';
2917                    break;
2918                case 'meals':
2919                    siteSection = 'meals';
2920                    pageType = 'meals';
2921                    break;
2922                case 'assistant':
2923                    siteSection = 'albertsons-ai';
2924                    pageType = 'albertsons-ai';
2925                    break;
2926                default:
2927                    break;
2928            }
2929        }
2930        if (window.digitalData && window.digitalData.pageDetails) {
2931            if (digitalData.pageDetails.banner === 'sincerely-food') {
2932                siteSection = 'e-community';
2933                pageType = 'Sincerely-Food';
2934            }
2935            digitalData.pageDetails.channel = siteSection;
2936            digitalData.pageDetails.pageType = pageType;
2937        }
2938    };
2939
2940    /**
2941     * return autoReplenishment object with deliveryWindow
2942     * @param slotPreference 
2943     */
2944    this.setDeliveryWindowAR = function (slotPreference, caller) {
2945
2946        let deliveryDay;
2947        let deliveryTime;
2948        let delieveryStartTime;
2949        let delieveryEndTime;
2950        let autoReplenishment = {
2951            arDeliveryWindow: ''
2952        };
2953        const days = {
2954            sunday: 1,
2955            monday: 2,
2956            tuesday: 3,
2957            wednesday: 4,
2958            thursday: 5,
2959            friday: 6,
2960            saturday: 7
2961        };
2962
2963        // set delivery day as number
2964        if (slotPreference?.fulfillmentDay || slotPreference?.dayOfWeek) {
2965            deliveryDay = caller === 'newSNSPage' ? slotPreference?.dayOfWeek.toLowerCase() : days[slotPreference?.fulfillmentDay?.toLowerCase()];
2966        }
2967
2968        // set delivery time
2969        if (slotPreference?.slotType || slotPreference?.priceType?.[0]) {
2970            const checkVal = slotPreference?.priceType?.[0] || slotPreference?.slotType;
2971            switch (checkVal) {
2972                case 'B2B_DELIVERY_1HR':
2973                case 'B2C_DELIVERY_1HR':
2974                case 'B2B_DUG':
2975                case 'B2C_DUG':
2976                case 'ONEHR':
2977                    deliveryTime = caller === 'newSNSPage' ? '1' : '1-hour';
2978                    break;
2979                case 'B2B_DELIVERY_2HR':
2980                case 'B2C_DELIVERY_2HR':
2981                case 'TWOHR':
2982                    deliveryTime = caller === 'newSNSPage' ? '2' : '2-hours';
2983                    break;
2984                case 'B2B_DELIVERY_4HR':
2985                case 'B2C_DELIVERY_4HR':
2986                case 'FOURHR':
2987                    deliveryTime = caller === 'newSNSPage' ? '4' : '4-hours';
2988                    break;
2989                default:
2990                    break;
2991            }
2992        }
2993
2994        // set delivery time
2995        if (caller === 'newSNSPage' && slotPreference?.slotStartTime && slotPreference?.slotEndTime) {
2996            const timeConvertor = (rawTime) => {
2997                const time = rawTime > 24 ? Math.floor(rawTime / 100) : rawTime;
2998                return `${time > 12 ? time % 12 : time}${time > 11 ? 'pm' : 'am'}`;
2999            }
3000            const slotStartTime = slotPreference?.slotStartTime?.toString()?.includes('T') ? new Date(slotPreference?.slotStartTime).getHours() : slotPreference?.slotStartTime;
3001            const slotEndTime = slotPreference?.slotEndTime?.toString()?.includes('T') ? new Date(slotPreference?.slotEndTime).getHours() : slotPreference?.slotEndTime;
3002            delieveryStartTime = timeConvertor(slotStartTime);
3003            delieveryEndTime = timeConvertor(slotEndTime);
3004        }
3005
3006
3007        if (deliveryDay && deliveryTime) {
3008            autoReplenishment.arDeliveryWindow = `${deliveryDay}|${deliveryTime}${caller === 'newSNSPage' && delieveryStartTime && delieveryEndTime ? `|${delieveryStartTime}-${delieveryEndTime}` : ''}`;
3009        }
3010
3011        return autoReplenishment;
3012    }
3013
3014    /**  
3015     * sets the error event for
3016     * error messages generated when the user is writing a review for a product
3017     */
3018    this.setErrorsReviewProductsForm = function () {
3019        document.querySelectorAll('form.review input#headline, form.review textarea#comments').forEach((element) => {
3020            element.addEventListener('keyup', () => {
3021                if (document.querySelector(`.review__field__error#review-${element.id}-error`) &&
3022                    AB.DATALAYER.isVisible(document.querySelector(`.review__field__error#review-${element.id}-error`))) {
3023                    const errorMessage = document.querySelector(`.review__field__error#review-${element.id}-error`)?.innerText?.trim()?.replace('Error:\n', '');
3024                    AB.DATALAYER.setError('3365', 'reviews', errorMessage);
3025                }
3026            });
3027        });
3028    }
3029
3030    /**
3031     * Sets OTP modal events
3032     * @param event - VIEW or CLICK event
3033     * @param modal - The modal being interacted with
3034     * @param message - The message sent if any
3035    */
3036    this.OTPModalEvents = function (event, modal, message) {
3037        if (!event) {
3038            return
3039        } else {
3040            event = event == 'view' ? this.EVENTS.MODAL_VIEW : this.EVENTS.MODAL_CLICK;
3041        }
3042
3043        if (window.digitalData && window.digitalData.modal) {
3044            window.digitalData.modal.modalAction = modal;
3045            if (message) {
3046                window.digitalData.modal.modalMessage = message;
3047            }
3048        }
3049        if (window.AB && window.AB.DATALAYER) {
3050            let payload = {
3051                modal: {
3052                    modalAction: modal
3053                },
3054                page: digitalData?.pageDetails,
3055                pageFilter: digitalData?.pageFilter
3056            };
3057            if (message) {
3058                payload.modal.modalMessage = message;
3059            }
3060            AB.DATALAYER.pushEvent(event, payload);
3061        } else {
3062            console.warn('AB.DATALAYER is not defined on this page');
3063        }
3064    }
3065
3066    /**
3067     * Sets OTP modal events
3068     * @param event - VIEW or CLICK event
3069     * @param payload - The subsections object or link_click value
3070    */
3071
3072    this.OTPPageEvents = function (event, payload) {
3073        if (!event) {
3074            return;
3075        } else if (window.AB && window.AB.DATALAYER) {
3076            if (event === 'view' && payload && typeof (payload) === 'object') {
3077                if (payload.ss3) {
3078                    digitalData.pageDetails.subSection3 = payload.ss3;
3079                }
3080                if (payload.ss4) {
3081                    digitalData.pageDetails.subSection4 = payload.ss4;
3082                }
3083                AB.DATALAYER.setPageLoad();
3084                sessionStorage.removeItem('OTPtype');
3085            } else if (event === 'click' && payload && typeof (payload) === 'string') {
3086                AB.DATALAYER.setLinkClickEvents(payload);
3087                sessionStorage.setItem('OTPtype', 'page');
3088            }
3089        } else {
3090            console.warn('AB.DATALAYER is not defined on this page');
3091        }
3092    }
3093
3094    this.analyticsCTATracking = function (value) {
3095        const santitizedValue = value?.toLowerCase()?.indexOf('cta:foru:coupons-deals|button|') !== -1 ?
3096            (value?.toLowerCase().indexOf('freshpass') !== -1 ? 'cta:foru:coupons-deals|button|fresh-pass'
3097                : this.sanitizeAnalyticsText(value.replace('&', 'and')))
3098            : this.sanitizeAnalyticsText(value);
3099        this.setLSItem('analyticsCTAValue', santitizedValue);
3100    }
3101
3102    /**
3103     * Returns the referring URL with the current URL 'r' parameter, if found
3104     * the default value is document.referrer
3105     */
3106    this.getReferringUrl = function () {
3107        return AB.DATALAYER.analyticsGetURLParameterByName('r') || document.referrer;
3108    };
3109
3110    /**
3111     * Returns the third party info
3112     */
3113    this.getThirdParty = function () {
3114        let reportThirdParty = '';
3115        this.arrThirParty.forEach(x => {
3116            if (document.querySelectorAll(`.${x}`).length > 0) {
3117                reportThirdParty = x;
3118            }
3119        });
3120        return reportThirdParty;
3121    };
3122
3123    /** 
3124     * Returns topNav value
3125     * topNav = nav structure from previous page (level) > nav structure from current page (level)
3126     * nav structure = concatenation of subSection1 to subSection4
3127     * level = number of subsections populated
3128     */
3129    this.initTopNav = function () {
3130        let topNav = '';
3131        let isMarketplace = window.isAnalyticsMarketplacePage;
3132        if (localStorage.getItem('analyticsPageInfo')) {
3133            localStorage.removeItem('analyticsPageInfo');
3134        }
3135        if (localStorage.getItem('topNavPreviousPage') || this.getCookie('topNavPreviousPage')) {
3136            const topNavPreviousPage = localStorage.getItem('topNavPreviousPage') || this.getCookie('topNavPreviousPage');
3137            const subSections = [digitalData.pageDetails.subSection1, digitalData.pageDetails.subSection2, digitalData.pageDetails.subSection3, digitalData.pageDetails.subSection4].filter(function (x) {
3138                return x;
3139            });
3140            const topNavCurrentPage = subSections.join(':') + ' (L' + subSections.length + ')';
3141            topNav = `${topNavPreviousPage} > ${isMarketplace ? 'mkp|' : ''}${topNavCurrentPage}`;
3142            localStorage.removeItem('topNavPreviousPage');
3143            if (this.getCookie('topNavPreviousPage')) {
3144                this.setLSItem('shopOrTopNavFlag', 'true');
3145                this.deleteCookie('topNavPreviousPage', `${digitalData.pageDetails.banner}.com`);
3146            }
3147            if (window.location.pathname.startsWith('/freshpass/manage/subscribe')) {
3148                this.setLSItem('analyticsGetFreshPass', topNav);
3149            }
3150        } else if (localStorage.getItem('aislesPreviousPage')) {
3151            topNav = localStorage.getItem('aislesPreviousPage');
3152            localStorage.removeItem('aislesPreviousPage');
3153            if (this.isMarketplaceCategoryPage()) {
3154                this.pfmSourceMktpCategories = topNav.substring(0, topNav.lastIndexOf('-'));
3155            }
3156        } else if (localStorage.getItem('topNavDFTAPage')) {
3157            topNav = localStorage.getItem('topNavDFTAPage');
3158            localStorage.removeItem('topNavDFTAPage');
3159        } else if (localStorage.getItem('analyticsTopNavStudent')) {
3160            topNav = localStorage.getItem('analyticsTopNavStudent');
3161            localStorage.removeItem('analyticsTopNavStudent');
3162        } else if (localStorage.getItem('topNavSimilarItemsBIA')) {
3163            topNav = localStorage.getItem('topNavSimilarItemsBIA');
3164            localStorage.removeItem('topNavSimilarItemsBIA');
3165        } else if (localStorage.getItem('analyticsOTPFlowPP')) {
3166            topNav = localStorage.getItem('analyticsOTPFlowPP');
3167            localStorage.removeItem('analyticsOTPFlowPP');
3168        } else if (this.getLSItem('analyticsCTAValue') && !this.isExpediaPageSource()) {
3169            topNav = this.handleGetLSValue('analyticsCTAValue');
3170        } else if (this.getLSItem('analyticsSNSlink')) {
3171            topNav = this.handleGetLSValue('analyticsSNSlink');
3172        } else if (this.getLSItem('topNavCheckoutPage')) {
3173            topNav = this.handleGetLSValue('topNavCheckoutPage');
3174        } else if (this.getLSItem('analyticsMealsCarouselTopNav')) {
3175            topNav = this.handleGetLSValue('analyticsMealsCarouselTopNav');
3176        }
3177        if (this.getLSItem('manageSnsFromOrderConfirm')) {
3178            topNav = this.handleGetLSValue('manageSnsFromOrderConfirm');
3179        }
3180        return topNav;
3181    };
3182
3183    this.handleFeatureExpiration = function (featureTimeLimit) {
3184        let isFeatureExpired = true;
3185        const currentTime = new Date().getTime();
3186        if (featureTimeLimit >= currentTime) {
3187            isFeatureExpired = false;
3188        }
3189        return isFeatureExpired;
3190    }
3191
3192    /**
3193     * Legal/compliance: alcohol products in featured sponsored ad slots must not
3194     * be tracked in Adobe or OneTag.
3195     * @param product
3196     */
3197    this.isAlcoholAdTrackingDisabled = function (product) {
3198        if (!window?.SWY?.CONFIGSERVICE?.featureToggleConfig?.sponsoredAlcohol) {
3199            return false;
3200        }
3201        return !!(product?.containsAlcohol && product?.featured);
3202    };
3203
3204    /**
3205     * pushes a new event in the data layer
3206     * @param name must be a non blank string
3207     * @param data associated with the event
3208     */
3209    this.pushEvent = function (event, data) {
3210        data = data && typeof data === 'object' && !Array.isArray(data) ? data : {};
3211        if (!data.isTrackingExpired) {
3212            digitalData = digitalData || {};
3213            digitalData.pageFlags = digitalData.pageFlags || {};
3214            digitalData.serverData = digitalData.serverData || {};
3215            digitalData.user = digitalData.user || {};
3216
3217            if (typeof event === 'string' || event instanceof String) {
3218                data.serverData = data.serverData || {};
3219                data.serverData.eventId = this.generateEventId();
3220                data.serverData.currentTime = this.generateCurrentTime();
3221                data.serverData.experimentIds = this.getExperimentIds();
3222
3223                if (AB.DATALAYER.getLSItem('analyticsDUGPharmacyInfoBanner')) {
3224                    if (data?.page) {
3225                        data.page.engagementLadderImpressions = 'pharmacy:need-prescription-banner';
3226                        AB.DATALAYER.removeLSItem('analyticsDUGPharmacyInfoBanner');
3227                    }
3228                }
3229                if (data?.page && !data.page.feature) {
3230                    data.page.feature = AB.DATALAYER.getFeatureValue(event);
3231                }
3232
3233                data.user = data.user ? { ...digitalData.user, ...data.user } : digitalData.user;
3234
3235                let dataClone = structuredClone({
3236                    event,
3237                    ...data
3238                });
3239                // add serverData for batch coupon event
3240                if (event === 'coupon_clipped') {
3241                    const lsCouponGroup = AB.DATALAYER.getLSItem('couponGroup') ? AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('couponGroup')) : [];
3242                    if (lsCouponGroup.length > 0) {
3243                        lsCouponGroup[lsCouponGroup.length - 1].serverData = data.serverData;
3244                        AB.DATALAYER.setLSItem('couponGroup', JSON.stringify(lsCouponGroup))
3245                    }
3246                }
3247
3248                let sessionIdStatus = function () {
3249                    AB?.DATALAYER?.initUser();
3250                    const isSessionIdLoaded = digitalData.user.sessionId && digitalData.user.sessionId !== 'ID not found';
3251                    return isSessionIdLoaded;
3252                }
3253
3254                let isSessionIdLoaded = digitalData.user.sessionId && digitalData.user.sessionId !== 'ID not found';
3255
3256                if (!isSessionIdLoaded) {
3257                    isSessionIdLoaded = sessionIdStatus();
3258                }
3259
3260                let pushClonedData = function () {
3261                    isSessionIdLoaded = sessionIdStatus();
3262                    if (isSessionIdLoaded) {
3263                        appEventData.push(dataClone);
3264                        if (AB.DATALAYER.shouldSendDatatoOneTag(event, dataClone)) {
3265                            if(dataClone?.experimentationReturnPromise && event === 'target-experiment-exposure'){
3266                                return AB.DATALAYER.sendDataToOneTag(event, dataClone);
3267                            }else{
3268                                AB.DATALAYER.sendDataToOneTag(event, dataClone);
3269                            }
3270                        }
3271                    }
3272                }
3273
3274                if (AB?.DATALAYER?.shouldDelayEvent(event) && !AB.DATALAYER.isOrderAheadPage()) {
3275                    if (isSessionIdLoaded) {
3276                        appEventData.push(dataClone);
3277                        if (AB.DATALAYER.shouldSendDatatoOneTag(event, dataClone)) {
3278                            if(dataClone?.experimentationReturnPromise && event === 'target-experiment-exposure'){
3279                                return AB.DATALAYER.sendDataToOneTag(event, dataClone);
3280                            }else{
3281                                AB.DATALAYER.sendDataToOneTag(event, dataClone);
3282                            }
3283                        }
3284                    } else {
3285                        document.addEventListener('onGetUserInfoLoad', pushClonedData);
3286                        setTimeout(() => {
3287                            isSessionIdLoaded = sessionIdStatus();
3288                            if (!isSessionIdLoaded) {
3289                                appEventData.push(dataClone);
3290                                if (AB.DATALAYER.shouldSendDatatoOneTag(event, dataClone)) {
3291                                    AB.DATALAYER.sendDataToOneTag(event, dataClone);
3292                                }
3293                                document.removeEventListener('onGetUserInfoLoad', pushClonedData);
3294                            }
3295                        }, 3000);
3296                    }
3297                } else {
3298                    appEventData.push(dataClone);
3299                    if (AB.DATALAYER.shouldSendDatatoOneTag(event, dataClone)) {
3300                        if(dataClone?.experimentationReturnPromise && event === 'target-experiment-exposure'){
3301                            return AB.DATALAYER.sendDataToOneTag(event, dataClone);
3302                        }else{
3303                            AB.DATALAYER.sendDataToOneTag(event, dataClone);
3304                        }
3305                    }
3306                }
3307                digitalData = { ...digitalData, ...data };
3308                if (event !== AB.DATALAYER.BATCHCOUPONCLIPPED && event !== 'coupon_clipped' && !AB.DATALAYER.isCRSClickEvent(event, dataClone)) {
3309                    AB.DATALAYER.setBatchCoupon();
3310                }
3311            }
3312        }
3313    }
3314
3315    // set pageFilter.recommendationType
3316    this.setRecommendationType = function (recommendationType) {
3317        if (digitalData && digitalData.pageFilter) {
3318            digitalData.pageFilter.recommendationType = recommendationType;
3319        }
3320    };
3321
3322    /**
3323     * Initializes the user journey status and status code, using the status code from local storage
3324     */
3325    this.getJourneyStatus = function () {
3326        return this.JOURNEY_STATUSES[this.journeyStatusCode];
3327    };
3328
3329    /**
3330     * Initializes the user journey status code, using the status code from local storage
3331     */
3332    this.initJourneyStatus = function () {
3333        this.journeyStatusCode = localStorage.getItem('journeyStatusCode') || this.JourneyStatusCode.EMPTY;
3334    };
3335
3336    /**
3337     * Sets the user journey status and the status code
3338     * @param code
3339     */
3340    this.setJourneyStatus = function (code) {
3341        this.journeyStatusCode = code;
3342        digitalData.user.journeyStatus = this.JOURNEY_STATUSES[this.journeyStatusCode];
3343        localStorage.setItem('journeyStatusCode', this.journeyStatusCode);
3344    };
3345
3346    /**
3347     * Updates the user journey status and the status code
3348     * @param flag
3349     */
3350    this.updateJourneyStatus = function (flag) {
3351        this.journeyStatusCode |= flag;
3352        digitalData.user.journeyStatus = this.JOURNEY_STATUSES[this.journeyStatusCode];
3353        localStorage.setItem('journeyStatusCode', this.journeyStatusCode);
3354    };
3355
3356    // set pageFilter.carousel
3357    this.setCarouselName = function (carouselName) {
3358        if (typeof (carouselName) === 'undefined') {
3359            const carouselNamefromLS = this.handleGetLSValue('analyticsCarouselName');
3360            return carouselNamefromLS;
3361        }
3362        if (digitalData?.pageFilter) {
3363            digitalData.pageFilter.carousel = this.sanitizeAnalyticsText(carouselName);
3364        }
3365    }
3366
3367    this.setPageFilterPlacement = (placement, mediaType, recommendationType) => {
3368        if (digitalData) {
3369            const { pageFilter } = digitalData;
3370            pageFilter.placement = placement;
3371            pageFilter.mediaType = mediaType;
3372            pageFilter.recommendationType = recommendationType ? recommendationType : pageFilter.recommendationType ? pageFilter.recommendationType : '';
3373        }
3374    }
3375
3376    /**
3377     * return the pageName string
3378     * @param {*} channel in case we need a specific channel
3379     * @param {*} getExistingPathSections in case we need subsections other than what we have in the pathSections
3380     * @param {*} checkoutStepIndex index of the checkout step
3381     */
3382    this.setPageName = function (channel, getExistingPathSections, checkoutStepIndex) {
3383        if (digitalData) {
3384            if (this.isCartAndCheckoutPage('checkout') && checkoutStepIndex) {
3385                digitalData.pageDetails.pageName = `${this.getBanner()}:delivery:${channel ? channel : digitalData.pageDetails.channel}:step ${checkoutStepIndex} - ${digitalData.pageDetails.subSection2}`;
3386            } else {
3387                if (this.isDFTAPage() || this.isCartAndCheckoutPage('cart') || this.isCartAndCheckoutPage('confirmation') || this.isCartAndCheckoutPage('prebook') || this.isCartAndCheckoutPage('', true)) {
3388                    channel = 'delivery';
3389                } else if (this.isWeeklyAdPage()) {
3390                    channel = 'weekly-ad';
3391                }
3392                digitalData.pageDetails.pageName = `${this.getBanner()}${!this.isRecipesAndMealsPage() ? (`:${channel ? channel : digitalData.pageDetails.channel}`) : ''}:${this.isCartAndCheckoutPage('prebook') ? 'Prebook Store' : (getExistingPathSections ? this.initPathSections(getExistingPathSections).join(':') : this.pathSections.join(':'))}`;
3393            }
3394        }
3395    }
3396
3397    /**
3398     * Set Previous Page name
3399     */
3400    this.setPreviousPageName = function () {
3401        if (digitalData && digitalData.pageDetails) {
3402            const pName = digitalData.pageDetails.pageName;
3403            const previousPName = digitalData.crossPageData?.analyticsPreviousPageName?.data || this.handleGetLSValue('analyticsPreviousPageName') || pName;
3404            this.setAnalyticsCrossPageData({ action: 'remove', name: 'analyticsPreviousPageName' });
3405            digitalData.pageDetails.previousPageName = previousPName;
3406            if (pName) {
3407                this.setLSItem('analyticsPreviousPageName', pName);
3408                this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsPreviousPageName', data: pName, isAcrossPages: true });
3409            }
3410        }
3411    }
3412
3413    /**
3414     * Set the values from pathsections to subsections from 1 to 4
3415     */
3416    this.setSubsections = function () {
3417        if (digitalData) {
3418            digitalData.pageDetails.subSection1 = this.pathSections[0];
3419            digitalData.pageDetails.subSection2 = this.pathSections[1];
3420            digitalData.pageDetails.subSection3 = this.pathSections[2];
3421            digitalData.pageDetails.subSection4 = this.pathSections[3];
3422        }
3423    }
3424
3425    /**
3426     * Set the restricted product flag for search and aisle pages
3427     */
3428    this.setRestrictedProductPageFlag = function (isProductTrackingDisabled) {
3429        if (digitalData) {
3430            digitalData.pageFlags = digitalData.pageFlags || {};
3431            if (isProductTrackingDisabled) {
3432                digitalData.pageFlags.isProductTrackingDisabled = isProductTrackingDisabled;
3433                this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsRestrictedProductPage', data: isProductTrackingDisabled, isAcrossPages: true });
3434            }
3435        }
3436    }
3437
3438    this.getAllItems = function (data) {
3439        const allItems = [];
3440        data.orderItems.forEach((item) => {
3441            if (item.name && item.totalPrice > 0 && item.isFound) {
3442                allItems.push({
3443                    'productID': item.itemId,
3444                    'productName': item.name,
3445                    'units': item.quantity.toString(),
3446                    'basePrice': item.basePrice.toString(),
3447                    'totalPrice': item.totalPrice.toString(),
3448                    'isProductTrackingDisabled': !!item.isProductTrackingDisabled
3449                });
3450            }
3451        });
3452
3453        return allItems;
3454    }
3455
3456    /**
3457     * Function which will handle analytics data and flags used across the pages
3458     * @param {*} action get or set the content of the pageFlags
3459     * @param {*} name set the name of the flag
3460     * @param {*} data set the value of the flag
3461     * @param {*} isAcrossPages should this flag be available when the user refreshes the page or navigates to another
3462     */
3463    this.setAnalyticsCrossPageData = function ({ action, name, data, isAcrossPages } = {}) {
3464        if (digitalData) {
3465            const { crossPageData } = digitalData;
3466            if (action === 'set' && name) {
3467                crossPageData[`${name}`] = {
3468                    'data': data ? data : false,
3469                    'isAcrossPages': isAcrossPages ? isAcrossPages : false
3470                };
3471                isAcrossPages && this.setLSItem('analyticsLSObject', JSON.stringify(crossPageData));
3472                //Should check the behaviour of the top nav
3473            } else if (action === 'get') {
3474                const crossPageDataFromLS = this.getLSItem('analyticsLSObject') && this.safeJSONParse(this.getLSItem('analyticsLSObject'));
3475                Object.assign(digitalData.crossPageData, crossPageDataFromLS);
3476            } else if (action === 'remove' && name) {
3477                if (crossPageData.hasOwnProperty(`${name}`)) {
3478                    delete crossPageData[`${name}`];
3479                }
3480                let onlyCrossPageData = {};
3481                for (const [key, value] of Object.entries(crossPageData)) {
3482                    if (value?.isAcrossPages === true) {
3483                        onlyCrossPageData[key] = value;
3484                    }
3485                }
3486                Object.keys(onlyCrossPageData).length > 0 && this.setLSItem('analyticsLSObject', JSON.stringify(onlyCrossPageData));
3487            }
3488        }
3489    }
3490
3491    /**
3492     * Function to set impression on the same page
3493     * @param {*} impression impression value that needs to be set
3494     */
3495    this.setImpression = function (impression) {
3496        if (digitalData?.pageFilter && !digitalData?.pageFilter?.impressions?.includes(impression)) {
3497            digitalData.pageFilter.impressions = digitalData.pageFilter.impressions ? `${digitalData.pageFilter.impressions},${impression}` : impression;
3498        }
3499    }
3500
3501    /**
3502     * Function to clear impression on the same page
3503     * @param {*} impression impression value that needs to be cleared
3504     */
3505    this.removeImpression = function (impression) {
3506        if (digitalData?.pageFilter?.impressions && digitalData?.pageFilter?.impressions?.includes(impression)) {
3507            let regEX = new RegExp(',?' + impression + '');
3508            digitalData.pageFilter.impressions = digitalData.pageFilter.impressions.replace(regEX, '').replace(/^,/, '');
3509        }
3510    }
3511
3512    this.setTopNavLinkClicks = function (linkTitle) {
3513        if (linkTitle.indexOf('Health') != -1) {
3514            this.setLinkClickEvents('navigation|health');
3515        } else if (linkTitle.indexOf('Pharmacy') != -1) {
3516            this.setLinkClickEvents('navigation|pharmacy');
3517        } else if (linkTitle.indexOf('Business') != -1) {
3518            this.setLinkClickEvents('navigation|for-business');
3519        } else if (linkTitle.indexOf('Grocery') != -1) {
3520            AB.DATALAYER.setLSItem('analyticsNavTracking', 'top-nav');
3521        }
3522    }
3523
3524    this.setTopNavCategory = function (element) {
3525        if (element && element instanceof Element) {
3526            let topNav;
3527            const l1Title = AB.DATALAYER.sanitizeAnalyticsText(element.closest('.categories-item__drilldown > div[role="menu"]')?.ariaLabel?.trim());
3528            const l2Title = AB.DATALAYER.sanitizeAnalyticsText(element.closest('ul.t_nav__dd__parent-list > li')?.querySelector('a')?.textContent?.trim());
3529            const l3Title = AB.DATALAYER.sanitizeAnalyticsText(element.closest('ul.t_nav__dd__parent-list-2 > li')?.querySelector('a')?.textContent?.trim());
3530            const l4Title = AB.DATALAYER.sanitizeAnalyticsText(element.closest('ul.t_nav__dd__parent-list-3 > li')?.querySelector('a')?.textContent?.trim());
3531            topNav = `${l1Title}${l2Title ? `>${l2Title}` : ''}${l3Title ? `>${l3Title}` : ''}${l4Title ? `>${l4Title}` : ''}`;
3532            AB.DATALAYER.setLSItem('analyticsTopTertiaryNavTracking', topNav);
3533        }
3534    }
3535
3536    this.trackTopNavOneTag = function (action, categoryName) {
3537        if (action === 'hover') {
3538            const eventTrigger = this.setEventOncePerPage(categoryName, 'hover-over-impressions');
3539            !eventTrigger && AB.DATALAYER.pushEvent('hover-over-impressions', {
3540                hover: {
3541                    linkName: categoryName,
3542                    feature: 'top-nav-oneTag',
3543                    isSendToSS: true,
3544                },
3545                user: digitalData.user,
3546                page: digitalData.pageDetails,
3547                pageFilter: digitalData.pageFilter
3548            });
3549        } else if (action === 'click') {
3550            AB.DATALAYER.setLinkClickEvents(categoryName, true, 'top-nav-oneTag', true);
3551        }
3552    }
3553
3554    /**
3555     * Track clicks on products for AMC
3556    */
3557    this.trackOneTagProductClick = function ({ product, placement, feature } = {}) {
3558        if (this.isHomePage() && feature === 'carousel') {
3559            const component = AB.DATALAYER.getCRSComponent({
3560                section: product?.carouselSection,
3561                detail: product?.p13nAdobeMetrics?.metricA || product?.adobeMetrics?.metricA || product?.impressionAdditionalDetail || product?.adobeMetricA,
3562                sponsored: product?.featured,
3563                placement: placement
3564            });
3565            AB.DATALAYER.setCRSClickEvent({
3566                linkName: 'product-click',
3567                mTyp: 'product-carousel',
3568                placement: placement,
3569                component: component,
3570                product: product
3571            });
3572        }
3573        if ((this.isSearchResultsPage() || this.isAislesPage() || (this.isPdp() && feature === 'carousel')) && !this.isWineShopPage() && !this.isAnalyticsMarketplacePage) {
3574            let payload = {
3575                link: {
3576                    linkName: `${digitalData.pageDetails.subSection1}-product-click`,
3577                    isSendToSS: true,
3578                    feature: `${feature}-product-clicks-oneTag`
3579                },
3580                serverData: {
3581                    attributionToken: digitalData.user.storedAttributionToken
3582                },
3583                search: digitalData.search || {},
3584                page: digitalData.pageDetails,
3585                pageFilter: digitalData.pageFilter,
3586                user: digitalData.user,
3587            };
3588            if (product) {
3589                payload.productInfo = {
3590                    productID: product?.id,
3591                    bia: product?.pastPurchased,
3592                    oos: product?.inventoryAvailable > 0 ? false : true,
3593                    sponsored: product?.featured,
3594                    mp: product?.isMarketplaceItem || 'N',
3595                    display: feature,
3596                    placement: placement,
3597                    isProductTrackingDisabled: !!product.isProductTrackingDisabled,
3598                    isCustomCake: product?.isCustomCake,
3599                    productName: product?.name + (product?.isCustomCake ? '|event424=1' : '')
3600                }
3601            }
3602
3603            payload.pageFilter.placement = '';
3604            payload.pageFilter.pdpID = feature === 'carousel' && this.isPdp() && AB.DATALAYER.getLSItem('analyticsAMCPDPInfo') ? AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('analyticsAMCPDPInfo'))?.productID : '';
3605            payload.pageFilter.carousel = feature === 'carousel' ? product?.carouselSection : '';
3606            payload.pageFilter.mediaType = feature === 'carousel' ? 'product-carousel' : 'product-grid';
3607            delete payload.search.impressions;
3608
3609            this.pushEvent(this.EVENTS.LINK_CLICK, payload);
3610        }
3611    }
3612
3613    this.trackWeeklyAdIcmpid = function (feature, navPath) {
3614        let trackingValue = '';
3615        if (AB.DATALAYER.isWeeklyAdPage()) {
3616            trackingValue = `${navPath && navPath.includes('?') ? '&' : '?'}icmpid=weekly-ad-${AB.DATALAYER.isWeeklyAdDealsPage() ? 'pv-' : ''}guest-${feature}`;
3617        }
3618        return trackingValue;
3619    }
3620
3621    this.defaultCTANavTracking = function (value) {
3622        window['AB']['DATALAYER'].analyticsCTATracking(`cta:${window['AB']['DATALAYER'].pathSections?.join(':')}|${value}`);
3623    }
3624
3625    this.trackPartnerNavLink = function (link) {
3626        if (link?.indexOf('/rewards/partners') !== -1) {
3627            window['AB']['DATALAYER'].setAnalyticsCrossPageData({ action: 'set', name: 'analyticsFeatureTracking', data: 'partnerHub413315', isAcrossPages: true });
3628            this.defaultCTANavTracking('button|partner-offers')
3629        }
3630        if (link?.indexOf('/loyalty/discovery') !== -1) {
3631            window['AB']?.['DATALAYER']?.analyticsCTATracking('cta:' + window['AB']?.['DATALAYER']?.initPathSections(true).join(':') + '|link|' + link);
3632        }
3633    }
3634
3635    this.handlePDPAccordionClick = function (tab, element) {
3636        if (element && tab) {
3637            if (element?.nodeName === 'SPAN') {
3638                element = element.closest('button');
3639            }
3640            this.setLinkClickEvents(`pdp|${tab}:${element?.getAttribute('aria-expanded') == 'true' ? 'expand' : 'collapse'}`, true);
3641        }
3642    }
3643
3644    this.getFeatureValue = function (eventName) {
3645        let feature = '';
3646        if (AB.DATALAYER.isB2BPage()) {
3647            switch (eventName) {
3648                case 'cart_add':
3649                case 'add_quantity':
3650                case 'remove_quantity':
3651                case 'remove_cart':
3652                    feature = 'productactions|b2b|342524|302266';
3653                    break;
3654                case 'pdp_page':
3655                    feature = 'pdp-page|b2b-grocery|ACIP-345643|ACIP-302266';
3656                    break;
3657                case 'checkout':
3658                case 'checkout_step1':
3659                case 'checkout_step2':
3660                case 'checkout_step3':
3661                case 'checkout_step4':
3662                    feature = 'checkout-page|b2b-grocery|ACIP-345643|ACIP-302266';
3663                    break;
3664                default:
3665                    break;
3666            }
3667        } else {
3668            switch (digitalData.crossPageData?.analyticsFeatureTracking?.data) {
3669                case 'bundlesACIP400316':
3670                    feature = 'standard-bundle|pzn|389325|364106';
3671                    break;
3672                case 'mediumbannerACIP397009':
3673                    feature = 'deals-advert-medium-banner|collective|392111|391882';
3674                    break;
3675                case 'freshpassDiscountACIP392731':
3676                    feature = 'fp|fp-pre|392731|353274';
3677                    break;
3678                case 'partnerCodesACIP404189':
3679                    feature = 'fp|loyalty|ACIP-404189|397110';
3680                    break;
3681                case 'subsPrefACIP405518':
3682                    feature = 'sub-phase-shop-assist|shp-exp|397917|357630';
3683                    break;
3684                case 'casSubPrefACIP409006':
3685                    feature = 'cas-sub-phase|shp-exp|409006|357630';
3686                    break;
3687                case 'partnerHub413315':
3688                    feature = 'partners|loyalty|403134|413315';
3689                    break;
3690                case 'expedia414687':
3691                    feature = 'expedia|shp-exp|394681|383353';
3692                    break;
3693                case 'expediaMobile508929':
3694                    feature = 'loyalty|exp|500714|495176';
3695                    break;
3696                case 'dietaryPrefACIP455391':
3697                    feature = 'dietary-pref|shp-exp|452129|338908';
3698                    break;
3699                case 'selectiveCartACIP462764':
3700                    feature = 'selective-cart|shp-exp|460977|452569';
3701                    break;
3702                case 'selectiveCartACIP498475':
3703                    feature = 'selective-cart|shp-exp|492731|492728';
3704                    break;
3705                case 'subsUpdateACIP468396':
3706                    feature = 'substitution|shp-exp|459602|270001';
3707                    break;
3708                case 'smartBasketACIP416781':
3709                    feature = 'smart-basket|pzn|395920|396472';
3710                    break;
3711                default:
3712                    break;
3713            }
3714            delete digitalData.crossPageData?.analyticsFeatureTracking;
3715            AB.DATALAYER.setAnalyticsCrossPageData({ action: 'remove', name: 'analyticsFeatureTracking' });
3716        }
3717        return feature;
3718    }
3719
3720    /**
3721     * Returns the quantity currently in the cart for a given product id.
3722     * Checks every known cart shape used across the app (live + persisted).
3723     * Gated by SWY.CONFIGSERVICE.featureToggleConfig.isSponsoredImpressionFixDisabled
3724     * (killswitch). When the flag is truthy the fix is OFF and callers fall back
3725     * to inline `quantity || qty || 0` logic.
3726     */
3727    this.getProductCartUnits = function (productId) {
3728        if (window?.SWY?.CONFIGSERVICE?.featureToggleConfig?.isSponsoredImpressionFixDisabled) {
3729            return 0;
3730        }
3731        if (!productId) return 0;
3732        try {
3733            const cart = window?.digitalData?.cart || {};
3734            const absCart = AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('abCart')) || {};
3735            const pools = [
3736                cart.absItems, cart.cartItems, cart.cartItemsList, cart.orderItems,
3737                absCart?.cart?.abs?.cartItems, absCart?.cartItems, absCart?.cartItemsList
3738            ];
3739            const target = String(productId);
3740            for (const list of pools) {
3741                if (!Array.isArray(list) || !list.length) continue;
3742                const found = list.find(i => String(i?.id ?? i?.itemId ?? i?.productId ?? i?.pId) === target);
3743                if (found) return Number(found.quantity ?? found.qty ?? found.units ?? 0) || 0;
3744            }
3745        } catch (e) { /* noop */ }
3746        return 0;
3747    }
3748
3749    this.getBadgeInfo = function (badges) {
3750        let badgeInfo = 'no-badge';
3751        if (badges && Array.isArray(badges)) {
3752            if (badges.length === 1 && badges[0]?.badgeName) {
3753                badgeInfo = AB.DATALAYER.sanitizeAnalyticsText(badges[0].badgeName);
3754            } else if (badges.length > 1) {
3755                badgeInfo = badges.map(badge => {
3756                    return badge.badgeName && AB.DATALAYER.sanitizeAnalyticsText(badge.badgeName)
3757                }).join(':');
3758            }
3759        }
3760        return badgeInfo;
3761    }
3762
3763    this.getUIBadge = function (carouselElement, productId) {
3764        if (!window?.SWY?.CONFIGSERVICE?.featureToggleConfig?.isSponsoredImpressionFixDisabled) {
3765            const slideWrapper = carouselElement?.querySelector(`[data-bpn="${productId}"]`)?.closest('.slick-slide, product-carousel-item, product-carousel-item-v2, product-carousel-item-al-v1, product-carousel-item-al-v2');
3766            const rawBadge = slideWrapper?.querySelector('.pc__badge, .pds-tag')?.textContent?.trim();
3767            if (!rawBadge) return 'no-badge';
3768            return AB.DATALAYER.sanitizeAnalyticsText(rawBadge) || 'no-badge';
3769        }
3770        const UIBadge = carouselElement?.querySelector(`[data-bpn="${productId}"]`)?.closest('.slick-slide')?.querySelector('.pc__badge, .pds-tag')?.textContent || 'no-value';
3771        return AB.DATALAYER.sanitizeAnalyticsText(UIBadge);
3772    }
3773
3774}).call(AB.DATALAYER);
3775
3776'use strict';
3777
3778(function () {
3779
3780    /**
3781     * Handles modal view, modal click and link click events
3782     */
3783    this.handleEvents = function () {
3784        AB.DATALAYER.initModalClickEvents();
3785        AB.DATALAYER.initForgotPasswordReset();
3786        AB.DATALAYER.initModalViewEvents();
3787    };
3788
3789    /**
3790     * Handles create account, sign in and sign out events
3791     */
3792    this.handleAccountEvents = function () {
3793        AB.DATALAYER.handleRegistration();
3794        AB.DATALAYER.handleSignIn();
3795        AB.DATALAYER.handleSignOut();
3796        localStorage.setItem('previousPageStatus', AB.DATALAYER.checkAuthorization());
3797        localStorage.setItem('pageNameTrackForLogout', digitalData.pageDetails.pageName);
3798        localStorage.setItem('pageURLTrackForLogout', window.location.href);
3799    }
3800
3801    /**
3802     * Sets create account event
3803     */
3804    this.handleRegistration = function () {
3805        if (this.getLSItem('create-account-success') && !window.location.pathname.includes('error')) {
3806            this.isRegistrationSuccess = true;
3807            this.initEmailAndSmsOptIn();
3808            if (digitalData.user && Object.keys(digitalData.user).length > 0) {
3809                digitalData.user.accountType = `${this.getLSItem('create-account-success') === 'convert' ? 'converted' : 'new'}`;
3810            }
3811            this.pushEvent(
3812                this.EVENTS.CREATEACC, {
3813                page: digitalData?.pageDetails,
3814                user: digitalData?.user
3815            }
3816            );
3817        }
3818        if (this.getLSItem('create-account-success') === 'convert' && !window.location.pathname.includes('error')) {
3819            if (typeof (window.gtag) === 'function') {
3820                this.removeLSItem('create-account-success');
3821            } else {
3822                document.addEventListener('ga4LoadComplete', function () {
3823                    window.AB?.DATALAYER?.removeLSItem('create-account-success');
3824                }, false);
3825            }
3826        } else this.removeLSItem('create-account-success');
3827        if (this.isRegistrationSuccess) {
3828            this.setJourneyStatus(this.JourneyStatusCode.NO_ACTION);
3829        }
3830    };
3831
3832    /**
3833     * Sets the sign-in event
3834     */
3835    this.handleSignIn = function () {
3836        // the subscription status is only set on sign in
3837        if (!this.isRegistrationSuccess && AB.DATALAYER.checkAuthorization() && localStorage.getItem('previousPageStatus') === 'false') {
3838            AB.DATALAYER.pushEventSignIn();
3839        }
3840    };
3841
3842    /**
3843     * Sets the sign-in event name, the journey status
3844     */
3845    this.pushEventSignIn = function () {
3846        let otpPrefix = localStorage.getItem('otp_sign_in') || ''; // set on signInWithOTP
3847        if (otpPrefix) {
3848            otpPrefix = `otp-${otpPrefix}-`;
3849            localStorage.removeItem('otp_sign_in');
3850        }
3851
3852        this.setJourneyStatus(this.JourneyStatusCode.NO_ACTION);
3853        AB.DATALAYER.pushEvent(
3854            otpPrefix + AB.DATALAYER.EVENTS.SIGNIN, {
3855            user: digitalData.user,
3856            page: digitalData.pageDetails,
3857            pageFilter: digitalData.pageFilter
3858        }
3859        );
3860    };
3861
3862    /**
3863     * Sets the sign out event
3864     */
3865    this.handleSignOut = function () {
3866        this.setAnalyticsCrossPageData({ action: 'remove', name: 'acip371626Social' });
3867        let signOutDetails = {
3868            pageName: localStorage.getItem('pageNameTrackForLogout'),
3869            channel: digitalData.pageDetails.channel,
3870            banner: digitalData.pageDetails.banner,
3871            subSection1: digitalData.pageDetails.subSection1,
3872            subSection2: digitalData.pageDetails.subSection2,
3873            subSection3: digitalData.pageDetails.subSection3,
3874            subSection4: digitalData.pageDetails.subSection4,
3875            pageUrl: digitalData.pageDetails.pageUrl,
3876            platform: digitalData.pageDetails.platform,
3877            previousPageUrl: localStorage.getItem('pageURLTrackForLogout'),
3878            referringURL: this.getReferringUrl(),
3879            thirdParty: this.getThirdParty()
3880        }
3881        if (localStorage.getItem('pageNameTrackForLogout') === null) {
3882            signOutDetails.pageName = digitalData.pageDetails.pageName;
3883        }
3884        if (!this.isRegistrationSuccess && !AB.DATALAYER.checkAuthorization() && localStorage.getItem('previousPageStatus') === 'true') {
3885            if (localStorage.getItem('analyticsLogoutFlag') === undefined) {
3886                if (localStorage.getItem('analyticsSellerCartsInfo')) {
3887                    localStorage.removeItem('analyticsSellerCartsInfo');
3888                }
3889                if (localStorage.getItem('analyticsSellerIds')) {
3890                    localStorage.removeItem('analyticsSellerIds')
3891                }
3892                if (this.getLSItem('analyticsPromoBannerView')) {
3893                    this.removeLSItem('analyticsPromoBannerView');
3894                }
3895                AB.DATALAYER.pushEvent(
3896                    this.EVENTS.SIGN_OUT, {
3897                    user: digitalData.user,
3898                    page: signOutDetails
3899                }
3900                );
3901            }
3902        }
3903        if (localStorage.getItem('analyticsLogoutFlag')) {
3904            if (localStorage.getItem('analyticsSellerCartsInfo')) {
3905                localStorage.removeItem('analyticsSellerCartsInfo');
3906            }
3907            if (localStorage.getItem('analyticsSellerIds')) {
3908                localStorage.removeItem('analyticsSellerIds')
3909            }
3910            if (this.getLSItem('analyticsPromoBannerView')) {
3911                this.removeLSItem('analyticsPromoBannerView');
3912            }
3913            if (localStorage.getItem('analyticsLogoutFlag') === 'false') {
3914                AB.DATALAYER.pushEvent(
3915                    AB.DATALAYER.EVENTS.SIGN_OUT, {
3916                    user: digitalData.user,
3917                    page: signOutDetails
3918                }
3919                );
3920            } else {
3921                AB.DATALAYER.pushEvent(
3922                    AB.DATALAYER.EVENTS.SIGN_OUT_USER, {
3923                    user: digitalData.user,
3924                    page: signOutDetails
3925                }
3926                );
3927            }
3928            localStorage.removeItem('analyticsLogoutFlag');
3929        }
3930    };
3931
3932    /**
3933     * Checks the modal link URL parameter (ml) and the modal link cookie(SAFEWAY_MODAL_LINK)
3934     * (digitalData.event.push)
3935     * Kept the Jquery since the event listener can't listen to the shown.bs.modal bootstrap custom event
3936     */
3937    this.initModalViewEvents = function () {
3938        // multiaddress delivery unavailable modal
3939        if (jQuery && typeof jQuery !== 'undefined') {
3940            $('#address-not-deliverable-modal').on('shown.bs.modal', function () {
3941                AB.DATALAYER.setModalViewEvents('multiaddress-deliveryunavailable|view');
3942            });
3943
3944            // check if sign in modal is displayed
3945            $('#signInModal').on('shown.bs.modal', function () {
3946                AB.DATALAYER.setModalViewEvents('signIn Modal|view');
3947            });
3948
3949            // create account modal
3950            $('#unifiedRegistrationModal').on('shown.bs.modal', function () {
3951                AB.DATALAYER.setModalViewEvents('createAccount Modal|view');
3952            });
3953        }
3954
3955        // on-boarding widget
3956        const urlStateParameter = AB.DATALAYER.analyticsGetURLParameterByName('state');
3957        if (document.querySelectorAll('on-boarding-widget')?.length > 0) {
3958            if (urlStateParameter === 'results' || urlStateParameter === 'pre-results' || urlStateParameter === 'locator') {
3959                AB.DATALAYER.setModalViewEvents('fulfillment-landing|view');
3960            } else if (urlStateParameter === 'signin') {
3961                AB.DATALAYER.setModalViewEvents('signIn Modal|view');
3962            } else if (urlStateParameter === 'signup') {
3963                AB.DATALAYER.setModalViewEvents('createAccount Modal|view');
3964            }
3965        }
3966    };
3967
3968    /**
3969     * Sets modal click event from 'SAFEWAY_MODAL_LINK' cookie, url parameter 'ml' or 'analyticsModalAction' localStorage item
3970     */
3971    this.initModalClickEvents = function () {
3972        const modalLinkParameter = AB.DATALAYER.analyticsGetURLParameterByName('ml');
3973        const modalLinkCookie = decodeURI(AB.DATALAYER.getCookie(this.cookieNames.MODAL_LINK));
3974        if (localStorage.getItem('analyticsModalAction')) {
3975            const unavailableItems = this.handleGetLSValue('analyticsUnavailableCount');
3976            const modalAction = this.handleGetLSValue('analyticsModalAction');
3977            const modalMessage = this.handleGetLSValue('analyticsModalMessage');
3978            this.setModalClickEvents(modalAction, unavailableItems ? `Items Not Available${unavailableItems}` : modalMessage);
3979        } else if (modalLinkCookie) {
3980            const modalAction = modalLinkCookie.split(/(-u|-m)/)[0];
3981            const unavailableCount = modalLinkCookie.split(/(-u)/)[2];
3982            const modalMessage = modalLinkCookie.split(/(-m)/)[2];
3983            if (modalAction) {
3984                this.setModalClickEvents(modalAction, unavailableCount ? `Items Not Available${unavailableCount}` : modalMessage);
3985            }
3986        } else if (modalLinkParameter) {
3987            this.setModalClickEvents(decodeURIComponent(modalLinkParameter));
3988        }
3989        if (window.SWY?.CONFIGSERVICE) {
3990            SWY.CONFIGSERVICE.setDomainCookie(this.cookieNames.MODAL_LINK, '', SWY.CONFIGSERVICE.resolvedBanner + '.com', 0);
3991        }
3992    }
3993
3994    /**
3995     * Sets fulfillment modal view event
3996     */
3997    this.setFulfillmentModalView = function () {
3998        if (digitalData?.user?.userType !== 'R') {
3999            digitalData.pageFilter.topNav = AB.DATALAYER.initTopNav();
4000        }
4001        if (localStorage.getItem('analyticsTwoTabsModal') === 'true') {
4002            AB.DATALAYER.pushEvent(
4003                this.EVENTS.MODAL_VIEW,
4004                {
4005                    modal: {
4006                        modalAction: 'fulfillment-shop|view'
4007                    },
4008                    page: digitalData?.pageDetails,
4009                    pageFilter: digitalData?.pageFilter
4010                }
4011            );
4012            localStorage.removeItem('analyticsTwoTabsModal');
4013        } else {
4014            AB.DATALAYER.pushEvent(
4015                this.EVENTS.MODAL_VIEW,
4016                {
4017                    modal: {
4018                        modalAction: 'fulfillment-global|view'
4019                    },
4020                    page: digitalData?.pageDetails,
4021                    pageFilter: digitalData?.pageFilter
4022                }
4023            );
4024        }
4025        digitalData.pageFilter.topNav = '';
4026    }
4027
4028    /**
4029     * Sets link click events for forgot password flow
4030     */
4031    this.initForgotPasswordReset = function () {
4032        // create account on forgot password page
4033        if (localStorage.getItem('create_account_clicked') === 'true') {
4034            this.setLinkClickEvents('createAccount');
4035            localStorage.removeItem('create_account_clicked');
4036        }
4037        // forgot password email sent event
4038        if (localStorage.getItem('analyticsPwdEmail') === 'true') {
4039            this.setLinkClickEvents('passwordEmailSent');
4040            localStorage.removeItem('analyticsPwdEmail');
4041        }
4042        // reset password success event
4043        if (localStorage.getItem('pwdResetAnalytics')) {
4044            // new forgot password flow for email and phone number
4045            this.setLinkClickEvents(localStorage.getItem('pwdResetAnalytics'));
4046            localStorage.removeItem('pwdResetAnalytics');
4047            localStorage.removeItem('analyticsPwdResetSuccess');
4048        } else if (localStorage.getItem('analyticsPwdResetSuccess') === 'true') {
4049            this.setLinkClickEvents('passwordResetSuccess');
4050            localStorage.removeItem('analyticsPwdResetSuccess');
4051        }
4052    }
4053
4054    /**
4055     * Sets the reward Id and the number of rewards used to redeem the specific reward Id
4056     * @param reward 
4057     */
4058    this.clipReward = function (reward) {
4059        if (digitalData) {
4060            digitalData.rewards = {
4061                rewardsID: `${reward.groceryRewardId}|${reward.title}`,
4062                rewardsRedeemed: reward.rewardsRequired?.toString(),
4063                multipleRewardsRedeemed: reward?.clipDetails?.clippedCount || reward?.clipDetails?.clippedCount === 0 ? (Number(reward.clipDetails.clippedCount) + 1).toString() : ''
4064            }
4065            this.pushEvent(
4066                this.EVENTS.REWARDS, {
4067                rewards: digitalData.rewards,
4068                page: digitalData?.pageDetails,
4069                pageFilter: digitalData?.pageFilter
4070            }
4071            );
4072        }
4073    }
4074
4075    /**
4076     * Sets the reward Id and title for the unclipped reward
4077     * @param reward 
4078     */
4079    this.unclipReward = function (reward) {
4080        if (digitalData) {
4081            digitalData.rewards = {
4082                rewardsID: `${reward.groceryRewardId}|${reward.title}`
4083            }
4084            this.pushEvent(
4085                this.EVENTS.REWARD_UNCLIPPED, {
4086                rewards: digitalData.rewards,
4087                page: digitalData?.pageDetails,
4088                pageFilter: digitalData?.pageFilter
4089            }
4090            );
4091        }
4092    }
4093
4094    /**
4095     * sets modal view event for substitution drawer
4096     * @param substitutionProducts 
4097     * @param substitutionPreference 
4098     */
4099    this.setSubstitutionModalView = function (substitutionProducts, substitutionPreference, item, isAutoClipEnabled) {
4100        if (typeof item !== 'object' || item === null) {
4101            return;
4102        }
4103
4104        let productID = item?.itemId || '';
4105        let substitutionData = [];
4106        let modalAction = this.isCartAndCheckoutPage('cart') ? 'sub-pref' : 'substitution';
4107        let modalMessage = '';
4108
4109        if (substitutionProducts?.length > 0 && item?.substitutionPreference !== 'Do Not Sub') {
4110            substitutionProducts.forEach((product, index) => {
4111                const offersCount = isAutoClipEnabled && product.offers?.filter(offer => offer.isDisplayable)?.length || 0;
4112                substitutionData.push({
4113                    isSubstitution: product.Subflag ? 'true' : 'false',
4114                    productID: productID,
4115                    substitutionOption: `${product.algoType === 'selected' ? 'past-choice' : 'substitute'}:${product?.id}`,
4116                    searchTerm: '',
4117                    searchResults: '',
4118                    rowSlot: `r${index + 1 > 9 ? index + 1 : '0' + (index + 1)}#s01`,
4119                    isCouponAvailable: offersCount > 0 ? true : false,
4120                    couponsCount: offersCount,
4121                });
4122            });
4123            if (item?.substituteItems?.length) {
4124                modalAction = `edit-substitution${item.substituteItems[0].algoType === 'selected' ? '-past-choice' : ''}`;
4125            }
4126        } else if (item?.substitutionPreference === 'Do Not Sub') {
4127            substitutionData.push({
4128                productID: productID,
4129                substitutionOption: 'dont-substitute',
4130            });
4131            modalAction = 'dont-substitute';
4132            modalMessage = 'substitution-dont-substitute';
4133        } else {
4134            modalMessage = 'substitution-not-available';
4135        }
4136        window['AB']['DATALAYER'].setAnalyticsCrossPageData({ action: 'set', name: 'analyticsFeatureTracking', data: 'subsUpdateACIP468396' });
4137        AB.DATALAYER.pushEvent(
4138            this.EVENTS.MODAL_VIEW,
4139            {
4140                modal: {
4141                    modalAction: `${modalAction}|view`,
4142                    modalMessage: modalMessage ? modalMessage : ''
4143                },
4144                productInfo: {
4145                    productID: productID,
4146                    substitution: substitutionData
4147                },
4148                page: digitalData?.pageDetails,
4149                pageFilter: digitalData?.pageFilter
4150            }
4151        );
4152        digitalData.modal = {};
4153        digitalData.productInfo = {};
4154    }
4155
4156    /**
4157     * Sets modal click events for substitution drawer
4158     * @param modalAction 
4159     * @param substitutionObj 
4160     * @param modalMessage 
4161     */
4162    this.setModalClickEventsSubstitution = function (modalAction, substitutionObj, substitutionProducts, item) {
4163        if (typeof item !== 'object' || item === null) {
4164            return;
4165        }
4166
4167        const productID = item.itemId || '';
4168        const searchTerm = modalAction === 'search' ? substitutionObj?.searchTerm : '';
4169        const searchResults = modalAction === 'search' ? substitutionObj?.searchResults : '';
4170        let substitutionData = [];
4171        let modalMessage = '';
4172
4173        let modalName = item?.substituteItems?.length > 0
4174            ? `edit-substitution${item.substituteItems[0].algoType === 'selected' ? '-past-choice' : ''}`
4175            : item?.substitutionPreference === 'Do Not Sub' || item?.substitutionPreferenceV2 === 'Do Not Substitute'
4176                ? 'dont-substitute' : 'substitution';
4177
4178        if (modalAction === 'substitute' && substitutionObj) {
4179            const lastTwoEvents = appEventData?.slice(-2);
4180            if (lastTwoEvents?.some(event => event?.event === 'modalClick' && event?.modal?.modalAction?.includes('|search'))) {
4181                modalAction = 'search-substitute';
4182                modalMessage = `substitution-search-substitute-${substitutionObj.rowSlot}`;
4183            } else {
4184                modalMessage = `substitution-substitute-${substitutionObj.rowSlot}`;
4185            }
4186        } else if (modalAction === 'search') {
4187            modalAction = searchTerm ? modalAction : `not-available-search`;
4188            modalMessage = searchTerm ? `substitution-search-${searchTerm}` : `substitution-search-not-available-${searchTerm}`;
4189        }
4190
4191
4192        if (substitutionProducts === null && modalAction === 'dont-substitute') {
4193            if (this.isCartAndCheckoutPage('cart')) {
4194                modalName = 'sub-pref';
4195                modalAction = 'dont-substitute:save-substitution';
4196            }
4197            substitutionData.push({
4198                productID: productID,
4199                substitutionOption: 'dont-substitute',
4200            });
4201        } else if (substitutionProducts) {
4202            const substitutionProductsArray = Array.isArray(substitutionProducts) ? substitutionProducts : [substitutionProducts];
4203            if (substitutionProductsArray?.length > 0) {
4204                substitutionData = substitutionProductsArray.map((product, index) => {
4205                    const offersCount = substitutionObj?.isAutoClipEnabled && product.offers?.filter(offer => offer.isDisplayable)?.length || 0;
4206                    return {
4207                        isSubstitution: product.Subflag ? 'true' : 'false',
4208                        productID: productID,
4209                        substitutionOption: `${product.algoType === 'selected' ? 'past-choice' : modalAction === 'search-substitute' ? 'search-substitute' : 'substitute'}:${product?.id}`,
4210                        searchTerm: searchTerm,
4211                        searchResults: searchResults,
4212                        rowSlot: `r${index + 1 > 9 ? index + 1 : '0' + (index + 1)}#s01`,
4213                        isCouponAvailable: offersCount > 0 ? true : false,
4214                        couponsCount: offersCount
4215                    }
4216                });
4217            }
4218        }
4219
4220        if (modalAction === 'substitute-with-next-best-match:save-substitution' && this.isCartAndCheckoutPage('cart')) {
4221            modalName = 'sub-pref';
4222            substitutionData.push({
4223                productID: productID,
4224                substitutionOption: 'next-best-match',
4225            });
4226        }
4227
4228        AB.DATALAYER.pushEvent(
4229            this.EVENTS.MODAL_CLICK,
4230            {
4231                modal: {
4232                    modalAction: `${modalName}|${modalAction}`,
4233                    modalMessage: modalMessage || ''
4234                },
4235                productInfo: {
4236                    substitution: substitutionData
4237                },
4238                page: digitalData?.pageDetails,
4239                pageFilter: digitalData?.pageFilter
4240            }
4241        );
4242        digitalData.modal = {};
4243        digitalData.productInfo = {};
4244    }
4245
4246    this.setModalClickSubstitutionAllItems = function (modalAction, substitutionObj) {
4247        const allCartItems = substitutionObj.cartItems;
4248        const cartItemsSubs = [];
4249        allCartItems.forEach(cartItem => {
4250            const substitutions = cartItem.substituteData;
4251            const substitutionData = substitutions && Array.isArray(substitutions) && substitutions.length > 0 ? substitutions.map((product) => {
4252                return {
4253                    isSubstitution: product.Subflag ? 'true' : 'false',
4254                    productID: cartItem.id,
4255                    substitutionOption: cartItem.substitutionPreferenceV2 == 'Do Not Substitute' ? 'dont-substitute' : cartItem.substitutionPreferenceV2 == 'Best Available' ? 'next-best-match' : `${product.algoType === 'selected' ? 'past-choice' : 'substitute'}:${product?.id}`,
4256                }
4257            })[0] : {
4258                productID: cartItem.id,
4259                substitutionOption: cartItem.substitutionPreferenceV2 == 'Do Not Substitute' ? 'dont-substitute' : cartItem.substitutionPreferenceV2 == 'Best Available' ? 'next-best-match' : ''
4260            };
4261            cartItemsSubs.push(substitutionData);
4262        });
4263        const payload = {
4264            modal: {
4265                modalAction: `sub-pref|${modalAction}`
4266            },
4267            productInfo: {
4268                substitution: cartItemsSubs
4269            },
4270            page: digitalData?.pageDetails,
4271            pageFilter: digitalData?.pageFilter
4272        };
4273        AB.DATALAYER.pushEvent(this.EVENTS.MODAL_CLICK, payload);
4274        digitalData.modal = {};
4275        digitalData.productInfo = {};
4276    }
4277
4278    /**
4279     * Sets modal click events for Schedule & Save (AR)
4280     * @param modalAction 
4281     * @param autoReplenishmentObj 
4282     */
4283    this.setModalClickEventsAR = function (modalAction, autoReplenishmentObj) {
4284        AB.DATALAYER.pushEvent(
4285            this.EVENTS.MODAL_CLICK,
4286            {
4287                modal: {
4288                    modalAction: modalAction
4289                },
4290                page: digitalData?.pageDetails,
4291                pageFilter: digitalData?.pageFilter,
4292                autoReplenishment: autoReplenishmentObj || undefined
4293            }
4294        );
4295    }
4296
4297    /**
4298     * Sends BR widget obj for pixel
4299     * @param widgetObj 
4300     */
4301    this.pathwayWidgetView = function (widgetObj) {
4302        AB.DATALAYER.pushEvent(
4303            this.EVENTS.PATHWAY_WIDGET_VIEW,
4304            {
4305                productInfo: {
4306                    pathwaysWidget: widgetObj
4307                },
4308                page: digitalData?.pageDetails,
4309                pageFilter: digitalData?.pageFilter
4310            }
4311        );
4312    }
4313
4314    /**
4315     * Banner clicks tracking - WeeklyAd page
4316     */
4317    this.bannerClickWeeklyAd = function (adTitle, adPosition) {
4318        if (adTitle && adPosition) {
4319            // placement
4320            let bannerPlacement = '';
4321            if (adPosition === 'weeklyadtop') {
4322                bannerPlacement = 'R01';
4323            } else if (adPosition === 'weeklyadbottom') {
4324                bannerPlacement = 'R02';
4325            }
4326            // link name
4327            const currentBannerTitle = 'bannerClicked|' + adTitle.replace(/\s/g, '');
4328
4329            window.digitalData.pageFilter = window.digitalData.pageFilter || {};
4330
4331            window.digitalData.pageFilter.placement = bannerPlacement;
4332            window.digitalData.pageFilter.recommendationType = 'sponsored';
4333            window.digitalData.pageFilter.mediaType = 'banner';
4334            window.digitalData.link = {
4335                linkName: currentBannerTitle
4336            };
4337
4338            AB.DATALAYER.pushEvent(
4339                this.EVENTS.LINK_CLICK,
4340                {
4341                    link: digitalData.link,
4342                    page: digitalData?.pageDetails,
4343                    pageFilter: digitalData?.pageFilter
4344                }
4345            );
4346        }
4347    }
4348
4349    /**
4350     * Sets the link click event for the reviews tab
4351     */
4352    this.setReviewsTabLinkClick = function () {
4353        if (window.analyticsReviewLinkClickFlag !== true) {
4354            const productID = sessionStorage.getItem('analyticsProductIdPDP') || '';
4355            AB.DATALAYER.setLinkClickCustomerReviews('pdp-page-reviews|reviews-tab', productID);
4356        }
4357    };
4358
4359    /**
4360     * Sets the link click events for customer reviews on PDP
4361     * @param linkClicked 
4362     * @param productID
4363     */
4364    this.setLinkClickCustomerReviews = function (linkClicked, productID) {
4365        AB.DATALAYER.pushEvent(
4366            this.EVENTS.LINK_CLICK,
4367            {
4368                link: {
4369                    linkName: linkClicked
4370                },
4371                productInfo: {
4372                    productID: productID,
4373                    isProductTrackingDisabled: digitalData.pageFlags?.isProductTrackingDisabled
4374                },
4375                page: digitalData?.pageDetails,
4376                pageFilter: digitalData?.pageFilter
4377            }
4378        );
4379    }
4380
4381    /**
4382     * Sets the modal click events for customer reviews
4383     * @param modalAction 
4384     * @param isPDP 
4385     */
4386    this.setModalClickCustomerReviews = function (modalAction, isPDP) {
4387        if (isPDP) {
4388            const productID = sessionStorage.getItem('analyticsProductIdPDP') || '';
4389            AB.DATALAYER.pushEvent(
4390                this.EVENTS.MODAL_CLICK,
4391                {
4392                    modal: {
4393                        modalAction: modalAction
4394                    },
4395                    productInfo: {
4396                        productID: productID,
4397                        isProductTrackingDisabled: digitalData?.pageFlags?.isProductTrackingDisabled
4398                    },
4399                    page: digitalData?.pageDetails,
4400                    pageFilter: digitalData?.pageFilter
4401                }
4402            );
4403            if (window.digitalData && window.digitalData.modal) {
4404                window.digitalData.modal.modalAction = modalAction;
4405            }
4406        } else {
4407            AB.DATALAYER.setModalClickEvents(modalAction);
4408        }
4409    }
4410
4411    /**
4412     * Sets the modal view event for customer reviews modal on PDP
4413     * @param modalAction 
4414     * @param productID 
4415     */
4416    this.setModalViewCustomerReviews = function (modalAction, productID) {
4417        if (window.digitalData && window.digitalData.modal) {
4418            window.digitalData.modal.modalAction = modalAction;
4419        }
4420        AB.DATALAYER.pushEvent(
4421            this.EVENTS.MODAL_VIEW,
4422            {
4423                modal: {
4424                    modalAction: modalAction,
4425                },
4426                productInfo: {
4427                    productID: productID
4428                },
4429                page: digitalData?.pageDetails,
4430                pageFilter: digitalData?.pageFilter
4431            }
4432        );
4433    }
4434
4435    /**
4436    * Sets the link click event for cancel order confirmation
4437    * @param linkClicked 
4438    * @param orderId
4439    */
4440    this.setLinkClickCancelOrder = function (linkClicked, order) {
4441        const orderId = order?.orderID || '';
4442        const revenueCancelled = order?.orderTotal || '';
4443        const isMarketplaceOrder = order?.isMarketPlace;
4444        const isWineShop = order?.isWine;
4445        const isB2b = order?.isB2B;
4446
4447        AB.DATALAYER.pushEvent(
4448            this.EVENTS.LINK_CLICK,
4449            {
4450                link: {
4451                    linkName: linkClicked
4452                },
4453                transaction: {
4454                    orderID: isMarketplaceOrder || isB2b ? orderId : isWineShop ? `wine-shop:${orderId}` : '',
4455                    revenueCancelled: revenueCancelled
4456                },
4457                page: digitalData?.pageDetails,
4458                pageFilter: digitalData?.pageFilter
4459            }
4460        );
4461    }
4462
4463    this.setModalViewEventsSnsSubs = function (data) {
4464        if (data) {
4465            const substitutionOption = data.subData?.substitutionValue
4466                ? data.subData.substitutionValue.toLowerCase() === 'best available' ? 'best-available' : `substitute:${data.subData?.substituteItem?.[0]?.itemBpn}`
4467                : 'dont-substitute';
4468            AB.DATALAYER.pushEvent(
4469                this.EVENTS.MODAL_VIEW,
4470                {
4471                    modal: {
4472                        modalAction: `${data.showSetSubstitution ? 'substitution' : 'edit-substitution'}|view`,
4473                        modalMessage: substitutionOption === 'dont-substitute' ? 'substitution-dont-substitute' : ''
4474                    },
4475                    productInfo: {
4476                        substitution: {
4477                            isSubstitution: substitutionOption === 'dont-substitute' ? 'false' : 'true',
4478                            productID: data.productID || '',
4479                            substitutionOption: substitutionOption
4480                        }
4481                    },
4482                    page: digitalData?.pageDetails,
4483                    pageFilter: digitalData?.pageFilter
4484                }
4485            );
4486        }
4487    }
4488
4489    this.setModalClickEventsSnsSubs = function (action, data) {
4490        if (data) {
4491            let modalMessage = '';
4492            let substitutionObj = {
4493                productID: data.productID || '',
4494                isSubstitution: action === 'dont-substitute' ? 'false' : data.subData?.substituteItem?.length > 0 ? 'true' : 'false',
4495                substitutionOption: action === 'dont-substitute' ? 'dont-substitute' : action === 'substitute' ? `substitute:${data.selectedProduct?.itemBpn}` : ''
4496            };
4497            if (action === 'search') {
4498                modalMessage = data.subData?.substituteItem ? `substitution-search-${data.searchTerm}` : `substitution-search-not-available-${data.searchTerm}`;
4499                substitutionObj.searchResults = data.subData?.substituteItem?.length || '0';
4500                substitutionObj.searchTerm = data.searchTerm;
4501                if (!data.subData?.substituteItem) {
4502                    action = 'not-available-search';
4503                }
4504            } else if (action === 'substitute') {
4505                const index = data.subData?.substituteItem?.findIndex(item => item.itemBpn === data.selectedProduct?.itemBpn) + 1;
4506                substitutionObj.rowSlot = index ? `R0${index}#S01` : '';
4507                modalMessage = `substitution-substitute-${substitutionObj.rowSlot}`;
4508            }
4509
4510            AB.DATALAYER.pushEvent(
4511                this.EVENTS.MODAL_CLICK,
4512                {
4513                    modal: {
4514                        modalAction: `${data?.showSetSubstitution ? 'substitution' : 'edit-substitution'}|${action}`,
4515                        modalMessage: modalMessage
4516                    },
4517                    productInfo: {
4518                        substitution: substitutionObj
4519                    },
4520                    page: digitalData?.pageDetails,
4521                    pageFilter: digitalData?.pageFilter
4522                }
4523            );
4524        }
4525    }
4526
4527    this.casReviewSubsModalEvents = function (item, status) {
4528        if (item && item.bpnNum) {
4529            const currentSubCard = document.querySelector(`a[data-bpn="${item.bpnNum}"]`)?.closest('.sub-card');
4530            const currentSubItem = document.querySelector(`a[data-bpn="${item.bpnNum}"]`)?.closest('.sub-item-container');
4531            const isSubPref = item?.replacements?.some(item => !!item.saveAsFutureSubPreference) || false;
4532            let modalMessage = '';
4533            if (currentSubCard && currentSubItem) {
4534                const itemIndex = Array.from(currentSubCard.querySelectorAll('.sub-item-container'))?.indexOf(currentSubItem) + 1;
4535                modalMessage = `substitution-substitute-${itemIndex < 10 ? `0${itemIndex}` : itemIndex}#01`;
4536            }
4537            let substitutionObj = {
4538                productID: item.bpnNum,
4539                substitutionOption: item.replacements ? `substitute:${item.replacements.map(item => item.itemId)?.join(':')}` : ''
4540            };
4541            if (isSubPref) {
4542                this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsFeatureTracking', data: 'casSubPrefACIP409006' });
4543            }
4544            AB.DATALAYER.pushEvent(
4545                this.EVENTS.MODAL_CLICK,
4546                {
4547                    modal: {
4548                        modalAction: `cas-review-substitutions${isSubPref ? '-pref-sub-tag' : ''}|${status === 'APPROVED' ? 'approve' : 'decline'}`,
4549                        modalMessage: modalMessage
4550                    },
4551                    productInfo: {
4552                        substitution: substitutionObj
4553                    },
4554                    page: digitalData?.pageDetails,
4555                    pageFilter: digitalData?.pageFilter
4556                }
4557            );
4558        }
4559    }
4560
4561}).call(AB.DATALAYER);
4562
4563'use strict';
4564
4565(function () {
4566    /**
4567     * Updates mapping for product info
4568     * @param infoObj 
4569     * @param cart 
4570     * @returns 
4571     */
4572    this.getProductInfo = function (infoObj, cart) {
4573        const units = infoObj.units || infoObj.qty || infoObj.quantity;
4574        const carouselSec = infoObj.carouselSection && ((infoObj.carouselSection?.toLowerCase()?.indexOf('picks for you') !== -1) || (infoObj.carouselSection?.toLowerCase()?.indexOf('picked for you') !== -1)) ? infoObj.carouselSection.trim().toLowerCase().split(' ').join('-').replace(/[^\w-,|#:]/gi, '').replace('--', '-') : infoObj.carouselSection;
4575
4576        let productInfo = {
4577            productID: infoObj.id || infoObj.itemId?.toString(),
4578            productName: infoObj.name,
4579            impressionAdditionalDetail: infoObj.adobeMetricA ? infoObj.adobeMetricA : this.isBundlesLP() ? digitalData.pageDetails?.abTestDetails : '',
4580            channel: infoObj.channel ? infoObj.channel : {},
4581            fullName: infoObj.fullName,
4582            units: units,
4583            unitType: infoObj.unitType ? infoObj.unitType : infoObj.unitQuantity ? infoObj.unitQuantity : '',
4584            lbs: this.isCartAndCheckoutPage() ? infoObj.unitQuantity == 'LB' ? infoObj.selectedWeight : '0' : infoObj.lbs && infoObj.lbs !== '0' ? infoObj.lbs : '',
4585            each: this.isCartAndCheckoutPage() ? (infoObj.unitQuantity == 'EACH' ? units : '0') : (infoObj.unitType == 'EACH' ? infoObj.each : '0'),
4586            pricePerUnit: infoObj.pricePerUnit ? infoObj.pricePerUnit.toString() : infoObj.unitPrice ? infoObj.unitPrice.toString() : '',
4587            listPrice: this.isCartAndCheckoutPage() ? infoObj.price : infoObj.listPrice ? infoObj.listPrice : infoObj.basePrice?.toString(),
4588            totalPrice: infoObj.totalPrice ? infoObj.totalPrice.toString() : infoObj.basePrice && units ? (infoObj.basePrice * (units || 1))?.toString() : '0',
4589            carouselSection: carouselSec ? AB.DATALAYER.sanitizeAnalyticsText(carouselSec) : '',
4590            carouselSectionUncurated: infoObj.carouselSection,
4591            pathwaysWidget: infoObj.pathwaysWidget || '',
4592            basePrice: infoObj.basePrice,
4593            pricingType: infoObj.pricingType || infoObj.promoDescription || 'not available',
4594            couponFlag: infoObj.couponFlag || 'not available',
4595            couponClipped: infoObj.couponClipped || 'not available',
4596            couponID: infoObj.couponID || 'not available',
4597            aisleId: infoObj.aisleId,
4598            upc: infoObj.upc,
4599            pfmDetail: !this.isCartAndCheckoutPage() ? (infoObj.pfmDetail || digitalData.pageDetails.pfmDetail) : '',
4600            crossSellTitle: infoObj.crossSellTitle,
4601            isCrossSell: infoObj.isCrossSell,
4602            isFound: infoObj.isFound,
4603            mto: (!!infoObj.isMTO).toString(),
4604            departmentName: infoObj.departmentName || '',
4605            aisleName: infoObj.aisleName || '',
4606            shelfName: infoObj.shelfName || '',
4607            sellerId: this.isCartAndCheckoutPage() ? (cart?.seller?.sellerId ? cart?.seller.sellerId : cart?.cartCategory === '1P_WINE' ? '22222222' : '11111111') : (infoObj.sellerId || ''),
4608            sellerName: infoObj.sellerName || '',
4609            editOrderFlow: infoObj.editOrderFlow ? infoObj.editOrderFlow : this.isEditOrderMode() ? this.isEditOrderMode() : this.isCartAndCheckoutPage('edit/cart') ? this.isCartAndCheckoutPage('edit/cart') : false,
4610            isUndoClick: infoObj.isUndoClick || false,
4611            isBIACarousalProduct: infoObj.isBIACarousalProduct,
4612            snapEligible: !this.isCartAndCheckoutPage() ? infoObj.snapEligible === true ? 'true' : 'false' : '',
4613            isProductTrackingDisabled: !!infoObj.isProductTrackingDisabled,
4614            inventory: infoObj.isAvailable ? 'available' : 'not-available',
4615            placement: infoObj.placement,
4616            isP13nGrid: infoObj.isP13nGrid,
4617            scheduleandSaveSource: infoObj.scheduleandSaveSource,
4618            previousPrice: infoObj.previousPrice,
4619            isPriceDecreased: infoObj.isPriceDecreased,
4620            badges: infoObj.badges,
4621            isPreOrderItem: infoObj.isPreOrderItem,
4622            mealsPfmSource: infoObj.mealsPfmSource ? `${this.isMealsPlansPage() ? 'meals_' : ''}${infoObj.mealsPfmSource}` : undefined,
4623            isCustomCake: infoObj.isCustomCake,
4624            isOrderAmendsFlow: infoObj.isOrderAmendsFlow || false,
4625            containsAlcohol: infoObj.containsAlcohol,
4626            featured: infoObj.featured
4627        };
4628        return productInfo;
4629    }
4630
4631    /**
4632     * Sets the product information
4633     * @param infoObj
4634     */
4635    this.productInfo = function (infoObj, calledBy, cart) {
4636        if (digitalData && infoObj && Object.keys(infoObj).length > 0) {
4637            digitalData.productInfo = AB.DATALAYER.getProductInfo(infoObj, cart);
4638            digitalData.pageFilter.pfmSource = digitalData.pageFilter.pfmSource || infoObj.adobeMetricC;
4639            if (calledBy === 'product-detail') {
4640                digitalData.pageFlags = digitalData.pageFlags || {};
4641                digitalData.pageFlags.isProductTrackingDisabled = !!digitalData?.productInfo?.isProductTrackingDisabled;
4642                AB.DATALAYER._bentoPdpPfmMirror = '';
4643            }
4644
4645            if (this.isDFTAPage()) {
4646                if (infoObj.previousQty !== undefined) {
4647                    digitalData.productInfo.previousQty = infoObj.previousQty;
4648                } else {
4649                    this.setPreviousQuantityDFTA(digitalData.productInfo.productID);
4650                }
4651            }
4652            if (this.isCartAndCheckoutPage()) {
4653                digitalData.cart.cartInfo.currentCartId = cart?.cartId?.toString() || '';
4654                if (infoObj.isArProduct && infoObj.snsSub && infoObj.snsSub.isSnsSub) {
4655                    const snsFrequency = infoObj?.snsSub?.snsFrequency?.unit?.toLowerCase().replace(/\s/g, '-');
4656                    digitalData.productInfo.scheduleandSaveSource = `full-cart#subscribe#every-${snsFrequency}`;
4657                } else {
4658                    digitalData.productInfo.scheduleandSaveSource = '';
4659                }
4660                if (cart?.isWYSIWYGEnabled) {
4661                    digitalData.productInfo = { ...digitalData.productInfo, ...AB.DATALAYER.setCartItemsWYSIWYG(infoObj, digitalData.productInfo?.sellerId, digitalData.cart?.cartInfo?.currentCartId) };
4662                } else {
4663                    digitalData.productInfo = { ...digitalData.productInfo, ...AB.DATALAYER.setCartItemsNonWYSIWYG(infoObj, digitalData.productInfo?.sellerId, digitalData.cart?.cartInfo?.currentCartId) };
4664                }
4665            }
4666        }
4667    };
4668
4669    // To remove after 8.1 release [CLEANUP]
4670    this.setProductInfoSavingsCnc = function (item) {
4671        if (item.savings) {
4672            let couponsClipped = 0, couponsApplied = 0, totalItemSavings = 0;
4673            let itemSavings = item.savings || [];
4674            let savings = AB.DATALAYER.calculateCartSavings(itemSavings, 'item');
4675            let ccSavings = item.clubCardSaving && !isNaN(parseFloat(item.clubCardSaving)) ? parseFloat(item.clubCardSaving) : 0;
4676            let totalCCSavings = savings.clubcardSavings + ccSavings;
4677            let totalItemSavingsWithCC = savings.total + ccSavings;
4678
4679            digitalData.productInfo.j4uItemSavings = savings.j4uSavings;
4680            digitalData.productInfo.rewardsItemSavings = savings.rewardsSavings;
4681            digitalData.productInfo.employeeItemSavings = savings.employeeSavings;
4682            digitalData.productInfo.promocodeItemSavings = savings.promoCodeSavings;
4683            digitalData.productInfo.clubcardItemSavings = totalCCSavings;
4684            totalItemSavings = totalItemSavingsWithCC;
4685
4686            let offerTypeArray = [];
4687            let offerTextArray = [];
4688            if (itemSavings.length > 0) {
4689                itemSavings.forEach(offer => {
4690                    let externalOfferId = offer.externalOfferId || '';
4691                    let isNDOffer = externalOfferId.indexOf('-ND') !== -1;
4692                    if (offer.categoryName) {
4693                        offerTypeArray.push(`${isNDOffer ? 'ND:' : ''}${offer.categoryName}`);
4694                    }
4695                    if (offer.displayOfferTxt) {
4696                        offerTextArray.push(`${isNDOffer ? 'ND:' : ''}${offer.displayOfferTxt}`);
4697                    } else if (offer.linkPluNumber && offer.source === 'CMS') {
4698                        offerTextArray.push(`${isNDOffer ? 'ND:' : ''}Buy 1 Get 1 Free`);
4699                    } else if (offer.discountMessage) {
4700                        offerTextArray.push(`${isNDOffer ? 'ND:' : ''}${offer.discountMessage}`);
4701                    }
4702                });
4703            }
4704
4705            if (item.clipped) {
4706                item.clipped.forEach(e => { couponsClipped++; });
4707            }
4708            digitalData.productInfo.offerText = offerTextArray.join('#');
4709            digitalData.productInfo.offerType = offerTypeArray.join('#');
4710            digitalData.productInfo.totalItemSavings = totalItemSavings;
4711
4712            digitalData.productInfo.itemPrice = this.cleanPrice(((item.basePrice * item.deltaQty) - totalItemSavings) / item.deltaQty);
4713            digitalData.productInfo.totalPrice = this.cleanPrice((item.basePrice * item.deltaQty) - totalItemSavings);
4714
4715            digitalData.productInfo.couponFlag = '';
4716            digitalData.productInfo.couponClipped = couponsClipped;
4717            digitalData.productInfo.couponApplied = couponsApplied;
4718
4719            digitalData.productInfo = this.toStringAll(digitalData.productInfo);
4720        }
4721    }
4722
4723    /**
4724     * sets the pfm detail
4725     * (product finding method)
4726     * the templates for pfmDetail are:
4727     * subSection1:subSection2:subSection3:subSection4
4728     * subSection1:subSection2:subSection3:subSection4:carouselSection
4729     * subSection1:search-term
4730     * subSection1:search-term:filterSelection
4731     * @param pfmDetail
4732     */
4733    this.setPfmDetail = function (pfmDetail) {
4734        if (digitalData && digitalData.productInfo) {
4735            digitalData.productInfo.pfmDetail = pfmDetail;
4736        }
4737    };
4738
4739    /**
4740    * Sets localStorage items pfmDetail and pfmDetailSearch to be used on PDP init
4741    */
4742    this.setLsPfmDetailOnInit = function () {
4743        if (this.isSearchResultsPage()) {
4744            this.setLSItem('pfmDetail', 'search-results');
4745            const urlParams = AB.DATALAYER.analyticsGetURLParameterByName('q');
4746            if (urlParams) {
4747                this.setLSItem('pfmDetailSearch', urlParams);
4748            }
4749        } else {
4750            localStorage.setItem('pfmDetail', this.pathSections.join(':'));
4751            this.removeLSItem('pfmDetailSearch');
4752        }
4753    }
4754
4755    // Set product placement in grid and cross-sell placement
4756    this.setProductGridPosition = function ({ productId, eventName, nativeElement } = {}) {
4757        if (digitalData) {
4758            let placement = '';
4759            if (document.getElementById('miniCart')?.style.visibility !== 'visible') {
4760                let productPosition = '';
4761                const currentProductId = productId ? productId : digitalData.productInfo.productID;
4762                const isCrossSell = digitalData.productInfo.isCrossSell;
4763
4764                // recipes detail page
4765                if (AB.DATALAYER.isRecipesPage()) {
4766                    const currentProductRecipe = document.querySelector(`.recipe-details-card #pg${currentProductId}`)?.closest('.recipe-card-pad');
4767                    const currentGrid = currentProductRecipe?.closest('meals-product-grid');
4768                    const allProducts = Array.from(currentGrid?.querySelectorAll('.recipe-card-pad'));
4769                    const productPosition = allProducts ? allProducts.indexOf(currentProductRecipe) + 1 : 0;
4770
4771                    // main products
4772                    const mainProducts = Array.from(document.querySelectorAll('.main-products .recipe-card-pad'));
4773                    const mainProductPosition = mainProducts ? mainProducts.indexOf(currentProductRecipe) + 1 : 0;
4774                    const mainProductsCount = mainProducts?.length;
4775
4776                    // pantry products
4777                    const pantryProducts = Array.from(document.querySelectorAll('.pantry-products .recipe-card-pad'));
4778                    const pantryProductPosition = pantryProducts ? pantryProducts.indexOf(currentProductRecipe) + 1 : 0;
4779
4780                    // set pageFilter.mediaType
4781                    if (digitalData.pageFilter) {
4782                        digitalData.pageFilter.mediaType = 'product-grid';
4783                    }
4784
4785                    // determine product row
4786                    let productRow = 0;
4787                    if (window.innerWidth >= 992) {
4788                        // 4 products/row
4789                        if (mainProductPosition > 0) {
4790                            productRow = mainProductPosition <= 4 ? 1 : Math.ceil(mainProductPosition / 4);
4791                        } else {
4792                            const mainProductsRows = Math.ceil(mainProductsCount / 4);
4793                            const pantryProductRow = pantryProductPosition <= 4 ? 1 : Math.ceil(pantryProductPosition / 4);
4794                            productRow = mainProductsRows + pantryProductRow;
4795                        }
4796                    } else if (window.innerWidth >= 768 && window.innerWidth < 992) {
4797                        // 3 products/row
4798                        if (mainProductPosition > 0) {
4799                            productRow = mainProductPosition <= 3 ? 1 : Math.ceil(mainProductPosition / 3);
4800                        } else {
4801                            const mainProductsRows = Math.ceil(mainProductsCount / 3);
4802                            const pantryProductRow = pantryProductPosition <= 3 ? 1 : Math.ceil(pantryProductPosition / 3);
4803                            productRow = mainProductsRows + pantryProductRow;
4804                        }
4805                    } else {
4806                        // 1 product/row
4807                        productRow = productPosition;
4808                    }
4809                    // position to be displayed
4810                    const displayableSPosition = productPosition < 10 ? `0${productPosition}` : productPosition;
4811                    const displayablePGPosition = productRow < 10 ? `0${productRow}` : productRow;
4812                    placement = `R${displayablePGPosition}#S${displayableSPosition}`;
4813
4814                } else {
4815                    let currentProduct;
4816                    let currentGrid;
4817                    let gridProducts;
4818                    let productRow;
4819
4820                    currentProduct = isCrossSell
4821                        ? document.querySelector(`cross-sell product-item .product-item-${currentProductId}, cross-sell product-item-v2 .product-item-${currentProductId}, cross-sell  product-item-al-v1 .product-item-${currentProductId}, cross-sell product-item-al-v2 div[data-bpn='${currentProductId}']`)?.closest('product-item, product-item-v2, product-item-al-v1, product-item-al-v2')
4822                        : document.querySelector(`product-item-al-v1 .product-item-${currentProductId}, product-item .product-item-${currentProductId}, product-item-v2 .product-item-${currentProductId}, product-item-al-v2 div[data-bpn='${currentProductId}']`)?.closest('product-item-al-v1, product-item, product-item-v2, product-item-al-v2');
4823
4824                    if (currentProduct) {
4825                        let isNewDesign = currentProduct.localName === 'product-item-al-v2';
4826                        if (digitalData.pageFilter) {
4827                            if (isCrossSell) {
4828                                digitalData.pageFilter.mediaType = 'product-carou
4828sel';
4829                                currentGrid = currentProduct.closest('cross-sell');
4830                                gridProducts = Array.from(currentGrid?.querySelectorAll('product-item, product-item-v2, product-item-al-v1, product-item-al-v2'));
4831                            } else {
4832                                // Placement for grid products
4833                                digitalData.pageFilter.mediaType = 'product-grid';
4834                                currentGrid = currentProduct.closest('product-generic-grid-al-v1, search-grid, product-generic-grid, buy-it-again-grid');
4835                                gridProducts = Array.from(currentGrid?.querySelectorAll('product-item-al-v1, product-item, product-item-v2, product-item-al-v2'));
4836                            }
4837                        }
4838                        productPosition = gridProducts ? gridProducts.indexOf(currentProduct) + 1 : 0;
4839                        productRow = productPosition < 4 ? 1 : Math.ceil(productPosition / 4);
4840                        if (window.innerWidth < 768 && !isCrossSell) {
4841                            productRow = productPosition < 2 ? 1 : Math.ceil(productPosition / 2);
4842                        }
4843
4844                        if (isNewDesign && !isCrossSell) {
4845                            if (window.innerWidth < 470) {
4846                                productRow = productPosition < 2 ? 1 : Math.ceil(productPosition / 2);
4847                            } else if (window.innerWidth >= 470 && window.innerWidth < 616) {
4848                                productRow = productPosition < 3 ? 1 : Math.ceil(productPosition / 3);
4849                            } else if ((window.innerWidth >= 762 && window.innerWidth < 908) || (window.innerWidth >= 1019 && window.innerWidth < 1214)) {
4850                                productRow = productPosition < 5 ? 1 : Math.ceil(productPosition / 5);
4851                            } else if ((window.innerWidth >= 908 && window.innerWidth < 992) || (window.innerWidth >= 1214 && window.innerWidth < 1280)) {
4852                                productRow = productPosition < 6 ? 1 : Math.ceil(productPosition / 6);
4853                            }
4854                        }
4855
4856                        const displayableSPosition = productPosition < 10 ? `0${productPosition}` : productPosition;
4857                        const displayablePGPosition = productRow < 10 ? `0${productRow}` : productRow;
4858                        placement = `R${displayablePGPosition}#S${displayableSPosition}`;
4859
4860                    }
4861                    this.trackAEMZone(eventName, nativeElement ? nativeElement : currentProduct, 'product-grid');
4862                }
4863                if (digitalData.pageFilter) {
4864                    digitalData.pageFilter.placement = placement;
4865                }
4866            }
4867            return placement;
4868        }
4869    }
4870
4871    // Set product placement in carousel and carousel position in page
4872    this.setCarouselPosition = function ({ productId, carouselSection, eventName, nativeElement } = {}) {
4873        if (digitalData) {
4874            let placement = '';
4875            const currentCarouselSection = carouselSection ? carouselSection : digitalData.productInfo?.carouselSectionUncurated;
4876            const currentProductId = productId ? productId : digitalData.productInfo?.productID;
4877            let currentDepartment = digitalData.productInfo?.departmentName;
4878            const isCrossSell = digitalData.productInfo?.isCrossSell;
4879            const isSpImpFixOn = !window?.SWY?.CONFIGSERVICE?.featureToggleConfig?.isSponsoredImpressionFixDisabled;
4880            const carouselsAvailable = digitalData.pageDetails?.subSection3 === 'category-view'
4881                ? this.isVisible(document.querySelectorAll('.bia-carousel-list-item'))
4882                : this.isVisible(document.querySelectorAll(isSpImpFixOn ? '.slick-product-carousel, .master-product-carousel' : '.slick-product-carousel'));
4883            let currentCarouselParent = carouselsAvailable && Array.from(carouselsAvailable).filter((element) => {
4884                return (this.isDFTAPage() && element?.previousElementSibling?.textContent?.trim() === currentCarouselSection)
4885                    || (isCrossSell && element?.querySelector(`a[data-bpn="${currentProductId}"]`))
4886                    || (currentCarouselSection && (element?.querySelector(`lazy-wrapper[data-carousel-title="${currentCarouselSection}"]`) ||
4887                        element?.querySelector('.carousel-header-text')?.textContent?.trim() === currentCarouselSection ||
4888                        element?.previousElementSibling?.textContent?.trim() === currentCarouselSection) || element?.querySelector('.carousel-nav span.carousel-nav__header-title')?.textContent?.trim() === currentCarouselSection)
4889                    || (currentDepartment && element?.querySelector('h2')?.textContent?.trim()?.includes(`${currentDepartment}`));
4890            });
4891            currentCarouselParent = currentCarouselParent[0];
4892            if ((!currentCarouselParent || (currentCarouselParent && Array.isArray(currentCarouselParent) && currentCarouselParent.length === 0)) && nativeElement && nativeElement instanceof Element) {
4893                currentCarouselParent = nativeElement.closest(isSpImpFixOn ? '.master-product-carou
4893sel, .slick-product-carousel' : '.slick-product-carousel');
4894            }
4895
4896            const currentProduct = currentCarouselParent && currentCarouselParent.querySelector(`[data-bpn="${currentProductId}"]`)?.closest('product-carousel-item, product-carousel-item-v2, product-carousel-item-al-v1, product-carousel-item-al-v2');
4897            let displayableCRPosition;
4898            let productsInCarousel;
4899            let displayableSPosition;
4900            if (isSpImpFixOn) {
4901                const carouselPosition = carouselsAvailable && Array.from(carouselsAvailable).indexOf(currentCarouselParent) + 1;
4902                const safeCarouselPosition = Number.isFinite(carouselPosition) && carouselPosition > 0 ? carouselPosition : 0;
4903                displayableCRPosition = safeCarouselPosition < 10 ? `0${safeCarouselPosition}` : safeCarouselPosition;
4904                productsInCarousel = currentCarouselParent?.querySelectorAll('product-carousel-item, product-carousel-item-v2, product-carousel-item-al-v1, product-carousel-item-al-v2');
4905                if (digitalData.productInfo) {
4906                    digitalData.productInfo.carouselSize = productsInCarousel?.length;
4907                }
4908                const productPositionCarousel = productsInCarousel && Array.from(productsInCarousel).indexOf(currentProduct) + 1;
4909                const safeProductPosition = Number.isFinite(productPositionCarousel) && productPositionCarousel > 0 ? productPositionCarousel : 0;
4910                displayableSPosition = safeProductPosition < 10 ? `0${safeProductPosition}` : safeProductPosition;
4911            } else {
4912                const carouselPosition = carouselsAvailable && Array.from(carouselsAvailable).indexOf(currentCarouselParent) + 1;
4913                displayableCRPosition = carouselPosition < 10 ? `0${carouselPosition}` : carouselPosition;
4914                productsInCarousel = currentCarouselParent?.querySelectorAll('product-carousel-item, product-carousel-item-v2, product-carousel-item-al-v1, product-carousel-item-al-v2');
4915                if (digitalData.productInfo) {
4916                    digitalData.productInfo.carouselSize = productsInCarousel?.length;
4917                }
4918                const productPositionCarousel = productsInCarousel && Array.from(productsInCarousel).indexOf(currentProduct) + 1;
4919                displayableSPosition = productPositionCarousel < 10 ? `0${productPositionCarousel}` : productPositionCarousel;
4920            }
4921            placement = `R${displayableCRPosition}#S${displayableSPosition}`;
4922            if (digitalData.pageFilter) {
4923                digitalData.pageFilter.placement = placement;
4924                digitalData.pageFilter.mediaType = 'product-carousel';
4925            }
4926            this.trackAEMZone(eventName, nativeElement ? nativeElement : currentProduct, currentCarouselSection);
4927            return placement;
4928        }
4929    }
4930
4931    this.setImpressionGridPosition = function ({ productId } = {}) {
4932        let placement;
4933        let productRow;
4934        let productPosition;
4935        const products = digitalData?.gridImpressionsProducts;
4936
4937        productPosition = products ? products.indexOf(productId) + 1 : 0;
4938        productRow = productPosition < 4 ? 1 : Math.ceil(productPosition / 4);
4939        if (window.innerWidth < 768) {
4940            productRow = productPosition < 2 ? 1 : Math.ceil(productPosition / 2);
4941        }
4942
4943        // TODO: This check is for Target flag for new product cards design; it needs to be removed once flag is disabled and new product cards are enabled globally
4944        if (window.analyticsSwy?.testFlags?.ACIP248676 === 'b' || AB.DATALAYER.getLSItem('abACIP248676') === 'b') {
4945            if (window.innerWidth < 470) {
4946                productRow = productPosition < 2 ? 1 : Math.ceil(productPosition / 2);
4947            } else if (window.innerWidth >= 470 && window.innerWidth < 616) {
4948                productRow = productPosition < 3 ? 1 : Math.ceil(productPosition / 3);
4949            } else if ((window.innerWidth >= 762 && window.innerWidth < 908) || (window.innerWidth >= 1019 && window.innerWidth < 1214)) {
4950                productRow = productPosition < 5 ? 1 : Math.ceil(productPosition / 5);
4951            } else if ((window.innerWidth >= 908 && window.innerWidth < 992) || (window.innerWidth >= 1214 && window.innerWidth < 1280)) {
4952                productRow = productPosition < 6 ? 1 : Math.ceil(productPosition / 6);
4953            }
4954        }
4955
4956        // position to be displayed
4957        const displayableSPosition = productPosition < 10 ? `0${productPosition}` : productPosition;
4958        const displayablePGPosition = productRow < 10 ? `0${productRow}` : productRow;
4959        placement = `R${displayablePGPosition}#S${displayableSPosition}`;
4960
4961        return placement;
4962    }
4963
4964    this.updatePfmDetail = function (filter) {
4965        if (digitalData?.productInfo) {
4966            digitalData.productInfo.pfmDetail = `${AB.DATALAYER.getLSItem('pfmDetail')}:${filter}`;
4967        }
4968    };
4969
4970    /**
4971     * Updates cart items and subtotal when an item is removed from cart
4972     * @param removedItem
4973     */
4974    this.removeFromCart = function (removedItem) {
4975        if (digitalData?.cart && removedItem) {
4976            digitalData.cart.absItems = digitalData.cart.absItems && digitalData.cart.absItems.filter((item) => {
4977                return item.productName !== removedItem.name;
4978            });
4979            digitalData.cart.item = digitalData.cart.item && digitalData.cart.item.filter((item) => {
4980                return item.productName !== removedItem.name;
4981            });
4982            let subTotal = 0;
4983            digitalData.cart.absItems.forEach(item => {
4984                subTotal += Number(item.totalPrice);
4985            });
4986            if (digitalData.cart.transaction) {
4987                digitalData.cart.transaction.subTotal = subTotal;
4988            }
4989        }
4990    };
4991
4992    /**
4993     * Handles add to cart event
4994     * Sets event name, pfmDetail
4995     * @param product
4996     * @param cartId
4997     * @param source
4998     * @param deltaQty
4999     * @param isUndoClick
5000     */
5001    this.addItemToCart = function (product, cartId, source, cart, deltaQty, isUndoClick = false) {
5002        if (this.isCartAndCheckoutPage() && !this.isCartAndCheckoutPage('erums/cart/dnf') && product) {
5003            digitalData.pageFilter.carousel = 'shop|full_cart';
5004            product.deltaQty = deltaQty && deltaQty < 0 ? Math.abs(deltaQty) : deltaQty;
5005            product.isUndoClick = isUndoClick;
5006            product.sellerId = cart?.seller?.sellerId ? cart?.seller?.sellerId : cart?.cartCategory === '1P_WINE' ? '22222222' : AB.DATALAYER.getBannerSellerId();
5007            this.updateCart(cart, product);
5008            if (localStorage.getItem('grs-search-attribution-token')) {
5009                localStorage.removeItem('grs-search-attribution-token');
5010            }
5011        }
5012        if (window.location?.pathname?.startsWith('/rewards/point-reward-details')) {
5013            AB.DATALAYER.setLinkClickEvents('cta:rewards-dashboard|link|rewards:add');
5014        }
5015        if (AB.DATALAYER.isARManagePage()) {
5016            AB.DATALAYER.snsProdAction('cart_add');
5017        } else {
5018            this.handleItemEvent('cart_add', product, cartId, source, cart);
5019        }
5020        this.updateJourneyStatus(this.Flag.PRODUCT_ADDED);
5021    };
5022
5023    /**
5024     * Handles remove from cart event
5025     * Sets event name, pfmDetail
5026     * @param product
5027     * @param cart
5028     */
5029    this.removeItemFromCart = function (product, cart) {
5030        if (this.isCartAndCheckoutPage() && !this.isCartAndCheckoutPage('erums/cart/dnf') && product) {
5031            digitalData.pageFilter.carousel = 'shop|full_cart';
5032            product.sellerId = cart?.seller?.sellerId ? cart?.seller?.sellerId : cart?.cartCategory === '1P_WINE' ? '22222222' : AB.DATALAYER.getBannerSellerId();
5033            this.updateCart(cart);
5034        }
5035        if (AB.DATALAYER.isARManagePage()) {
5036            AB.DATALAYER.snsProdAction('remove_cart');
5037        } else {
5038            this.handleItemEvent('remove_cart', product, undefined, undefined, cart);
5039        }
5040    };
5041
5042    /**
5043     * Handles increased cart quantity event
5044     * Sets event name, pfmDetail
5045     * @param product
5046     * @param cart
5047     * @param deltaQty
5048     * @param isUndoClick
5049     */
5050    this.increaseItemQuantity = function (product, cart, deltaQty, isUndoClick = false) {
5051        if (this.isCartAndCheckoutPage() && !this.isCartAndCheckoutPage('erums/cart/dnf') && product) {
5052            digitalData.pageFilter.carousel = 'shop|full_cart';
5053            product.isUndoClick = isUndoClick;
5054            product.deltaQty = deltaQty;
5055            product.sellerId = cart?.seller?.sellerId ? cart?.seller?.sellerId : cart?.cartCategory === '1P_WINE' ? '22222222' : AB.DATALAYER.getBannerSellerId();
5056            this.updateCart(cart);
5057        }
5058        if (AB.DATALAYER.isARManagePage()) {
5059            AB.DATALAYER.snsProdAction('add_quantity');
5060        } else {
5061            this.handleItemEvent('add_quantity', product, undefined, undefined, cart);
5062        }
5063    };
5064
5065    /**
5066     * Handles decreased cart quantity event
5067     * Sets event name, pfmDetail
5068     * @param product
5069     * @param cart
5070     * @param deltaQty
5071     */
5072    this.decreaseItemQuantity = function (product, cart, deltaQty) {
5073        if (this.isCartAndCheckoutPage() && !this.isCartAndCheckoutPage('erums/cart/dnf') && product) {
5074            digitalData.pageFilter.carousel = 'shop|full_cart';
5075            product.deltaQty = deltaQty;
5076            product.sellerId = cart?.seller?.sellerId ? cart?.seller?.sellerId : cart?.cartCategory === '1P_WINE' ? '22222222' : AB.DATALAYER.getBannerSellerId();
5077            this.updateCart(cart);
5078        }
5079        if (AB.DATALAYER.isARManagePage()) {
5080            AB.DATALAYER.snsProdAction('remove_quantity');
5081        } else {
5082            this.handleItemEvent('remove_quantity', product, undefined, undefined, cart);
5083        }
5084    };
5085
5086    // To remove after 8.1 release [CLEANUP]
5087    this.getCurrentItem = function (cart, itemFromCart, deltaQty, isUndoClick) {
5088        let currentItemId = itemFromCart?.itemId;
5089        let cartItems = cart?.cartItemsList || cart?.orderItems || [];
5090        let itemObj = {};
5091        cartItems.forEach((product) => {
5092            if (product.itemId?.toString() === currentItemId?.toString()) {
5093                itemObj = product;
5094            }
5095        });
5096        itemObj.deltaQty = deltaQty && deltaQty < 0 ? Math.abs(deltaQty) : deltaQty;
5097        itemObj.isUndoClick = isUndoClick;
5098        return itemObj;
5099    };
5100
5101    /**
5102     * Handles cart item events (add, remove, increase or decrease quantity)
5103     * Sets event name, pfmDetail
5104     * @param eventName
5105     * @param product
5106     */
5107    this.handleItemEvent = function (eventName, product, cartId, source, cart) {
5108        if (AB.DATALAYER.isAlcoholAdTrackingDisabled(product || digitalData.productInfo)) {
5109            return;
5110        }
5111        if (digitalData) {
5112            if (product) {
5113                this.productInfo(product, undefined, cart);
5114            }
5115            if (digitalData.productInfo && (!digitalData.productInfo.sellerId || digitalData.productInfo.sellerId === `${AB.DATALAYER.getBannerSellerId()}`) && !AB.DATALAYER.isOrderAheadPage()) {
5116                this.martechProductAction(eventName, digitalData.productInfo);
5117            }
5118            window['analyticsSellerIds'] = window['analyticsSellerIds'] || [];
5119            this.setCarouselValueDFTA(eventName, digitalData.productInfo);
5120            if (eventName === 'cart_add') {
5121                if (!this.isRecipesAndMealsPage()) {
5122                    this.setPfmSourceCategories();
5123                    this.setP13nData();
5124                    this.similarItemsBiaAddToCart();
5125                    this.biaCarousalProductPDPAddToCart();
5126                    if (digitalData.pageFilter?.mediaType === 'product-carousel' || digitalData.productInfo?.carouselSection) {
5127                        this.setPastPurchasedImpressions(digitalData.pageFilter?.recommendationType === 'pastPurchased' ? 'buyItAgainCarousel' : '');
5128                    }
5129                } else {
5130                    digitalData.pageFilter.pfmSource = source || '';
5131                    digitalData.martech.cartId = cartId || ''
5132                    digitalData.cart.cartInfo.cartId = cartId || ''
5133                }
5134                if (AB.DATALAYER.isPdp()) {
5135                    const snsCheckbox = document.querySelector('.product-info[data-pagetype="pdp"] .sns-container input.checkbox__input');
5136                    if (snsCheckbox?.checked) {
5137                        const subscriptionValue = `pdp#subscribe#${digitalData.crossPageData?.snsAnalyticsFrequency?.data && digitalData.crossPageData?.snsAnalyticsFrequency?.data[digitalData.productInfo?.productID]}`;
5138                        digitalData.productInfo.scheduleandSaveSource = subscriptionValue;
5139                        this.setSnsProductInStorage(digitalData.productInfo?.productID);
5140                    }
5141                    if(product?.isCustomCake) {
5142                        let itemObj = cart.cartItems.find((item) => {
5143                            return item.itemId?.toString() === product.id?.toString();
5144                        });
5145                        if(itemObj && itemObj.options && itemObj.options.length > 0) {
5146                            digitalData.modal.modalMessage = `pdp-ck-add|${itemObj.options.map(option => option.name).join('|')}`;
5147                        }
5148                        digitalData.pageFilter.topNav = `cta:${digitalData.page?.previousPageName}|link|customise`;
5149                    }
5150                }
5151                if (digitalData.crossPageData?.recipeRelatedPfm && digitalData.crossPageData.recipeRelatedPfm[digitalData.productInfo?.productID]) {
5152                    digitalData.productInfo.pfmDetail = digitalData.crossPageData.recipeRelatedPfm[digitalData.productInfo.productID];
5153                }
5154                if (product?.aiProductType === 'recipe' && product?.attributes?.recipeId && digitalData.crossPageData.aiAssistantRecipePFM && digitalData.crossPageData.aiAssistantRecipePFM[product?.attributes?.recipeId]) {
5155                    digitalData.productInfo.pfmDetail = digitalData.crossPageData.aiAssistantRecipePFM[product?.attributes?.recipeId];
5156                } else if (digitalData.crossPageData?.aiAssistantProductPFM && digitalData.crossPageData.aiAssistantProductPFM[digitalData.productInfo?.productID]) {
5157                    digitalData.productInfo.pfmDetail = digitalData.crossPageData.aiAssistantProductPFM[digitalData.productInfo.productID];
5158                    delete digitalData.crossPageData.aiAssistantProductPFM[digitalData.productInfo.productID];
5159                } else if (product?.aiProductType && !(digitalData.crossPageData?.aiAssistantProductPFM && digitalData.crossPageData.aiAssistantProductPFM[digitalData.productInfo?.productID]) && !(product?.attributes?.recipeId && digitalData.crossPageData.aiAssistantRecipePFM && digitalData.crossPageData.aiAssistantRecipePFM[product?.attributes?.recipeId])) {
5160                    digitalData.productInfo.pfmDetail = `${AB.DATALAYER.pathSections?.join(':')}#added-by-ai-assistant#non-search#not-recommended#R00#S00#no-badge`;
5161                }
5162            } else {
5163                if (digitalData.productInfo.isBIACarousalProduct) {
5164                    digitalData.productInfo.impressionAdditionalDetail = '';
5165                    digitalData.pageFilter.pfmSource = '';
5166                }
5167            }
5168            digitalData.pageFilter.placement = '';
5169
5170            !this.isRecipesAndMealsPage() && !this.isAssistantPage() && this.setPfmDetailOnProductAction(eventName);
5171            if (digitalData.cart.cartInfo) {
5172                digitalData.cart.cartInfo.currentCartId = window.digitalData.cart.cartInfo.cartIDMap && window.digitalData.cart.cartInfo.cartIDMap[digitalData.productInfo.sellerId] ? window.digitalData.cart.cartInfo.cartIDMap[digitalData.productInfo.sellerId].toString() : '';
5173            }
5174
5175            // Handles persistent pfm tracking - used on order confirmation, updated across pages
5176            if (digitalData.productInfo.sellerId && digitalData.productInfo.sellerId !== `${AB.DATALAYER.getBannerSellerId()}` && digitalData.productInfo.sellerId !== '22222222') {
5177                let sellerPFM = `${digitalData.productInfo.sellerId}#${digitalData.productInfo.pfmDetail}`;
5178                window.digitalData.cart.marketplace = window.digitalData.cart.marketplace || {};
5179                if (Object.keys(window.digitalData.cart.marketplace).length === 0 && localStorage.getItem('analyticsSellerCartsInfo') && localStorage.getItem('analyticsSellerCartsInfo') !== 'undefined') {
5180                    window.digitalData.cart.marketplace = AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('analyticsSellerCartsInfo'));
5181                }
5182
5183                for (let i = 1; i <= 8; i++) {
5184                    if (digitalData.cart.marketplace[`seller${i}`] && digitalData.cart.marketplace[`seller${i}`].sellerId === digitalData.productInfo.sellerId) {
5185                        if (eventName === 'cart_add') {
5186                            digitalData.cart.marketplace[`seller${i}`].sellerPfm = digitalData.cart.marketplace[`seller${i}`].sellerPfm || {};
5187                            digitalData.cart.marketplace[`seller${i}`].sellerPfm[`${digitalData.productInfo.productID}`] = sellerPFM;
5188                            break;
5189                        } else if (eventName === 'remove_cart' && digitalData.cart.marketplace[`seller${i}`].sellerPfm[`${digitalData.productInfo.productID}`]) {
5190                            delete digitalData.cart.marketplace[`seller${i}`].sellerPfm[`${digitalData.productInfo.productID}`];
5191                            if (digitalData.cart.marketplace[`seller${i}
5191`].sellerPfm && Object.keys(digitalData.cart.marketplace[`seller${i}`].sellerPfm)?.length === 0) {
5192                                delete digitalData.cart.marketplace[`seller${i}`];
5193                            }
5194                        }
5195                    }
5196                }
5197
5198                localStorage.setItem('analyticsSellerCartsInfo', JSON.stringify(window.digitalData.cart.marketplace));
5199            }
5200
5201            if (eventName === 'remove_cart') {
5202                if (digitalData.cart.cartInfo) {
5203                    const currentProduct = digitalData.cart.item.find(item => {
5204                        return item.productID == digitalData.productInfo.productID;
5205                    });
5206                    if (currentProduct) {
5207                        digitalData.cart.cartInfo.currentCartId = currentProduct?.productCartId?.toString();
5208                    }
5209                    digitalData.productInfo.sellerId = digitalData.productInfo.sellerId || currentProduct?.productSellerId?.toString();
5210                    digitalData.cart.item = digitalData.cart.item.filter(item => {
5211                        return item.productID != digitalData.productInfo.productID;
5212                    });
5213                }
5214                if (window.digitalData.cart.sellerCarts && window.digitalData.cart.sellerCarts[`sellerItem${digitalData.productInfo.sellerId}`] && window.digitalData.cart.sellerCarts[`sellerItem${digitalData.productInfo.sellerId}`].length === 1) {
5215                    delete digitalData.cart.sellerCarts[`sellerItem${digitalData.productInfo.sellerId}`];
5216                    digitalData.cart.item = digitalData.cart.item.filter(item => {
5217                        return item.productID !== digitalData.productInfo.productID;
5218                    });
5219                    if (digitalData.productInfo.sellerId === '22222222') {
5220                        digitalData.cart.transaction.subTotalWineCart = digitalData.cart.transaction.subTotalWineCart || {};
5221                        digitalData.cart.transaction.subTotalWineCart.subTotal = 0;
5222                        digitalData.cart.transaction.subTotalWineCart.sellerId = '22222222';
5223                    } else {
5224                        digitalData.cart.transaction.subTotalMarketplaceCarts = digitalData.cart.transaction.subTotalMarketplaceCarts || '';
5225                        const splitMarketplaceCarts = digitalData.cart.transaction.subTotalMarketplaceCarts.split('#');
5226                        let newMarketplaceCarts = [];
5227                        splitMarketplaceCarts.forEach(cartInfo => {
5228                            let id = cartInfo.split(':')[0];
5229                            let newCartInfo = [];
5230                            if (id == digitalData.productInfo?.sellerId) {
5231                                newCartInfo = [id, 0].join(':');
5232                            } else {
5233                                newCartInfo = cartInfo;
5234                            };
5235                            newMarketplaceCarts.push(newCartInfo);
5236                        })
5237                        digitalData.cart.transaction.subTotalMarketplaceCarts = newMarketplaceCarts.join('#');
5238                    }
5239                    window['analyticsSellerIds'].splice(window['analyticsSellerIds'].indexOf(digitalData.productInfo.sellerId), 1);
5240                }
5241                if (digitalData.cart.absItems && digitalData.cart.absItems.length === 1 && digitalData.productInfo.sellerId === AB.DATALAYER.getBannerSellerId()) {
5242                    let isItemInSwyCart = false;
5243                    digitalData.cart.absItems.forEach(item => {
5244                        if (item.productID == digitalData.productInfo.productID) {
5245                            isItemInSwyCart = true;
5246                        }
5247                    });
5248                    if (isItemInSwyCart) {
5249                        digitalData.cart.absItems = digitalData.cart.absItems.filter(item => {
5250                            return item.productID != digitalData.productInfo.productID;
5251                        });
5252                    }
5253                    window['analyticsSellerIds'].splice(window['anal
5253yticsSellerIds'].indexOf(digitalData.productInfo.sellerId), 1);
5254                }
5255                this.removeFromCart(digitalData.productInfo);
5256            }
5257            AB.DATALAYER.setActiveCarts(digitalData.cart?.item);
5258            // Track user message toast on order edit product action
5259            if (digitalData.productInfo.previousPrice && eventName === 'add_quantity' && digitalData.productInfo.editOrderFlow) {
5260                digitalData.modal = digitalData.modal || {};
5261                digitalData.modal.modalMessage = `pricechange|price${digitalData.productInfo.isPriceDecreased ? 'decreased' : 'increased'}`;
5262            }
5263            digitalData.pageDetails.sellerId = window['analyticsSellerIds'].join(',');
5264
5265            this.pushEvent(
5266                eventName, {
5267                productInfo: digitalData.productInfo ? AB.DATALAYER.safeJSONParse(JSON.stringify(digitalData.productInfo)) : {},
5268                page: digitalData.pageDetails,
5269                pageFilter: digitalData.pageFilter ? AB.DATALAYER.safeJSONParse(JSON.stringify(digitalData.pageFilter)) : {},
5270                cart: digitalData.cart,
5271                martech: digitalData.martech,
5272                modal: digitalData.modal
5273            }
5274            );
5275            this.resetDataLayerPfmValues();
5276            if (window['analyticsSellerIds']) {
5277                localStorage.setItem('analyticsSellerIds', window['analyticsSellerIds'].join(','));
5278            }
5279            digitalData.modal = {};
5280        }
5281    };
5282
5283    this.setActiveCarts = function (products) {
5284        let activeCarts = ''
5285        if (products && products.length > 0) {
5286            const activeCartArray = products.map(product => (`${product.productCartId}:${product.productSellerId}`))
5287            let unique = [...new Set(activeCartArray)]
5288            activeCarts = unique.join();
5289        }
5290        if (digitalData.cart.cartInfo) {
5291            digitalData.cart.cartInfo.activeCarts = activeCarts;
5292        }
5293    }
5294
5295    this.resetDataLayerPfmValues = function () {
5296        digitalData.productInfo.impressionAdditionalDetail = '';
5297        digitalData.pageFilter.pfmSource = '';
5298        // Resetting bannerCardCarousel here for convenience, needs to be reset to not persist information between hits
5299        digitalData.pageFilter.bannerCardCarousel = '';
5300        digitalData.pageFilter.impressions = '';
5301    }
5302
5303    /**
5304     * Determines if the product actions is an increases or decrease to item quantity on weight quantity dropdowns
5305     * @param productAddedId 
5306     * @param newQuantity 
5307     * @returns 
5308     */
5309    this.weightSelectionActionType = function (productAddedId, newQuantity) {
5310        let actionType = '';
5311        let existingCart = this.safeJSONParse(localStorage.getItem('itemsInCartBeforeUpdate')) || [];
5312
5313        existingCart.forEach(item => {
5314            let productID = item.itemId || item.id || item.productBpn || item.productID;
5315            if (Number(productID) === Number(productAddedId)) {
5316                const quantity = item.quantityValue || item.units;
5317                actionType = Number(newQuantity) > Number(quantity) ? 'increase' : Number(newQuantity) < Number(quantity) ? 'decrease' : '';
5318            }
5319        });
5320        return actionType;
5321    }
5322
5323    /**
5324     * Processes info when adding products to cart for martech initiatives, such as cart abandonment
5325     * @param {String} eventName - current product action
5326     * @param {Object} product - product object with all attached information passed
5327     */
5328    this.martechProductAction = function (eventName, product, cart) {
5329        // Initialize/Reset the martech object on each product action
5330        window.digitalData.martech = {};
5331        if (product && !product.sellerId || product.sellerId === `${AB.DATALAYER.getBannerSellerId()}`) {
5332            // Set current product info to build into martech string
5333            const productID = product?.productID ? Number(product.productID) : product?.itemId ? Number(product.itemId) : product?.id ? Number(product.id) : 'no-value';
5334            const storeID = window.digitalData.user?.shopStoreId;
5335            const potentialUnits = product?.lbs && product.lbs !== '0' ? Number(product.lbs) : product?.each && product.each !== '0' ? Number(product.each) : product?.units ? product.units : product?.qty;
5336            const currentListPrice = Number(product.listPrice) || Number(product.price);
5337            const currentBasePrice = product?.basePrice;
5338            const currentUnitType = product?.unitType || product?.quantityType;
5339            const currentUnitPrice = product?.pricePerUnit || product?.pricePer;
5340            const currentProductPrice = Number(currentListPrice) * Number(potentialUnits);
5341            const dlProductName = window.digitalData.productInfo?.productName || 'no-value';
5342            const currentName = product?.fullName ? product.fullName : dlProductName;
5343            let finalValue;
5344            let cartId;
5345            /**
5346             * List of all products in cart after products with undefined or empty values are removed
5347             */
5348            let filteredProducts = [];
5349            /**
5350             * List of the last 6 products added to cart
5351             */
5352            let lastProductsAdded = [];
5353            /**
5354             * List of IDs of the last 6 products added to cart
5355             */
5356            let lastProductsSKUs = [];
5357            // Initialized with 0 because there is addition reduce perfomed later that throws an error if the array is empty
5358            let itemPrices = [0];
5359            /**
5360             * Counter for the number of product actions done by the user, stored in 'absItemCounter' cookie
5361             */
5362            let currentCounter = Number(AB.DATALAYER.getCookie('absItemCounter'));
5363            /**
5364             * Items currently in cart, before invalid products are removed
5365             * On the first action on the page, the datalayer isn't populated so this information is taken from the 'abCart' localStorage item
5366             * If the add to cart actions are triggered from the BIA Add All Items button, we need to get the cart items from a different LS
5367             * because the API cart update does not trigger on each product added, but rather updates in bulk
5368             */
5369            let cartItems = [];
5370            if (this.getLSItem('analyticsBIACartUpdate') ) {
5371                cartItems = this.safeJSONParse(this.getLSItem('analyticsBIACartUpdate')).bi
5371aItems || [];
5372            } else if (this.getLSItem('analyticsBundleCartUpdate')) {
5373                cartItems = this.safeJSONParse(this.getLSItem('analyticsBundleCartUpdate')).bundleItems || [];
5374            }
5375            else {
5376                cartItems = window?.digitalData?.cart?.absItems?.length > 0 ? window.digitalData.cart.absItems : cart?.cartItemsList ? cart.cartItemsList : cart?.orderItems ? cart?.orderItems : this.safeJSONParse(this.getLSItem('abCart'))?.cart?.abs?.cartItems ? this.safeJSONParse(this.getLSItem('abCart')).cart.abs.cartItems : this.safeJSONParse(this.getLSItem('abCart'))?.cartItems ? this.safeJSONParse(this.getLSItem('abCart')).cartItems : [];
5377            }
5378            let lsCartId = this.getLSItem('cartId') && this.safeJSONParse(this.getLSItem('cartId')) && this.safeJSONParse(this.getLSItem('cartId'))?.abs ? this.safeJSONParse(this.getLSItem('cartId')).abs : this.safeJSONParse(this.getLSItem('cartId'));
5379            cartId = window?.digitalData?.cart?.item?.length > 0 ? window.digitalData.cart.cartInfo.cartId : lsCartId;
5380
5381            cartItems.forEach(item => {
5382                if ((item.name && item.price) || (item.productName && item.listPrice)) {
5383                    filteredProducts.push(item);
5384                }
5385            });
5386
5387            function setSapientCookie(hitValue) {
5388                document.cookie = `absItemCounter=${hitValue}; expires=0; path=/; secure`;
5389            };
5390
5391            // Increase the counter and set the new value in cookie
5392            currentCounter++;
5393            setSapientCookie(currentCounter);
5394
5395            /**
5396             * Creates the product string for martech variables from the cart datalayer info
5397             * @param counter - current product action counter
5398             * @param product - product information from cart
5399             */
5400            function setProductString(counter, product) {
5401                let productString = `${counter}|${product.productID || product.itemId || product.id}|${product.productName || product.name}|${product.basePrice}|${product.listPrice || product.price}|${product.pricePerUnit || product.unitPrice}|${product.unitType || product.unitQuantity}`;
5402                return productString;
5403            }
5404
5405            // Remove invalid products from cart items
5406            filteredProducts.forEach(item => {
5407                let id = item.productID || item.itemId || item.id;
5408                if (id && productID && productID !== 'no-value' && id !== productID) {
5409                    const totalPrice = item.totalPrice && item.units && item.basePrice ? Number(item.units) * Number(item.basePrice) : 0;
5410                    itemPrices.push(Number(totalPrice));
5411                }
5412            });
5413            // Populate the martech object based on the type of product action / eventName
5414            switch (eventName) {
5415                case 'cart_add':
5416                    if (this.getLSItem('analyticsBIACartUpdate') || this.getLSItem('analyticsBundleCartUpdate')) {
5417                        // The current product added info is not available in the item array in the datalayer so the information is taken from passed productInfo
5418                        digitalData.martech.product1 = `${currentCounter}|${productID}|${currentName}|${currentBasePrice}|${currentListPrice}|${currentUnitPrice}|${currentUnitType}`;
5419                        lastProductsAdded = filteredProducts.slice(0, 5);
5420                        lastProductsSKUs.push(productID);
5421                    } else {
5422                        lastProductsAdded = filteredProducts.slice(0, 6);
5423                    }
5424                    lastProductsAdded.forEach(item => {
5425                        let cartProductId = item.productID || item.itemId || item.id;
5426                        // productNumber = this.getLSItem('analyticsBIACartUpdate')  ? lastProductsAdded.indexOf(item) + 2 : lastProductsAdded.indexOf(item) + 1;
5427                        productNumber = this.getLSItem('analyticsBundleCartUpdate')
5428                            ? lastProductsAdded.indexOf(item) + 2
5429                            : this.getLSItem('analyticsBIACartUpdate')
5430                                ? lastProductsAdded.indexOf(item) + 2
5431                                : lastProductsAdded.indexOf(item) + 1;
5432                        digitalData.martech[`product${productNumber}`] = setProductString(currentCounter, item);
5433                        lastProductsSKUs.push(cartProductId);
5434                    });
5435                    break;
5436                case 'add_quantity':
5437                    lastProductsAdded = filteredProducts.slice(0, 6);
5438                    lastProductsAdded.forEach(item => {
5439                        let cartProductId = item.productID || item.itemId || item.id;
5440                        productNumber = lastProductsAdded.indexOf(item) + 1;
5441                        digitalData.martech[`product${productNumber}`] = setProductString(currentCounter, item);
5442                        lastProductsSKUs.push(cartProductId);
5443                    });
5444                    break;
5445                case 'remove_cart':
5446                    let finalProductsList = [];
5447                    let finalProductsSKUs = [];
5448                    let arrayToBeReduced = filteredProducts.slice(0, 7);
5449                    lastProductsAdded = filteredProducts.slice(0, 6);
5450                    lastProductsAdded.forEach(item => {
5451                        let cartProductId = item.productID || item.itemId || item.id;
5452                        lastProductsSKUs.push(cartProductId);
5453                    });
5454                    // On product removal, if the removed product is within the last 6 products added, we iterate through the last 7 products and remove current product
5455                    if (lastProductsSKUs.indexOf(productID) >= 0) {
5456                        arrayToBeReduced.forEach(item => {
5457                            let cartProductId = item.productID ? item.productID : item.itemId;
5458                            if (cartProductId !== productID) {
5459                                finalProductsSKUs.push(cartProductId);
5460                                finalProductsList.push(item);
5461                            }
5462                        });
5463                        lastProductsSKUs = finalProductsSKUs;
5464                    } else {
5465                        lastProductsAdded.forEach(item => {
5466                            finalProductsList.push(item);
5467                        });
5468                    }
5469                    finalProductsList.forEach(item => {
5470                        if (lastProductsAdded.length === 1 && lastProductsSKUs.indexOf(digitalData.productInfo.productID?.toString()) !== -1) {
5471                            itemPrices = [0];
5472                            lastProductsSKUs = [];
5473                        } else {
5474                            productNumber = finalProductsList.indexOf(item) + 1;
5475                            digitalData.martech[`product${productNumber}`] = setProductString(currentCounter, item);
5476                        }
5477                    });
5478                    break;
5479                case 'remove_quantity':
5480                    lastProductsAdded = filteredProducts.slice(0, 6);
5481                    lastProductsAdded.forEach(item => {
5482                        let cartProductId = item.productID || item.itemId || item.id;
5483                        productNumber = lastProductsAdded.indexOf(item) + 1;
5484                        digitalData.martech[`product${productNumber}`] = setProductString(currentCounter, item);
5485                        lastProductsSKUs.push(cartProductId);
5486                    });
5487                    break;
5488                default:
5489                    break;
5490            };
5491            // Value of the entire cart, keep only 2 decimals after comma
5492            finalValue = window.AB.DATALAYER.roundUpValue(itemPrices.filter(price => !isNaN(parseFloat(price))).reduce(AB.DATALAYER.safeReducer, 0), 2);
5493            digitalData.martech.cartValue = finalValue;
5494            digitalData.martech.cartId = cartId;
5495            digitalData.martech.cartDetails = `${currentCounter}#${lastProductsSKUs.join('|')}#${finalValue}#${storeID}`;
5496        }
5497    }
5498
5499    /**
5500     * Sets placement, mediaType and recommendationType based on pfmDetail for add to cart on pdp
5501     * @param pfmDetail 
5502     */
5503    this.setPDPPlacementMediaType = function (pfmDetail) {
5504        const pfmParts = pfmDetail.split('#');
5505        const [page, mediaType, search, recommendationType, row, slot] = pfmParts;
5506        const isProductGrid = mediaType === 'product-grid' || mediaType?.includes('drawer');
5507
5508        digitalData.pageFilter.mediaType = isProductGrid
5509            ? 'product-grid'
5510            : mediaType?.toLowerCase() === 'pdp-landing' ? 'PDP-landing' : 'product-carou
5510sel';
5511        digitalData.pageFilter.placement = `${row}#${slot}`;
5512        digitalData.pageFilter.recommendationType = recommendationType === 'not-recommended' ? 'notrecommended' : recommendationType;
5513    }
5514
5515    /**
5516     * Sets pfmDetail on product actions
5517     */
5518    this.setPfmDetailOnProductAction = function (eventName) {
5519        const bentoCtx = digitalData._bentoProductContext;
5520        if (bentoCtx) {
5521            const badgeInfo = AB.DATALAYER.getBadgeInfo(digitalData.productInfo?.badges);
5522            const pfmStart = `${AB.DATALAYER.pfmFromCurrentPage}#${bentoCtx.content}#non-search`;
5523            digitalData.productInfo.pfmDetail = this.createPaPfmBasedOnRecType(pfmStart, bentoCtx.recommendationType, bentoCtx.placement, badgeInfo);
5524            digitalData.pageFilter.mediaType = bentoCtx.mediaType;            // V80 media type -> bento-hero-card:product-grid
5525            // V80 recommendation (rTyp): set explicitly so it reflects this click, not a stale value.
5526            digitalData.pageFilter.recommendationType = bentoCtx.recommendationType || 'no-value';
5527            // V80 ROW#SLOT: onetag composes V80 from mediaType#recommendationType#placement, and handleItemEvent
5528            // clears pageFilter.placement just before this — restore the bento card position (e.g. R01#S03).
5529            digitalData.pageFilter.placement = bentoCtx.placement;
5530            digitalData.pageFilter.bannerCardCarousel = bentoCtx.bannerCardCarousel; // V218
5531            if (bentoCtx.mediaPlacementClick) {
5532                digitalData.pageFilter.mediaPlacementClick = bentoCtx.mediaPlacementClick; // V80 (canonical mediaType#rec#r#s)
5533            }
5534            return;
5535        }
5536        if (digitalData.productInfo.carouselSection || digitalData.pageDetails.subSection3 === 'category-view') {
5537            // product actions on carousel items
5538            this.setCarouselPosition({ eventName: eventName });
5539            this.paPfmCarousel();
5540        } else {
5541            // product actions on product grid, offer drawer, cross-sell, pdp
5542            this.setProductGridPosition({ eventName: eventName });
5543            if (this.isPdp()) {
5544                // for product actions on pdp (for products that are not in a carousel)
5545                this.paPfmPDP();
5546            } else if (this.isSearchResultsPage()) {
5547                // sets pfm detail on product actions on search-results pages
5548                this.paPfmOnSearch();
5549            } else if (this.isARManagePage()) {
5550                // sets pfm detail on product actions on schedule & save page
5551                this.paPfmOnSns();
5552            } else {
5553                // sets pfm detail on non-search pages product actions
5554                this.paPfmNonSearch();
5555            }
5556        }
5557    }
5558
5559    /**
5560     * Product actions (add, remove, increase/decrease quantity) on carousels
5561     */
5562    this.paPfmCarousel = function () {
5563        let carouselTitle = digitalData.productInfo.carouselSection || digitalData.productInfo.departmentName;
5564        const productID = digitalData.productInfo.productID;
5565        let isPicksForYou = false;
5566        let isP13nGeneric = false;
5567        const badgeInfo = AB.DATALAYER.getBadgeInfo(digitalData.productInfo?.badges);
5568
5569        if (carouselTitle) {
5570            isPicksForYou = carouselTitle.search(/picks for you|picked for you|picks-for-you|picked-for-you/i) !== -1;
5571            carouselTitle = carouselTitle.toLowerCase();
5572            carouselTitle = carouselTitle.includes('picks for you') || carouselTitle.includes('picked for you')
5573                ? this.sanitizeTitlePicksForYouAndP13n(carouselTitle) : carouselTitle.replace(/[, ]+/g, '-');
5574        }
5575        if (productID) {
5576            const currentCarousel = document.querySelector(`a[data-bpn="${productID}"]`)?.closest('.slick-product-carousel');
5577            const p13nCarousel = currentCarousel?.querySelector('[data-carousel-driven=p13n-generic]');
5578            isP13nGeneric = p13nCarousel && p13nCarousel.length > 0;
5579        }
5580
5581        const recType = isPicksForYou || isP13nGeneric ? 'recommended' : digitalData.pageFilter.recommendationType;
5582        const pfmDetailStart = `${AB.DATALAYER.pfmFromCurrentPage}#${carouselTitle}#non-search`;
5583        const placement = digitalData.productInfo.placement;
5584        digitalData.productInfo.pfmDetail = this.createPaPfmBasedOnRecType(pfmDetailStart, recType, placement, badgeInfo);
5585    }
5586
5587    /**
5588     * Product actions (add, remove, increase/decrease quantity) on search results pages
5589     */
5590    this.paPfmOnSearch = function () {
5591        const pfmDetailSearch = this.getLSItem('pfmDetailSearch');
5592        const badgeInfo = AB.DATALAYER.getBadgeInfo(digitalData.productInfo?.badges);
5593
5594        if (pfmDetailSearch) {
5595            const currentProductId = digitalData.productInfo.productID;
5596            const pfmFromCurrentPage = AB.DATALAYER.pfmFromCurrentPage;
5597            const isCrossSell = digitalData.productInfo.isCrossSell;
5598
5599            let pfmDetailStart = `${pfmFromCurrentPage}#product-grid#${pfmDetailSearch}`;
5600            if (isCrossSell) {
5601                const currentProduct = document.querySelector(`cross-sell .product-item-${currentProductId}, cross-sell product-item-al-v2 div[data-bpn='${currentProductId}']`)?.closest('product-item-v2, product-item-al-v1, product-item-al-v2');
5602                const crossSellTitle = currentProduct?.closest('cross-sell')?.querySelector('.cross-sell__title')?.textContent?.trim()?.replace(/[, ]+/g, '-');
5603                pfmDetailStart = `${pfmFromCurrentPage}#${crossSellTitle}#${pfmDetailSearch}`;
5604            } else if (this.getDrawerStatus(currentProductId)) {
5605                const drawerType = this.getDrawerType(currentProductId);
5606                pfmDetailStart = `${pfmFromCurrentPage}#${drawerType}#${pfmDetailSearch}`;
5607            }
5608            digitalData.productInfo.pfmDetail = this.createPaPfmBasedOnRecType(pfmDetailStart, null, null, badgeInfo);
5609        } else if (this.isARManagePage()) {
5610            this.paPfmOnSns();
5611        }
5612    }
5613
5614    /**
5615     * Product actions (add, remove, increase/decrease quantity) on all non-search-results pages
5616     */
5617    this.paPfmNonSearch = function () {
5618        const currentProductId = digitalData.productInfo.productID;
5619        const isCrossSell = digitalData.productInfo.isCrossSell;
5620        const pfmFromCurrentPage = AB.DATALAYER.pfmFromCurrentPage;
5621        const instoreReceiptProductPlacement = this.getLSItem('instoreReceiptProductPlacement')
5622        let pfmDetailStart = `${pfmFromCurrentPage}#product-grid#non-search`;
5623        const badgeInfo = AB.DATALAYER.getBadgeInfo(digitalData.productInfo?.badges);
5624
5625        if (this.getDrawerStatus(currentProductId)) {
5626            const drawerType = this.getDrawerType(currentProductId);
5627            pfmDetailStart = `${pfmFromCurrentPage}#${drawerType}#non-search`;
5628        } else if (isCrossSell) {
5629            const currentProduct = document.querySelector(`cross-sell .product-item-${currentProductId}, cross-sell product-item-al-v2 div[data-bpn='${currentProductId}']`)?.closest('product-item-v2, product-item-al-v1, product-item-al-v2');
5630            const crossSellTitle = currentProduct?.closest('cross-sell')?.querySelector('.cross-sell__title')?.textContent?.trim()?.replace(/[, ]+/g, '-');
5631            pfmDetailStart = `${pfmFromCurrentPage}#${crossSellTitle}#non-search`;
5632        } else if (instoreReceiptProductPlacement) {
5633            pfmDetailStart = `${AB.DATALAYER.initPathSections(true).join(':')}#instore-receipt#non-search`;
5634            digitalData.pageFilter.placement = instoreReceiptProductPlacement
5635        }
5636        digitalData.productInfo.pfmDetail = this.createPaPfmBasedOnRecType(pfmDetailStart, null, null, badgeInfo);
5637    }
5638
5639    /**
5640     * Product actions (add, remove, increase/decrease quantity) on PDP
5641     */
5642    this.paPfmPDP = function () {
5643        const lsPfmDetail = this.getLSItem('pfmDetail');
5644        const drawerStatus = this.getDrawerStatus(digitalData.productInfo?.productID);
5645        const badgeInfo = AB.DATALAYER.getBadgeInfo(digitalData.productInfo?.badges);
5646
5647        if (drawerStatus) {
5648            const drawerType = this.getDrawerType(digitalData.productInfo.productID);
5649            digitalData.productInfo.pfmDetail = `product-details#${drawerType}#non-search#${digitalData.pageFilter.recommendationType}#${digitalData.pageFilter.placement}#${badgeInfo}`;
5650        } else if (lsPfmDetail) {
5651            digitalData.productInfo.pfmDetail = lsPfmDetail;
5652            this.setPDPPlacementMediaType(lsPfmDetail);
5653        }
5654    }
5655
5656    /**
5657     * Product actions (add, increase/decrease quantity) on Schedule & Save
5658     */
5659    this.paPfmOnSns = function () {
5660        if (digitalData?.productInfo) {
5661            const searchTerm = document.querySelector('.sns-modal-content-wrapper input')?.value;
5662            const badgeInfo = AB.DATALAYER.getBadgeInfo(digitalData.productInfo?.badges);
5663            const pfmDetailStart = searchTerm ? `search-results#product-grid#${searchTerm}:ota` : 'customer-account:ota:bia#buy-it-again#non-search';
5664            digitalData.productInfo.pfmDetail = this.createPaPfmBasedOnRecType(pfmDetailStart, searchTerm ? 'notRecommended' : 'pastPurchased', null, badgeInfo);
5665        }
5666    }
5667
5668    this.setPlacementInfoCarouselItems = function (element) {
5669        if (element) {
5670            const parentCarousel = element.closest('.slick-product-carousel, .bia-carousel-list-item');
5671            const visibleProds = this.findVisibleElement(document.querySelectorAll('.slick-product-carousel, .bia-carousel-list-item'));
5672            const carouselIndex = visibleProds?.indexOf(parentCarousel) + 1;
5673            const currentProduct = element.closest('product-carousel-item, product-carousel-item-v2, product-carousel-item-al-v1, product-carousel-item-al-v2');
5674            const productPosition = parentCarousel ? Array.from(parentCarousel.querySelectorAll('product-carousel-item-v2, product-carousel-item-al-v1, product-carousel-item-al-v2'))?.indexOf(currentProduct) + 1 : 0;
5675            const displayableSPosition = productPosition < 10 ? `0${productPosition}` : productPosition;
5676            const displayableCRPosition = carouselIndex < 10 ? `0${carouselIndex}` : carouselIndex;
5677            const placement = `R${displayableCRPosition}#S${displayableSPosition}`;
5678            return placement;
5679        }
5680    }
5681
5682    /**
5683     * 
5684     * @param pfmDetailStart The starting part of the pfmDetail string
5685     * @param recType the recommendation type
5686     * @returns the pfmDetail string
5687     */
5688    this.createPaPfmBasedOnRecType = function (pfmDetailStart, recType, placement, badgeInfo) {
5689        let pfmDetailValue = '';
5690        const recommendationType = recType ? recType : digitalData.pageFilter.recommendationType;
5691        const placementValue = placement ? placement : digitalData.pageFilter.placement;
5692        digitalData.pageFilter.placement = placementValue;
5693        switch (recommendationType) {
5694            case 'sponsored':
5695            case 'cross-sell:sponsored':
5696            case 'cross-sell':
5697            case 'recipes':
5698                pfmDetailValue = `${pfmDetailStart}#${recommendationType}#${placementValue}#${badgeInfo}`;
5699                break;
5700            case 'pastPurchased':
5701                const page = this.isBIAPage() && localStorage.getItem('analyticsBiaLoadMore') ? `:${localStorage.getItem('analyticsBiaLoadMore')}` : '';
5702                pfmDetailValue = `${pfmDetailStart}#past-purchase${page}#${placementValue}#${badgeInfo}`;
5703                break;
5704            case 'recommended':
5705                pfmDetailValue = `${pfmDetailStart}#recs#${placementValue}#${badgeInfo}`;
5706                break;
5707            default:
5708                pfmDetailValue = `${pfmDetailStart}#not-recommended#${placementValue}#${badgeInfo}`;
5709        }
5710        return pfmDetailValue;
5711    }
5712    /**
5713     * Sets the pfmDetail in localStorage when clicking on the product item to navigate to the product details page
5714     * @param element html element
5715     * @param product product object
5716     * @param productInfoObj additional information from componenet
5717     */
5718    this.setPfmDetailProductItemToPDP = function (element, product, productInfoObj) {
5719        if (AB.DATALAYER.isAlcoholAdTrackingDisabled(product)) {
5720            return;
5721        }
5722        let productRow;
5723        let productPosition;
5724        const badgeInfo = AB.DATALAYER.getBadgeInfo(product?.badges);
5725        const crossSellElement = element?.closest('cross-sell');
5726        if (element) {
5727            const modelId = element.closest('lazy-wrapper')?.getAttribute('data-model-id');
5728            if (modelId) {
5729                this.setLSItem('analyticsProductMsg', digitalData.productTrackingInfo && digitalData.productTrackingInfo[modelId] && digitalData.productTrackingInfo[modelId].msgExperiment || 'no-value');
5730            }
5731        }
5732
5733        if (productInfoObj.isSpotlight) {
5734            const currentProduct = element?.closest('.banner-unit-spotlight__content__product');
5735            const allProducts = currentProduct ? Array.from(currentProduct.closest('.banner-unit-spotlight__content').querySelectorAll('.banner-unit-spotlight__content__product')) : [];
5736            productPosition = allProducts.indexOf(currentProduct) + 1;
5737            productRow = 1;
5738            this.setLSItem('analyticsMediaType', 'spotlight-banner');
5739        } else {
5740            const currentGrid = crossSellElement ? crossSellElement : element.closest('search-grid, product-generic-grid, buy-it-again-grid, product-generic-grid-al-v1');
5741            const gridProducts = currentGrid ? Array.from(currentGrid.querySelectorAll('product-item-v2, product-item-al-v1, product-item-al-v2')) : [];
5742            let isNewDesign = element?.localName === 'product-item-al-v2';
5743            productPosition = gridProducts.indexOf(element) + 1;
5744            productRow = window.innerWidth < 768 && !crossSellElement
5745                ? productPosition < 2 ? 1 : Math.ceil(productPosition / 2)
5746                : productPosition < 4 ? 1 : Math.ceil(productPosition / 4);
5747
5748            if (isNewDesign && !crossSellElement) {
5749                if (window.innerWidth < 470) {
5750                    productRow = productPosition < 2 ? 1 : Math.ceil(productPosition / 2);
5751                } else if (window.innerWidth >= 470 && window.innerWidth < 616) {
5752                    productRow = productPosition < 3 ? 1 : Math.ceil(productPosition / 3);
5753                } else if ((window.innerWidth >= 762 && window.innerWidth < 908) || (window.innerWidth >= 1019 && window.innerWidth < 1214)) {
5754                    productRow = productPosition < 5 ? 1 : Math.ceil(productPosition / 5);
5755                } else if ((window.innerWidth >= 908 && window.innerWidth < 992) || (window.innerWidth >= 1214 && window.innerWidth < 1280)) {
5756                    productRow = productPosition < 6 ? 1 : Math.ceil(productPosition / 6);
5757                }
5758            }
5759            this.setLSItem('analyticsMediaType', 'product-grid');
5760            const crossSellTitle = crossSellElement?.querySelector('.cross-sell__title')?.textContent?.trim()?.replace(/[, ]+/g, '-');
5761            if (crossSellTitle) {
5762                this.setLSItem('analyticsCrossSellTitle', crossSellTitle);
5763                this.setLSItem('analyticsMediaType', 'product-carou
5763sel');
5764            }
5765        }
5766        const displayableSPosition = productPosition < 10 ? `0${productPosition}` : productPosition;
5767        const displayablePGPosition = productRow < 10 ? `0${productRow}` : productRow;
5768        const placement = `R${displayablePGPosition}#S${displayableSPosition}`;
5769        this.setLSItem('analyticsProductPlacement', placement);
5770
5771        let pfmDetailPDP = `not-recommended#${placement}#${badgeInfo}`;
5772        if (productInfoObj.sponsoredProduct || product.adId || product.eventTracking) {
5773            pfmDetailPDP = crossSellElement ? `cross-sell:sponsored#${placement}#${badgeInfo}` : `sponsored#${placement}#${badgeInfo}`;
5774        } else if (productInfoObj.isPastPurchased || productInfoObj.calledBy === 'buy-it-again' || productInfoObj.calledBy === 'buy-it-again-qsc') {
5775            const page = this.isBIAPage() && localStorage.getItem('analyticsBiaLoadMore') ? `|${this.handleGetLSValue('analyticsBiaLoadMore')}` : '';
5776            pfmDetailPDP = `past-purchase${page}#${placement}#${badgeInfo}`;
5777        }
5778
5779        if (product && placement) {
5780            this.trackOneTagProductClick({ product: product, placement: placement, feature: 'grid' });
5781        }
5782        this.setLSItem('pfmDetailProductPDP', pfmDetailPDP);
5783
5784        if (this.getDrawerStatus(product.id)) {
5785            let drawerType = 'drawer';
5786            const productGridApiType = element.closest('product-generic-grid')?.getAttribute('data-api-type');
5787            if (productGridApiType === 's-bogo') {
5788                drawerType = 'BOGO-drawer';
5789            } else if (productGridApiType === 'c-products-by-upc-drawer') {
5790                drawerType = 'J4U-drawer';
5791            }
5792            this.setLSItem('analyticsDrawerPfm', drawerType);
5793        }
5794
5795        if (productInfoObj.pathwaysWidget) {
5796            this.setLSItem('analyticsPathwaysWidget', JSON.stringify(productInfoObj.pathwaysWidget));
5797        }
5798
5799        this.trackAEMZone('pdp-card', element, 'product-grid');
5800
5801        this.setPfmSourceCategoriesPDP();
5802        this.setPfmSourceBiaPDP();
5803    }
5804
5805    /**
5806     * Sets the pfmDetail in localStorage when clicking on the carousel product item to navigate to the product details page
5807     * @param carousel carousel object
5808     * @param element product html element 
5809     * @param product product object
5810     */
5811    this.setPfmDetailCarouselToPDP = function (carousel, element, product) {
5812        if (AB.DATALAYER.isAlcoholAdTrackingDisabled(product)) {
5813            return;
5814        }
5815        const badgeInfo = AB.DATALAYER.getBadgeInfo(product?.badges);
5816        const biaCarousel = element.closest('.bia-carousel-list-item');
5817        const isSponsored = carousel.dataDriven === 'featured-products' || product['adId'] || product.eventTracking;
5818        const isPastPurchased = carousel.behaviour === 'buy-it-again' || carousel.dataDriven === 'buy-it-again' || biaCarousel;
5819        const isBrPathway = carousel.dataDriven === 'pathway-search';
5820        const isPicksForYou = carousel.dataDriven === 'picked-for-you';
5821        const isP13nGeneric = carousel.dataDriven === 'p13n-generic';
5822        const isBiaSpaCarousel = carousel.behaviour === 'bia-spaCarousel';
5823        const currentPagePfm = AB.DATALAYER.pfmFromCurrentPage;
5824        const parentCarousel = element.closest('.slick-product-carousel, .bia-carousel-list-item');
5825        const alternateCarouselTitle = parentCarousel.querySelector('lazy-wrapper')
5826            ? parentCarousel.querySelector('lazy-wrapper').dataset?.carouselTitle
5827            : isBiaSpaCarousel ? parentCarousel.closest('.bia-spa-carousel-container')?.querySelector('.bia-spa-carousel-container-header')?.textContent?.trim() : '';
5828        const visibleProds = this.findVisibleElement(document.querySelectorAll('.slick-product-carousel, .bia-carousel-list-item'));
5829        const carouselIndex = visibleProds.indexOf(parentCarousel) + 1;
5830        const productPosition = parentCarousel ? Array.from(parentCarousel.querySelectorAll('product-carousel-item-v2, product-carousel-item-al-v1, product-carousel-item-al-v2')).indexOf(element) + 1 : 0;
5831        const displayableSPosition = productPosition < 10 ? `0${productPosition}` : productPosition;
5832        const displayableCRPosition = carouselIndex < 10 ? `0${carouselIndex}` : carouselIndex;
5833        const placement = `R${displayableCRPosition}#S${displayableSPosition}`;
5834        const productAdobeMetricA = product['adobeMetrics']?.metricA;
5835        const productAdobeMetricC = product['adobeMetrics']?.metricC;
5836        this.setLSItem('analyticsBIAProductImpressionAdDetail', productAdobeMetricA);
5837        this.setLSItem('analyticsBIAPfmSource', productAdobeMetricC);
5838        this.setLSItem('analyticsIsBIACarousal', isBiaSpaCarousel);
5839        this.setLSItem('analyticsBIACarousalProductId', product.id);
5840
5841        this.setLSItem('analyticsProductPlacement', placement);
5842        this.setLSItem('analyticsMediaType', 'product-carousel');
5843
5844        let title = carousel.title ? carousel.title : alternateCarouselTitle;
5845        if (title) {
5846            title = isPicksForYou || isP13nGeneric ? this.sanitizeTitlePicksForYouAndP13n(title) : title.trim().replace(/[, ]+/g, '-');
5847            this.setLSItem('analyticsCarouselName', `shop|${title}`);
5848        }
5849
5850        //TO DO: verify this.pathwaysWidget=this.carousel.pathwaysWidget
5851        if (carousel.pathwaysWidget) {
5852            this.setLSItem('analyticsPathwaysWidget', JSON.stringify(carousel.pathwaysWidget));
5853        }
5854        if (element) {
5855            const modelId = element.closest('lazy-wrapper')?.getAttribute('data-model-id');
5856            if (modelId) {
5857                this.setLSItem('analyticsProductMsg', digitalData.productTrackingInfo && digitalData.productTrackingInfo[modelId] && digitalData.productTrackingInfo[modelId].msgExperiment || 'no-value');
5858            }
5859        }
5860
5861        const pfmDetailCarouselPDPObj = {
5862            sponsored: `${currentPagePfm}#${title}#non-search#sponsored#${placement}#${badgeInfo}`,
5863            recs: `${currentPagePfm}#${title}#non-search#recs#${placement}#${badgeInfo}`,
5864            pastPurchase: `${currentPagePfm}#${biaCarousel?.querySelector('.bia-carousel-title .department-name')?.textContent || title}#non-search#past-purchase#${placement}#${badgeInfo}`,
5865            br: `${currentPagePfm}#${title}#non-search#br#${placement}#${badgeInfo}`,
5866            notRecommended: `${currentPagePfm}#${title}#non-search#not-recommended#${placement}#${badgeInfo}`
5867        };
5868
5869        let pfmDetailCarouselPDP = pfmDetailCarouselPDPObj.notRecommended;
5870        if (isSponsored) {
5871            pfmDetailCarouselPDP = pfmDetailCarouselPDPObj.sponsored;
5872        } else if (carousel.isRecommended || isPicksForYou || isP13nGeneric) {
5873            pfmDetailCarouselPDP = pfmDetailCarouselPDPObj.recs;
5874        } else if (isPastPurchased) {
5875            pfmDetailCarouselPDP = pfmDetailCarouselPDPObj.pastPurchase;
5876        } else if (isBrPathway) {
5877            pfmDetailCarouselPDP = pfmDetailCarouselPDPObj.br;
5878        }
5879
5880        if (product && placement && carousel.dataDriven === 'featured-products') {
5881            product.carouselSection = title;
5882            this.trackOneTagProductClick({ product: product, placement: placement, feature: 'carousel' });
5883        }
5884        this.trackAEMZone('pdp-card', element, title);
5885        this.setLSItem('pfmDetailCarouselPDP', pfmDetailCarouselPDP);
5886        if (isP13nGeneric) {
5887            const pId = element.querySelector('.product-carousel-item-v3__image-link')?.getAttribute('data-bpn')
5888            const currentDietPrefItem = digitalData.dietPrefItems?.find(item => item.productID === pId);
5889            const dataImpressionTracking = parentCarousel.querySelector('lazy-wrapper')?.getAttribute('data-impression-tracking')
5890            const isImpTrackEnabled = dataImpressionTracking ? dataImpressionTracking : 'no-value';
5891            this.setLSItem('analyticsp13nDataPDP', `${currentDietPrefItem?.impressionAdditionalDetail}#${isImpTrackEnabled}`)
5892        }
5893        this.setPfmSourceCategoriesPDP();
5894        if (this.isSearchResultsPage() && carousel.dataDriven === 'featured-products') {
5895            this.analyticsCTATracking(`cta:${AB.DATALAYER.pathSections.join(':')}|link|${title}`);
5896        }
5897    }
5898
5899    /**
5900     * Initializes pfmDetail on pdp pages
5901     */
5902    this.initPDPPfm = function (productInfoObj) {
5903        const badgeInfo = AB.DATALAYER.getBadgeInfo(productInfoObj?.badges);
5904        const lsPfmDetail = localStorage.getItem('pfmDetail');
5905        let pfmDetailValue = '';
5906
5907        // carousel item to pdp
5908        const handlePfmDetailCarouselPDP = () => {
5909            const lsPfmDetailCarouselPDP = this.handleGetLSValue('pfmDetailCarouselPDP');
5910            if (lsPfmDetailCarouselPDP) {
5911                pfmDetailValue = lsPfmDetailCarouselPDP;
5912
5913                // save p13nData so it can be used on add to cart on pdp-TO DO: check if it can be move inside setPDPevent
5914                const analyticsp13nDataPDP = this.handleGetLSValue('analyticsp13nDataPDP');
5915                if (analyticsp13nDataPDP) {
5916                    AB.DATALAYER.p13nData = analyticsp13nDataPDP;
5917                }
5918            }
5919        };
5920
5921        // product grid item to pdp
5922        const handlePfmDetailProductPDP = () => {
5923            const lsPfmDetailProductPDP = this.handleGetLSValue('pfmDetailProductPDP');
5924            if (lsPfmDetailProductPDP) {
5925                const pfmDetailProduct = lsPfmDetailProductPDP;
5926                const lsPfmDetailSearch = this.handleGetLSValue('pfmDetailSearch');
5927                if (lsPfmDetailSearch) {
5928                    handlePfmDetailSearch(pfmDetailProduct, lsPfmDetailSearch);
5929                } else {
5930                    handleNonSearchGridProducts(pfmDetailProduct);
5931                }
5932            }
5933        };
5934
5935        // search-results grid to pdp
5936        const handlePfmDetailSearch = (pfmDetailProduct, lsPfmDetailSearch) => {
5937            const drawerType = this.handleGetLSValue('analyticsDrawerPfm');
5938            const mediaType = this.getLSItem('analyticsMediaType');
5939            const crossSellTitle = this.handleGetLSValue('analyticsCrossSellTitle');
5940            if (drawerType) {
5941                // product on offer-drawer to PDP
5942                pfmDetailValue = `${lsPfmDetail}#${drawerType}#${lsPfmDetailSearch}#${pfmDetailProduct}`;
5943            } else if (mediaType === 'spotlight-banner') {
5944                // product on spotlight banner to PDP
5945                pfmDetailValue = `${lsPfmDetail}#spotlight-banner#${lsPfmDetailSearch}#${pfmDetailProduct}`;
5946            } else if (crossSellTitle) {
5947                // cross sell product to PDP
5948                pfmDetailValue = `${lsPfmDetail}#${crossSellTitle}#${lsPfmDetailSearch}#${pfmDetailProduct}`;
5949            } else {
5950                pfmDetailValue = `${lsPfmDetail}#product-grid#${lsPfmDetailSearch}#${pfmDetailProduct}`;
5951            }
5952        };
5953
5954        // non-search grid products to pdp
5955        const handleNonSearchGridProducts = (pfmDetailProduct) => {
5956            const drawerType = this.handleGetLSValue('analyticsDrawerPfm');
5957            const crossSellTitle = this.handleGetLSValue('analyticsCrossSellTitle');
5958            const receiptType = this.handleGetLSValue('analyticsReceiptType');
5959            if (drawerType) {
5960                if (digitalData.pageDetails?.referringURL?.indexOf('product-details') !== -1) {
5961                    // PDP drawer to PDP
5962                    pfmDetailValue = `product-details#${drawerType}#non-search#${pfmDetailProduct}`;
5963                } else {
5964                    // other pages to PDP - from offer-drawer
5965                    pfmDetailValue = `${lsPfmDetail}#${drawerType}#non-search#${pfmDetailProduct}`;
5966                }
5967            } else if (crossSellTitle) {
5968                // cross sell product to PDP
5969                pfmDetailValue = `${lsPfmDetail}#${crossSellTitle}#non-search#${pfmDetailProduct}`;
5970            } else if (receiptType) {
5971                // receipt product to pdp
5972                pfmDetailValue = `${lsPfmDetail}#${receiptType}#non-search#${pfmDetailProduct}`;
5973            } else {
5974                pfmDetailValue = `${lsPfmDetail}#product-grid#non-search#${pfmDetailProduct}`;
5975            }
5976        };
5977
5978        const handleBentoPdpPfm = () => {
5979            const lsBentoPfm = this.handleGetLSValue('bentoHeroPdpPfm') || AB.DATALAYER._bentoPdpPfmMirror;
5980            if (lsBentoPfm) {
5981                AB.DATALAYER._bentoPdpPfmMirror = lsBentoPfm;
5982                pfmDetailValue = `product-details#${lsBentoPfm}`;
5983            }
5984        };
5985
5986        // directly landing on pdp
5987        const setDefaultPfmDetail = () => {
5988            pfmDetailValue = `product-details#PDP-landing#non-search#not-recommended#R01#S01#${badgeInfo}`;
5989        };
5990
5991        handleBentoPdpPfm();
5992
5993        if (!pfmDetailValue && lsPfmDetail) {
5994            handlePfmDetailCarouselPDP();
5995            handlePfmDetailProductPDP();
5996        }
5997
5998        if (!pfmDetailValue) {
5999            setDefaultPfmDetail();
6000        }
6001
6002        digitalData.pageDetails.pfmDetail = pfmDetailValue;
6003        this.setLSItem('pfmDetail', pfmDetailValue);
6004
6005        // set recommendation type
6006        const recommendationType = this.getRecommendationType(digitalData.pageDetails.pfmDetail);
6007        this.setRecommendationType(recommendationType);
6008    };
6009
6010    /**
6011     * Initializes placement and mediaType on pdp pages
6012     */
6013    this.initPDPPlacementMediaType = function () {
6014        if (this.isPdp()) {
6015            digitalData.pageFilter.placement = this.handleGetLSValue('analyticsProductPlacement') || 'R01#S01';
6016            digitalData.pageFilter.mediaType = this.handleGetLSValue('analyticsMediaType') || 'product-details';
6017        }
6018    }
6019
6020    this.addAllBundleItemsToCart = function (items, cartId, source = 'bundle-products', calledBy = 'bundleCTA') {
6021        let itemsToAdd = [];
6022        let itemsToUpdate = [];
6023        // Fetch cart from localStorage
6024        let cartData = AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('abCart'));
6025        let cart = cartData && cartData.cart ? cartData.cart : cartData;
6026        let cartItems = cart?.abs?.cartItems || cart?.cartItems || [];
6027        // Helper function robustly checks if product is in cart
6028        const isProductInCart = (productId) => {
6029            return cartItems.some((item) => item.id == productId || item.itemId == productId);
6030        };
6031        // Set eVar12 manually
6032        digitalData.pageFilter.pfmSource = source;
6033        // Iterate through items
6034        items.forEach((item) => {
6035            const isInCart = isProductInCart(item.id);
6036            const productInfo = this.getProductInfoObject(item);
6037            if (isInCart) {
6038                // Prepare for quantity update
6039                itemsToUpdate.push({ ...productInfo, deltaQty: item.qty || 1 });
6040            } else {
6041                // Prepare for add to cart
6042                itemsToAdd.push(productInfo);
6043            }
6044        });
6045        // Update cart type, cart, and cartId before analytics calls
6046        window['AB']['DATALAYER'].updateCartType(calledBy === 'minicart' ? 'mini_cart' : '');
6047        window['AB']['DATALAYER'].updateCart(cartItems, itemsToAdd[0] || itemsToUpdate[0] || {}, cart.isWYSIWYGEnabled, false);
6048        window['AB']['DATALAYER'].updateCartId(cartId);
6049        let itemsAddedToCart = this.setItemDataFromCartList(cartItems);
6050        let updatedCartObj = {
6051            cartWithBundleItems: itemsAddedToCart
6052        };
6053        localStorage.setItem('analyticsBundleCartUpdate', JSON.stringify(updatedCartObj));
6054        // Batch analytics calls for add
6055        itemsToAdd.forEach((item) => {
6056            AB.DATALAYER.addItemToCart(item, cartId, source, cart);
6057        });
6058        // Batch analytics calls for update
6059        itemsToUpdate.forEach((item) => {
6060            AB.DATALAYER.increaseItemQuantity(item, cart, item.deltaQty);
6061        });
6062    };
6063
6064    this.addAllBIAItemsToCart = function (items, caller, cartId, calledBy) {
6065        const pageDetails = { ...digitalData.pageDetails };
6066        let itemsToAdd = [];
6067        let cartProducts = [];
6068        let linkClickName = caller === 'quickAdd' ? 'add-products-to-cart' : caller === 'qs-component' ? 'bia:instant-basket:add-all-to-cart' : 'no-value';
6069        if (caller === 'quickAdd' || caller === 'quickAdd-topCTA') {
6070            let quickAddProductsId = AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('quickAddBasket'))?.cartItemsList ? AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('quickAddBasket')).cartItemsList : [];
6071            let quickAddItems = items.cartItems.filter(i => quickAddProductsId.some(i2 => parseInt(i2.itemId) === i.itemId));
6072            itemsToAdd = quickAddItems;
6073            cartProducts = items.cartItems;
6074            cartId = items.cartId;
6075        } else if (caller === 'qs-component') {
6076            itemsToAdd = items;
6077            if (AB.DATALAYER.getLSItem('abCart')) {
6078                cartProducts = AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('abCart')).cart?.abs?.cartItems ? AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('abCart')).cart.abs.cartItems : AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('abCart')).cartItems ? AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('abCart')).cartItems : [];
6079            }
6080        }
6081        const lastIndex = itemsToAdd.length - 1;
6082        let itemsAddedToCart = this.setItemDataFromCartList(cartProducts);
6083        let quickAddItemsTop = [];
6084        itemsToAdd.forEach((item, index) => {
6085            setTimeout(() => {
6086                if (item.name) {
6087                    let productInfoObj = {
6088                        id: item.id || item.itemId,
6089                        productID: item.id || item.itemId,
6090                        name: item.name,
6091                        productName: item.name,
6092                        fullName: item.fullName,
6093                        units: item.qty,
6094                        unitType: item.unitQuantity,
6095                        lbs: '0',
6096                        each: '0',
6097                        pricePerUnit: item.pricePer?.toString(),
6098                        basePrice: item.basePrice?.toString(),
6099                        listPrice: item.price?.toString(),
6100                        price: item.price,
6101                        totalPrice: item.price?.toString(),
6102                        carouselSection: '',
6103                        pricingType: item.promoType,
6104                        couponFlag: '0',
6105                        couponClipped: '0',
6106                        couponID: '',
6107                        aisleId: item.aisleId,
6108                        upc: item.upc,
6109                        isMTO: item.isMtoProduct,
6110                        isCrossSell: false,
6111                        isPastPurchased: true,
6112                        departmentName: item.departmentName
6113                    };
6114                    if (item.unitQuantity == 'EACH') {
6115                        productInfoObj.each = item.quantity ? item.quantity.toString() : item.qty?.toString();
6116                    }
6117                    let updatedCartObj = {
6118                        biaItems: itemsAddedToCart
6119                    };
6120
6121                    window['AB']['DATALAYER'].updateCartType(calledBy === 'minicart' ? 'mini_cart' : '');
6122                    AB.DATALAYER.updateCart(itemsAddedToCart, productInfoObj, items.isWYSIWYGEnabled, true);
6123                    AB.DATALAYER.updateCartId(cartId);
6124                    localStorage.setItem('analyticsBIACartUpdate', JSON.stringify(updatedCartObj));
6125                    AB.DATALAYER.setRecommendationType('past-purchase');
6126                    if (caller !== 'quickAdd-topCTA') {
6127                        AB.DATALAYER.addItemToCart(productInfoObj);
6128                    } else {
6129                        let qckAddProductInfo = AB.DATALAYER.getProductInfo(item) || {};
6130                        quickAddItemsTop.unshift(qckAddProductInfo);
6131                    }
6132                    itemsAddedToCart.unshift(productInfoObj);
6133                    if (index === lastIndex && caller !== 'quickAdd-topCTA') {
6134                        AB.DATALAYER.setLinkClickEvents(linkClickName);
6135                        localStorage.removeItem('analyticsBIACartUpdate');
6136                    } else if (index === lastIndex && caller === 'quickAdd-topCTA') {
6137                        digitalData.cart = digitalData.cart || {};
6138                        digitalData.cart.quickAddItemsTop = quickAddItemsTop;
6139                        AB.DATALAYER.pushEvent(
6140                            this.EVENTS.LINK_CLICK, {
6141                            link: {
6142                                linkName: 'cart_add_all'
6143                            },
6144                            page: pageDetails,
6145                            cart: digitalData.cart
6146                        }
6147                        );
6148                    }
6149                }
6150            }, 500);
6151        });
6152    }
6153
6154    /**
6155    * Sets the pfmDetail for all prroducts added to cart and sends the link click event for add all items to cart on instore receipt details page
6156    * @param selectedReceipt receipt data object
6157    * @param cartResponse cart Response after add to cart action
6158    */
6159    this.addAllInstoreReceiptItemsToCart = function (selectedReceipt, cartResponse) {
6160        const receiptItems = selectedReceipt?.items;
6161        const cartItems = [];
6162        cartResponse.forEach(cart => cartItems.push(...cart.cartItemsList));
6163        let itemsAddedToCart = cartItems.filter(item => receiptItems.find(({ bpn }) => bpn == item.itemId));
6164        const noOfItemsAddedToCart = itemsAddedToCart.length;
6165        const cartModified = {
6166            cart: cartResponse
6167        }
6168
6169        if (window.digitalData) {
6170            digitalData.modal = digitalData.modal || {};
6171            digitalData.modal.modalMessage = `toast-message|${noOfItemsAddedToCart}-actual-items-were-added-to-cart`;
6172            digitalData.pageFilter = digitalData.pageFilter || {};
6173            digitalData.pageFilter.orderID = selectedReceipt?.transactionId;
6174        }
6175        const receiptProducts = this.setItemDataFromCartList(itemsAddedToCart);
6176        receiptItems.forEach(item => {
6177            const cartItem = receiptProducts.find(rItem => rItem.productID == item.bpn);
6178            const cartItemIndex = receiptProducts.findIndex(rItem => rItem.productID == item.bpn);
6179            const cartObj = cartResponse.find(cart => cart.cartItemsList.filter(cItem => cItem.itemId == item.bpn)?.length > 0);
6180            if (cartItem && cartItem.name && cartItemIndex >= 0) {
6181                const placement = cartItemIndex + 1 <= 9 ? `r0${cartItemIndex + 1}#s01` : `r${cartItemIndex + 1}#s01`
6182                AB.DATALAYER.setLSItem('instoreReceiptProductPlacement', placement)
6183                const productInfoObj = this.getProductInfoObject(cartItem);
6184                AB.DATALAYER.updateCart(cartModified, productInfoObj, cartObj.isWYSIWYGEnabled, false);
6185                AB.DATALAYER.updateCartId(cartObj.cartId);
6186                AB.DATALAYER.setRecommendationType('not-recommended');
6187                AB.DATALAYER.addItemToCart(productInfoObj);
6188            }
6189        })
6190        AB.DATALAYER.removeLSItem('instoreReceiptProductPlacement')
6191        AB.DATALAYER.pushEvent(
6192            this.EVENTS.LINK_CLICK, {
6193            link: {
6194                linkName: 'account|add-all-to-cart'
6195            },
6196            page: digitalData?.pageDetails,
6197            pageFilter: digitalData?.pageFilter,
6198            user: digitalData?.user,
6199            productInfo: digitalData?.productInfo,
6200            modal: digitalData?.modal,
6201            receiptItems: receiptProducts
6202        }
6203        )
6204    }
6205
6206    this.setItemDataFromCartList = function (ItemArray) {
6207        const products = [];
6208        ItemArray.forEach(item => {
6209            if (item.name) {
6210                products.push(this.getProductInfoObject(item));
6211            }
6212        })
6213        return products
6214    }
6215
6216    this.getProductInfoObject = function (item) {
6217        let cartItem = {
6218            id: item.id || item.itemId,
6219            productID: item.id || item.itemId,
6220            name: item.name,
6221            productName: item.name,
6222            fullName: item.name || item.fullName,
6223            units: item.qty,
6224            unitType: item.unitQuantity,
6225            lbs: '0',
6226            each: '0',
6227            pricePerUnit: item?.pricePer?.toString(),
6228            basePrice: item?.basePrice?.toString(),
6229            listPrice: item?.price?.toString(),
6230            price: item.price,
6231            totalPrice: (item.price * item.qty)?.toString(),
6232            carouselSection: '',
6233            pricingType: item.promoType,
6234            couponFlag: '0',
6235            couponClipped: '0',
6236            couponID: '',
6237            aisleId: item.aisleId,
6238            upc: item.upc,
6239            isMTO: item.isMtoProduct,
6240            isCrossSell: false,
6241            sellerId: item.sellerId || AB.DATALAYER.getBannerSellerId(),
6242            isPastPurchased: item['pastPurchased'] || true,
6243            departmentName: item.departmentName
6244        };
6245        if (item.unitQuantity == 'EACH') {
6246            cartItem.each = item.quantity ? item.quantity?.toString() : item.qty?.toString();
6247        }
6248        return cartItem;
6249    }
6250
6251}).call(AB.DATALAYER);
6252
6253'use strict';
6254
6255(function () {
6256    this.trackEliteSlots = function (data) {
6257        const eliteSlotsValues = ['flash', 'flash_unavailable', 'premium', 'best', 'fastest'];
6258        const eliteSlotSubstring = `${this.isCartAndCheckoutPage('prebook') ? 'prebook' : 'checkout'}-slot-`;
6259        let eliteSlotsAvailable = [];
6260        let eliteSlotsFromAPI = [];
6261        const slotsArray = data?.eliteSlots?.fulfillmentType?.delivery || data?.fulfillmentType?.delivery || [];
6262        if (slotsArray.length > 0) {
6263            slotsArray.forEach(slot => eliteSlotsFromAPI.push(slot?.type?.toLowerCase()));
6264        }
6265
6266        if (eliteSlotsFromAPI.length > 0) {
6267            eliteSlotsFromAPI.forEach(slotType => {
6268                if (slotType && eliteSlotsValues.indexOf(slotType) !== -1 && !(slotType?.toLowerCase() === 'fastest' && eliteSlotsFromAPI.indexOf('flash_unavailable') === -1 && this.isCartAndCheckoutPage('prebook'))) {
6269                    eliteSlotsAvailable.push(`${eliteSlotSubstring}${slotType?.toLowerCase() === 'flash_unavailable'
6270                        ? 'flash' : slotType?.toLowerCase() === 'best'
6271                            ? 'best-value' : slotType?.toLowerCase()}`);
6272                }
6273            });
6274        }
6275
6276        digitalData.pageFilter.impressions = eliteSlotsAvailable.length > 0
6277            ? (digitalData.pageFilter.impressions ? `${digitalData.pageFilter.impressions},${eliteSlotsAvailable.join(',')}` : eliteSlotsAvailable.join(',')) :
6278            (digitalData.pageFilter.impressions ? `${digitalData.pageFilter.impressions},${eliteSlotSubstring}more-delivery-times` : `${eliteSlotSubstring}more-delivery-times`);
6279    }
6280
6281    this.setPaymentMethodPaypal = function (caller, paymentMethod) {
6282        if (caller === 'checkout') {
6283            const isContinueClicked = this.handleGetLSValue('continueButtonClicked');
6284            if ((digitalData.pageDetails.subSection2 === 'checkout_step3' || digitalData.pageDetails.subSection2 === 'checkout_step4') && isContinueClicked && paymentMethod) {
6285                digitalData.pageFilter.impressions = `${digitalData.pageFilter.impressions ? `${digitalData.pageFilter.impressions},` : ''}chkout-paypal`;
6286            }
6287        } else if (caller === 'edit_checkout' && paymentMethod) {
6288            digitalData.pageFilter.impressions = `${digitalData.pageFilter.impressions ? `${digitalData.pageFilter.impressions},` : ''}edit-order-paypal`;
6289        }
6290    }
6291
6292    this.sendCOALinkEvent = function (appliedCoa, coaBalance, orderSummaryEstimatedTotal) {
6293        let coaLabel = '';
6294        switch (true) {
6295            case (appliedCoa > 0 && appliedCoa === coaBalance):
6296                coaLabel = `credit-on-account-applied-${(coaBalance - orderSummaryEstimatedTotal) > 0 ? 'partial' : 'full'}-credit`;
6297                break;
6298            case (appliedCoa > 0 && coaBalance === 0):
6299                coaLabel = 'credit-on-account-applied-full-credit';
6300                break;
6301            case (appliedCoa > 0 && appliedCoa < coaBalance):
6302                coaLabel = 'credit-on-account-applied-partial-credit';
6303                break;
6304            case appliedCoa === 0:
6305                coaLabel = 'Credit-on-account-no-credit-applied';
6306                break;
6307
6308        }
6309        this.setLinkClickEvents(`checkout|${coaLabel}`);
6310    }
6311
6312    this.checkoutMoreDeliveryTimesLinkClick = function () {
6313        if (digitalData) {
6314            digitalData.pageDetails.subSection3 = 'more-delivery-times';
6315            this.pushEvent(this.EVENTS.LINK_CLICK, {
6316                link: {
6317                    linkName: 'checkout-more-delivery-times'
6318                },
6319                page: digitalData?.pageDetails,
6320                pageFilter: digitalData?.pageFilter,
6321                user: digitalData?.user,
6322                cart: digitalData?.cart
6323            });
6324        }
6325    }
6326
6327    this.applyPromoCodeLinkClick = function (promoCode) {
6328        if (digitalData) {
6329            this.pushEvent(this.EVENTS.LINK_CLICK, {
6330                link: {
6331                    linkName: 'checkout|promocode'
6332                },
6333                modal: {
6334                    modalMessage: `checkout|${promoCode}`
6335                },
6336                page: digitalData?.pageDetails,
6337                pageFilter: digitalData?.pageFilter,
6338                user: digitalData?.user
6339            });
6340        }
6341    }
6342
6343    this.setLinkClickToastMessage = function (modalMessage) {
6344        if (modalMessage) {
6345            let modalMessageLC = modalMessage.toLowerCase();
6346            if (modalMessageLC.indexOf('freshpass') === -1) {
6347                this.pushEvent(this.EVENTS.LINK_CLICK, {
6348                    link: {
6349                        linkName: 'toast-message'
6350                    },
6351                    modal: {
6352                        modalMessage: `toast-message|${modalMessage}`
6353                    },
6354                    page: digitalData?.pageDetails,
6355                    pageFilter: digitalData?.pageFilter,
6356                    user: digitalData?.user
6357                });
6358            }
6359        }
6360    }
6361
6362    this.setActiveCartsModalView = function (cartData) {
6363        if (cartData) {
6364            let activeCarts = [];
6365            cartData.forEach(cart => {
6366                if (cart.seller) {
6367                    activeCarts.push(cart.seller.sellerName);
6368                } else if (cart.cartCategory === '1P_WINE') {
6369                    activeCarts.push('wineshop');
6370                } else {
6371                    activeCarts.unshift(cart.banner);
6372                }
6373            });
6374            const modalAction = `view|active-carts-${activeCarts.join(',')}`;
6375            this.setModalViewEvents(modalAction);
6376        }
6377    }
6378
6379    this.setActiveCartsModalClick = function (cart) {
6380        const cartClicked = cart?.seller?.sellerName ? cart.seller.sellerName : cart?.cartCategory === '1P_WINE' ? 'wineshop' : cart?.banner;
6381        this.setModalClickEvents(`active-carts-${cartClicked}`);
6382    }
6383
6384
6385    // Full Cart methods
6386    this.updateScheduleAndSaveInfo = function (items) {
6387        if (items.some(item => item.isArProduct)) {
6388            digitalData.cart.cartInfo.scheduleAndSaveUnchecked = items.filter(item => item.isArProduct && item.isAvailable && item.price > 0 && (!item.snsSub || !item.snsSub.isSnsSub))?.length?.toString();
6389            const scheduledProducts = items.filter(item => item.isArProduct && item.isAvailable && item.price > 0 && item.snsSub && item.snsSub.isSnsSub)?.length?.toString();
6390            this.setLSItem('analyticsscheduledProducts', scheduledProducts);
6391            digitalData.pageFilter.impressions = `${digitalData.pageFilter.impressions ? `${digitalData.pageFilter.impressions},` : ''}sschkd:${scheduledProducts}`;
6392        }
6393        digitalData.cart.cartInfo.eligiblescheduleAndSaveproducts = items.filter(item => item.isArProduct && item.isAvailable && item.price > 0)?.length?.toString();
6394    }
6395
6396    this.initScheduledItemsImpressions = function () {
6397        if ((this.isCartAndCheckoutPage('erums/checkout') || this.isDFTAPage()) && digitalData?.cart?.cartInfo) {
6398            digitalData.cart.cartInfo.scheduledProducts = this.handleGetLSValue('analyticsscheduledProducts');
6399        }
6400    }
6401
6402    this.setPromoBannerImpressions = function (cart) {
6403        if (Number(localStorage.getItem('abOrderCount')) == 0 && cart?.cartCategory === '1P') {
6404            digitalData.pageFilter = digitalData.pageFilter || {};
6405            digitalData.pageFilter.impressions = `${digitalData.pageFilter.impressions ? `${digitalData.pageFilter.impressions},` : ''}cart-promo-banner-${cart?.serviceType?.toLowerCase() === 'delivery' ? 'save20' : 'save30'}`;
6406            this.setLSItem('analyticsPromoBannerView', 'checkout-promo-banner-visible');
6407        }
6408    }
6409
6410    this.setPromoBannerInfo = function () {
6411        const modalMessagePromoBanner = digitalData.crossPageData?.promoBannerView?.data || this.handleGetLSValue('analyticsPromoBannerView');
6412        if (modalMessagePromoBanner) {
6413            const { pageFilter, modal } = digitalData;
6414            if (pageFilter?.promoCode && (pageFilter.promoCode.includes('SAVE20') || pageFilter.promoCode.includes('SAVE30'))) {
6415                modal.modalMessage = modal.modalMessage ? `${modal.modalMessage},${modalMessagePromoBanner}` : modalMessagePromoBanner;
6416            }
6417            this.setAnalyticsCrossPageData({ action: 'remove', name: 'promoBannerView' });
6418        }
6419    }
6420
6421    this.initMkpGoToCart = function () {
6422        if (localStorage.getItem('analyticsMkpGoToCart')) {
6423            digitalData.pageFilter = digitalData.pageFilter || {};
6424            digitalData.pageFilter.topNav = localStorage.getItem('analyticsMkpGoToCart');
6425            this.removeLSItem('analyticsMkpGoToCart');
6426        }
6427    }
6428
6429    this.initCart = function (cart, isEditCart) {
6430        if (digitalData.crossPageData?.subsShouldSendCartEvent?.data) {
6431            AB.DATALAYER.setAnalyticsCrossPageData({ action: 'remove', name: 'subsShouldSendCartEvent' });
6432            return;
6433        }
6434        if (AB.DATALAYER.initCartAndCheckoutPages) {
6435            AB.DATALAYER.initCartAndCheckoutPages();
6436        }
6437        const isSelectiveCart = cart?.selectiveCartBannerEnabled && cart?.selectiveCartEnabled && AB.DATALAYER.analyticsGetURLParameterByName('selective') == 'true';
6438        window['analyticsCartnumber'] = window['analyticsNumberOfCarts'] == 1 ? 1 : isSelectiveCart ? window['analyticsNumberOfCarts'] : window['analyticsCartnumber'] && window['analyticsNumberOfCarts'] && window['analyticsNumberOfCarts'] > 1 && window['analyticsCartnumber'] < window['analyticsNumberOfCarts'] ? Number(window['analyticsCartnumber']) + 1 : window['analyticsCartnumber'] && window['analyticsNumberOfCarts'] && window['analyticsCartnumber'] == window['analyticsNumberOfCarts'] ? window['analyticsCartnumber'] : 1;
6439
6440        window['analyticsSellerIds'] = window['analyticsSellerIds'] ? window['analyticsSellerIds'] : localStorage.getItem('analyticsSellerIds') && localStorage.getItem('analyticsSellerIds').split(',').length > 0 ? localStorage.getItem('analyticsSellerIds').split(',') : [];
6441        digitalData.cart.marketplace = digitalData.cart.marketplace || {};
6442        digitalData.cart.cartInfo.cartIDMap = digitalData.cart.cartInfo.cartIDMap || {};
6443
6444        if (Object.keys(digitalData.cart.marketplace).length === 0 && localStorage.getItem('analyticsSellerCartsInfo') && localStorage.getItem('analyticsSellerCartsInfo') !== 'undefined') {
6445            digitalData.cart.marketplace = AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('analyticsSellerCartsInfo'));
6446        }
6447        digitalData.cart.sellerCarts = digitalData.cart.sellerCarts || [];
6448
6449        AB.DATALAYER.updateCartType(isSelectiveCart ? 'selective_cart' : 'Full_Cart');
6450        AB.DATALAYER.setCartObj(cart, null, false, isEditCart);
6451        if (isSelectiveCart) {
6452            digitalData.pageFilter.topNav = AB.DATALAYER.initTopNav();
6453            digitalData.pageDetails.subSection2 = 'selective-cart';
6454            AB.DATALAYER.setPageName(false, true);
6455            this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsFeatureTracking', data: 'selectiveCartACIP462764' });
6456        } else {
6457            digitalData.pageDetails.subSection2 = '';
6458        }
6459        this.setPromoBannerImpressions(cart);
6460
6461        //if there is a banner related to the 'Disclaimer for WA DUG orders containing Alcohol' add alcohol-disclaimer to impressions
6462        if (cart?.alcDisclamer && cart?.serviceType?.toLowerCase() === 'dug') {
6463            digitalData.pageFilter.impressions = digitalData.pageFilter.impressions
6464                ? `${digitalData.pageFilter.impressions},alcohol-disclaimer`
6465                : 'alcohol-disclaimer';
6466        }
6467
6468        if ((window['analyticsNumberOfCarts'] && Number(window['analyticsCartnumber']) === Number(window['analyticsNumberOfCarts'])) || (!window['analyticsNumberOfCarts'])) {
6469            digitalData.pageDetails.sellerId = window['analyticsSellerIds'].join(',');
6470            digitalData.cart.cartInfo.currentCartId =
6471                digitalData.cart.cartInfo.cartIDMap
6472                    ? Object.values(digitalData.cart.cartInfo.cartIDMap).join()
6473                    : '';
6474            sellerCartsCombined = Array.prototype.concat.apply([], Object.values(digitalData.cart.sellerCarts));
6475            digitalData.cart.item = (digitalData.cart?.absItems && Array.isArray(digitalData.cart.absItems) ? digitalData.cart.absItems : []).concat(sellerCartsCombined);
6476            if (digitalData.cart.marketplace && Object.keys(digitalData.cart.marketplace).length > 0) {
6477                for (let i = 1; i <= 8; i++) {
6478                    if (digitalData.cart.marketplace[`seller${i}`] && window['analyticsSellerIds'].indexOf(digitalData.cart.marketplace[`seller${i}`].sellerId) === -1) {
6479                        delete digitalData.cart.marketplace[`seller${i}`];
6480                    }
6481                }
6482                localStorage.setItem('analyticsSellerCartsInfo', JSON.stringify(window.digitalData.cart.marketplace));
6483                this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsSellerCartsInfo', data: window.digitalData.cart.marketplace, isAcrossPages: true });
6484            }
6485            this.setLSItem('analyticsSellerCartsInfo', JSON.stringify(digitalData.cart.marketplace));
6486            AB.DATALAYER.setPreviousPageName();
6487            AB.DATALAYER.setRestrictedPageCnc();
6488
6489            this.pushEvent(isEditCart ? AB.DATALAYER.EVENTS.EDIT_CART : isSelectiveCart ? AB.DATALAYER.EVENTS.SELECTIVE_CART : AB.DATALAYER.EVENTS.FULL_CART, {
6490                page: digitalData.pageDetails,
6491                pageFilter: digitalData.pageFilter,
6492                user: digitalData.user,
6493                productInfo: digitalData.productInfo,
6494                modal: digitalData.modal,
6495                cart: digitalData.cart
6496            });
6497        }
6498    }
6499
6500    this.resetPfmDetailsAndMartechInfo = function () {
6501        if (digitalData?.martech) {
6502            delete digitalData.martech;
6503        }
6504        if (digitalData?.productInfo?.pfmDetail) {
6505            delete digitalData.productInfo.pfmDetail;
6506        }
6507        if (digitalData?.pageFilter) {
6508            delete digitalData.pageFilter?.mediaType;
6509            delete digitalData.pageFilter?.placement;
6510            delete digitalData.pageFilter?.recommendationType;
6511        }
6512    }
6513
6514    this.sendUndoAnalytics = function (cartData, cartItem, addRemovedItemToCart) {
6515        if (addRemovedItemToCart === true && cartItem) {
6516            let qty = cartItem.qty ? cartItem.qty : cartItem.quantity;
6517            if (qty > 0) {
6518                for (let i = 0; i < qty; i++) {
6519                    if (i === 0) {
6520                        this.addItemToCart(cartItem, undefined, undefined, cartData, 1, true);
6521                        this.resetPfmDetailsAndMartechInfo();
6522                    } else {
6523                        this.increaseItemQuantity(cartItem, cartData, 1, true);
6524                    }
6525                }
6526            }
6527        }
6528    }
6529
6530    this.initCoupons = function (couponCount, couponsApplied) {
6531        digitalData.cart.savings.totalCoupons = couponCount + '';
6532        digitalData.cart.savings.couponsApplied = couponsApplied + '';
6533    }
6534
6535    /**
6536     * Substitution impressions on modal view
6537     */
6538    this.setSubstitutionImpressionClick = function (substitutionData, substitutePreference) {
6539        let productID = window.sessionStorage.getItem('analytics_subs_prodId') || '';
6540        const substitution = [];
6541        substitutionData?.forEach((product, i) => {
6542            substitution.push({
6543                isSubstitution: product?.Subflag ? 'true' : 'false',
6544                productID: productID,
6545                substitutionOption: `${substitutePreference}:${product?.id}`,
6546                rowSlot: `r${i + 1 > 9 ? i + 1 : '0' + (i + 1)}#s01`,
6547                impressionAdditionalDetail: product?.adobeMetrics?.metricA || 'no-value#no-value#no-value#no-value#no-value#no-value#no-value',
6548                subsAdditionalDetail: product?.adobeMetrics?.metricB || 'no-value#no-value#no-value#no-value#no-value#no-value#no-value#no-value#no-value'
6549
6550            })
6551        })
6552        if (substitution.length > 0) {
6553            this.pushEvent('linkClick',
6554                {
6555                    link: {
6556                        linkName: 'cart-substitution-impressions'
6557                    },
6558                    productInfo: {
6559                        substitution: substitution
6560                    }
6561                });
6562        }
6563    }
6564
6565    /**
6566     * Substitution impressions on search
6567     * To do: merge substitution impresssion methods
6568     */
6569    this.setSubstitutionImpressionEvent = function (subsImpressionData) {
6570        if (subsImpressionData?.data?.length > 0) {
6571            const substitution = [];
6572            subsImpressionData?.data?.forEach((product, i) => {
6573                substitution.push({
6574                    isSubstitution: `${subsImpressionData?.subConfirmFlag}`,
6575                    productID: subsImpressionData?.productID,
6576                    substitutionOption: `${subsImpressionData?.substitutionValue}:${product?.id}`,
6577                    searchTerm: subsImpressionData?.searchTerm,
6578                    searchResults: subsImpressionData?.searchResults,
6579                    rowSlot: `r${i > 9 ? i : '0' + i}#s01`,
6580                    impressionAdditionalDetail: product?.adobeMetrics?.metricA || 'no-value#no-value#no-value#no-value#no-value#no-value#no-value',
6581                    subsAdditionalDetail: product?.adobeMetrics?.metricB || 'no-value#no-value#no-value#no-value#no-value#no-value#no-value#no-value#no-value#no-value#no-value'
6582                })
6583            })
6584            this.pushEvent(
6585                this.EVENTS.LINK_CLICK, {
6586                link: {
6587                    linkName: 'cart-substitution-impressions'
6588                },
6589                productInfo: {
6590                    substitution: substitution
6591                }
6592            }
6593            );
6594        }
6595    }
6596
6597    this.setCheckoutPaymentAccordion = function (updateTopNav = false) {
6598        digitalData.pageDetails.subSection3 = 'saved-payments';
6599
6600        digitalData.pageFilter.topNav = updateTopNav ? 'cta:checkout|payment|arrow' : '';
6601        const payload = {
6602            link: {
6603                linkName: 'checkout-payment-saved-payments'
6604            }
6605        };
6606        this.pushEvent(this.EVENTS.LINK_CLICK, payload);
6607    }
6608
6609    this.setSnsProductInStorage = function (productId, calledBy) {
6610        const snsProductObject = AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('snsSubscriptionProducts'));
6611        const isFullCartChecked = this.isCartAndCheckoutPage('erums/cart') && (document.querySelector(`#sns-checkbox-${productId}`)?.checked || calledBy === 'frequencyModal');
6612        const isPdpChecked = this.isPdp() && document.querySelector('.product-info[data-pagetype="pdp"] .sns-container input.checkbox__input')?.checked;
6613
6614        if (productId) {
6615            if (isFullCartChecked || isPdpChecked) {
6616                snsProductObject[productId] = isFullCartChecked ? 'full-cart' : isPdpChecked ? 'pdp' : '';
6617            } else if (snsProductObject.hasOwnProperty(productId)) {
6618                delete snsProductObject[productId]
6619            }
6620        }
6621        localStorage.setItem('snsSubscriptionProducts', JSON.stringify(snsProductObject))
6622    }
6623
6624    this.snsFrequencyCheckboxClick = function (linkName, subscribe, item, frequency, isSnSmodal) {
6625        const eventSent = appEventData.some(eventObj => eventObj?.link?.linkName === linkName);
6626        this.setSnsProductInStorage(item?.itemId);
6627        const snsFrequency = frequency ? frequency.toLowerCase().replace(/\s/g, '-') : item?.snsSub?.snsFrequency?.unit?.toLowerCase().replace(/\s/g, '-');
6628        linkName = `${linkName}${subscribe === 'subscribe' && isSnSmodal ? '|subscribed' : ''}`;
6629        if (!eventSent && !isSnSmodal) {
6630            this.pushEvent('linkClick',
6631                {
6632                    link: {
6633                        linkName: linkName
6634                    },
6635                    productInfo: {
6636                        productID: item?.itemId,
6637                        scheduleandSaveSource: `full-cart#${subscribe}#every-${snsFrequency}`
6638                    }
6639                });
6640        }
6641        if (isSnSmodal) {
6642            this.pushEvent('modalClick',
6643                {
6644                    modal: {
6645                        modalAction: linkName,
6646                        modalMessage: frequency === 'week' ? 'frequency-not-modified' : 'frequency-modified'
6647                    },
6648                    productInfo: {
6649                        productID: item?.itemId,
6650                        scheduleandSaveSource: `cart#${subscribe}#every-${snsFrequency}`
6651                    }
6652                });
6653        }
6654        if (linkName === 'ar:unsubscribe-schedule-and-save') {
6655            this.updateScheduledProductsCount('unsubscribe');
6656        }
6657    }
6658
6659    this.getDefautTipping = function (checkout) {
6660        if (checkout.isDriverTippingEnabled && checkout.driverTipInfo?.driverTipOptions) {
6661            const driverTipOptions = checkout.driverTipInfo.driverTipOptions;
6662            const driverTipLookup = driverTipOptions.filter((tip) => { if (tip.tipSelected === true) { return tip } });
6663            const selectedOption = driverTipLookup.length > 0 ? driverTipLookup[0] : {};
6664            const tipPercentage = selectedOption?.tipPercentage ? (selectedOption.tipPercentage.toLowerCase() === 'other' ? 'default' : selectedOption.tipPercentage) : 'no-option';
6665            const tipAmount = selectedOption?.tipAmount && !isNaN(parseFloat(selectedOption?.tipAmount)) ? Number(selectedOption.tipAmount).toFixed(2) : 'zero';
6666            const defaultTippingMode = `${tipPercentage}|${tipAmount}`;
6667            this.setLSItem('analyticsTippingMode', defaultTippingMode);
6668            this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsTippingMode', data: defaultTippingMode, isAcrossPages: true });
6669        }
6670    }
6671
6672    this.totalPromoSavings = function (promotions) {
6673        let totalPromotions = [];
6674        if (promotions && Array.isArray(promotions) && promotions.length > 0) {
6675            promotions.forEach((promotion) => {
6676                totalPromotions.push(promotion.discount || 0);
6677            });
6678        }
6679        return totalPromotions.reduce(AB.DATALAYER.safeReducer, 0);
6680    }
6681
6682    this.allPromoCodes = function (promotions) {
6683        const allPromoCodes = [];
6684        if (promotions && promotions.length) {
6685            promotions.forEach((promotion) => {
6686                allPromoCodes.push(promotion.code);
6687            });
6688        }
6689        return allPromoCodes.toString();
6690    }
6691
6692    this.frequencyModalTracking = function (event, modalAction, item, frequency, modalMessage) {
6693        const subscribe = `${modalAction === 'ar:subscribe-schedule-and-save|view' ? 'un' : ''}subscribe`;
6694        const frequencyModalObj = {
6695            modal: {
6696                modalAction: modalAction,
6697                modalMessage: modalMessage || ''
6698            },
6699            productInfo: {
6700                productID: item?.itemId,
6701                scheduleandSaveSource: `full-cart#${subscribe}#${frequency?.count && frequency?.count !== 1 ? `every-${frequency.count}-weeks` : 'every-1-week'}`
6702            }
6703        }
6704        this.pushEvent(event, frequencyModalObj);
6705        if (modalAction === 'ar:subscribe-schedule-and-save|subscribed') {
6706            this.setSnsProductInStorage(item?.itemId, 'frequencyModal');
6707            this.updateScheduledProductsCount('subscribe');
6708        }
6709    }
6710
6711    this.updateScheduledProductsCount = function (action) {
6712        const scheduledProductsCount = Number(this.getLSItem('analyticsscheduledProducts')) || 0;
6713        const updatedScheduledProductsCount = action === 'unsubscribe' ? scheduledProductsCount - 1 : scheduledProductsCount + 1;
6714        this.setLSItem('analyticsscheduledProducts', updatedScheduledProductsCount);
6715    }
6716
6717    this.setExperimentExposureLoaded = function (carousels) {
6718        carousels.forEach(carousel => {
6719            if (carousel.p13nAdobeMetrics?.msgExperiment) {
6720                this.setP13nExperimentExposure(carousel);
6721            }
6722        });
6723    }
6724
6725    this.setMarketplaceCartInfo = function (orderInfo, orderSummary, cartType) {
6726        if ((orderInfo.seller && orderInfo.seller.sellerName) || (orderInfo.cartCategory === '1P_WINE')) {
6727            const marketplaceCartId = orderInfo.cartId;
6728            const sellerId = orderInfo.seller && orderInfo.seller.sellerId ? orderInfo.seller.sellerId : orderInfo.cartCategory === '1P_WINE' ? '22222222' : AB.DATALAYER.getBannerSellerId();
6729            let marketplaceCartItems;
6730            if (cartType === 'checkout') {
6731                marketplaceCartItems = orderInfo.cartItems || [];
6732            } else {
6733                marketplaceCartItems = orderInfo.orderItems || [];
6734            }
6735            const marketplaceCartTotal = orderSummary.totalBasePrice.toString();
6736            let marketplaceCartSKUs = [];
6737            marketplaceCartItems.forEach(item => {
6738                marketplaceCartSKUs.push(item.itemId);
6739            });
6740            const marketplaceCartInfo = `${sellerId}#${marketplaceCartId}#${cartType}#${marketplaceCartSKUs.join(':')}#${marketplaceCartTotal}`;
6741            if (sellerId === '22222222') {
6742                digitalData.cart.cartInfo.cartIDWineShop = `${sellerId}#${marketplaceCartId}#${cartType}#${marketplaceCartSKUs.join(',')}#${marketplaceCartTotal}`;
6743                digitalData.cart.transaction.subTotalWineCart =
6744                    digitalData.cart.transaction.subTotalWineCart || {};
6745                digitalData.cart.transaction.subTotalWineCart.subTotal = +marketplaceCartTotal;
6746                digitalData.cart.transaction.subTotalWineCart.sellerId = sellerId;
6747            } else if (sellerId && sellerId !== '22222222' && sellerId !== `${AB.DATALAYER.getBannerSellerId()}`) {
6748                digitalData.cart.marketplace = digitalData.cart.marketplace || {};
6749                if (Object.keys(digitalData.cart.marketplace).length === 0 && this.getLSItem('analyticsSellerCartsInfo') && this.getLSItem('analyticsSellerCartsInfo') !== 'undefined') {
6750                    digitalData.cart.marketplace = this.safeJSONParse(this.getLSItem('analyticsSellerCartsInfo')) || digitalData.pageFlags.analyticsSellerCartsInfo.flagValue;
6751                }
6752                for (let i = 1; i <= 8; i++) {
6753                    if (digitalData.cart.marketplace[`seller${i}`] && digitalData.cart.marketplace[`seller${i}`].sellerId === sellerId) {
6754                        digitalData.cart.marketplace[`seller${i}`].sellerCartID = marketplaceCartInfo;
6755                        break;
6756                    }
6757                }
6758                if (digitalData.cart.transaction) {
6759                    const marketplaceCart = digitalData.cart.marketplace;
6760                    for (const key in marketplaceCart) {
6761                        const sellerInfo = marketplaceCart[key];
6762                        const sellerSubTotal = sellerInfo.sellerCartID.split('#').pop();
6763                        const subTotalMarketplaceCarts = digitalData.cart.transaction.subTotalMarketplaceCarts;
6764                        digitalData.cart.transaction.subTotalMarketplaceCarts = subTotalMarketplaceCarts
6765                            ? `${subTotalMarketplaceCarts}#${sellerInfo.sellerId}:${sellerSubTotal}`
6766                            : `${sellerInfo.sellerId}:${sellerSubTotal}`;
6767                    }
6768                }
6769                this.setLSItem('analyticsSellerCartsInfo', JSON.stringify(digitalData.cart.marketplace));
6770                this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsSellerCartsInfo', data: digitalData.cart.marketplace, isAcrossPages: true });
6771            }
6772        }
6773    }
6774
6775    this.getPaymentUpdatedStatus = function () {
6776        const paymentUpdated = this.getLSItem('edit-order-payment-updated') || this.getLSItem('checkout-order-payment-updated') || digitalData.crossPageData?.confirmationPaymentUpdated?.data;
6777        return `${this.isCartAndCheckoutPage('order/confirmation') ? '' : 'edit-'}order-confirmation|payment-arrow-${paymentUpdated ? '' : 'not-'}selected`;
6778    }
6779
6780    this.updateDefaultStoreValues = function (serviceType, deliveryType, premiumSelected, storeId) {
6781        digitalData.user.deliveryPreference = serviceType || '';
6782        digitalData.user.deliveryCombo = deliveryType || '';
6783        digitalData.pageFilter.premiumSlots = premiumSelected || '';
6784        digitalData.user.shopStoreId = storeId?.toString() || '';
6785    }
6786
6787    this.updateSaveSlot = function (slot) {
6788        this.setDeliveryWindow(slot);
6789        this.pushEvent(this.EVENTS.LINK_CLICK, {
6790            link: {
6791                linkName: 'prebook-update'
6792            },
6793            page: digitalData?.pageDetails,
6794            cart: {
6795                transaction: digitalData?.cart?.transaction
6796            },
6797            user: digitalData?.user
6798        });
6799    }
6800
6801    this.updateSlotPlan = function (slotPlanValue) {
6802        digitalData.pageFilter.premiumSlots = slotPlanValue === 'false' ? '' : 'true';
6803    }
6804
6805    this.updateCheckout = function (checkout) {
6806        digitalData.productInfo.substitution = digitalData.productInfo.substitution || {};
6807        const sellerId = checkout?.seller?.sellerId ? checkout.seller.sellerId : checkout?.cartCategory === '1P_WINE' ? '22222222' : AB.DATALAYER.getBannerSellerId();
6808
6809        if (this.getLSItem('erums-referral') || digitalData.crossPageData?.erumsReferral) {
6810            digitalData.pageDetails.referringURL = this.getLSItem('erums-referral') || digitalData.crossPageData?.erumsReferral?.data;
6811        }
6812
6813        if (checkout?.eliteSlots?.fulfillmentType?.delivery && Array.isArray(checkout.eliteSlots.fulfillmentType.delivery) && checkout.eliteSlots.fulfillmentType.delivery.length > 0) {
6814            checkout.eliteSlots.fulfillmentType.delivery.forEach(slot => {
6815                if (slot.type === 'FLASH') {
6816                    this.isFlashSlotAvailable = true;
6817                }
6818            });
6819        }
6820
6821        if (checkout?.slots?.reservedSlot) {
6822            digitalData.pageFilter.premiumSlots = this.getLSItem('dtm-premiumslots') || digitalData.crossPageData?.dtmPremiumslots?.data;
6823        }
6824
6825        digitalData.pageDetails.sellerId = sellerId;
6826        digitalData.user.deliveryPreference = checkout.serviceType || '';
6827        digitalData.user.deliveryCombo = checkout.deliveryType || '';
6828        digitalData.user.shopStoreId = checkout?.storeId?.toString();
6829
6830        if (checkout.orderSummary) {
6831            let summary = checkout.wysiwygOrderSummary || checkout.orderSummary;
6832            digitalData.pageFilter.promoCode = this.allPromoCodes(summary.promotions);
6833
6834            digitalData.cart.transaction.subscriptionStatus = checkout.customerPreferences?.subscriptionType ? checkout.customerPreferences.subscriptionType : 'no subscription';
6835            digitalData.cart.transaction.paymentMethod = (checkout.orderSummary.orderSummary) ? 'cc & coa' : 'cc';
6836
6837            if (checkout?.slots?.reservedSlot) {
6838                let reservedSlotInfo = checkout?.slots?.reservedSlot ? this.safeJSONParse(JSON.stringify(checkout.slots.reservedSlot)) : {};
6839
6840                if (checkout?.slots?.serviceType === 'DUG' && checkout?.slots?.isPickupStore === false) {
6841                    let lastPickupTS = '';
6842                    if (checkout?.slots?.availableSlots && Array.isArray(checkout.slots.availableSlots) && checkout.slots.availableSlots.length > 0) {
6843                        checkout.slots.availableSlots?.forEach(function (s) {
6844                            for (let slot in s) {
6845                                if (s[slot].displayLastPickupTime) {
6846                                    lastPickupTS = s[slot].displayLastPickupTime;
6847                                }
6848                            }
6849                        });
6850                    }
6851                    if (lastPickupTS) {
6852                        reservedSlotInfo['lastPickupTS'] = lastPickupTS;
6853                    }
6854                }
6855                this.setDeliveryWindow(reservedSlotInfo);
6856            }
6857
6858            if (checkout.orderSummary?.deliveryFee) {
6859                digitalData.cart.transaction.shippingFee = !checkout.orderSummary.deliveryFee.feeWaived ? checkout.orderSummary.deliveryFee.actualFee?.toString() : checkout.orderSummary.deliveryFee.currentFee?.toString();
6860            }
6861            if (checkout.orderSummary?.fuelSurcharge) {
6862                digitalData.cart.transaction.fuelSurcharge = !checkout.orderSummary.fuelSurcharge.feeWaived ? checkout.orderSummary?.fuelSurcharge?.actualFee?.toString() : checkout.orderSummary.fuelSurcharge.currentFee?.toString();
6863            }
6864            if (checkout.orderSummary?.serviceFee) {
6865                digitalData.cart.transaction.serviceFee = checkout.orderSummary.serviceFee && !checkout.orderSummary.serviceFee.feeWaived ? checkout.orderSummary?.serviceFee?.actualFee?.toString() : checkout.orderSummary.serviceFee.currentFee?.toString();
6866            }
6867
6868            let totalSavings = summary.totalCardSavings && !isNaN(parseFloat(summary.totalCardSavings)) ? parseFloat(summary.totalCardSavings) : summary.estimatedClubCardSavings && !isNaN(parseFloat(summary.estimatedClubCardSavings)) ? parseFloat(summary.estimatedClubCardSavings) : 0;
6869            let totalPromos = this.totalPromoSavings(summary.promotions);
6870            let totalPrice = summary.totalBasePrice && !isNaN(parseFloat(summary.totalBasePrice)) ? parseFloat(summary.totalBasePrice) : 0;
6871
6872            digitalData.cart.savings.clubcardSavings = totalSavings?.toString();
6873            digitalData.cart.savings.promocodeSavings = totalPromos?.toString();
6874            digitalData.cart.savings.totalSavings = this.cleanPrice(totalSavings + totalPromos)?.toString();
6875            digitalData.cart.cartInfo.totalunits = summary.totalItemQuantity?.toString();
6876            digitalData.cart.transaction.subTotal = totalPrice.toString();
6877            digitalData.cart.transaction.revenue = this.cleanPrice(totalPrice - (totalSavings + totalPromos))?.toString();
6878
6879            this.setMarketplaceCartInfo(checkout, summary, 'checkout');
6880        }
6881
6882        digitalData.cart.cartInfo.cartId = checkout.cartId;
6883        digitalData.cart.cartInfo.currentCartId = checkout?.cartId?.toString();
6884        digitalData.cart.cartInfo.cartType = digitalData.pageDetails.subSection2;
6885        digitalData.productInfo.substitution.isSubstitution = checkout?.['isSubstitutions2Enabled'] || '';
6886
6887        this.getDefautTipping(checkout);
6888        if (this.getLSItem('abOrderCount') || digitalData.crossPageData?.abOrderCount) {
6889            const orderStatus = this.getLSItem('abOrderCount') || digitalData.crossPageData?.abOrderCount?.data;
6890            this.setLSItem('abOrderCountAnalyticsCC', orderStatus);
6891            this.setAnalyticsCrossPageData({ action: 'set', name: 'abOrderCountAnalyticsCC', data: orderStatus, isAcrossPages: true });
6892        }
6893    }
6894
6895    this.updateDigitalData = function ({ checkoutData, ACTION, PAGE } = {}) {
6896        digitalData.productInfo.substitution = digitalData.productInfo.substitution || {};
6897        let fullDeliveryTime = '', actionType = ACTION === 'RESCHEDULE' ? 'reschedule' : 'edit', reservedSlotInfo;
6898        let event = '';
6899        //Here we should call initCartAndCheckoutPages() in order to set the values for this page but for the moment we leave this here
6900
6901        this.initCartAndCheckoutPages();
6902
6903        switch (ACTION) {
6904            case 'CONFIRM':
6905            case 'CANCEL':
6906                digitalData.pageDetails.subSection1 = 'edit order';
6907                digitalData.pageDetails.subSection2 = `edit ${PAGE === 'editSlot' ? 'date and time' : PAGE === 'editCheckout' ? 'order checkout' : ''}`;
6908                this.setPageName('', true, undefined);
6909                event = ACTION === 'CONFIRM' ? 'confirm_changes' : ACTION === 'CANCEL' ? 'cancel_edits' : '';
6910                break;
6911            case 'LOAD':
6912                digitalData.pageDetails.subSection1 = 'edit order';
6913                digitalData.pageDetails.subSection2 = `edit ${PAGE === 'editSlot' ? 'delivery date and time' : 'order '}${PAGE === 'editCheckout' ? 'checkout' : PAGE === 'editCheckoutConfirmation' ? 'confirmation' : ''}`;
6914                event = PAGE === 'editSlot' ? 'edit_order_date_time' : PAGE === 'editCheckout' || PAGE === 'editCheckoutConfirmation' ? digitalData.pageDetails.subSection2.replaceAll(' ', '_') : '';
6915                this.setPageName('', true, undefined);
6916                break;
6917            case 'RESCHEDULE':
6918                digitalData.pageDetails.subSection1 = 'reschedule order';
6919                digitalData.pageDetails.subSection2 = `reschedule ${PAGE === 'expired' ? 'order expired' : 'delivery date and time'}`;
6920                event = this.EVENTS.PAGE_LOADED;
6921                this.setPageName('', true, undefined);
6922                break;
6923        }
6924
6925        digitalData.cart.cartInfo.cartId = '';
6926        digitalData.cart.cartInfo.currentCartId = '';
6927
6928        if (checkoutData.order) {
6929            digitalData.user.deliveryPreference = checkoutData.order.serviceType;
6930            digitalData.user.deliveryCombo = checkoutData.order.deliveryType;
6931            digitalData.user.shopStoreId = checkoutData.order.storeId.toString();
6932            digitalData.cart.transaction.orderID = checkoutData.order.orderId;
6933            digitalData.cart.cartInfo.cartId = checkoutData.order.cartId;
6934            digitalData.cart.cartInfo.currentCartId = checkoutData.order.cartId?.toString();
6935        } else if (checkoutData) {
6936            digitalData.user.deliveryPreference = checkoutData.serviceType;
6937            digitalData.user.deliveryCombo = checkoutData.deliveryType;
6938            digitalData.user.shopStoreId = (checkoutData.storeId || checkoutData.storeInfo.storeId)?.toString();
6939        }
6940        if (checkoutData.orderSummary) {
6941            let summary = checkoutData.wysiwygOrderSummary || checkoutData.orderSummary, totalSavings = 0, totalPromos = this.totalPromoSavings(summary.promotions);
6942
6943            digitalData.pageFilter.promoCode = this.allPromoCodes(checkoutData.orderSummary.promotions);
6944
6945            digitalData.cart.transaction.orderID = checkoutData.orderId ? checkoutData.orderId : '';
6946            if (checkoutData.orderSummary.deliveryFee) {
6947                digitalData.cart.transaction.shippingFee = (!checkoutData.orderSummary.deliveryFee.feeWaived) ? checkoutData.orderSummary.deliveryFee.actualFee?.toString() : checkoutData.orderSummary.deliveryFee.currentFee?.toString();
6948            }
6949            if (checkoutData.orderSummary.fuelSurcharge) {
6950                digitalData.cart.transaction.fuelSurcharge = (!checkoutData.orderSummary.fuelSurcharge.feeWaived) ? checkoutData.orderSummary.fuelSurcharge.actualFee?.toString() : checkoutData.orderSummary.fuelSurcharge.currentFee?.toString();
6951            }
6952            if (checkoutData.orderSummary.serviceFee) {
6953                digitalData.cart.transaction.serviceFee = (checkoutData.orderSummary.serviceFee && !checkoutData.orderSummary.serviceFee.feeWaived) ? checkoutData.orderSummary.serviceFee.actualFee?.toString() : checkoutData.orderSummary.serviceFee.currentFee?.toString();
6954            }
6955            digitalData.cart.transaction.deliveryTime = fullDeliveryTime;
6956            digitalData.cart.transaction.paymentMethod = (checkoutData.orderSummary.orderSummary) ? 'cc & coa' : 'cc';
6957
6958            totalSavings = (summary.cardSavings || summary.totalCardSavings !== undefined) ? summary.totalCardSavings : summary.estimatedClubCardSavings;
6959
6960            digitalData.cart.savings.clubcardSavings = totalSavings?.toString();
6961            digitalData.cart.savings.promocodeSavings = totalPromos?.toString();
6962            digitalData.cart.savings.totalSavings = this.cleanPrice(totalSavings + totalPromos)?.toString();
6963
6964            digitalData.cart.transaction.subTotal = summary.totalBasePrice?.toString();
6965            digitalData.cart.cartInfo.totalUnits = summary.totalItemQuantity?.toString();
6966            digitalData.cart.transaction.revenue = this.cleanPrice(summary.totalBasePrice - (totalSavings + totalPromos))?.toString();
6967
6968        }
6969        digitalData.cart.cartInfo.cartType = actionType + '_date_time';
6970
6971        if (checkoutData.order) {
6972            if (checkoutData.order.orderId.length) {
6973                event = 'edit_order_confirmation';
6974                digitalData.cart.transaction.editOrderID = `${checkoutData.order.orderId}|${checkoutData.order.versionNumber}`;
6975            }
6976            if (checkoutData.order.orderItems.length) {
6977                digitalData.cart.item = this.getAllItems(checkoutData.order);
6978            }
6979        }
6980        reservedSlotInfo = checkoutData?.order?.deliveryInfo?.slotInfo ? AB.DATALAYER.safeJSONParse(JSON.stringify(checkoutData.order.deliveryInfo.slotInfo)) : checkoutData?.deliveryInfo?.slotInfo ? AB.DATALAYER.safeJSONParse(JSON.stringify(checkoutData.deliveryInfo.slotInfo)) : {};
6981
6982        if (reservedSlotInfo) {
6983            if ((checkoutData.serviceType === 'DUG' && checkoutData.isPickupStore === false) || (checkoutData.order?.serviceType === 'DUG' && checkoutData.order?.isPickupStore === false)) {
6984                reservedSlotInfo['lastPickupTS'] = reservedSlotInfo['displayLastPickupTime'];
6985            }
6986            this.setDeliveryWindow(reservedSlotInfo);
6987        }
6988
6989        if (event === 'edit_order_checkout') {
6990            const isPaypalPayment = checkoutData.customerPreferences?.fundsAllocation?.tenderAllocationSummary?.some((x) => x.paymentSubType === 'PAYPAL')
6991            this.setPaymentMethodPaypal('edit_checkout', isPaypalPayment)
6992        } else if (event === 'edit_order_confirmation') {
6993            digitalData.cart.transaction.paymentMethod = this.getPaymentMethod(checkoutData.order.payments).method;
6994        }
6995        AB.DATALAYER.setPreviousPageName();
6996        if (event === 'edit_cart' || event === 'edit_order_confirmation') {
6997            AB.DATALAYER.setRestrictedPageCnc();
6998        }
6999
7000        this.pushEvent(
7001            event, {
7002            page: digitalData?.pageDetails,
7003            pageFilter: digitalData?.pageFilter,
7004            user: digitalData?.user,
7005            productInfo: digitalData?.productInfo,
7006            modal: digitalData?.modal,
7007            cart: digitalData?.cart
7008        }
7009        );
7010    }
7011
7012    this.confirmationPage = function ({ orderData, isRoktEnabled } = {}) {
7013        const { pageDetails, pageFilter, user, cart, crossPageData } = digitalData;
7014
7015        this.initCartAndCheckoutPages({ pageSpecificData: orderData });
7016
7017        const order = orderData.order,
7018            isWysiwyg = orderData.isWYSIWYGEnabled,
7019            orderSummary = orderData.wysiwygOrderSummary;
7020
7021        pageDetails.sellerId = order?.seller?.sellerId ? order?.seller?.sellerId : order?.cartCategory === '1P_WINE' ? '22222222' : AB.DATALAYER.getBannerSellerId();
7022        pageFilter.premiumSlots = this.getLSItem('dtm-premiumslots') || crossPageData?.dtmPremiumslots?.data || '';
7023
7024        cart.isWYSIWYGEnabled = orderData.isWYSIWYGEnabled;
7025        cart.transaction.orderID = order.orderId;
7026        cart.cartInfo.cartId = order.cartId || '';
7027        cart.cartInfo.currentCartId = order?.cartId?.toString() || '';
7028        if (order?.snsSubExists === true) {
7029            cart.cartInfo.scheduleandsaveproducts = order.snsSubCount || '';
7030        }
7031        if (order.deliveryInfo?.slotInfo?.displayStartTS) {
7032            let reservedSlotInfo = order?.deliveryInfo?.slotInfo ? AB.DATALAYER.safeJSONParse(JSON.stringify(order.deliveryInfo.slotInfo)) : {};
7033            if (order.serviceType === 'DUG' && order.isPickupStore === false && reservedSlotInfo.displayLastPickupTime) {
7034                reservedSlotInfo['lastPickupTS'] = reservedSlotInfo['displayLastPickupTime'];
7035            }
7036            this.setDeliveryWindow(reservedSlotInfo);
7037        }
7038
7039        user.shopStoreId = order.storeId;
7040        user.deliveryPreference = order.serviceType;
7041        user.deliveryCombo = order.deliveryType;
7042        user.isGiftOrder = order.deliveryInfo?.gift?.isGift;
7043        cart.transaction.deliverySlotType = sessionStorage.getItem('elite_tag') || 'more-delivery-times';
7044
7045        // payment method
7046        cart.transaction.paymentMethod = this.getPaymentMethod(order.payments).method;
7047        if (order.isSnap2) {
7048            cart.transaction.paymentType = this.getPaymentMethod(order.payments).type;
7049        }
7050        if (order.orderItems?.length) {
7051            if (isWysiwyg) {
7052                order.orderItems.forEach(orderItem => {
7053                    let product = this.setCartItemsWYSIWYG(orderItem, pageDetails.sellerId);
7054                    cart?.item?.push(product);
7055                });
7056            } else {
7057                order.orderItems?.forEach(orderItem => {
7058                    let product = this.setCartItemsNonWYSIWYG(orderItem, pageDetails.sellerId);
7059                    cart?.item?.push(product);
7060                });
7061            }
7062        }
7063
7064        this.updateCartSavings(0, 0, orderData);
7065        pageFilter.promoCode = this.allPromoCodes(orderSummary?.promotions);
7066        cart.transaction.subTotal = orderSummary?.totalBasePrice?.toString();
7067        cart.cartInfo.totalUnits = orderSummary?.totalItemQuantity?.toString();
7068        cart.transaction.revenue = this.cleanPrice(orderSummary?.totalBasePrice - cart.savings?.totalSavings)?.toString();
7069        cart.transaction.isPromoApplied = !isNaN(parseFloat(digitalData?.cart?.savings?.promocodeSavings)) && Number(digitalData?.cart?.savings?.promocodeSavings) > 0 ? true : false;
7070        cart.transaction.isRewardsApplied = !isNaN(parseFloat(digitalData?.cart?.savings?.rewardsSavings)) && Number(digitalData?.cart?.savings?.rewardsSavings) > 0 ? true : false;
7071
7072        //get icmpid and emailClipAllCoupon from query params and set uniqueSKUCount from items
7073        cart.cartInfo.uniqueSKUCnt = [...new Set(cart.item?.map((item) => item.productID))].length;
7074        if (this.getLSItem('analyticsQueryParamEmailClipAllCoupon') || crossPageData.analyticsQueryParamEmailClipAllCoupon?.data) {
7075            const analyticsQueryParamEmailClipAllCoupon = crossPageData.analyticsQueryParamEmailClipAllCoupon?.data || this.handleGetLSValue('analyticsQueryParamEmailClipAllCoupon');
7076            cart.transaction.emailClipAllCoupon = analyticsQueryParamEmailClipAllCoupon;
7077            this.removeLSItem('analyticsQueryParamEmailClipAllCoupon');
7078            this.setAnalyticsCrossPageData({ action: 'remove', name: 'analyticsQueryParamEmailClipAllCoupon' });
7079        }
7080        if (crossPageData.analyticsQueryParamIcmpid?.data || this.getLSItem('analyticsQueryParamIcmpid')) {
7081            const analyticsQueryParamIcmpid = crossPageData.analyticsQueryParamIcmpid?.data || this.handleGetLSValue('analyticsQueryParamIcmpid');
7082            cart.transaction.icmpId = analyticsQueryParamIcmpid;
7083            this.setAnalyticsCrossPageData({ action: 'remove', name: 'analyticsQueryParamIcmpid' });
7084        }
7085        if (crossPageData.analyticsQueryParamCmpid?.data || this.getLSItem('analyticsQueryParamCmpid')) {
7086            const analyticsQueryParamCmpid = crossPageData.analyticsQueryParamCmpid?.data || this.handleGetLSValue('analyticsQueryParamCmpid');
7087            pageDetails.parameters = analyticsQueryParamCmpid;
7088            this.setAnalyticsCrossPageData({ action: 'remove', name: 'analyticsQueryParamCmpid' });
7089        }
7090        if (crossPageData.analyticsQueryParamReferringUrl?.data || this.getLSItem('analyticsQueryParamReferringUrl')) {
7091            const analyticsQueryParamReferringUrl = crossPageData.analyticsQueryParamReferringUrl?.data || this.handleGetLSValue('analyticsQueryParamReferringUrl');
7092            pageDetails.referringURL = analyticsQueryParamReferringUrl;
7093            this.setAnalyticsCrossPageData({ action: 'remove', name: 'analyticsQueryParamReferringUrl' });
7094        }
7095
7096        //set topNav
7097        let subSections = [pageDetails.subSection1, pageDetails.subSection2, pageDetails.subSection3, pageDetails.subSection4].filter(
7097Boolean);
7098        let topNavPreviousPage = subSections.join(':') + ' (L' + subSections.length + ')';
7099        localStorage.setItem('topNavPreviousPage', topNavPreviousPage);
7100
7101        // set pickupLocation
7102        if (order.serviceType === 'Delivery') {
7103            user.pickupLocation = 'delivery';
7104        } else if (order.serviceType === 'DUG') {
7105            if (order.isPickupStore && order.deliveryInfo.locationType) {
7106                const locationInfo = order.deliveryInfo.locationType;
7107                let pickupLocation;
7108                switch (locationInfo) {
7109                    case 'LOCKER-OUTSIDE':
7110                    case 'LOCKER-INSIDE':
7111                    case 'DRIVEUP':
7112                        pickupLocation = 'locker';
7113                        break;
7114                    case 'COUNTER-OUTSIDE':
7115                    case 'COUNTER-INSIDE':
7116                        pickupLocation = 'counter';
7117                        break;
7118                    case 'KIOSK-OUTSIDE':
7119                    case 'KIOSK-INSIDE':
7120                        pickupLocation = 'kiosk';
7121                        break;
7122                }
7123                if (pickupLocation) {
7124                    user.pickupLocation = pickupLocation;
7125                }
7126            } else {
7127                user.pickupLocation = 'dug';
7128            }
7129        }
7130
7131        //set defaults
7132        cart.transaction.shippingFee = '0';
7133        cart.transaction.fuelSurcharge = '0';
7134        cart.transaction.serviceFee = '0';
7135        cart.transaction.bagFee = '0';
7136
7137        if (orderSummary?.deliveryFee && Object.keys(orderSummary.deliveryFee).length > 0) {
7138            cart.transaction.shippingFee = (orderSummary?.deliveryFee?.feeWaived)
7139                ? orderSummary?.deliveryFee?.actualFee?.toString() : orderSummary?.deliveryFee?.currentFee ? orderSummary?.deliveryFee?.currentFee?.toString() : '';
7140        }
7141
7142        if (orderSummary?.fuelSurcharge && Object.keys(orderSummary.fuelSurcharge).length > 0) {
7143            cart.transaction.fuelSurcharge = (orderSummary?.fuelSurcharge?.feeWaived)
7144                ? orderSummary?.fuelSurcharge?.actualFee?.toString() : orderSummary?.fuelSurcharge?.currentFee ? orderSummary?.fuelSurcharge?.currentFee?.toString() : '';
7145        }
7146        if (orderSummary?.serviceFee && Object.keys(orderSummary.serviceFee).length > 0) {
7147            cart.transaction.serviceFee = (orderSummary?.serviceFee?.feeWaived)
7148                ? orderSummary?.serviceFee?.actualFee?.toString() : orderSummary?.serviceFee?.currentFee ? orderSummary?.serviceFee?.currentFee?.toString() : '';
7149        }
7150
7151        if (order.charges?.length > 0) {
7152            order.charges.forEach(charge => {
7153                switch (charge.category) {
7154                    case 'shipping':
7155                        if (!cart.transaction.shippingFee || cart.transaction.shippingFee == '0') {
7156                            cart.transaction.shippingFee = charge.amount?.toString();
7157                        }
7158                        break;
7159                    case 'service':
7160                        if ((!cart.transaction.serviceFee || cart.transaction.serviceFee == '0') && charge.name != 'BagFee') {
7161                            cart.transaction.serviceFee = charge.amount?.toString();
7162                        }
7163                        break;
7164                    case 'ServiceFee':
7165                        if ((!cart.transaction.bagFee || cart.transaction.bagFee == '0') && charge.name == 'BagFee') {
7166                            cart.transaction.bagFee = charge.amount?.toString();
7167                        }
7168                        break;
7169                    default:
7170                        break;
7171                }
7172
7173            })
7174        }
7175
7176        // tipping
7177        if ((crossPageData?.tippingMode || this.getLSItem('analyticsTippingMode')) && orderSummary.tipAmount !== undefined && orderSummary.tipAmount !== null) {
7178            cart.transaction.tippingRevenue = Number(orderSummary.tipAmount).toFixed(2);
7179            cart.transaction.tippingMode = crossPageData.tippingMode?.data || this.handleGetLSValue('analyticsTippingMode');
7180            this.setAnalyticsCrossPageData({ action: 'remove', name: 'tippingMode' });
7181        }
7182
7183        if (order?.bagFeePreference) {
7184            cart.transaction.bagPreference = order.bagFeePreference?.toggleEnabled === true ? 'true' : 'false';
7185        }
7186
7187        //counting unique transactions: uniqueOrderFlag will only be 1 when the transaction_complete event fires the first time, and 0 whenever the
7188        //Order Confirmation page is reloaded and the event re-fired 
7189        cart.transaction.uniqueOrderFlag = (crossPageData.uniqueTransactionComplete?.data || this.getLSItem('uniqueTransactionComplete')) ? 0 : 1;
7190        this.setMarketplaceCartInfo(order, orderSummary, 'order_confirmation');
7191        let analyticsSellerIds = crossPageData.sellerIds?.data ? crossPageData.sellerIds.data?.split(',') : this.getLSItem('analyticsSellerIds')
7192            ? this.getLSItem('analyticsSellerIds').split(',') : [];
7193        if (analyticsSellerIds.indexOf(pageDetails.sellerId) !== -1) {
7194            analyticsSellerIds.splice(analyticsSellerIds.indexOf(pageDetails.sellerId), 1);
7195        }
7196        this.setLSItem('analyticsSellerIds', analyticsSellerIds.join(','));
7197        this.setAnalyticsCrossPageData({ action: 'add', name: 'sellerIds', data: analyticsSellerIds.join(','), isAcrossPages: true });
7198
7199
7200
7201        if (crossPageData.switchedToPaypal?.data || this.getLSItem('analyticsSwitchedToPaypal')) {
7202            pageFilter.topNav = crossPageData?.switchedToPaypal?.data || this.handleGetLSValue('analyticsSwitchedToPaypal');
7203            this.setAnalyticsCrossPageData({ action: 'remove', name: 'switchedToPaypal' });
7204        }
7205
7206        if (this.getLSItem('analyticsExpressCTAValue') || crossPageData.expressCTAValue?.data) {
7207            pageFilter.topNav = crossPageData?.expressCTAValue?.data || this.handleGetLSValue('analyticsExpressCTAValue');
7208            this.setAnalyticsCrossPageData({ action: 'remove', name: 'expressCTAValue' });
7209        }
7210
7211        this.setPromoBannerImpressions();
7212        AB.DATALAYER.setPreviousPageName();
7213        AB.DATALAYER.setRestrictedPageCnc();
7214
7215        this.pushEvent(
7216            this.EVENTS.TRANSACTION_COMPLETE, {
7217            page: digitalData?.pageDetails,
7218            pageFilter: digitalData?.pageFilter,
7219            user: digitalData?.user,
7220            productInfo: digitalData?.productInfo,
7221            modal: digitalData?.modal,
7222            cart: digitalData?.cart
7223        }
7224        );
7225
7226        if (pageFilter?.subscriptionFunnel?.includes('confirmation')) {
7227            this.pushEvent(
7228                this.EVENTS.DS_CONFIRMATION, {
7229                page: digitalData?.pageDetails,
7230                pageFilter: digitalData?.pageFilter,
7231                user: digitalData?.user,
7232                productInfo: digitalData?.productInfo,
7233                modal: digitalData?.modal,
7234                cart: digitalData?.cart
7235            }
7236            );
7237        }
7238
7239        this.removeLSItem('checkout-order-payment-updated');
7240        this.removeLSItem('edit-order-payment-updated');
7241        this.removeLSItem('continueButtonClicked');
7242        this.setAnalyticsCrossPageData({ action: 'remove', name: 'confirmationPaymentUpdated' });
7243        this.setAnalyticsCrossPageData({ action: 'remove', name: 'continueButtonClicked' });
7244        this.setAnalyticsCrossPageData({ action: 'set', name: 'shouldRemovePfm', data: true, isAcrossPages: true });
7245        AB.DATALAYER.trackRoktAdImpression(isRoktEnabled);
7246    };
7247
7248    this.removeAnalyticsPlanData = function () {
7249        this.removeLSItem('analyticsSubscriptionPlan');
7250        this.removeLSItem('analyticsFPPlanPrice');
7251        this.removeLSItem('analyticsFPDiscountedMonths');
7252        if (digitalData?.pageFilter?.subscriptionFunnel) {
7253            digitalData.pageFilter.subscriptionFunnel = '';
7254        }
7255    }
7256
7257    this.updateCheckoutModalData = function (event, modalType, modalInfo, conflict) {
7258        try {
7259            conflict = modalType || digitalData.modal.conflict || 'store';
7260
7261            let eventInfo = (modalType && modalType.toLowerCase() === 'custom' && modalInfo) ? modalInfo : {
7262                appendEvent: true,
7263                name: (modalInfo ? modalInfo.name : '') || this.EVENTS.MODA
7263L_CLICK,
7264                prefix: (modalInfo ? modalInfo.prefix : '') || 'checkout-address-'
7265            };
7266
7267            if (event.toLowerCase() === 'view') {
7268                eventInfo.name = this.EVENTS.MODAL_VIEW;
7269                digitalData.modal.conflict = conflict;
7270            }
7271
7272            eventInfo['link'] = ((modalInfo ? modalInfo.link : '') ||
7273                eventInfo.prefix +
7274                conflict +
7275                (eventInfo.appendEvent ? '|' + event : ''))?.toLowerCase();
7276
7277            if (eventInfo.link) {
7278                this.pushEvent(eventInfo.name, {
7279                    modal: {
7280                        modalAction: eventInfo.link,
7281                        conflict
7282                    },
7283                    page: digitalData?.pageDetails,
7284                    pageFilter: digitalData?.pageFilter,
7285                    user: digitalData?.user
7286                });
7287                if (eventInfo.name?.includes('Click')) {
7288                    digitalData.modal.modalAction = '';
7289                    digitalData.modal.conflict = '';
7290                }
7291            }
7292        } catch (e) { console.error('[DD]ERROR: @updateCheckoutModalData: %O', e) }
7293    }
7294
7295    this.updateRescheduleSlot = function (slot) {
7296        if (slot) {
7297            this.setDeliveryWindow(slot);
7298        } else {
7299            this.pushEvent(this.EVENTS.LINK_CLICK, {
7300                link: {
7301                    linkName: 'reschedule-order-update'
7302                },
7303                page: digitalData?.pageDetails,
7304                pageFilter: digitalData?.pageFilter,
7305                cart: digitalData?.cart,
7306                user: digitalData.user
7307            });
7308        }
7309    }
7310
7311    this.setDefaultValues = function (resp) {
7312        const { pageFilter, cart } = digitalData;
7313        if (resp?.deliveryInfo?.slotInfo?.slotPlan) {
7314            pageFilter.premiumSlots = this.premiumSelected(resp.deliveryInfo.slotInfo.slotPlan);
7315        }
7316        cart.transaction = cart.transaction || {};
7317        cart.savings = cart.savings || {};
7318
7319        cart.transaction.orderID = resp?.orderId;
7320        if (resp?.deliveryInfo?.slotInfo && resp?.deliveryInfo?.slotInfo?.displayStartTS) {
7321            let reservedSlotInfo = resp?.deliveryInfo?.slotInfo ? AB.DATALAYER.safeJSONParse(JSON.stringify(resp.deliveryInfo.slotInfo)) : {};
7322            let lastPickupTS = reservedSlotInfo?.displayLastPickupTime;
7323            if (lastPickupTS && resp?.serviceType === 'DUG' && resp?.isPickupStore === false) {
7324                reservedSlotInfo['lastPickupTS'] = lastPickupTS;
7325            }
7326            cart.transaction.deliveryTime = this.getFullDeliveryTime(reservedSlotInfo);
7327        }
7328        if (resp?.orderSummary || resp?.wysiwygOrderSummary) {
7329            const orderSummary = resp?.orderSummary || resp?.wysiwygOrderSummary || {};
7330            pageFilter.promoCode = orderSummary.promotions ? this.allPromoCodes(orderSummary.promotions) : '';
7331            cart.transaction.revenue = orderSummary?.totalEstimatedPrice?.toString() || '';
7332            cart.transaction.subTotal = orderSummary?.totalBasePrice?.toString() || '';
7333            cart.transaction.totalSavings = orderSummary?.estimatedClubCardSavings?.toString() || '';
7334
7335            if (orderSummary?.deliveryFee) {
7336                cart.transaction.shippingFee = !orderSummary?.deliveryFee?.feeWaived && (orderSummary?.deliveryFee?.actualFee || orderSummary?.deliveryFee?.actualFee == 0) ? orderSummary?.deliveryFee?.actualFee?.toString() : orderSummary?.deliveryFee?.currentFee ||  orderSummary?.deliveryFee?.currentFee == 0 ? orderSummary?.deliveryFee?.currentFee?.toString() : '0';
7337            }
7338            if (orderSummary?.fuelSurcharge) {
7339                cart.transaction.fuelSurcharge = !orderSummary?.fuelSurcharge?.feeWaived && (orderSummary?.fuelSurcharge?.actualFee || orderSummary?.fuelSurcharge?.actualFee == 0) ? orderSummary?.fuelSurcharge?.actualFee?.toString() : orderSummary?.fuelSurcharge?.currentFee || orderSummary?.fuelSurcharge?.currentFee == 0 ? orderSummary?.fuelSurcharge?.currentFee?.toString() : '0';
7340            }
7341            if (orderSummary?.serviceFee) {
7342                cart.transaction.serviceFee = !orderSummary?.serviceFee?.feeWaived && (
7342orderSummary?.serviceFee?.actualFee || orderSummary?.serviceFee?.actualFee == 0) ? orderSummary?.serviceFee?.actualFee?.toString() : orderSummary?.serviceFee?.currentFee || orderSummary?.serviceFee?.currentFee == 0 ? orderSummary?.serviceFee?.currentFee?.toString() : '0';
7343            }
7344            cart.transaction.paymentMethod = (orderSummary?.orderSummary) ? 'cc & coa' : 'cc';
7345
7346            cart.savings.clubcardSavings = cart.savings?.clubcardSavings ? cart.savings?.clubcardSavings : orderSummary?.estimatedClubCardSavings ? orderSummary?.estimatedClubCardSavings?.toString() : '0';
7347            cart.savings.promocodeSavings = cart.savings.promocodeSavings ? cart.savings.promocodeSavings : orderSummary?.promotions ? this.totalPromoSavings(orderSummary?.promotions) : 0;
7348            cart.savings.totalSavings = cart.savings.totalSavings ? cart.savings.totalSavings : (Number(cart.savings.clubcardSavings) + Number(cart.savings.promocodeSavings)).toString();
7349        }
7350    }
7351
7352    this.premiumSelected = function (slotPlan) {
7353        return slotPlan === 'PREMIUM' ? 'true-default' : '';
7354    }
7355
7356    this.subscriptionLearnMoreClick = function () {
7357        let isDUG = digitalData.user?.deliveryPreference?.toLowerCase() === 'dug';
7358        digitalData.pageFilter.subscriptionFunnel = isDUG ? 'pickup-freshpass-view-plans' : '';
7359        AB.DATALAYER.setLinkClickEvents(isDUG ? 'subscription-checkout-pickup-view-plans' : 'subscription-checkout-learnmore');
7360    }
7361
7362    //set topNav for when the user departs the confirmation screen via the Manage SNS link
7363    this.setSnsManageTopNav = function () {
7364        AB.DATALAYER.setLSItem('manageSnsFromOrderConfirm', `ar:manage-schedule-and-save-${digitalData?.cart?.transaction?.paymentMethod?.includes('ebt') ? 'pending-payment-ebt' : 'successful-submission'}`);
7365    }
7366
7367    this.setTippingModeAnalytics = function (orderInfo) {
7368        const defaultTippingMode = this.getLSItem('analyticsTippingMode');
7369        let driverTip = orderInfo?.driverTip ? orderInfo.driverTip : {};
7370        const driverTipInfo = orderInfo?.driverTipInfo?.driverTipOptions;
7371
7372        if (driverTip && Object.keys(driverTip).length === 0 && driverTipInfo) {
7373            const driverTipLookup = driverTipInfo.filter((tip) => { if (tip.tipSelected === true) { return tip } });
7374            driverTip = driverTipLookup.length > 0 ? driverTipLookup[0] : {};
7375        }
7376
7377        if (defaultTippingMode && driverTip && Object.keys(driverTip).length > 0) {
7378            const tipAmount = driverTip.tipAmount ? Number(driverTip.tipAmount).toFixed(2) : 'zero';
7379            const tipPercentage = driverTip.tipPercentage ? (driverTip.tipPercentage.toLowerCase() === 'other' ? 'custom' : driverTip.tipPercentage) : 'no-option';
7380            const tippingMode = `${defaultTippingMode},${tipPercentage}|${tipAmount}`;
7381            this.setLSItem('analyticsTippingMode', tippingMode);
7382        } else {
7383            this.setLSItem('analyticsTippingMode', 'no-option|zero,no-option|zero');
7384        }
7385    }
7386
7387    this.analyticsTipChangedEvent = function (driverTipInfo, selectedTip) {
7388        const initialTip = driverTipInfo?.['driverTipOptions']?.filter(data => data.tipSelected)[0]?.['tipAmount'];
7389        if (initialTip !== selectedTip) {
7390            this.setLinkClickEvents('edit-order|tip-changed');
7391        }
7392    }
7393
7394    this.setRestrictedPageCnc = function () {
7395        if (digitalData?.cart) {
7396            if (AB.DATALAYER.isCartAndCheckoutPage('erums/checkout') && digitalData.cart.item?.length === 0 && AB.DATALAYER.getLSItem('analyticsCartItemLS')) {
7397                digitalData.cart.item = AB.DATALAYER.getLSItem('analyticsCartItemLS') ? AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('analyticsCartItemLS')) : [];
7398            }
7399            if (digitalData.cart.item?.length > 0) {
7400                const hasTrackingDisabledItems = digitalData.cart.item.some(item => item.isProductTrackingDisabled === true);
7401                AB.DATALAYER.setRestrictedProductPageFlag(hasTrackingDisabledItems);
7402                AB.DATALAYER.updatePageNameAndSubSectionRestrictedFlag();
7403                if (AB.DATALAYER.isCartAndCheckoutPage('erums/cart')) {
7404                    AB.DATALAYER.setLSItem('analyticsCartItemLS', JSON.stringify(digitalData.cart.item));
7405                } else if (this.isCartAndCheckoutPage('order/confirmation')) {
7406                    AB.DATALAYER.removeLSItem('analyticsCartItemLS');
7407                }
7408            }
7409        }
7410    }
7411
7412    this.setSelectiveCartImpressions = function (impressionType) {
7413        if (digitalData?.pageFilter && impressionType) {
7414            const isMtoImpressionAdded = digitalData?.pageFilter?.impressions && digitalData?.pageFilter?.impressions?.indexOf('mto-') != -1;
7415            digitalData.pageFilter.impressions = `${digitalData.pageFilter?.impressions ? digitalData.pageFilter.impressions : ''}${digitalData.pageFilter?.impressions && !isMtoImpressionAdded ? ',' : ''}${!isMtoImpressionAdded ? `mto-${impressionType === 'deli' ? 'sp' : impressionType === 'extra-time' ? 'lp' : ''}` : ''}`;
7416        }
7417    }
7418
7419}).call(AB.DATALAYER);
7420
7421'use strict';
7422
7423(function () {
7424    try {
7425        digitalData.pageDetails = {
7426            subSection1: this.pathSections[0],
7427            subSection2: this.pathSections[1] || '',
7428            subSection3: this.pathSections[2] || '',
7429            subSection4: this.pathSections[3] || '',
7430            banner: this.getBanner(),
7431            platform: 'web',
7432            siteTypePath: this.isShopPage() || this.isCartAndCheckoutPage() || this.isDFTAPage() ? 'eCom' : 'loyalty',
7433            channel: this.isWineShopPage() ? 'vineandcellar' : this.isShopPage() ? 'delivery' : 'loyalty',
7434            server: window.location.hostname,
7435            pageUrl: window.location.pathname === '/' ? '/home.html' : (this.isCartAndCheckoutPage() || this.isDFTAPage()) ? window.location.href : window.location.pathname === '/weeklyad/' ? '/weeklyad' : window.location.pathname,
7436            referringURL: this.getReferringUrl(),
7437            deliveryBanner: 'no off banner delivery',
7438            thirdParty: this.getThirdParty(),
7439            sellerId: this.isWineShopPage() ? '22222222' : AB.DATALAYER.getBannerSellerId(),
7440            pfmDetail: this.pathSections.join(':'),
7441            deviceType: this.getBrowserType()
7442        };
7443        this.setPageName();
7444
7445        digitalData.pageFilter = {
7446            carousel: this.setCarouselName(),
7447            filterType: '',
7448            filterSelection: '',
7449            sortSelection: '',
7450            adaFlag: 'no',
7451            topNav: this.initTopNav(),
7452            isNewLeftNav: this.getLSItem('analyticsNavTracking') === 'left-nav',
7453            isNewTopNav: this.handleGetLSValue('analyticsNavTracking') === 'top-nav' || !!this.getLSItem('analyticsTopTertiaryNavTracking'),
7454            tertiaryTopNav: this.handleGetLSValue('analyticsTopTertiaryNavTracking')
7455        };
7456        digitalData.user = {
7457            deviceInfo: this.getDeviceInfo()
7458        };
7459        digitalData.modal = digitalData.modal || {
7460            modalAction: '',
7461            modalMessage: ''
7462        };
7463        digitalData.link = digitalData.link || {
7464            linkName: ''
7465        };
7466        digitalData.boxtop = digitalData.boxtop || {};
7467        digitalData.cart = digitalData.cart || {
7468            cartInfo: {},
7469            item: [],
7470            transaction: {
7471                subTotal: ''
7472            },
7473            savings: {}
7474        };
7475        digitalData.productInfo = {};
7476        digitalData.pageFlags = {
7477            shouldTrackGiftOption: true,
7478            // Tracked below flag for gift option on angular lib instead of the one used on checkout so I am adding here to enable tracking for lib component
7479            // both shouldTrackGiftLinkClicks and shouldTrackGiftOption should be removed from here and anywhere else it is referenced anytime after 2.1 release
7480            shouldTrackGiftLinkClicks: true,
7481            isStickyBannerImpressionSent: false,
7482            isStickyBannerExposureSent: false
7483        };
7484        digitalData.crossPageData = {};
7485        digitalData.storeFlags = window.AB?.storeFlagsData || {};
7486        document.addEventListener('storeFlagsLoadComplete', () => {
7487            digitalData.storeFlags = window.AB?.storeFlagsData;
7488        });
7489        this.setAnalyticsCrossPageData({ action: 'get' });
7490        if (digitalData.crossPageData?.analyticsRestrictedProductPage?.data) {
7491            digitalData.pageFlags.isPreviousPageTrackingRestricted = digitalData.crossPageData.analyticsRestrictedProductPage.data;
7492            this.setAnalyticsCrossPageData({ action: 'remove', name: 'analyticsRestrictedProductPage' });
7493        }
7494        if (digitalData.crossPageData?.expediaBookingSignIn?.data && !this.isAuthSignInPage()) {
7495            delete digitalData.crossPageData.expediaBookingSignIn;
7496            this.setAnalyticsCrossPageData({ action: 'remove', name: 'expediaBookingSignIn' });
7497        }
7498    } catch (e) {
7499        console.warn('@AnalyticsTeam - Failed to initialise digitalData value due to following error: ', e);
7500    }
7501
7502    /**
7503     * Sets events and info from previous pages before pageLoaded event
7504     */
7505    this.initEventsFromPreviousPage = function () {
7506        this.initPrebookAEM();
7507        this.initRequestRefund();
7508        this.initOrderReschedule();
7509        this.initBannerPosition();
7510        this.removeLSItem('uniqueTransactionComplete');
7511        this.removeLSItem('abOrderCountAnalyticsCC');
7512    }
7513
7514    /**
7515     * Prevents the pageLoad event from being globally triggered on pages that have a separate pageLoad setup
7516     */
7517    this.globalPageLoadRules = function () {
7518        return !this.isDUGNotification() &&
7519            !this.isSearchResultsPage() &&
7520            !this.isPdp() &&
7521            !this.isAislesPage() &&
7522            !this.isErumsPage() &&
7523            !this.isARManagePage() &&
7524            !this.isFreshpassManagePage() &&
7525            !this.isBIAPage() &&
7526            !this.isOrdersPage() &&
7527            !this.isHelpCenterPage() &&
7528            !this.isMarketplaceSearchPage() &&
7529            !this.isPharmacyRxPage() &&
7530            !this.isStudentsPage() &&
7531            !this.isARTestManagePage() &&
7532            !this.isResetPasswordPage() &&
7533            !this.isCartAndCheckoutPage() &&
7534            !this.isReviewsPage() &&
7535            !this.isRewardsPage() &&
7536            !this.isGamesSPAPage() &&
7537            !this.isSelfMergeAccountsPage() &&
7538            !this.isWeeklyAdPage() &&
7539            !this.isB4USPA() &&
7540            !this.isSpotlightPage();
7541    }
7542
7543    /**
7544     * Initializes data layer pageDetails object additional information
7545     */
7546    this.initPage = function () {
7547        if (!this.isOrdersPage() && !this.isARManagePage() && !this.isHelpCenterPage() && !this.isAccountResetPage() && !this.isSpotlightPage()) {
7548            let mktpCategoryPillClicked = this.handleGetLSValue('mktpCategoryPillClicked')
7549            // Set pageDetails.channel and pageDetails.pageType
7550            AB.DATALAYER.sortSiteSections();
7551            // Set custom page name for just for U Registration - Welcome Offer
7552            this.justforURegistration();
7553            // Set custom page info for Sincerely-food
7554            this.initSCFPage();
7555            // Sets flag isAnalyticsMarketplacePage on window object
7556            this.setMarketplacePage();
7557            // Set custom subSections
7558            if (window.isAnalyticsMarketplacePage) {
7559                if (this.isMarketplaceCategoryPage()) {
7560                    this.initMarketplaceCategory();
7561                }
7562                if (!this.isMarketplaceCategoryPage() && !this.isMarketplaceSearchPage() && !this.isPdp()) {
7563                    if (digitalData.pageDetails.subSection2 && !digitalData.pageDetails.subSection3) {
7564                        this.initMarketplaceSellerListing();
7565                    } else {
7566                        this.initMarketplaceSellerLanding();
7567                    }
7568                }
7569            } else if (this.isGamesPage()) {
7570                this.initGamesPages();
7571            }
7572            this.initContactUs();
7573            AB.DATALAYER.pfmFromCurrentPage = [digitalData.pageDetails.subSection1, digitalData.pageDetails.subSection2, digitalData.pageDetails.subSection3, digitalData.pageDetails.subSection4].filter(function (x) {
7574                return x;
7575            }).join(':');
7576            if (mktpCategoryPillClicked) {
7577                digitalData.pageFilter.bannerCardCarousel = mktpCategoryPillClicked;
7578            }
7579        }
7580    };
7581
7582    /**
7583     * gets and stores the 'cmpid', 'icmpid' and EmailClipAllCoupon attributes 'totalCoupons,couponsClipped,autoclipError,clipFailCode,clipFailMessage' in local storage
7584     */
7585    this.initQueryParams = function () {
7586        const icmpid = AB.DATALAYER.analyticsGetURLParameterByName('icmpid');
7587        if (icmpid) {
7588            this.setLSItem('analyticsQueryParamIcmpid', icmpid);
7589            this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsQueryParamIcmpid', data: icmpid, isAcrossPages: true });
7590        }
7591        digitalData.pageDetails = digitalData.pageDetails || {};
7592        const cmpid = AB.DATALAYER.analyticsGetURLParameterByName('cmpid');
7593        if (cmpid) {
7594            this.setLSItem('analyticsQueryParamCmpid', cmpid);
7595            this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsQueryParamCmpid', data: cmpid, isAcrossPages: true });
7596            digitalData.pageDetails.parameters = cmpid;
7597        }
7598        const totalcoupons = AB.DATALAYER.analyticsGetURLParameterByName('totalcoupons');
7599        const couponsclipped = AB.DATALAYER.analyticsGetURLParameterByName('couponsclipped');
7600        const autocliperror = AB.DATALAYER.analyticsGetURLParameterByName('autocliperror');
7601        const clipfailcode = AB.DATALAYER.analyticsGetURLParameterByName('clipfailcode');
7602        const clipfailmessage = AB.DATALAYER.analyticsGetURLParameterByName('clipfailmessage');
7603        if (totalcoupons || couponsclipped || autocliperror || clipfailcode || clipfailmessage) {
7604            const emailClipAllCoupon = [totalcoupons || '', couponsclipped || '', autocliperror || '', clipfailcode || '', clipfailmessage || ''].join(':')
7605            this.setLSItem('analyticsQueryParamEmailClipAllCoupon', emailClipAllCoupon);
7606            this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsQueryParamEmailClipAllCoupon', data: emailClipAllCoupon, isAcrossPages: true });
7607        }
7608        const referringUrl = AB.DATALAYER.getReferringUrl();
7609        if (referringUrl && referringUrl?.toLowerCase()?.indexOf(AB?.DATALAYER?.getBanner()) == -1) {
7610            this.setLSItem('analyticsQueryParamReferringUrl', referringUrl);
7611            this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsQueryParamReferringUrl', data: referringUrl, isAcrossPages: true });
7612            digitalData.pageDetails.referringURL = referringUrl;
7613        }
7614        AB.DATALAYER.setParamsandRurlSessionBased();
7615    }
7616
7617    /**
7618     * to set params and referring Url session based
7619     */
7620    this.setParamsandRurlSessionBased = function () {
7621        const isFirstVisit = !AB.DATALAYER.getCookie('absVisitorId');
7622        const cmpid = !!this.getLSItem('analyticsQueryParamCmpid');
7623        const referringUrlStored = this.getLSItem('analyticsQueryParamReferringUrl');
7624        const referringUrl = AB.DATALAYER.getReferringUrl();
7625        const icmpid = !!this.getLSItem('analyticsQueryParamIcmpid');
7626        let paramValue = '';
7627        if (isFirstVisit && !cmpid && !icmpid && !referringUrlStored && referringUrl && referringUrl?.toLowerCase()?.indexOf(AB?.DATALAYER?.getBanner()) > -1) {
7628            paramValue = 'refresh'
7629        }
7630        if (isFirstVisit && !cmpid && !icmpid && referringUrlStored && referringUrlStored?.toLowerCase()?.indexOf('direct') > -1) {
7631            paramValue = 'true'
7632        }
7633        if (!cmpid && !icmpid && !referringUrlStored && !referringUrl) {
7634            this.setLSItem('analyticsQueryParamReferringUrl', 'direct');
7635            this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsQueryParamReferringUrl', data: 'direct', isAcrossPages: true });
7636            digitalData.pageDetails.referringURL = 'direct';
7637        }
7638        if (paramValue) {
7639            this.setLSItem('analyticsQueryParamCmpid', paramValue);
7640            this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsQueryParamCmpid', data: paramValue, isAcrossPages: true });
7641            digitalData.pageDetails.parameters = paramValue;
7642        }
7643
7644    }
7645
7646    /**
7647     * Initializes the data layer user object information
7648     */
7649    this.initUser = function () {
7650        digitalData.user = digitalData.user || {};
7651        this.initJourneyStatus();
7652        digitalData.user.journeyStatus = this.getJourneyStatus();
7653        digitalData.user.addressType = this.handleGetLSValue('addressType');
7654
7655        this.initUserDataFromCookies();
7656        this.initOrderCount();
7657        if (digitalData.user?.loginStatus === 'guest') {
7658            this.setAnalyticsCrossPageData({ action: 'remove', name: 'acip371626Social' });
7659        }
7660    };
7661
7662    /**
7663     * Initializes the datalayer with info from LS
7664     * Updates LS items
7665     * Method is called before sending the 'pageLoaded' event
7666     */
7667    this.updatesFromLSBeforePageLoad = function () {
7668        // Remove LS items on new pageLoad
7669        this.removeLSItem('analyticsSimilarItemsPDP');
7670        this.removeLSItem('analyticsSimilarItemsCart');
7671        this.removeLSItem('analyticsSimilarItemsBIA');
7672        this.removeLSItem('analyticsMetaInfo');
7673        this.removeLSItem('analyticsProductIdPDP');
7674        this.removeLSItem('itemsInCartBeforeUpdate');
7675        this.removeLSItem('aaBiaSimilarItemsMetrics');
7676        this.removeLSItem('analyticsBiaLoadMore');
7677        if (!this.isWeeklyAdPage()) {
7678            this.removeLSItem('analyticsWeeklyAdPageInfo');
7679        }
7680        if (!this.isPdp() || this.isWineShopPage() || window.isAnalyticsMarketplacePage) {
7681            this.removeLSItem('analyticsAMCPDPInfo');
7682        }
7683        // Remove sns frequency trackig on non-PDP pages
7684        if (!this.isPdp()) {
7685            AB.DATALAYER.setAnalyticsCrossPageData({ action: 'remove', name: 'snsAnalyticsFrequency' });
7686        }
7687
7688        // Remove data related to freshpass cancel plan benefits flow on pages other than Manage Freshpass
7689        if (!this.isFreshpassManagePage()) {
7690            this.setAnalyticsCrossPageData({ action: 'remove', name: 'analyticsTrackDiscBnftFunnel' })
7691            this.setAnalyticsCrossPageData({ action: 'remove', name: 'analyticsTrackCancelReasonId' });
7692            this.setAnalyticsCrossPageData({ action: 'remove', name: 'analyticsTrackCancelReasonText' });
7693        }
7694
7695        // Initialise various info from other pages
7696        this.removeLSItemFromBIACarousal();
7697        this.initFPSItems();
7698        this.initPetDetails();
7699        this.initEngagementLadderImpressions();
7700        this.initCartPromoBannerImpressions();
7701        this.initFlexCardDetails();
7702        this.initAEMZoneTracking();
7703        this.initDFTACarousel();
7704        this.initSignInMessage();
7705        this.initTopNavPageFlag();
7706        this.initMkpGoToCart();
7707        this.initScheduledItemsImpressions();
7708        this.initHeroBannerAbTestDetails();
7709        this.initBundleAbTestDetails();
7710    }
7711
7712    this.removeLSItemFromBIACarousal = function () {
7713        if (!this.isPdp()) {
7714            localStorage.removeItem('analyticsBIAPfmSource');
7715            localStorage.removeItem('analyticsBIAProductImpressionAdDetail');
7716            localStorage.removeItem('analyticsIsBIACarousal');
7717            localStorage.removeItem('analyticsBIACarousalProductId');
7718        }
7719    }
7720
7721    this.updatePathsectionsForSPA = function () {
7722        if (this.isAccountResetPage()) {
7723            this.initPathSections();
7724            this.setSubsections();
7725            this.setPageName('loyalty');
7726        }
7727    }
7728
7729    /**
7730     * Sets isShopOrTopNav pageFlag when clicking on shop or top nav links
7731     */
7732    this.initTopNavPageFlag = function () {
7733        if (this.getLSItem('shopOrTopNavFlag') && digitalData) {
7734            digitalData.pageFlags = digitalData.pageFlags || {};
7735            digitalData.pageFlags.isShopOrTopNav = this.handleGetLSValue('shopOrTopNavFlag');
7736        }
7737    }
7738
7739    /**
7740     * update page name with :hpp(health restricted product page) if its a restricted page
7741     */
7742    this.updatePageNameAndSubSectionRestrictedFlag = function () {
7743        if (digitalData?.pageFlags?.isProductTrackingDisabled && digitalData?.pageDetails?.pageName.indexOf(':hpp') == -1) {
7744            digitalData.pageDetails.pageName += ':hpp';
7745        }
7746        if (digitalData?.pageFlags?.isProductTrackingDisabled) {
7747            if (digitalData.pageDetails.subSection2) {
7748                if (digitalData.pageDetails.subSection3) {
7749                    if (digitalData.pageDetails.subSection4) {
7750                        digitalData.pageDetails.subSection4 = digitalData.pageDetails.subSection4 + ':hpp';
7751                    } else {
7752                        digitalData.pageDetails.subSection4 = 'hpp';
7753                    }
7754                } else {
7755                    digitalData.pageDetails.subSection3 = 'hpp';
7756                }
7757            } else {
7758                digitalData.pageDetails.subSection2 = 'hpp';
7759            }
7760        }
7761    }
7762
7763    /**
7764     * Sets the 'pageLoaded' event
7765     */
7766    this.setPageLoad = function () {
7767        this.updatesFromLSBeforePageLoad();
7768        if (digitalData?.user && Object.keys(digitalData.user).length <= 1) {
7769            this.initUser();
7770        }
7771        if (window.digitalData?.pageDetails?.pageUrl?.indexOf('/offer-details-modal-simple') !== -1) {
7772            AB.DATALAYER.setModalViewEvents('offer-details-modal|view');
7773        } else {
7774            AB.DATALAYER.updatePageNameAndSubSectionRestrictedFlag();
7775            AB.DATALAYER.setPreviousPageName();
7776            AB.DATALAYER.pushEvent(
7777                AB.DATALAYER.EVENTS.PAGE_LOADED, {
7778                page: digitalData.pageDetails,
7779                pageFilter: digitalData.pageFilter,
7780                user: digitalData.user,
7781                recipes: digitalData.recipes,
7782                productInfo: digitalData.productInfo,
7783                modal: digitalData.modal
7784            }
7785            );
7786        }
7787        // Reset property so that values don't persist between hits
7788        digitalData.pageFilter.bannerCardCarousel = '';
7789        digitalData.pageFilter.impressions = '';
7790        digitalData.pageFilter.topNav = '';
7791    }
7792
7793    /**
7794     * Initializes the datalayer with info from LS on aisles page
7795     * Method is called before sending the 'pageLoaded' event 
7796     */
7797    this.updatesFromLSforAislesPage = function (productInfo) {
7798        // pfmSource set for Similar Items flow
7799        if (localStorage.getItem('analyticsSimilarItemsPDP')) {
7800            if (localStorage.getItem('analyticsSimilarItemsPDP') === productInfo.aisleId) {
7801                window.digitalData.pageFilter.pfmSource = 'similar-items_pdp';
7802            } else {
7803                localStorage.removeItem('analyticsSimilarItemsPDP');
7804            }
7805        }
7806        if (localStorage.getItem('analyticsSimilarItemsCart')) {
7807            if (localStorage.getItem('analyticsSimilarItemsCart') === productInfo.aisleId) {
7808                window.digitalData.pageFilter.pfmSource = 'similar-items_cart';
7809            } else {
7810                localStorage.removeItem('analyticsSimilarItemsCart');
7811            }
7812        }
7813        if (localStorage.getItem('analyticsSimilarItemsBIA')) {
7814            window.digitalData.pageFilter.pfmSource = localStorage.getItem('analyticsSimilarItemsBIA');
7815            localStorage.removeItem('analyticsSimilarItemsBIA');
7816        }
7817        if (localStorage.getItem('analyticsMetaInfo')) {
7818            localStorage.removeItem('analyticsMetaInfo');
7819        }
7820        if (sessionStorage.getItem('analyticsProductIdPDP')) {
7821            sessionStorage.removeItem('analyticsProductIdPDP');
7822        }
7823        this.removeLSItemFromBIACarousal();
7824        this.initEngagementLadderImpressions();
7825        this.initCartPromoBannerImpressions();
7826        this.initFlexCardDetails();
7827        this.initDFTACarousel();
7828        this.initTopNavPageFlag();
7829        this.initAEMZoneTracking();
7830        this.initHeroBannerAbTestDetails();
7831        this.initBundleAbTestDetails();
7832    }
7833
7834    this.initAislesL3L4Page = function (flag) {
7835        if (this.isAislesL3Page() || this.isAislesL4Page()) {
7836            this.setRestrictedProductPageFlag(flag);
7837            this.initAislesPage();
7838        }
7839    }
7840
7841    /**
7842     * Sets the pageLoaded event on aisles pages with specific aisles attributes
7843     */
7844    this.initAislesPage = function () {
7845        // Sets the aisle ID on aisles pages from the digitalData object, which is updated in product-carousel service, dynamic-tile-item-l2 and search-filter-selected components
7846        const productInfo = {
7847            aisleId: digitalData.productInfo ? digitalData.productInfo.aisleId : '',
7848            upc: digitalData.productInfo ? digitalData.productInfo.upc : ''
7849        };
7850
7851        this.updatesFromLSforAislesPage(productInfo);
7852        AB.DATALAYER.updatePageNameAndSubSectionRestrictedFlag();
7853        AB.DATALAYER.setPreviousPageName();
7854        AB.DATALAYER.pushEvent(
7855            AB.DATALAYER.EVENTS.PAGE_LOADED, {
7856            page: digitalData.pageDetails,
7857            pageFilter: digitalData.pageFilter,
7858            user: digitalData.user,
7859            productInfo: productInfo
7860        }
7861        );
7862
7863        // Reset property so that values don't persist between hits
7864        digitalData.pageFilter.bannerCardCarousel = '';
7865
7866        this.setLinkClickSimilarItems();
7867
7868        // Handles sign-in, sign-out event flows for analytics
7869        this.handleAccountEvents();
7870    }
7871
7872    /**
7873     * Initializes the PDP page events
7874     */
7875    this.initPDP = function () {
7876        if (localStorage.getItem('productInfoAnalyticsPDP')) {
7877            const productInfoPDP = this.safeJSONParse(AB.DATALAYER.getLSItem('productInfoAnalyticsPDP'));
7878            this.setPDPevent(productInfoPDP);
7879            AB.DATALAYER.removeLSItem('productInfoAnalyticsPDP');
7880        }
7881    }
7882
7883    /**
7884     * Initializes BIA page load events
7885     */
7886    this.initBIAPage = function () {
7887        if (this.isBIAPage()) {
7888            if (sessionStorage.getItem('analyticsBIADelayedPageLoad')) {
7889                this.updateBIAViewType();
7890                sessionStorage.removeItem('analyticsBIADelayedPageLoad');
7891            } else if (localStorage.getItem('analyticsBIAview')) {
7892                this.updateBIAViewType(localStorage.getItem('analyticsBIAview'));
7893                localStorage.removeItem('analyticsBIAview');
7894            }
7895        }
7896    }
7897
7898    /**
7899     * Sets link click event if the similar items link for an unavailable product was clicked on minicart or fullcart
7900     */
7901    this.setLinkClickSimilarItems = function () {
7902        if (localStorage.getItem('analyticsSimilarItemsMini')) {
7903            AB.DATALAYER.setLinkClickEvents('view-similar-items|mini');
7904            localStorage.removeItem('analyticsSimilarItemsMini');
7905        }
7906        if (localStorage.getItem('analyticsViewSimilarItemsCart')) {
7907            AB.DATALAYER.setLinkClickEvents('view-similar-items|cart');
7908            localStorage.removeItem('analyticsViewSimilarItemsCart');
7909        }
7910    }
7911
7912    /**
7913      * Initializes pfmDetail and recommendationType field on product-details page and set value inside localStorage for pfmDetail for all the other pages
7914      * pfmDetail = [PAGE SUBSECTIONS]#[CAROUSEL NAME]#[RECOMMENDATION]#[ROW]#[SLOT]
7915    */
7916    this.initPfmDetail = function () {
7917        if (!this.isPdp()) {
7918            // for all the other pages save the pfmDetail value in ls to be used for the pdp
7919            this.setLsPfmDetailOnInit();
7920        }
7921    };
7922
7923    /**
7924     * Initializes the data layer user information with data that can be retrieved from cookies
7925     */
7926    this.initUserDataFromCookies = function () {
7927        this.initSharedSessionInfo();
7928        this.initSharedPiiSessionInfo();
7929        this.initKmsi();
7930        this.initAbsVisitorId();
7931        window.dispatchEvent(new CustomEvent('digitalDataReady'));
7932    };
7933
7934
7935    /**
7936     * Initializes the user object with info from 'absVisitorId' cookie
7937     */
7938    this.initAbsVisitorId = function () {
7939        if (digitalData.user) {
7940            digitalData.user.absVisitorId = AB.DATALAYER.getCookie('absVisitorId') || '';
7941        }
7942    }
7943
7944    /**
7945     * Initializes the user object with info from 'SWY_SHARED_SESSION_INFO' cookie
7946     */
7947    this.initSharedSessionInfo = function () {
7948        const sharedInfoCookie = AB.DATALAYER.getCookie('ACI_S_SWY_SHARED_SESSION_INFO') || AB.DATALAYER.getCookie('SWY_SHARED_SESSION_INFO');
7949        let user = digitalData.user;
7950        if (sharedInfoCookie && sharedInfoCookie != '') {
7951            let sharedSessionInfo = { 'info': '' };
7952            try {
7953                sharedSessionInfo = JSON.parse(decodeURI(sharedInfoCookie));
7954            } catch (e) {
7955                console.error('DATALAYER: Unable to parse the SWY_SHARED_SESSION_INFO cookie!');
7956            }
7957
7958            try {
7959                let userCookieData = sharedSessionInfo?.info?.SHOP || {};
7960                let userCookieCommonData = sharedSessionInfo?.info?.COMMON || {};
7961
7962                userCookieData.userType = userCookieData.userType || userCookieCommonData.userType;
7963
7964                user.userType = userCookieData.userType || '';
7965                user.type = userCookieData.userType || '';
7966                switch (userCookieData.userType) {
7967                    case 'A':
7968                    case 'G':
7969                        user.loginStatus = this.LoginStatus.GUEST;
7970                        break;
7971                    case 'R':
7972                    case 'C':
7973                    case 'D':
7974                    case 'M':
7975                        user.loginStatus = this.LoginStatus.REGISTERED;
7976                        break;
7977                    default:
7978                        break;
7979                }
7980
7981                user.shopStoreId = userCookieData.storeId;
7982                user.shopZipCode = userCookieData.zipcode;
7983
7984                if (userCookieData.userData?.deliveryBanner && digitalData.pageDetails.banner) {
7985                    const banner = this.getBanner();
7986                    const deliveryBanner = userCookieData.userData?.deliveryBanner.toLowerCase().trim();
7987                    if (banner !== deliveryBanner) {
7988                        user.deliveryPreference.deliveryBanner = `${banner}|'${deliveryBanner}`;
7989                    } else {
7990                        user.deliveryPreference.deliveryBanner = this.DEFAULT_DELIVERY_BANNER;
7991                    }
7992                }
7993
7994                user.houseHoldId = userCookieCommonData.houseId || 'ID not found';
7995                user.clubCardNumber = userCookieCommonData.clubCard || 'ID not found';
7996                user.sessionId = userCookieCommonData.grsSessionId || 'ID not found';
7997                user.sscustomerstatus = typeof (userCookieCommonData.isARenrolled) !== 'undefined'
7998                    ? (userCookieCommonData.isARenrolled === 'true' ? 'returning' : 'first') : 'ID not found';
7999                if (userCookieCommonData.preference) {
8000                    switch (userCookieCommonData.preference?.toLowerCase()) {
8001                        case 'dug':
8002                            user.deliveryPreference = 'dug';
8003                            break;
8004                        case 'delivery':
8005                            user.deliveryPreference = 'delivery';
8006                            break;
8007                        case 'j4u':
8008                            user.deliveryPreference = 'inStore';
8009                            break;
8010                    }
8011                }
8012            } catch (e) {
8013                console.error('DATALAYER: Missing fields from SWY_SHARED_SESSION_INFO cookie! (SHOP, J4U, COMMON)');
8014            }
8015        } else if (this.getLSItem('userInfo') || AB?.userInfo) {
8016            const userInfoLS = this.getLSItem('userInfo') ? this.safeJSONParse(this.getLSItem('userInfo')) : {};
8017            user.clubCardNumber = userInfoLS?.clubCardNumber || AB?.userInfo?.clubCard || '';
8018            const cookieInfo = AB.DATALAYER.getCookie('ACI_S_SWY_SYND_USER_INFO') || AB.DATALAYER.getCookie('SWY_SYND_USER_INFO');
8019            user.loginStatus = `${cookieInfo && cookieInfo !== '' && this.safeJSONParse(cookieInfo).hhid ? this.LoginStatus.REGISTERED : this.LoginStatus.GUEST}|${AB.DATALAYER.getCookie('SAFEWAY_KMSI') && AB.DATALAYER.getCookie('SAFEWAY_KMSI') !== '' ? this.KmsiStatus[AB.DATALAYER.getCookie('SAFEWAY_KMSI')] : 'nonkmsi'}`;
8020        }
8021    };
8022
8023    /**
8024     * Initializes the user object with info from 'SWY_SHARED_PII_SESSION_INFO' cookie
8025     */
8026    this.initSharedPiiSessionInfo = function () {
8027        const sharedPiiInfoCookie = AB.DATALAYER.getCookie('ACI_S_SWY_SHARED_PII_SESSION_INFO') || AB.DATALAYER.getCookie('SWY_SHARED_PII_SESSION_INFO');
8028        if (sharedPiiInfoCookie && sharedPiiInfoCookie != '') {
8029            let sharedPiiInfo;
8030            try {
8031                sharedPiiInfo = JSON.parse(decodeURI(sharedPiiInfoCookie));
8032            } catch (e) {
8033                console.error('DATALAYER: Unable to parse the SWY_SHARED_PII_SESSION_INFO cookie!');
8034            }
8035
8036            if (sharedPiiInfo) {
8037                let user = digitalData.user;
8038                user.customerId = sharedPiiInfo.gid || 'ID not found';
8039                user.uuid = sharedPiiInfo.uuid || 'ID not found';
8040            }
8041        }
8042    };
8043
8044    /**
8045     * Initializes the user object with info from 'SAFEWAY_KMSI' c
8045ookie
8046     * (digitalData.user.loginStatus)
8047     */
8048    this.initKmsi = function () {
8049        const kmsiCookie = AB.DATALAYER.getCookie('SAFEWAY_KMSI').toLowerCase();
8050        let user = digitalData.user;
8051        if (kmsiCookie && user.type) {
8052            // after re-sign-in, the kmsi status has special values
8053            const reSignInCookie = AB.DATALAYER.getCookie(this.cookieNames.RE_SIGN_IN);
8054            if (reSignInCookie == 'true') {
8055                SWY.CONFIGSERVICE.setDomainCookie(this.cookieNames.RE_SIGN_IN, false, `${SWY.CONFIGSERVICE.resolvedBanner}.com`, 0);
8056                if (this.KmsiStatusReSignIn[kmsiCookie]) {
8057                    user.loginStatus += '|' + this.KmsiStatusReSignIn[kmsiCookie];
8058                }
8059            } else {
8060                if (this.KmsiStatus[kmsiCookie]) {
8061                    user.loginStatus += '|' + this.KmsiStatus[kmsiCookie];
8062                }
8063            }
8064        }
8065    };
8066
8067    /**
8068     * Initializes the user object info from the LS item 'abOrderCount' or 'SWY_SHARED_SESSION_INFO' cookie
8069     */
8070    this.initOrderCount = function () {
8071        if (digitalData.user?.userType !== 'R' && digitalData.user?.userType !== 'C') {
8072            return;
8073        }
8074
8075        // try to get the order count from the local storage, otherwise from the shared info cookie
8076        if (localStorage) {
8077            this.updateOrderCount(this.getLSItem('abOrderCount') || this.getLSItem('abOrderCountAnalyticsCC'));
8078        } else {
8079            const sharedInfoCookie = AB.DATALAYER.getCookie('ACI_S_SWY_SHARED_SESSION_INFO') || AB.DATALAYER.getCookie('SWY_SHARED_SESSION_INFO');
8080            if (sharedInfoCookie && sharedInfoCookie != '') {
8081                let sharedSessionInfo = { 'info': '' };
8082                try {
8083                    sharedSessionInfo = JSON.parse(decodeURI(sharedInfoCookie));
8084                } catch (e) {
8085                    console.error('DATA Layer: Unable to parse the cookie');
8086                }
8087
8088                if (sharedSessionInfo?.info?.SHOP?.userData) {
8089                    this.updateOrderCount(sharedSessionInfo.info.SHOP.userData.orderCount);
8090                }
8091            }
8092        }
8093    };
8094
8095    /**
8096     * Sets the SAFEWAY_RE_SIGN_IN cookie, used when setting the kmsi flag
8097     */
8098    this.handleReSignIn = function () {
8099        SWY.CONFIGSERVICE.setDomainCookie(this.cookieNames.RE_SIGN_IN, AB.DATALAYER.isReSignInPage(), `${SWY.CONFIGSERVICE.resolvedBanner}.com`, 0);
8100    }
8101
8102    /**
8103     * Sets the cart savings (total number of coupons, total number of clipped coupons)
8104     * @param total
8105     * @param clipped
8106     */
8107    this.updateCartSavings = function (total, clipped, response) {
8108        if (response && response['isWYSIWYGEnabled'] === true) {
8109            const cartSavings = AB.DATALAYER.calculateCartSavings(response?.summary?.cardSavings || response?.order?.cardSavings, 'cart');
8110
8111            // Promocode savings are handled separately from other cart savings as they are in a different object in the response
8112            // They are initialized in cartSavings object as well, but they are set to 0
8113            const promocodeSavings = response?.wysiwygOrderSummary?.promotions ? AB.DATALAYER.totalPromoSavings(response?.wysiwygOrderSummary?.promotions) : 0;
8114            cartSavings.promocodeSavings = promocodeSavings;
8115
8116            // Get savings total value from cart response if it's available, otherwise attempt to calculate using analytics function
8117            const responseSavings = response?.summary?.totalCardSavings && !isNaN(parseFloat(response?.summary?.totalCardSavings)) ? parseFloat(response.summary.totalCardSavings) : 0;
8118            const analyticsSavings = cartSavings.total + promocodeSavings;
8119            const totalSavings = responseSavings ? responseSavings : analyticsSavings ? analyticsSavings : 0;
8120            const itemsList = response['cartItemsList'] || response?.['order']?.['orderItems'] || [];
8121            const couponIds = [];
8122
8123            if (itemsList && Array.isArray(itemsList) && itemsList.length > 0) {
8124                itemsList.forEach(item => {
8125                    if (item.name && item.price && item.isFound && item.savings && item.savings.length > 0) {
8126                        item.savings.forEach(offer => {
8127                            if (offer.offerId) {
8128                                couponIds.push(offer.offerId);
8129                            }
8130                        })
8131                    }
8132                });
8133            }
8134            if (digitalData?.cart) {
8135                digitalData.cart.savings = {
8136                    totalCoupons: total.toString(),
8137                    couponApplied: couponIds.join(),
8138                    clubcardSavings: cartSavings.clubcardSavings,
8139                    j4uSavings: cartSavings.j4uSavings,
8140                    rewardsSavings: cartSavings.rewardsSavings,
8141                    promocodeSavings: cartSavings.promocodeSavings.toString(),
8142                    employeeSavings: cartSavings.employeeSavings,
8143                    totalSavings: totalSavings.toString()
8144                };
8145            }
8146        } else if (response === undefined || response && response['isWYSIWYGEnabled'] === false || response && response['isWYSIWYGEnabled'] === undefined) {
8147            if (digitalData?.cart) {
8148                digitalData.cart.savings = {
8149                    totalCoupons: total,
8150                    couponsClipped: clipped
8151                };
8152            }
8153        }
8154    };
8155
8156    /**
8157     * Manage the link click data for the substritution and chat
8158     * @param {*} action chat / bottomchat / approve
8159     * @param {*} item reference to the item that is going to be substituted
8160     * @param {*} section section that might not be available in the item object
8161     */
8162    this.trackSubsAndChatLinkClick = function ({ action, item, section, element }) {
8163        digitalData.crossPageData = digitalData.crossPageData || {}
8164        const { productInfo, modal, crossPageData } = digitalData;
8165        const isSubPref = item?.replacements?.some(item => !!item.saveAsFutureSubPreference) || false;
8166        productInfo.substitution = productInfo.substitution || {};
8167
8168        const productID = section ? item.itemCode : item?.orderedItemId;
8169
8170        if (productID && action === 'approve') {
8171            const substitutionItems = item?.replacements?.map(item => item?.itemId ? item?.itemId : item?.itemCode);
8172            productInfo.substitution.productID = productID || '';
8173            productInfo.substitution.isSubstitution = true;
8174            productInfo.substitution.substitutionOption = `substitute:${substitutionItems ? substitutionItems.join('#') : ''}`;
8175        }
8176        if (isSubPref) {
8177            this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsFeatureTracking', data: 'subsPrefACIP405518' });
8178        }
8179
8180        const sectionFromAPI = section ? section : item?.substitutionPrefType === 'CustomerChoiceNotSubstitution' ? 'substitute-not-available' : `items-to-review${isSubPref ? '-pref-sub-tag' : ''}`;
8181        const eventString = action === 'saveSub' ? 'items-to-review-chat-pref-sub-tag|substitutions-approve' : action.includes('chat') ? `cta:order-details|${action === 'bottomchat' ? 'bottom-' : ''}button|chat-icon` : `${sectionFromAPI}|substitutions-approve`;
8182        const selectElement = action === 'approve' && document.querySelectorAll(`a[data-bpn="${productID}"]`) && Array.from(document.querySelectorAll(`a[data-bpn="${productID}"]`)).find(element => element.closest('.card.p-3'));
8183        const slotNumber = action === 'approve' && document.querySelectorAll('.card.p-3')?.length > 0 ?
8184            document.querySelectorAll('.card.p-3') && Array.from(document.querySelectorAll('.card.p-3'))?.indexOf(selectElement.closest('.card.p-3')) + 1 : 0;
8185
8186        modal.modalMessage = slotNumber ? `substitution-substitute-${slotNumber > 9 ? slotNumber : `0${slotNumber}`}#01` : '';
8187
8188        const setOncePerPage = (eventName, event, section) => {
8189            let eventSent = false;
8190            // Find the index of the last untilNextEvent in appEventData
8191            let eventIndex = -1;
8192            eventIndex = appEventData.findLastIndex((eventObj) => eventObj?.event === this.EVENTS.PAGE_LOADED);
8193
8194            if (eventIndex !== -1) {
8195                eventSent = appEventData.slice(eventIndex).some((eventObj) =>
8196                    eventObj?.[`${event.includes('modal') ? 'modal' : 'link'}`]?.[`${event.includes('modal') ? 'modalAction' : 'linkName'}`] === eventName &&
8197                    (action === 'bottomchat' || crossPageData?.chatSection?.data?.includes(section))
8198                );
8199            }
8200            return eventSent;
8201        }
8202        const eventSent = action.includes('chat') && setOncePerPage(eventString, this.EVENTS.LINK_CLICK, sectionFromAPI);
8203        if (action.includes('chat')) {
8204            !eventSent && this.setLinkClickEvents(eventString);
8205        } else {
8206            AB.DATALAYER.pushEvent(
8207                this.EVENTS.LINK_CLICK, {
8208                link: {
8209                    linkName: eventString
8210                },
8211                page: digitalData?.pageDetails,
8212                pageFilter: digitalData?.pageFilter,
8213                user: digitalData?.user,
8214                productInfo: digitalData?.productInfo,
8215                modal: digitalData?.modal
8216            }
8217            )
8218        }
8219
8220        if (action.includes('chat') && sectionFromAPI) {
8221            let listOfSections = [];
8222
8223            if (crossPageData?.chatSection?.data?.length > 0) {
8224                crossPageData?.chatSection?.data?.forEach(section => { listOfSections.push(section) });
8225                if (!listOfSections.includes(sectionFromAPI)) {
8226                    listOfSections.push(sectionFromAPI);
8227                }
8228            } else listOfSections.push(sectionFromAPI);
8229            this.setAnalyticsCrossPageData({ action: 'set', name: 'chatSection', data: listOfSections });
8230        }
8231
8232        digitalData.modal = {};
8233        digitalData.productInfo = {};
8234    }
8235
8236    /**
8237     * Manage the link modal interaction for the substritution and chat
8238     * @param {*} action chat / bottomchat / approve
8239     * @param {*} item reference to the item that is going to be substituted
8240     */
8241    this.trackSubsModalEvents = function ({ action, item, element }) {
8242        digitalData.crossPageData = digitalData.crossPageData || {}
8243        const { productInfo, modal, crossPageData } = digitalData;
8244        productInfo.substitution = productInfo.substitution || {};
8245
8246        const setOncePerPage = (eventName, event, productID) => {
8247            let eventSent = false;
8248            // Find the index of the last untilNextEvent in appEventData
8249            let eventIndex = -1;
8250            eventIndex = appEventData.findLastIndex((eventObj) => eventObj?.event === this.EVENTS.PAGE_LOADED);
8251
8252            if (eventIndex !== -1) {
8253                eventSent = appEventData.slice(eventIndex).some((eventObj) =>
8254                    eventObj?.[`${event.includes('modal') ? 'modal' : 'link'}`]?.[`${event.includes('modal') ? 'modalAction' : 'linkName'}`] === eventName &&
8255                    eventName.includes(section) &&
8256                    (!productID || (action === 'view' || action === 'cancel'
8257                        ? crossPageData.listOfIDs?.data?.includes(productID) : eventObj?.productInfo?.substitution?.productId === productID))
8258                );
8259            }
8260            return eventSent;
8261        }
8262
8263
8264        const productID = action === 'view' || action === 'cancel' ? document.getElementById('exampleModal')?.closest('.p-3')?.querySelector('a')?.dataset?.bpn : action === 'confirm' ? item?.itemCode ? item?.itemCode : item?.orderedItemId : '';
8265        const isSubPref = item?.replacements?.some(item => !!item.saveAsFutureSubPreference) || false;
8266        productInfo.substitution = productInfo.substitution || {};
8267        const section = (action === 'view' || action === 'cancel' ? (item?.replacedItems?.find(item => item?.orderedItemId === productID)) : item)?.substitutionPrefType === 'CustomerChoiceNotSubstitution' ? 'substitute-not-available' : 'items-to-review';
8268        const event = action === 'view' ? this.EVENTS.MODAL_VIEW : this.EVENTS.MODAL_CLICK;
8269        const eventString = `${section}-don't-substitute${isSubPref ? '-pref-sub-tag' : ''}|${action}`;
8270        const selectElement = action === 'view' && document.querySelectorAll(`a[data-bpn="${productID}"]`) && Array.from(document.querySelectorAll(`a[data-bpn="${productID}"]`)).find(element => element.closest('.card.p-3'));
8271        const slotNumber = action === 'view' && document.querySelectorAll('.card.p-3')?.length > 0 ?
8272            document.querySelectorAll('.card.p-3') && Array.from(document.querySelectorAll('.card.p-3'))?.indexOf(selectElement.closest('.card.p-3')) + 1 : 0;
8273
8274        modal.modalMessage = action !== 'confirm' ? '' : modal.modalMessage;
8275        if (isSubPref) {
8276            this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsFeatureTracking', data: 'subsPrefACIP405518' });
8277        }
8278        if (productID && (action === 'confirm')) {
8279            productInfo.substitution.productID = productID || '';
8280            productInfo.substitution.isSubstitution = false;
8281            productInfo.substitution.substitutionOption = `do-not-substitute:${productID}`;
8282        }
8283
8284        const eventSent = setOncePerPage(eventString, event, productID);
8285
8286        if (action === 'view') {
8287            !eventSent && this.setModalViewEvents(eventString);
8288        } else if (action === 'cancel') {
8289            !eventSent && this.setModalClickEvents(eventString);
8290        } else {
8291            AB.DATALAYER.pushEvent(
8292                event, {
8293                modal: {
8294                    modalAction: eventString,
8295                    modalMessage: modal.modalMessage
8296                },
8297                page: digitalData?.pageDetails,
8298                pageFilter: digitalData?.pageFilter,
8299                user: digitalData?.user,
8300                productInfo: digitalData?.productInfo
8301            }
8302            )
8303        }
8304        modal.modalMessage = slotNumber ? `do-not-substitute-${slotNumber > 9 ? slotNumber : `0${slotNumber}`}#01` : '';
8305        if (productID) {
8306            let listOfIDs = [];
8307
8308            if (crossPageData?.listOfIDs?.data?.length > 0) {
8309                crossPageData?.listOfIDs?.data?.forEach(id => { listOfIDs.push(id) });
8310                if (!listOfIDs.includes(productID)) {
8311                    listOfIDs.push(productID);
8312                }
8313            } else listOfIDs.push(productID);
8314            this.setAnalyticsCrossPageData({ action: 'set', name: 'listOfIDs', data: listOfIDs });
8315        }
8316
8317        if (action === 'cancel' || action === 'confirm') {
8318            digitalData.modal = {};
8319            digitalData.productInfo = {};
8320        }
8321    }
8322
8323    /**
8324     * Sets the cart id
8325     * @param id
8326     */
8327    this.updateCartId = function (id) {
8328        if (digitalData?.cart?.cartInfo) {
8329            digitalData.cart.cartInfo.cartId = id;
8330        }
8331    };
8332
8333    /**
8334     * Sets the cart type
8335     * @param type
8336     */
8337    this.updateCartType = function (type) {
8338        if (digitalData?.cart?.cartInfo) {
8339            digitalData.cart.cartInfo.cartType = type;
8340        }
8341    };
8342
8343    /**
8344     * Sets cart isMFC
8345     * @param isMFC
8346     */
8347    this.updateCartIsMFC = function (isMFC) {
8348        if (digitalData?.cart?.cartInfo) {
8349            digitalData.cart.cartInfo.isMFC = isMFC;
8350        }
8351    }
8352
8353    /**
8354     * Sets cart mfcUnavailableCount
8355     * @param mfcUnavailableCount
8356     */
8357    this.updateCartMFCUnavailableCount = function (mfcUnavailableCount) {
8358        if (digitalData?.cart?.cartInfo) {
8359            let computedStateCart = digitalData.cart;
8360            computedStateCart.cartInfo.mfcUnavailableCount = mfcUnavailableCount;
8361        }
8362    }
8363
8364    this.setCartObj = function (cart, newItem, isCalledFromBIA, isEditCart) {
8365        let wysiwygFlag = cart.guestCartId ? true : cart.isWYSIWYGEnabled;
8366        let allItems = cart && cart['cartItemsList'] ? cart['cartItemsList'] : cart && cart['orderItems'] ? cart['orderItems'] : cart && cart['cartItems'] ? cart['cartItems'] : cart ? cart : [];
8367        let sellerCartsCombined = [];
8368        digitalData.cart.sellerCarts = digitalData.cart.sellerCarts || [];
8369        digitalData.cart.absItems = digitalData.cart.absItems || [];
8370        const isSelectiveCart = cart?.selectiveCart;
8371
8372        let filtereredItems = [];
8373        if (Array.isArray(allItems) && allItems.length > 0) {
8374            if (!isCalledFromBIA) {
8375                let newFiltereredItems = allItems.filter(function (item) {
8376                    if (isSelectiveCart) {
8377                        return item.itemId && item.isFound && item.isAvailable;
8378                    }
8379                    return item.name && item.price && item.isFound;
8380                });
8381                filtereredItems = newFiltereredItems;
8382            } else {
8383                let BIAFiltered = allItems.filter(function (item) {
8384                    return item.name && item.price;
8385                });
8386                filtereredItems = BIAFiltered;
8387            }
8388        }
8389
8390        if (cart && (cart['seller'] && Object.keys(cart['seller']).length > 0 || cart.cartCategory === '1P_WINE')) {
8391            let mktpCartId = cart.guestCartId ? cart.guestCartId : cart.cartId;
8392            let mktpCartType = digitalData?.cart?.cartInfo?.cartType || '';
8393            let mktpSKUS = [];
8394            let mktpSubtotal = cart.summary?.totalBasePrice?.toString();
8395            let mktpSellerId = cart.seller ? cart.seller.sellerId : '22222222';
8396            digitalData.cart.cartInfo.cartIDMap[mktpSellerId] = mktpCartId;
8397
8398            if (window['analyticsSellerIds']?.indexOf(mktpSellerId) === -1) {
8399                window['analyticsSellerIds'].push(mktpSellerId);
8400            }
8401
8402            if (filtereredItems.length > 0) {
8403                if (wysiwygFlag && cart && cart.summary) {
8404                    filtereredItems.forEach(item => {
8405                        digitalData.cart.sellerCarts[`sellerItem${mktpSellerId}`] = filtereredItems.map((item) => {
8406                            return AB.DATALAYER.setCartItemsWYSIWYG(item, mktpSellerId, mktpCartId);
8407                        })
8408                        mktpSKUS.push(item.itemId);
8409                    });
8410                } else {
8411                    filtereredItems.forEach(item => {
8412                        digitalData.cart.sellerCarts[`sellerItem${mktpSellerId}`] = filtereredItems.map((item) => {
8413                            return AB.DATALAYER.setCartItemsNonWYSIWYG(item, mktpSellerId, mktpCartId);
8414                        });
8415                        mktpSKUS.push(item.itemId || item.productID || item.id);
8416                    });
8417                }
8418            }
8419
8420            let mktpCart = `${mktpSellerId}#${mktpCartId}#${mktpCartType}#${mktpSKUS.join(':')}#${mktpSubtotal}`;
8421            if (cart.cartCategory === '1P_WINE') {
8422                digitalData.cart.cartInfo.cartIDWineShop = `${mktpSellerId}#${mktpCartId}#${mktpCartType}#${mktpSKUS.join(',')}#${mktpSubtotal}`;
8423                digitalData.cart.transaction.subTotalWineCart = digitalData.cart.transaction.subTotalWineCart || {};
8424                digitalData.cart.transaction.subTotalWineCart.subTotal = +mktpSubtotal;
8425                digitalData.cart.transaction.subTotalWineCart.sellerId = mktpSellerId;
8426            } else {
8427                let sellerCartsIDs = [];
8428                if (Object.values(digitalData.cart.marketplace).length > 0) {
8429                    Object.values(digitalData.cart.marketplace).forEach(seller => {
8430                        sellerCartsIDs.push(seller['sellerId']);
8431                    });
8432                }
8433                for (let i = 1; i <= 8; i++) {
8434                    if (digitalData.cart.marketplace[`seller${i}`] && digitalData.cart.marketplace[`seller${i}`].sellerId === mktpSellerId) {
8435                        digitalData.cart.marketplace[`seller${i}`].sellerCartID = mktpCart;
8436                        break;
8437                    } else if (!digitalData.cart.marketplace[`seller${i}`] && sellerCartsIDs.indexOf(mktpSellerId) === -1) {
8438                        digitalData.cart.marketplace[`seller${i}`] = {
8439                            sellerCartID: mktpCart,
8440                            sellerId: mktpSellerId,
8441                            sellerPfm: {}
8442                        };
8443                        mktpSKUS.forEach(id => {
8444                            if (id) {
8445                                digitalData.cart.marketplace[`seller${i}`].sellerPfm[id] = digitalData.cart.marketplace[`seller${i}`].sellerPfm[id] ? digitalData.cart.marketplace[`seller${i}`].sellerPfm[id] : `${mktpSellerId}#product-details#PDP-landing#non-search#not-recommended#R01#S01`;
8446                            }
8447                        });
8448                        break;
8449                    }
8450                }
8451                if (digitalData.cart.transaction) {
8452                    digitalData.cart.transaction.subTotalMarketplaceCarts = digitalData.cart.transaction.subTotalMarketplaceCarts
8453                        ? digitalData.cart.transaction.subTotalMarketplaceCarts.includes(`${mktpSellerId}:`)
8454                            ? digitalData.cart.transaction.subTotalMarketplaceCarts
8455                            : `${digitalData.cart.transaction.subTotalMarketplaceCarts}#${mktpSellerId}:${mktpSubtotal}`
8456                        : `${mktpSellerId}:${mktpSubtotal}`;
8457                }
8458            }
8459        } else if (cart.cartCategory === '1P' || cart.cartCategory === '1P_B2B' || isEditCart) {
8460            let cartId = cart.guestCartId ? cart.guestCartId : cart.cartId;
8461            let sellerId = cart.seller ? cart.seller.sellerId : AB.DATALAYER.getBannerSellerId();
8462            if (window['analyticsSellerIds']?.indexOf(AB.DATALAYER.getBannerSellerId()) === -1) {
8463                window['analyticsSellerIds'].push(AB.DATALAYER.getBannerSellerId());
8464            }
8465
8466            // Banner is NOT WYSIWYG enabled
8467            if (wysiwygFlag === false || wysiwygFlag == undefined) {
8468                if (digitalData && digitalData.cart) {
8469                    if (filtereredItems.length > 0) {
8470                        digitalData.cart.absItems = filtereredItems.map((item) => {
8471                            return AB.DATALAYER.setCartItemsNonWYSIWYG(item, sellerId, cartId);
8472                        });
8473
8474                        let subTotal = 0;
8475                        // Add item prices to calculate subtotal
8476                        digitalData.cart.absItems.forEach(function (item) {
8477                            if (!isNaN(parseFloat(item.totalPrice))) {
8478                                subTotal += parseFloat(item.totalPrice);
8479                            }
8480                        });
8481                        if (digitalData.cart.transaction) {
8482                            digitalData.cart.transaction.subTotal = subTotal;
8483                        }
8484                    }
8485                    digitalData.cart.isWYSIWYGEnabled = false;
8486                    digitalData.cart.cartInfo.cartId = cart.guestCartId ? cart.guestCartId : cart.cartId ? cart.cartId : '';
8487                }
8488                if (digitalData && digitalData.productInfo && newItem) {
8489                    digitalData.productInfo.productName = newItem.name;
8490                    digitalData.productInfo.listPrice = newItem.price?.toString();
8491                }
8492            } else if (wysiwygFlag === true) {
8493                // Banner IS WYSIWYG enabled
8494                if (digitalData && digitalData.cart) {
8495                    if (filtereredItems.length > 0) {
8496                        digitalData.cart.absItems = filtereredItems.map((item) => {
8497                            return AB.DATALAYER.setCartItemsWYSIWYG(item, sellerId, cartId);
8498                        });
8499
8500                        let subTotal = 0;
8501                        digitalData.cart.absItems.forEach(function (item) {
8502                            if (!isNaN(parseFloat(item.totalPrice))) {
8503                                subTotal += parseFloat(item.totalPrice);
8504                            }
8505                        });
8506                        if (digitalData.cart.transaction) {
8507                            digitalData.cart.transaction.subTotal = subTotal;
8508                        }
8509                    }
8510                    digitalData.cart.isWYSIWYGEnabled = true;
8511                    digitalData.cart.cartInfo.cartId = cart.guestCartId ? cart.guestCartId : cart.cartId ? cart.cartId : '';
8512                }
8513
8514                if (digitalData && digitalData.productInfo) {
8515                    if (newItem) {
8516                        digitalData.productInfo.productName = newItem.name;
8517                        digitalData.productInfo.listPrice = newItem.price?.toString();
8518                    }
8519                    if (digitalData.productInfo.productID && digitalData.cart && digitalData.cart.item && digitalData.cart.item.length > 0) {
8520                        const productAdded = digitalData.cart.item.filter(item => item.productID == digitalData.productInfo.productID)[0];
8521                        if (productAdded) {
8522                            digitalData.productInfo.offerType = productAdded.offerType;
8523                            digitalData.productInfo.offerText = productAdded.offerText;
8524                        }
8525                    }
8526                }
8527            }
8528            window.digitalData.cart.cartInfo.cartIDMap[`${AB.DATALAYER.getBannerSellerId()}`] = cart.guestCartId ? cart.guestCartId : cart.cartId;
8529            if (cart?.summary?.cardSavings) {
8530                digitalData.cart.transaction.revenue = cart?.summary?.transactionTotal?.toString() || '0';
8531                this.updateCartSavings(0, 0, cart);
8532            } else {
8533                digitalData.cart.transaction.revenue = cart?.summary?.totalEstimatedPrice?.toString() || '0';
8534                digitalData.cart.savings.totalSavings = cart?.summary?.estimatedClubCardSavings?.toString() || '';
8535            }
8536        } else if (cart?.cartCategory === '1P_SNS') {
8537            digitalData.cart.cartInfo.cartId = cart?.cartId ? cart.cartId : '';
8538        }
8539        const currentProduct = digitalData.cart.item?.find(item => {
8540            return item.productID == digitalData.productInfo.productID;
8541        });
8542        digitalData.cart.cartInfo.currentCartId = currentProduct?.productCartId?.toString();
8543        digitalData.productInfo.sellerId = digitalData.productInfo.sellerId || currentProduct?.productSellerId?.toString();
8544        sellerCartsCombined = Array.prototype.concat.apply([], Object.values(digitalData.cart.sellerCarts));
8545        digitalData.cart.item = digitalData.cart.absItems.concat(sellerCartsCombined);
8546        if (digitalData.cart?.cartInfo?.cartType === 'mini_cart' || this.isCartAndCheckoutPage('erums/cart')) {
8547            digitalData.pageDetails.sellerId = window['analyticsSellerIds'].join(',');
8548        }
8549        AB.DATALAYER.setActiveCarts(digitalData.cart.item);
8550    }
8551
8552    /**
8553     * Updates the cart items list on product actions and minicart open
8554     * @param allItems 
8555     * @param newItem 
8556     * @param wysiwygFlag 
8557     */
8558    this.updateCart = function (cart, newItem, wysiwygFlag, isCalledFromBIA) {
8559        digitalData.cart = digitalData.cart || {};
8560        window['analyticsSellerIds'] = window['analyticsSellerIds'] ? window['analyticsSellerIds'] : localStorage.getItem('analyticsSellerIds') && localStorage.getItem('analyticsSellerIds').split(',').length > 0 ? localStorage.getItem('analyticsSellerIds').split(',') : [];
8561
8562        //if taxes table is visible add corresponding impression
8563        if (cart?.summary?.tax && !digitalData?.pageFilter?.impressions?.includes('minicart-tax') && digitalData?.cart?.cartInfo?.cartType === 'mini_cart') {
8564            digitalData.pageFilter.impressions = digitalData.pageFilter.impressions ? `${digitalData.pageFilter.impressions},minicart-tax` : 'minicart-tax';
8565        }
8566
8567        // Handling multicart response
8568        if (cart.cart && Object.values(cart.cart).length > 0) {
8569            digitalData.cart.cartsFromAPI = Object.values(cart.cart);
8570        } else {
8571            digitalData.cart.cartsFromAPI = [cart];
8572        }
8573        digitalData.cart.marketplace = digitalData.cart.marketplace || {};
8574        digitalData.cart.cartInfo = digitalData.cart.cartInfo || {};
8575        digitalData.cart.cartInfo.cartIDMap = digitalData.cart.cartInfo.cartIDMap || {};
8576
8577        if (Object.keys(digitalData.cart.marketplace).length === 0 && localStorage.getItem('analyticsSellerCartsInfo') && localStorage.getItem('analyticsSellerCartsInfo') !== 'undefined') {
8578            digitalData.cart.marketplace = AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('analyticsSellerCartsInfo'));
8579        }
8580
8581        if (digitalData?.cart?.cartsFromAPI && digitalData.cart.cartsFromAPI.length > 0) {
8582            digitalData.cart.cartsFromAPI.forEach(cart => {
8583                this.setCartObj(cart, newItem, isCalledFromBIA);
8584            });
8585            if (digitalData.cart.marketplace && Object.keys(digitalData.cart.marketplace).length > 0) {
8586                for (let i = 1; i <= 8; i++) {
8587                    if (digitalData.cart.marketplace[`seller${i}`] && window['analyticsSellerIds'].indexOf(digitalData.cart.marketplace[`seller${i}`].sellerId) === -1) {
8588                        delete digitalData.cart.marketplace[`seller${i}`];
8589                    }
8590                }
8591                localStorage.setItem('analyticsSellerCartsInfo', JSON.stringify(window.digitalData.cart.marketplace));
8592            }
8593        }
8594    };
8595
8596    this.setCartItemsWYSIWYG = function (item, sellerId, cartId) {
8597        let itemSavings = item.savings || [];
8598        let savings = AB.DATALAYER.calculateCartSavings(itemSavings, 'item');
8599        // Clubcard savings can be found in and out of the savings array, we must add the two values for the full CC Savings value
8600        let ccSavings = item.clubCardSaving && !isNaN(parseFloat(item.clubCardSaving)) ? item.clubCardSaving : 0;
8601        // savings.clubcardSavings is returned as a string from the method in utils, which we are also using for cart so it cannot be passed as integer from there
8602        let totalCCSavings = !isNaN(parseFloat(savings.clubcardSavings)) ? parseFloat(savings.clubcardSavings) + ccSavings : 0;
8603        let totalItemSavingsWithCC = savings.total + ccSavings;
8604
8605        let offerTypeArray = [];
8606        let offerTextArray = [];
8607        if (itemSavings.length > 0) {
8608            itemSavings.forEach(offer => {
8609                let externalOfferId = offer.externalOfferId || '';
8610                let isNDOffer = externalOfferId.indexOf('-ND') !== -1;
8611                if (offer.categoryName) {
8612                    offerTypeArray.push(`${isNDOffer ? 'ND:' : ''}${offer.categoryName}`);
8613                }
8614                if (offer.displayOfferTxt) {
8615                    offerTextArray.push(`${isNDOffer ? 'ND:' : ''}${offer.displayOfferTxt}`);
8616                } else if (offer.linkPluNumber && offer.source === 'CMS') {
8617                    offerTextArray.push(`${isNDOffer ? 'ND:' : ''}Buy 1 Get 1 Free`);
8618                } else if (offer.discountMessage) {
8619                    offerTextArray.push(`${isNDOffer ? 'ND:' : ''}${offer.discountMessage}`);
8620                }
8621            });
8622        }
8623
8624        // Setting default value for prices used for calculations, as the cart API response sometimes doesn't send a value for prices for some items
8625        let basePrice = item.basePrice ? item.basePrice : 0;
8626        let units = item.quantity ? item.quantity : item.qty ? item.qty : item.units ? item.units : 0;
8627        let totalBasePrice = basePrice * units;
8628        let totalItemPrice = totalBasePrice - totalItemSavingsWithCC;
8629        let itemPrice = totalItemPrice / units;
8630        if (itemPrice <= 0) {
8631            itemPrice = 0;
8632        }
8633        let clippedCoupons = '0';
8634        let savedCoupons = '0';
8635        if (item.clipped) {
8636            clippedCoupons = (item.clipped.length > 0) ? item.clipped.length.toString() : '0';
8637        }
8638        if (item.savings) {
8639            savedCoupons = (item.savings.length > 0) ? item.savings.length.toString() : '0';
8640        }
8641
8642        let product = {
8643            productID: item.id ? item.id.toString() : item.itemId ? item.itemId.toString() : '',
8644            productName: item.name,
8645            units: (units > 0) ? units.toString() : '',
8646            listPrice: item.price ? item.price.toString() : '',
8647            basePrice: (basePrice > 0) ? basePrice.toString() : '',
8648            pricePerUnit: item.pricePer ? item.pricePer.toString() : item.pricePerUnit ? item.pricePerUnit.toString() : item.unitPrice ? item.unitPrice.toString() : '',
8649            unitType: item.unitType ? item.unitType : item.unitQuantity ? item.unitQuantity : '',
8650            totalPrice: item.totalPrice ? item.totalPrice.toString() : '',
8651            itemPrice: (itemPrice > 0) ? itemPrice.toString() : '',
8652            inventory: (item.isAvailable ? '' : 'not-') + 'available',
8653            couponClipped: clippedCoupons,
8654            couponApplied: savedCoupons,
8655            clubcardItemSavings: totalCCSavings.toString(),
8656            j4uItemSavings: savings.j4uSavings,
8657            rewardsItemSavings: savings.rewardsSavings,
8658            employeeItemSavings: savings.employeeSavings,
8659            totalItemSavings: totalItemSavingsWithCC.toString(),
8660            offerType: offerTypeArray.join('#'),
8661            offerText: offerTextArray.join('#'),
8662            isFound: item.isFound,
8663            productSellerId: sellerId ? sellerId : '',
8664            source: item.source ? item.source.toLowerCase() : '',
8665            snapEligible: item.snapEligible === true ? 'true' : 'false',
8666            productCartId: cartId ? cartId : '',
8667            shelfName: item?.shelfName || '',
8668            isProductTrackingDisabled: !!item.isProductTrackingDisabled,
8669            productBrand: item?.brand
8670        }
8671
8672        // Set schedule and save source for order confirmation page
8673        if (item?.snsSub?.isSnsSub && item?.snsSub?.snsFrequency) {
8674            const snsProductObject = AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('snsSubscriptionProducts'));
8675            product.scheduleandSaveSource = `${snsProductObject[item.itemId?.toString()] || 'no-value'}#subscribe#every-${item?.snsSub?.snsFrequency.count}-${item?.snsSub?.snsFrequency.unit}${item?.snsSub?.snsFrequency.count > 1 ? 's' : ''}`;
8676            if (snsProductObject.hasOwnProperty(item.itemId?.toString())) {
8677                delete snsProductObject[item.itemId?.toString()];
8678            }
8679        }
8680
8681        return product;
8682    }
8683
8684    // We need to check if non WYSIWYG flow is still needed/available anywhere or if we can remove these functions
8685    this.setCartItemsNonWYSIWYG = function (item, sellerId, cartId) {
8686        let clippedCoupons = '0';
8687        let savedCoupons = '0';
8688        if (item.clipped) {
8689            clippedCoupons = (item.clipped.length > 0) ? item.clipped.length.toString() : '0';
8690        }
8691        if (item.savings) {
8692            savedCoupons = (item.savings.length > 0) ? item.savings.length.toString() : '0';
8693        }
8694
8695        let product = {
8696            productID: item.id ? item.id.toString() : item.itemId ? item.itemId.toString() : '',
8697            productName: item.name,
8698            units: item.quantity ? item.quantity.toString() : item.qty ? item.qty.toString() : item.units ? item.units.toString() : '',
8699            unitType: item.unitType ? item.unitType : item.unitQuantity ? item.unitQuantity : '',
8700            pricePerUnit: item.pricePer ? item.pricePer.toString() : item.pricePerUnit ? item.pricePerUnit.toString() : item.unitPrice ? item.unitPrice.toString() : '',
8701            basePrice: item.basePrice + '',
8702            listPrice: item.price + '',
8703            totalPrice: item.quantity && item.price ? (item.quantity * item.price).toString() : item.qty && item.price ? (item.qty * item.price).toString() : '',
8704            inventory: (item.isAvailable ? '' : 'not-') + 'available',
8705            isFound: item.isFound ? item.isFound : '',
8706            productSellerId: sellerId ? sellerId : '',
8707            couponClipped: clippedCoupons,
8708            couponApplied: savedCoupons,
8709            productCartId: cartId ? cartId : '',
8710            shelfName: item?.shelfName || '',
8711            isProductTrackingDisabled: !!item.isProductTrackingDisabled
8712        };
8713
8714        // Set schedule and save source for order confirmation page
8715        if (item?.snsSub?.isSnsSub && item?.snsSub?.snsFrequency) {
8716            const snsProductObject = AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('snsSubscriptionProducts'));
8717            product.scheduleandSaveSource = `${snsProductObject[item.itemId?.toString()] || 'no-value'}#subscribe#every-${item?.snsSub?.snsFrequency.count}-${item?.snsSub?.snsFrequency.unit}${item?.snsSub?.snsFrequency.count > 1 ? 's' : ''}`;
8718            if (snsProductObject.hasOwnProperty(item.itemId?.toString())) {
8719                delete snsProductObject[item.itemId?.toString()];
8720            }
8721        }
8722
8723        return product;
8724    }
8725
8726    /**
8727     * Sets the 'mini_cart' event on minicart open
8728     */
8729    this.updateMiniCartEvent = function () {
8730        window['analyticsCartnumber'] = window['analyticsCartnumber'] ? Number(window['analyticsCartnumber']) + 1 : 1;
8731        if ((window['analyticsNumberOfCarts'] && Number(window['analyticsCartnumber']) === Number(window['analyticsNumberOfCarts'])) || (!window['analyticsNumberOfCarts']) || (Number(window['analyticsCartnumber']) > Number(window['analyticsNumberOfCarts']))) {
8732            digitalData.pageDetails.sellerId = window['analyticsSellerIds'].join(',');
8733            window.digitalData.cart.cartInfo.currentCartId = window.digitalData.cart.cartInfo.cartIDMap ? Object.values(window.digitalData.cart.cartInfo.cartIDMap).join() : '';
8734            localStorage.setItem('analyticsSellerIds', window['analyticsSellerIds'].join(','));
8735            if (digitalData) {
8736                this.pushEvent(
8737                    this.EVENTS.MINICART,
8738                    {
8739                        cart: digitalData.cart,
8740                        page: digitalData.pageDetails,
8741                        pageFilter: digitalData.pageFilter
8742                    }
8743                );
8744            }
8745
8746            AB.DATALAYER.removeImpression('minicart-tax');
8747            AB.DATALAYER.removeImpression('exp-mini-chk');
8748
8749        }
8750    }
8751
8752    /**
8753     * Sets minicart promo banner impressions
8754     */
8755    this.setMiniCartBannerImpressions = function (cart, isNewUser) {
8756        if (digitalData?.pageFilter && cart?.cartCategory === '1P' && isNewUser) {
8757            const deliveryPreference = digitalData.user?.deliveryPreference;
8758            if (deliveryPreference && deliveryPreference !== 'inStore') {
8759                digitalData.pageFilter.impressions = `minicart-promo-banner-save${deliveryPreference === 'dug' ? '3' : '2'}0`;
8760            }
8761            this.setLSItem('analyticsPromoBannerView', 'checkout-promo-banner-visible');
8762        }
8763    }
8764
8765    /**
8766     * Track scroll impressions on initial product load
8767     */
8768    this.setAMCImpressionsGrid = function () {
8769        if ((this.isSearchResultsPage() || this.isAislesPage()) && !this.isWineShopPage() && !window.isAnalyticsMarketplacePage) {
8770            if (digitalData?.search.offset == 0) {
8771                digitalData.scrollImpressionsToTrack = digitalData.search.impressions ? structuredClone(digitalData.search.impressions) : [];
8772                digitalData.scrollImpressionsTracked = digitalData.scrollImpressionsTracked || [];
8773                let waitForElements;
8774
8775                function triggerImpression() {
8776                    let numberOfProducts;
8777                    const visibleProducts = [];
8778                    digitalData.scrollImpressionsToTrack.forEach((impression) => {
8779                        if (impression?.product?.id) {
8780                            const element = document.querySelector(`#pg${impression?.product?.id}`)?.closest('product-item, product-item-v2, product-item-al-v1, product-item-al-v2');
8781                            if (element) {
8782                                const currentGridTagName = element.closest('product-generic-grid-al-v1, search-grid, product-generic-grid, buy-it-again-grid')?.tagName;
8783                                numberOfProducts = document.querySelectorAll(`${currentGridTagName} product-item, ${currentGridTagName} product-item-v2, ${currentGridTagName} product-item-al-v1, ${currentGridTagName} product-item-al-v2`)?.length || 0;
8784                                if (AB.DATALAYER.isElementVisible(element) && digitalData.scrollImpressionsTracked.indexOf(impression.product.id) == -1) {
8785                                    if (waitForElements) {
8786                                        clearInterval(waitForElements);
8787                                        waitForElements = undefined;
8788                                    }
8789                                    digitalData.scrollImpressionsTracked.push(impression.product.id);
8790                                    visibleProducts.push(impression.product);
8791                                }
8792                            }
8793                        }
8794                    })
8795                    if (visibleProducts.length > 0) {
8796                        let payload = {
8797                            link: {
8798                                linkName: `${digitalData.pageDetails.subSection1}-scrolled-impressions`
8799                            },
8800                            serverData: {
8801                                attributionToken: digitalData.user.storedAttributionToken
8802                            },
8803                            page: digitalData.pageDetails,
8804                            search: digitalData.search,
8805                            user: digitalData.user
8806                        };
8807                        payload.search.impressions = visibleProducts;
8808                        AB.DATALAYER.pushEvent('scrolled-impressions', payload);
8809                    }
8810                    if ((Array.isArray(digitalData.scrollImpressionsTracked) && numberOfProducts && digitalData.scrollImpressionsTracked.length == numberOfProducts) || digitalData.scrollImpressionsToTrack?.length === 0) {
8811                        document.removeEventListener('scroll', triggerImpression);
8812                    }
8813                }
8814
8815                if (Array.isArray(digitalData.scrollImpressionsToTrack) && digitalData.scrollImpressionsToTrack.length > 0) {
8816                    waitForElements = setInterval(triggerImpression, 300);
8817                    document.addEventListener('scroll', triggerImpression);
8818                }
8819            }
8820        }
8821    }
8822
8823    this.setAMCImpressionsCarousel = function (lazyWrapper, productList, action) {
8824        if (((this.isSearchResultsPage() || this.isAislesPage() || this.isPdp()) && !this.isWineShopPage() && !window.isAnalyticsMarketplacePage) && lazyWrapper?.dataset?.carouselDriven === 'featured-products') {
8825            const carouselTitle = lazyWrapper?.closest('.master-product-carousel')?.querySelector('.carousel-header-text') ? lazyWrapper?.closest('.master-product-carousel')?.querySelector('.carousel-header-text')?.textContent : lazyWrapper?.closest('.master-product-carousel')?.querySelector('.carousel-nav__header-title') ? lazyWrapper?.closest('.master-product-carousel')?.querySelector('.carousel-nav__header-title')?.textContent : 'no-value';
8826            const formattedCarouselTitle = lazyWrapper?.closest('.master-product-carousel')?.querySelector('.carousel-header-text') ? AB.DATALAYER.sanitizeAnalyticsText(lazyWrapper?.closest('.master-product-carousel')?.querySelector('.carousel-header-text')?.textContent) : lazyWrapper?.closest('.master-product-carousel')?.querySelector('.carousel-nav__header-title') ? AB.DATALAYER.sanitizeAnalyticsText(lazyWrapper?.closest('.master-product-carousel')?.querySelector('.carousel-nav__header-title')?.textContent) : 'no-value';
8827            digitalData.carouselAMCImpressionsToTrack = digitalData.carouselAMCImpressionsToTrack || {};
8828            digitalData.carouselAMCImpressionsTracked = digitalData.carouselAMCImpressionsTracked || {};
8829            if (formattedCarouselTitle) {
8830                digitalData.carouselAMCImpressionsToTrack[formattedCarouselTitle] = digitalData.carouselAMCImpressionsToTrack[formattedCarouselTitle] && Array.isArray(digitalData.carouselAMCImpressionsToTrack[formattedCarouselTitle]) && productList && Array.isArray(productList) ? digitalData.carouselAMCImpressionsToTrack[formattedCarouselTitle].concat(productList) : productList && Array.isArray(productList) ? productList : [];
8831                digitalData.carouselAMCImpressionsTracked[formattedCarouselTitle] = digitalData.carouselAMCImpressionsTracked[formattedCarouselTitle] || [];
8832            }
8833
8834            function triggerImpression() {
8835                const visibleProducts = [];
8836                digitalData.carouselAMCImpressionsToTrack[formattedCarouselTitle]?.forEach((impression) => {
8837                    if (AB.DATALAYER.isAlcoholAdTrackingDisabled(impression)) {
8838                        return;
8839                    }
8840                    if (impression?.id) {
8841                        const element = lazyWrapper?.querySelector(`#pg${impression?.id}`)?.closest('product-carousel-item, product-carousel-item-v2, product-carousel-item-al-v1, product-carousel-item-al-v2');
8842                        if (element) {
8843                            if (AB.DATALAYER.isElementVisible(element) && digitalData.carouselAMCImpressionsTracked && digitalData.carouselAMCImpressionsTracked[formattedCarouselTitle].indexOf(impression.id) == -1) {
8844                                document.removeEventListener('scroll', triggerImpression);
8845                                digitalData.carouselAMCImpressionsTracked[formattedCarouselTitle].push(impression.id);
8846                                const isSpImpFixOn = !window?.SWY?.CONFIGSERVICE?.featureToggleConfig?.isSponsoredImpressionFixDisabled;
8847                                if (isSpImpFixOn) {
8848                                    const placement = AB.DATALAYER.setCarouselPosition({ productId: impression.id, carouselSection: carouselTitle, nativeElement: element }) || 'R00#S00';
8849                                    const isSponsored = !!(impression.adId || impression.featured);
8850                                    // recType is used only inside the pfm string; rTyp is the canonical eVar14 value.
8851                                    const recType = isSponsored ? 'sponsored' : 'recs';
8852                                    const rTyp = isSponsored ? 'sponsored' : 'recommended';
8853                                    const currentProductPfm = `${AB.DATALAYER.pfmFromCurrentPage}#${formattedCarouselTitle}#${AB.DATALAYER.isSearchResultsPage() ? digitalData.search?.internalSearchTerm : 'non-search'}#${recType}#${placement}`;
8854                                    const detail = impression?.adobeMetrics?.metricA
8855                                        || (AB.DATALAYER.returnImpressionAdditionalDetail ? AB.DATALAYER.returnImpressionAdditionalDetail(impression) : '');
8856
8857                                    visibleProducts.push({
8858                                        section: carouselTitle ? AB.DATALAYER.sanitizeAnalyticsText(carouselTitle) : '',
8859                                        lp: impression.price,
8860                                        pfm: currentProductPfm,
8861                                        pId: impression.id,
8862                                        units: AB.DATALAYER.getProductCartUnits(impression.id),
8863                                        pName: AB.DATALAYER.isPdp() ? impression.name : undefined,
8864                                        sponsored: isSponsored,
8865                                        badge: AB.DATALAYER.getUIBadge(lazyWra
8865pper, impression.id),
8866                                        display: 'carousel',
8867                                        placement: placement,
8868                                        detail: detail,
8869                                        rTyp: rTyp
8870                                    });
8871                                } else {
8872                                    const placement = AB.DATALAYER.setCarouselPosition({ productId: impression.id, carouselSection: carouselTitle });
8873                                    const recType = impression.adId || impression.featured ? 'sponsored' : 'recs';
8874                                    const currentProductPfm = `${AB.DATALAYER.pfmFromCurrentPage}#${formattedCarouselTitle}#${AB.DATALAYER.isSearchResultsPage() ? digitalData.search?.internalSearchTerm : 'non-search'}#${recType}#${placement}`;
8875
8876                                    visibleProducts.push({
8877                                        section: carouselTitle ? AB.DATALAYER.sanitizeAnalyticsText(carouselTitle) : '',
8878                                        lp: impression.price,
8879                                        pfm: currentProductPfm,
8880                                        pId: impression.id,
8881                                        units: impression.quantity || impression.qty || 0,
8882                                        pName: AB.DATALAYER.isPdp() ? impression.name : undefined,
8883                                        sponsored: true,
8884                                        badge: AB.DATALAYER.getUIBadge(lazyWrapper, impression.id)
8885                                    });
8886                                }
8887                            }
8888                        }
8889                    }
8890                })
8891                if (visibleProducts.length > 0) {
8892                    let payload = {
8893                        link: {
8894                            linkName: `${digitalData.pageDetails.subSection1}-product-impressions`
8895                        },
8896                        page: digitalData.pageDetails,
8897                        search: digitalData.search,
8898                        user: digitalData.user,
8899                        pageFilter: digitalData.pageFilter
8900                    };
8901                    if (AB.DATALAYER.isSearchResultsPage()) {
8902                        payload.search = digitalData.search;
8903                    }
8904                    if (AB.DATALAYER.isPdp()) {
8905                        payload.productInfo = AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('analyticsAMCPDPInfo'));
8906                    }
8907                    payload.carousel = visibleProducts;
8908                    payload.pageFilter.mediaType = 'product-carousel';
8909                    payload.pageFilter.placement = '';
8910                    if (!window?.SWY?.CONFIGSERVICE?.featureToggleConfig?.isSponsoredImpressionFixDisabled) {
8911                        // Drive rTyp (eVar14) from the first visible product's classification
8912                        const firstRTyp = visibleProducts[0]?.rTyp;
8913                        if (firstRTyp) {
8914                            payload.pageFilter.recommendationType = firstRTyp;
8915                        }
8916                    }
8917                    AB.DATALAYER.pushEvent('product-impressions', payload);
8918                    digitalData.pageFilter.mediaType = '';
8919                }
8920            }
8921
8922            if (Array.isArray(digitalData.carouselAMCImpressionsToTrack[formattedCarouselTitle]) && digitalData.carouselAMCImpressionsToTrack[formattedCarouselTitle].length > 0 && action === 'load') {
8923                document.addEventListener('scroll', triggerImpression);
8924            }
8925        }
8926    }
8927
8928    this.setSmartBasketImpressions = function (lazyWrapper) {
8929        if (lazyWrapper?.dataset?.targetedComponent === 'instant-grocery-basket') {
8930            const parsedData = AB.DATALAYER.safeJSONParse(lazyWrapper?.getAttribute('data-zone-response'));
8931            const productList = parsedData?.productsinfo || [];
8932            const formattedCarouselTitle = AB.DATALAYER.sanitizeAnalyticsText(parsedData?.title);
8933            const trackedProducts = [];
8934
8935            productList.forEach((impression) => {
8936                if (impression?.id) {
8937                    const slot = productList.indexOf(impression) + 1;
8938                    const sectionInfo = AB.DATALAYER.getZoneInfo(lazyWrapper);
8939                    const placement = `R01#S${slot < 10 ? `0${slot}` : slot}`;
8940                    const currentProductPfm = `${AB.DATALAYER.pfmFromCurrentPage}#${formattedCarouselTitle}#${AB.DATALAYER.isSearchResultsPage() ? digitalData.search?.internalSearchTerm : 'non-search'}#pastPurchased#${placement}`;
8941
8942                    trackedProducts.push({
8943                        section: formattedCarouselTitle,
8944                        pageNbr: '0',
8945                        lp: impression.price,
8946                        pfm: currentProductPfm,
8947                        pId: impression.id,
8948                        units: impression.quantity || impression.qty || 0,
8949                        pName: impression.name,
8950                        detail: impression?.adobeMetrics?.metricA,
8951                        display: 'carousel',
8952                        placement: `${placement}#ZONE${sectionInfo?.zone ? (sectionInfo?.zone < 10 ? `0${sectionInfo?.zone}` : sectionInfo?.zone) : '00'}`
8953                    });
8954
8955                }
8956            })
8957            if (trackedProducts.length > 0) {
8958                let payload = {
8959                    link: {
8960                        linkName: 'product-impressions'
8961                    },
8962                    page: digitalData.pageDetails,
8963                    search: digitalData.search,
8964                    user: digitalData.user,
8965                    pageFilter: digitalData.pageFilter
8966                };
8967                if (AB.DATALAYER.isSearchResultsPage()) {
8968                    payload.search = digitalData.search;
8969                }
8970                payload.carousel = trackedProducts;
8971                payload.pageFilter.mediaType = 'product-carousel';
8972                payload.pageFilter.placement = '';
8973                AB.DATALAYER.pushEvent('product-impressions', payload);
8974                digitalData.pageFilter.mediaType = '';
8975            }
8976        }
8977    }
8978
8979    /**
8980     * Sets the GRS impressions information
8981     * @param eventName
8982     * @param data
8983     * @param isCarousel // true if the impression is for a carousal
8984     */
8985    this.setGRSImpressions = function (eventName, data, isCarousel) {
8986        const searchData = this.setGRSVariables(data, isCarousel);
8987        let searchInfo = digitalData.search || {};
8988
8989        let search = {
8990            ...searchInfo,
8991            ...searchData
8992        };
8993        const miscInfo = data && data['miscInfo'] ? data['miscInfo'] : {};
8994        const attributionToken = miscInfo && miscInfo['attributionToken'] ? miscInfo['attributionToken'] : '';
8995        digitalData.user.storedAttributionToken = attributionToken;
8996        if (!this.isSearchResultsPage() && eventName === AB.DATALAYER.EVENTS.CATEGORY_IMPRESSIONS) {
8997            if (this.isDealsPage()) {
8998                eventName = AB.DATALAYER.EVENTS.DEALS_IMPRESSIONS;
8999            }
9000            search.searchType = 'search';
9001            AB.DATALAYER.pushEvent(
9002                eventName, {
9003                search: search,
9004                page: digitalData.pageDetails,
9005                pageFilter: digitalData.pageFilter,
9006                user: digitalData.user,
9007                serverData: {
9008                    attributionToken: attributionToken
9009                }
9010            });
9011        } else if (eventName === AB.DATALAYER.EVENTS.SEARCH_IMPRESSIONS || (this.isMarketplaceSearchPage() || this.isWineShopSearchPage()) || (miscInfo?.query && data?.isLoadMore)) {
9012            if (!this.isDealsPage()) {
9013                eventName = AB.DATALAYER.EVENTS.SEARCH_IMPRESSIONS;
9014                if (search.pageCategories) {
9015                    delete search.pageCategories;
9016                }
9017                if (search.autoSearchFlag) {
9018                    delete search.autoSearchFlag;
9019                }
9020                search.apiSearchTerm = miscInfo && miscInfo['query'] ? miscInfo['query'] : '';
9021                const selectPostion = this.handleGetLSValue('auto-search-selection-index');
9022                if (selectPostion) {
9023                    search.selectedPosition = selectPostion;
9024                    search.completionAttrToken = attributionToken || '';
9025                    search.autoSearchFlag = true;
9026                }
9027                AB.DATALAYER.pushEvent(
9028                    eventName, {
9029                    search: search,
9030                    page: digitalData.pageDetails,
9031                    pageFilter: digitalData.pageFilter,
9032                    user: digitalData.user,
9033                    productInfo: digitalData.productInfo || {},
9034                    serverData: {
9035                        attributionToken: attributionToken
9036                    }
9037                });
9038            }
9039        }
9040        // Commented out as requested in ACIP-490883
9041        // this.setAMCImpressionsGrid();
9042    }
9043
9044    /**
9045        * Sets the GRS impressions information
9046        * @param data
9047        * @param isCarousel // true if the impression is for a carousal
9048        */
9049    this.setGRSVariables = function (data, isCarousel) {
9050        const products = data && data['docs'] ? data['docs'] : data && data['products'] ? data['products'] : [];
9051        const productCount = data && data['numFound'] ? data['numFound'] : data && data['productsCounter'] ? data['productsCounter'] : 0;
9052        const miscInfo = data && data['miscInfo'] ? data['miscInfo'] : {};
9053        const offset = data && data['start'] ? data['start'] : 0;
9054        const searchInfo = {}
9055        const impressions = [];
9056        if (!isCarousel) {
9057            digitalData.gridImpressionsProducts = digitalData.gridImpressionsProducts || [];
9058            products.forEach(product => {
9059                if (digitalData.gridImpressionsProducts && product.id && digitalData.gridImpressionsProducts.indexOf(product.id) === -1) {
9060                    digitalData.gridImpressionsProducts.push(product.id);
9061                }
9062            })
9063        }
9064
9065        products.forEach(product => {
9066            if (AB.DATALAYER.isAlcoholAdTrackingDisabled(product)) {
9067                return;
9068            }
9069            impressions.push({
9070                product: {
9071                    id: product?.pid,
9072                    bia: product?.pastPurchased, //Buy it Again indicator | pastPurchased | boolean | true,false
9073                    oos: product?.inventoryAvailable > 0 ? false : true, //Out of Stock indicator | inventoryAvailable | boolean | if '0' = product, then not in stock (true), if '1' = product, then in stock (false)
9074                    sponsored: product?.featured, //Sponsored indicator | featured | boolean | true, false
9075                    mp: product?.isMarketplaceItem, //Marketplace indicator | isMarketplaceItem | string | 'Y' if marketplace item, 'N' if not marketplace item
9076                    display: isCarousel ? 'carousel' : 'grid', //Grid Carousel indicator | string | if product from primaryProdcuts, then 'grid'. if product from pgmList, then 'carousel'.
9077                    placement: !isCarousel ? AB.DATALAYER.setImpressionGridPosition({ productId: product?.pid }) : AB.DATALAYER.setCarouselPosition({ productId: product?.pid }),
9078                    pageNumber: offset && Number(offset) ? (Number(offset) / 30 + 1).toString() : '1'
9079                }
9080            })
9081        });
9082        searchInfo.offset = offset || 0;
9083        searchInfo.searchResults = productCount?.toString() || '0';
9084        searchInfo.filter = miscInfo && miscInfo['filter'] ? miscInfo['filter'] : '';
9085        searchInfo.orderBy = miscInfo && miscInfo['sort'] ? miscInfo['sort'] : '';
9086        searchInfo.impressions = impressions;
9087        const categoryRegex = /(?:categories: ANY\(")(.*?)(?:"\))/;
9088        const matchedCategories = categoryRegex.exec(searchInfo.filter);
9089        let pageCategory = matchedCategories?.length > 0 ? matchedCategories[1] : 'All Products';
9090        if (this.isWineShopCategoryPage() && pageCategory === 'All Products') {
9091            const departmentName = `${products[0]?.departmentName}`;
9092            const aisleName = `${products[0]?.aisleName && products[0]?.aisleName?.split('|')[0]}`;
9093            const shelfName = `${products[0]?.shelfName}`;
9094            // Wine Shop handled for BR feed, where categories are not available in the API filter property
9095            pageCategory = this.isWineShopL2Page() ? departmentName
9096                : this.isWineShopL3Page() ? `${departmentName} > ${aisleName}`
9097                    : this.isWineShopL4Page() ? `${departmentName} > ${aisleName} > ${shelfName}` : '';
9098        }
9099        searchInfo.pageCategories = [pageCategory] || [];
9100
9101        return searchInfo;
9102    }
9103
9104    /**
9105     * Sets the search information
9106     * @param searchInfo
9107     */
9108    this.setSearch = function (searchInfo) {
9109        if (!this.isAislesL2Page() && !this.isAislesL3Page() && !this.isAislesL4Page() && !this.isDealsPage() && !this.isMarketplaceCategoryPage() && !this.isWineShopCategoryPage() && !this.isLpPage()) {
9110            this.removeLSItem('analyticsSimilarItemsPDP');
9111            this.removeLSItem('analyticsSimilarItemsCart');
9112            this.removeLSItem('analyticsMetaInfo');
9113            this.removeSSItem('analyticsProductIdPDP');
9114            if (digitalData) {
9115                digitalData.search = digitalData.search || {};
9116                digitalData.search.searchType = searchInfo.searchType;
9117                digitalData.search.typedSearchTerm = searchInfo.typedSearchTerm || 'not available';
9118                digitalData.search.autoSearchFlag = searchInfo.autoSearchFlag;
9119                digitalData.search.typedSearchCount = searchInfo.typedSearchCount || 'not available';
9120                digitalData.search.internalSearchTerm = searchInfo.internalSearchTerm;
9121                digitalData.search.searchResults = searchInfo.searchResults;
9122                digitalData.search.searchResultPositionClicked = this.handleGetLSValue('analyticsBrandSearch');
9123
9124                // suggested category
9125                const departmentName = AB.DATALAYER.analyticsGetURLParameterByName('departmentName');
9126                if (departmentName && AB.DATALAYER.analyticsGetURLParameterByName('ref') === 'suggest') {
9127                    digitalData.search.internalSearchTerm = `${digitalData.search.internalSearchTerm}-in-${departmentName.toLowerCase().replace(/[, ]+/g, '-')}`;
9128                    digitalData.search.suggestedCategory = departmentName;
9129                }
9130
9131
9132                digitalData.pageDetails.sellerId = searchInfo.sellerId
9133                    ? searchInfo.sellerId
9134                    : searchInfo.crossSellerIds
9135                        ? searchInfo.crossSellerIds
9136                        : this.isWineShopPage() ? '22222222' : this.getBannerSellerId();
9137
9138                let zeroSearchResults = Number(digitalData.search.searchResults) === 0;
9139
9140                if (searchInfo.pastPurchased > 0) {
9141                    this.setImpression(`pastPurchased#${searchInfo.pastPurchased}`);
9142                }
9143                if (searchInfo.dynamicFacets) {
9144                    this.setImpression('dynmc');
9145                    digitalData.pageFlags = digitalData.pageFlags || {};
9146                    digitalData.pageFlags.isDynamicFacetsEnabled = true;
9147                }
9148                if (this.getLSItem('analyticsOwnBrandImpressions')) {
9149                    this.setImpression('v1');
9150                    this.removeLSItem('analyticsOwnBrandImpressions');
9151                }
9152                // AR - set link object when a user clicks on 'View All' link - Schedule & Save carousel
9153                const link = {
9154                    linkName: ''
9155                };
9156                if (this.getLSItem('analyticsARviewAll')) {
9157                    link.linkName = this.handleGetLSValue('analyticsARviewAll');
9158                }
9159
9160                if (digitalData.pageDetails.subSection1 === 'm' || digitalData.pageDetails.subSection1 === 'marketplace' || this.isWineShopPage()) {
9161                    if (digitalData.pageDetails.subSection2 === 'seller-search') {
9162                        digitalData.pageDetails.subSection1 = 'search-results';
9163                        digitalData.pageDetails.subSection2 = 'cross-sellers';
9164                        digitalData.pageDetails.pageName = digitalData.pageDetails.pageName.replace('seller-search', 'search-results:cross-sellers');
9165                    } else {
9166                        digitalData.pageDetails.subSection1 = 'search-results';
9167                        digitalData.pageDetails.subSection2 = '';
9168                    }
9169                } else if (window.location.pathname.startsWith('/schedule-and-save/manage')) {
9170                    digitalData.pageDetails.subSection1 = 'search-results';
9171                    digitalData.pageDetails.subSection2 = '';
9172                    digitalData.pageDetails.subSection3 = '';
9173                    digitalData.pageDetails.subSection4 = '';
9174                    digitalData.pageDetails.pageName = 'safeway:delivery:search-results';
9175                    digitalData.pageFilter = digitalData.pageFilter || {};
9176                    digitalData.pageFilter.topNav = '';
9177                }
9178
9179                if (zeroSearchResults) {
9180                    digitalData.pageDetails.subSection1 = 'zero-search-results';
9181                    digitalData.pageDetails.pageName = digitalData.pageDetails.pageName.replace('search-results', 'zero-search-results');
9182
9183                    if (digitalData.pageDetails.subSection2 === 'cross-sellers') {
9184                        this.mkpCrossSellersNoResultsClicks();
9185                    }
9186                }
9187
9188                if (this.getLSItem('analyticsCrossSellersNoResults') && digitalData.pageFilter) {
9189                    digitalData.pageFilter.topNav = this.handleGetLSValue('analyticsCrossSellersNoResults');
9190                }
9191
9192                if (!this.isRecipesAndMealsPage() && !window.location.pathname.startsWith('/schedule-and-save/manage')) {
9193                    this.initEngagementLadderImpressions();
9194                    this.initCartPromoBannerImpressions();
9195                    this.initFlexCardDetails();
9196                    this.initAEMZoneTracking();
9197                    this.initDFTACarousel();
9198                    this.initHeroBannerAbTestDetails();
9199                    this.initBundleAbTestDetails();
9200                }
9201
9202                AB.DATALAYER.updatePageNameAndSubSectionRestrictedFlag();
9203                AB.DATALAYER.setPreviousPageName();
9204                // If there are no search results, set the 'zero_search_results' event with all existing info otherwise set the regular search event
9205                AB.DATALAYER.pushEvent(
9206                    zeroSearchResults ? AB.DATALAYER.EVENTS.ZERO_SEARCH_RESULTS : AB.DATALAYER.EVENTS.SEARCH, {
9207                    search: digitalData.search,
9208                    page: digitalData.pageDetails,
9209                    pageFilter: digitalData.pageFilter,
9210                    user: digitalData.user,
9211                    productInfo: digitalData.productInfo || {},
9212                    link: link.linkName ? link : undefined,
9213                    modal: digitalData.modal
9214                });
9215
9216                // Reset property so that values don't persist between hits
9217                digitalData.pageFilter.bannerCardCarousel = '';
9218                this.handleAccountEvents();
9219                this.setFeaturedFacetsFilter();
9220            }
9221        }
9222    };
9223
9224    /**
9225     * updates the search information; still used in product-generic-grid - unsure if component is still in use anywhere so keeping method
9226     * @param searchInfo
9227     */
9228    this.updateSearch = function (searchTerm, numOfResults) {
9229        if (!this.isAislesL2Page() && !this.isAislesL3Page() && !this.isAislesL4Page()) {
9230            if (digitalData && digitalData.search) {
9231                let searchData = digitalData.search;
9232                searchData.internalSearchTerm = searchTerm;
9233                if (numOfResults === 0) {
9234                    searchData.searchResults = 'zero';
9235                } else {
9236                    searchData.searchResults = numOfResults.toString();
9237                }
9238                this.pushEvent(
9239                    this.EVENTS.SEARCH, {
9240                    search: searchData,
9241                    page: digitalData?.pageDetails,
9242                    pageFilter: digitalData?.pageFilter
9243                }
9244                );
9245            }
9246        }
9247    };
9248
9249    /**
9250     * Sets the PDP event on product page load
9251     * Separate setup & event than global pageLoad
9252     */
9253    this.setPDPevent = function (productInfoObj) {
9254        AB.DATALAYER.productInfo(productInfoObj, 'product-detail');
9255        this.initPDPPfm(productInfoObj);
9256        this.initPDPPlacementMediaType();
9257
9258        if (productInfoObj.isPastPurchased) {
9259            AB.DATALAYER.setPastPurchasedImpressions('buyItAgainPdp');
9260        }
9261        this.removeLSItem('analyticsSimilarItemsPDP');
9262        this.removeLSItem('analyticsSimilarItemsCart');
9263        this.removeLSItem('analyticsMetaInfo');
9264        this.removeLSItem('changeCardAnalyticsAR');
9265        this.removeLSItem('analyticsAMCPDPInfo');
9266
9267        if (digitalData && digitalData.pageDetails) {
9268            const productInfo = digitalData.productInfo || {};
9269            productInfo.pfmDetail = digitalData.pageDetails.pfmDetail;
9270            if (digitalData.productInfo.channel) {
9271                const delivery = digitalData.productInfo.channel.delivery ? digitalData.productInfo.channel.delivery : false;
9272                const pickup = digitalData.productInfo.channel.pickUp ? digitalData.productInfo.channel.pickUp : false;
9273                const inStore = digitalData.productInfo.channel.inStore ? digitalData.productInfo.channel.inStore : false;
9274                if (inStore === true && (delivery === true || pickup === true)) {
9275                    digitalData.productInfo.productAvailability = 'online,in-store';
9276                } else if (inStore === false && (delivery === true || pickup === true)) {
9277                    digitalData.productInfo.productAvailability = 'online-only';
9278                } else if (inStore === true && delivery === false && pickup === false) {
9279                    digitalData.productInfo.productAvailability = 'in-store-only';
9280                }
9281            }
9282
9283            // AR - set link object when a user clicks on 'Schedule & Save' on the product cards
9284            const link = {
9285                linkName: ''
9286            };
9287            if (this.getLSItem('analyticsARproductCard')) {
9288                link.linkName = this.getLSItem('analyticsARproductCard');
9289                this.removeLSItem('analyticsARproductCard');
9290            }
9291
9292            if (this.getLSItem('pfmSourceCategories')) {
9293                digitalData.pageFilter.pfmSource = this.handleGetLSValue('pfmSourceCategories');
9294            } else if (this.getLSItem('pfmSourceSimilarItemsBIA')) {
9295                digitalData.pageFilter.pfmSource = this.handleGetLSValue('pfmSourceSimilarItemsBIA');
9296            }
9297            if (this.getLSItem('analyticsBIAPfmSource') && this.getLSItem('analyticsBIAPfmSource') !== 'undefined') {
9298                digitalData.pageFilter.pfmSource = this.getLSItem('analyticsBIAPfmSource');
9299            }
9300            if (this.getLSItem('analyticsBIAProductImpressionAdDetail') && this.getLSItem('analyticsBIAProductImpressionAdDetail') !== 'undefined') {
9301                productInfo.impressionAdditionalDetail = this.getLSItem('analyticsBIAProductImpressionAdDetail');
9302            }
9303            if (this.getLSItem('analyticsIsBIACarousal') && this.getLSItem('analyticsIsBIACarousal') !== 'undefined') {
9304                productInfo.isBIACarousalProduct = this.getLSItem('analyticsIsBIACarousal') === 'true' ? true : false;
9305            }
9306            if (this.getLSItem('analyticsProductMsg')) {
9307                digitalData.pageDetails.abTestDetails = this.getLSItem('analyticsProductMsg');
9308            }
9309            this.initMarketplacePDP();
9310            this.initWineShopPDP();
9311            this.initEngagementLadderImpressions();
9312            this.initCartPromoBannerImpressions();
9313            this.initFlexCardDetails();
9314            this.initDFTACarousel();
9315            this.initAEMZoneTracking();
9316            this.initHeroBannerAbTestDetails();
9317            this.initBundleAbTestDetails();
9318
9319            if (AB.DATALAYER.isNewPdp()) {
9320                digitalData.pageDetails.subSection1 = 'product-details';
9321                digitalData.pageDetails.subSection2 = '';
9322                digitalData.pageDetails.subSection3 = '';
9323                AB.DATALAYER.setPageName(false, true);
9324                digitalData.pageFilter.topNav = this.initTopNav();
9325            }
9326
9327            AB.DATALAYER.updatePageNameAndSubSectionRestrictedFlag();
9328            AB.DATALAYER.setPreviousPageName();
9329            AB.DATALAYER.setLSItem('analyticsAMCPDPInfo', JSON.stringify(productInfo));
9330            AB.DATALAYER.pushEvent(
9331                AB.DATALAYER.EVENTS.PRODUCT_LOADED,
9332                {
9333                    page: digitalData.pageDetails,
9334                    pageFilter: digitalData.pageFilter,
9335                    user: digitalData.user,
9336                    productInfo: productInfo,
9337                    link: link.linkName ? link : undefined
9338                }
9339            );
9340
9341            // Reset property so that values don't persist between hits
9342            digitalData.pageFilter.bannerCardCarousel = '';
9343            digitalData.pageDetails.abTestDetails = '';
9344            this.handleAccountEvents();
9345        }
9346    };
9347
9348    this.initReviewsPage = function () {
9349        const { pageDetails, pageFilter } = digitalData;
9350        pageDetails.subSection1 = 'product-details';
9351        pageDetails.subSection2 = 'reviews';
9352        pageDetails.subSection3 = '';
9353        pageDetails.subSection4 = '';
9354        pageFilter.topNav = this.initTopNav();
9355        this.setPageName('', true);
9356        digitalData?.pageFlags?.isPageLoadSent && (digitalData.pageFlags.isPageLoadSent = false);
9357        this.setPageLoad();
9358        pageFilter.topNav = '';
9359    }
9360
9361    /**
9362     * Sends event when coupon is unclipped - currently (04/10/2021) only from MyList page
9363     * @param coupon coupon details object
9364     */
9365    this.unClipCoupon = function (coupon) {
9366        if (digitalData) {
9367            digitalData.coupon = {
9368                couponName: coupon.brand,
9369                couponType: coupon.offerType,
9370                couponId: coupon.offerId,
9371                couponSavings: coupon.offerPrice,
9372                carouselSection: coupon.carouselSection ? AB.DATALAYER.sanitizeAnalyticsText(coupon.carouselSection) : ''
9373            };
9374
9375            this.pushEvent(
9376                this.EVENTS.UNCLIP, {
9377                coupon: digitalData.coupon,
9378                page: digitalData?.pageDetails,
9379                pageFilter: digitalData?.pageFilter
9380            }
9381            );
9382        }
9383    };
9384
9385    /**
9386     * Sends event when coupon is clipped
9387     * @param  coupon coupon details object
9388     */
9389    this.clipCoupon = function (coupon, analyticsData) {
9390        let element = analyticsData?.nativeElement;
9391        digitalData.modal = digitalData.modal || {};
9392        if (digitalData) {
9393            if (coupon && digitalData.productInfo && digitalData.productInfo.carouselSection && digitalData.productInfo.carouselSection.toLowerCase().indexOf('picks for you') !== -1) {
9394                coupon.carouselSection = digitalData.productInfo.carouselSection;
9395                if (coupon.carouselSection.trim().toLowerCase() === 'picks for you') {
9396                    coupon.carouselSection = 'Picked for You';
9397                }
9398            }
9399            coupon = {
9400                couponName: coupon.brand,
9401                couponType: coupon.offerType,
9402                couponId: coupon.offerId,
9403                couponclipmethod: 'singleclip', // 'barcodescan' and 'stackandsave' not available on web
9404                numberofcouponsclipped: '1', // no multi-clip available on web
9405                couponSavings: coupon.offerPrice?.toString() || '0',
9406                productSKU: (typeof (digitalData.productInfo) === 'object') && digitalData.productInfo?.productID ? digitalData.productInfo.productID.toString() : '',
9407                carouselSection: (typeof (digitalData.coupon) === 'object') ? (coupon.carouselSection && coupon.carouselSection.toLowerCase().indexOf('picks for you') !== -1 || coupon.carouselSection && coupon.carouselSection.toLowerCase().indexOf('picked for you') !== -1 ? `${digitalData.coupon.carouselSection}-${coupon.carouselSection.trim().toLowerCase().split(' ').join('-').replace(/[^\w-,|#:]/gi, '').replace('--', '-')}` : digitalData.coupon.carouselSection) :
9408                    (coupon.carouselSection ? coupon.carouselSection : digitalData.pageFilter.carousel && digitalData.pageFilter.carousel.substring(digitalData.pageFilter.carousel.indexOf('|') + 1))
9409            };
9410            // Needed in order to accurately get the carousel name on weekly ad deals page
9411            if (AB.DATALAYER.isWeeklyAdDealsPage()) {
9412                coupon.carouselSection = AB.DATALAYER.getAnalyticsCarouselTitle(element);
9413                digitalData.modal.modalMessage = `weekly-ad:${AB.DATALAYER.sanitizeAnalyticsText(coupon.carouselSection)}`;
9414            }
9415            if (!coupon.carouselSection && digitalData.pageFilter && digitalData.pageFilter.bentoCarouselTitle) {
9416                coupon.carouselSection = digitalData.pageFilter.bentoCarouselTitle;
9417                digitalData.pageFilter.bentoCarouselTitle = '';
9418            }
9419            coupon.carouselSection = this.sanitizeAnalyticsText(coupon.carouselSection);
9420
9421            // Division name for batch coupon clip tracking
9422            coupon.divisionName = digitalData.storeFlags?.flags?.division?.name || 'no-value';
9423
9424            if (element) {
9425                const modelId = element.closest('lazy-wrapper')?.getAttribute('data-model-configuration-id');
9426                if (modelId) {
9427                    coupon.abTestDetails = digitalData.couponTrackingInfo && digitalData.couponTrackingInfo[modelId] && digitalData.couponTrackingInfo[modelId].msgExperiment || 'no-value';
9428                }
9429            }
9430
9431            // Setting metricA tracking for batch coupon clip tracking
9432            if (digitalData.couponTrackingInfo?.couponMetricAList && digitalData.couponTrackingInfo.couponMetricAList[coupon.couponId]) {
9433                coupon.msgData = digitalData.couponTrackingInfo.couponMetricAList[coupon.couponId];
9434            }
9435
9436            this.updateJourneyStatus(this.Flag.COUPON_CLIPPED);
9437
9438            let currentProduct = digitalData.productInfo;
9439            if (currentProduct && Object.keys(currentProduct).length > 0 && currentProduct.productID) {
9440                currentProduct.couponID = currentProduct.couponID || '';
9441
9442                if (currentProduct.couponID === '') {
9443                    currentProduct.couponID = coupon.offerId;
9444                    currentProduct.couponClipped = (parseInt(currentProduct.couponClipped) + 1).toString();
9445                } else {
9446                    let couponIds = currentProduct.couponID.split(',');
9447                    if (couponIds.indexOf(coupon.offerId) === -1) {
9448                        couponIds.push(coupon.offerId);
9449                        currentProduct.couponID = couponIds.toString();
9450                        currentProduct.couponClipped = (parseInt(currentProduct.couponClipped) + 1).toString();
9451                    }
9452                }
9453                if (!this.isDFTAPage()) {
9454                    if (currentProduct.carouselSection) {
9455                        digitalData.pageFilter.carousel = currentProduct.carouselSectionUncurated ? currentProduct.carouselSectionUncurated : currentProduct.carouselSection;
9456                        this.setCarouselPosition({ productId: currentProduct.productID, carouselSection: currentProduct.carouselSectionUncurated ? currentProduct.carouselSectionUncurated : currentProduct.carouselSection, eventName: 'coupon_clipped', nativeElement: element });
9457                    } else {
9458                        this.setProductGridPosition({ productId: currentProduct.productID, eventName: 'coupon_clipped', nativeElement: element });
9459                    }
9460                } else {
9461                    if (digitalData.pageFilter) {
9462                        digitalData.pageFilter.carousel = '';
9463                    }
9464                }
9465            } else {
9466                if (!this.isDFTAPage()) {
9467                    coupon.clipLocation = this.setCouponPlacement(coupon, element, 'clip-coupon');
9468                }
9469            }
9470            // Set abTestDetails and modalMessage when clipping coupon from splash modal
9471            if (digitalData.pageDetails) {
9472                digitalData.pageDetails.abTestDetails = analyticsData?.abTestDetails ? analyticsData.abTestDetails : ''
9473                digitalData.modal.modalMessage = analyticsData?.modalMessage ? analyticsData.modalMessage : digitalData.modal.modalMessage ? digitalData.modal.modalMessage : '';
9474                coupon.pageData = digitalData.pageDetails;
9475            }
9476            // Set page & user data where coupon was clipped for batch coupon clip tracking on next event/page
9477            if (digitalData.pageFilter) {
9478                coupon.pageFilterData = digitalData.pageFilter;
9479            }
9480            if (digitalData.user) {
9481                coupon.userData = digitalData.user;
9482            }
9483            if (digitalData.modal) {
9484                coupon.modalData = digitalData.modal;
9485            }
9486
9487            // Batch coupon tracking
9488            this.setBatchCouponTimer(coupon);
9489
9490        
9491            if (digitalData._bentoCouponV218 && digitalData.pageFilter) {
9492                digitalData.pageFilter.bannerCardCarousel = digitalData._bentoCouponV218;
9493                delete digitalData._bentoCouponV218;
9494            }
9495
9496            this.pushEvent(
9497                this.EVENTS.COUPONCLIPPED,
9498                {
9499                    coupon: coupon,
9500                    page: digitalData.pageDetails,
9501                    pageFilter: digitalData.pageFilter,
9502                    productInfo: currentProduct,
9503                    modal: digitalData.modal
9504                }
9505            );
9506
9507            if (AB.DATALAYER.isHomePage()) {
9508                const isProductCarouselCoupon = !!(currentProduct && Object.keys(currentProduct).length > 0 && currentProduct.productID);
9509                const crsMediaType = isProductCarouselCoupon ? 'product-carousel' : 'deals-carousel';
9510                const crsSection = isProductCarouselCoupon
9511                    ? (currentProduct.carouselSectionUncurated || currentProduct.carouselSection)
9512                    : coupon.carouselSection;
9513                AB.DATALAYER.setCRSClickEvent({
9514                    linkName: 'coupon-clip-click',
9515                    mTyp: crsMediaType,
9516                    element: element,
9517                    placement: digitalData.pageFilter?.placement || coupon.clipLocation,
9518                    component: AB.DATALAYER.getCRSComponent({
9519                        element: element,
9520                        section: crsSection,
9521                        detail: coupon.msgData,
9522                        placement: digitalData.pageFilter?.placement || coupon.clipLocation
9523                    }),
9524                    batchCouponsClipped: [coupon]
9525                });
9526            }
9527
9528            if (digitalData.coupon && digitalData.coupon.carouselSection && digitalData.coupon.carouselSection.indexOf('offer-drawer') !== -1) {
9529                delete digitalData.coupon;
9530            }
9531            digitalData.productInfo = {};
9532            // Resetting property to prevent data persistence between htis
9533            digitalData.pageFilter.bannerCardCarousel = '';
9534            // Defensive: clear the bento skip-flag so it can't leak to a later non-bento coupon clip.
9535            digitalData.pageFilter.bentoCouponV218Set = false;
9536        }
9537    };
9538
9539    /**
9540     * store's coupon object in local storage and starts timer for batch coupon even
9541     */
9542    this.setBatchCoupon = function () {
9543        let lsCurrentCouponClips = this.handleGetLSValue('couponGroup');
9544
9545        if (lsCurrentCouponClips) {
9546            const couponArray = AB.DATALAYER.safeJSONParse(lsCurrentCouponClips);
9547            if (couponArray.length > 0) {
9548                const pageDetails = couponArray[0].pageData;
9549                const pageFilter = couponArray[0].pageFilterData;
9550                const user = couponArray[0].userData;
9551                const modal = couponArray[0].modalData;
9552
9553                this.pushEvent(
9554                    this.EVENTS.BATCHCOUPONCLIPPED, {
9555                    batchCouponsClipped: couponArray,
9556                    page: pageDetails,
9557                    pageFilter: pageFilter,
9558                    user: user,
9559                    modal: modal
9560                });
9561            }
9562        }
9563    }
9564
9565    /**
9566     * store's coupon object in local storage and starts timer for batch coupon event
9567     * @param coupon coupon object when coupon clip happens
9568     */
9569    this.setBatchCouponTimer = function (coupon) {
9570        let lsCurrentCouponClips = this.getLSItem('couponGroup');
9571        let couponArray = [];
9572        if (lsCurrentCouponClips) {
9573            couponArray = AB.DATALAYER.safeJSONParse(lsCurrentCouponClips);
9574        }
9575        couponArray.push(coupon)
9576        this.setLSItem('couponGroup', JSON.stringify(couponArray))
9577        if (this.getLSItem('couponGroupTimeoutId')) {
9578            clearTimeout(Number(this.getLSItem('couponGroupTimeoutId')))
9579            localStorage.removeItem('couponGroupTimeoutId')
9580        }
9581        let timeoutID = setTimeout(() => {
9582            if (this.getLSItem('couponGroup')) {
9583                this.setBatchCoupon()
9584            }
9585        }, 15000)
9586        this.setLSItem('couponGroupTimeoutId', timeoutID)
9587    }
9588
9589    /**
9590     * sets the total number of available coupons and the coupon source
9591     * @param nr number of coupons available
9592     * @param source source of coupon clipping
9593     */
9594    this.setCouponsDetails = function (nr, source) {
9595        if (digitalData) {
9596            digitalData.coupon = {
9597                numberofcoupons: nr,
9598                couponSource: source
9599            };
9600
9601            this.pushEvent(
9602                this.EVENTS.COUPONNR, {
9603                coupon: digitalData.coupon,
9604                page: digitalData.pageDetails,
9605                pageFilter: digitalData.pageFilter
9606            }
9607            );
9608        }
9609    };
9610
9611    /**
9612     * Sets the sort event
9613     * @param sort the sort selection value, eg. Recently Purchsed, Recommended etc
9614     */
9615    this.sortBy = function (sort) {
9616        if (digitalData) {
9617            digitalData.pageFilter.sortSelection = sort;
9618            digitalData.gridImpressionsProducts = [];
9619            this.pushEvent(
9620                'page_sort', {
9621                page: digitalData?.pageDetails,
9622                pageFilter: digitalData?.pageFilter
9623            }
9624            );
9625        }
9626    };
9627
9628    this.setFilterType = function (type) {
9629        if (digitalData) {
9630            digitalData.gridImpressionsProducts = [];
9631            if (!localStorage.getItem('dontsetfilter')) {
9632                digitalData.pageFilter.filterType = type;
9633                this.pushEvent(
9634                    'page_filter', {
9635                    page: digitalData?.pageDetails,
9636                    pageFilter: digitalData?.pageFilter
9637                }
9638                );
9639            }
9640            localStorage.removeItem('dontsetfilter');
9641        }
9642    };
9643
9644    this.setFilterSelection = function (selection) {
9645        if (digitalData) {
9646            digitalData.gridImpressionsProducts = [];
9647            if (!localStorage.getItem('dontsetfilter')) {
9648                digitalData.pageFilter.filterSelection = selection;
9649                this.pushEvent(
9650                    'page_filter', {
9651                    page: digitalData?.pageDetails,
9652                    pageFilter: digitalData?.pageFilter
9653                }
9654                );
9655            }
9656            localStorage.removeItem('dontsetfilter');
9657        }
9658    };
9659    this.setPageFilter = function (linkName) {
9660        if (digitalData) {
9661            digitalData.gridImpressionsProducts = [];
9662            if (!localStorage.getItem('dontsetfilter')) {
9663                this.pushEvent(
9664                    'page_filter', {
9665                    page: digitalData?.pageDetails,
9666                    pageFilter: digitalData?.pageFilter,
9667                    link: {
9668                        linkName: linkName || digitalData?.link?.linkName
9669                    }
9670                }
9671                );
9672                digitalData.pageFilter.dynamicFilters = '';
9673            }
9674            localStorage.removeItem('dontsetfilter');
9675        }
9676    }
9677
9678    this.setFiltersSelectionsFromUrl = function () {
9679        if (digitalData) {
9680            if (digitalData.pageFilter.filterSelection === '') {
9681                let categories = AB.DATALAYER.analyticsGetURLParameterByName('category', false)
9682                    ? AB.DATALAYER.analyticsGetURLParameterByName('category', false).split(',').map(function (x) {
9683                        return `category: ${decodeURIComponent(x)}`;
9684                    }).join(',')
9685                    : '';
9686                let events = AB.DATALAYER.analyticsGetURLParameterByName('event', false)
9687                    ? AB.DATALAYER.analyticsGetURLParameterByName('event', false).split(',').map(function (x) {
9688                        return `event: ${decodeURIComponent(x)}`;
9689                    }).join(',')
9690                    : '';
9691                let offerTypes = AB.DATALAYER.analyticsGetURLParameterByName('offerPgm', false)
9692                    ? AB.DATALAYER.analyticsGetURLParameterByName('offerPgm', false).split(',').map(function (x) {
9693                        return `offerPgm: ${decodeURIComponent(x)}`;
9694                    }).join(',')
9695                    : '';
9696
9697                let filters = [];
9698                let filterTypes = [];
9699                if (categories) {
9700                    filters.push(categories);
9701                    filterTypes.push('category');
9702                }
9703                if (events) {
9704                    filters.push(events);
9705                    filterTypes.push('events');
9706                }
9707                if (offerTypes) {
9708                    filters.push(offerTypes);
9709                    filterTypes.push('offerPgm');
9710                }
9711
9712                digitalData.pageFilter.filterSelection = filters.join(', ');
9713                digitalData.pageFilter.filterType = filterTypes.join(', ');
9714            }
9715        }
9716    };
9717
9718    this.setBoxtopAuthState = function (state) {
9719        if (digitalData) {
9720            digitalData.boxtop.authState = state;
9721        }
9722    };
9723
9724    this.setBoxtopActionName = function (action) {
9725        if (digitalData) {
9726            digitalData.boxtop.actionName = action;
9727        }
9728    };
9729
9730    this.updateOrderCount = function (orderCount) {
9731        if (digitalData) {
9732            let user = digitalData.user;
9733            user.orderCount = orderCount?.toString();
9734            user.orderStatus = orderCount?.toString();
9735            if (user.orderStatus === '0') {
9736                user.customerStatus = 'first';
9737            } else if (user.orderStatus > 0) {
9738                user.customerStatus = 'returning';
9739            }
9740            if (digitalData.user) {
9741                digitalData.user.orderCount = digitalData.user.orderCount;
9742                digitalData.user.orderStatus = digitalData.user.orderStatus;
9743                digitalData.user.customerStatus = digitalData.user.customerStatus;
9744            }
9745
9746        }
9747    };
9748
9749    /**
9750     * sets the error information
9751     * @param id error id
9752     * @param feature where the error happened
9753     * @param message message the user received on error
9754     */
9755    this.setError = function (id, feature, message) {
9756        if (digitalData) {
9757            this.pushEvent(
9758                this.EVENTS.ERROR,
9759                {
9760                    error: {
9761                        errorID: id,
9762                        errorFeature: feature,
9763                        errorMessage: message
9764                    },
9765                    page: digitalData?.pageDetails,
9766                    pageFilter: digitalData?.pageFilter
9767                }
9768            );
9769        }
9770    };
9771
9772    /*
9773     * adds the filter type (search facet) to the selected filter types list, if not already added
9774     * @param filterType
9775     */
9776    this.addFilterType = function (filterType) {
9777        if (digitalData && digitalData.pageFilter) {
9778            const filterTypeValue = filterType.trim();
9779            if (this.selectedSearchFacets.indexOf(filterTypeValue) === -1) {
9780                this.selectedSearchFacets.push(filterTypeValue);
9781                digitalData.pageFilter.filterType = this.selectedSearchFacets.join(', ');
9782            }
9783            digitalData.link = digitalData.link || {};
9784            digitalData.link.linkName = 'page_filter';
9785        }
9786    };
9787
9788    /**
9789    * adds the filter selection to the selected filter selections list, if not already added
9790    * @param filterSelection
9791    */
9792
9793    this.addFilterSelection = function (filterSelection, filterGroupName) {
9794        if (digitalData && digitalData.pageFilter) {
9795            // if only one filter in a group can be selected at the same time check if a filter from group was previously selected and replace with new filter
9796            let previousFilterSelection;
9797            if (filterGroupName) {
9798                previousFilterSelection = this.selectedSearchSelections.find(selection => selection.includes(filterGroupName));
9799            }
9800            if (previousFilterSelection) {
9801                const filterSelectionIndex = this.selectedSearchSelections.indexOf(previousFilterSelection);
9802                const filterSelectionValue = filterSelection.trim();
9803                this.selectedSearchSelections[filterSelectionIndex] = filterSelectionValue;
9804                digitalData.pageFilter.filterSelection = this.selectedSearchSelections.join(', ');
9805            } else {
9806                const filterSelectionValue = filterSelection.trim();
9807                if (this.selectedSearchSelections.indexOf(filterSelectionValue) === -1) {
9808                    this.selectedSearchSelections.push(filterSelectionValue);
9809                    digitalData.pageFilter.filterSelection = this.selectedSearchSelections.join(', ');
9810                }
9811            }
9812            this.setTopNavMktpFilters(filterSelection);
9813        }
9814    };
9815
9816    /**
9817     * removes the filter type (search facet) from the selected filter types list
9818     * @param filterType
9819     */
9820    this.removeFilterType = function (filterType) {
9821        if (digitalData && digitalData.pageFilter) {
9822            if (filterType !== 'clearAll') {
9823                this.selectedSearchFacets = this.selectedSearchFacets.filter(function (x) {
9824                    return x !== filterType
9825                });
9826                digitalData.pageFilter.filterType = this.selectedSearchFacets.join(', ');
9827            } else {
9828                this.selectedSearchFacets = [];
9829                digitalData.pageFilter.filterType = this.selectedSearchFacets.join();
9830            }
9831            digitalData.link = digitalData.link || {};
9832            digitalData.link.linkName = this.isBIAPage() && filterType === 'clearAll' ? 'page_filter|clear-all' : 'page_filter';
9833        }
9834    };
9835
9836    this.removeFilterSelection = function (filterSelection) {
9837        if (digitalData && digitalData.pageFilter) {
9838            if (filterSelection !== 'clearAll') {
9839                this.selectedSearchSelections = this.selectedSearchSelections.filter(function (x) {
9840                    return x !== filterSelection
9841                });
9842                digitalData.pageFilter.filterSelection = this.selectedSearchSelections.join(', ');
9843            } else {
9844                this.selectedSearchSelections = [];
9845                digitalData.pageFilter.filterSelection = this.selectedSearchSelections.join();
9846            }
9847        }
9848    };
9849
9850    this.setDynamicFilters = function (filterType, filterSelection, facets, dynamicTile, hasConversationData) {
9851        if (filterType === 'Schedule & Save' || filterType === 'Deals') {
9852            return;
9853        }
9854        if (dynamicTile && digitalData?.pageFilter) {
9855            const position = facets?.findIndex(option => option.filterName === filterSelection) + 1;
9856            const updatedFilterSelection = position > 0 ? facets[position - 1]?.displayText : filterSelection;
9857            digitalData.pageFilter.dynamicFilters = position > 0
9858                ? `${hasConversationData ? 'cs-' : ''}ft:${updatedFilterSelection}:${position < 10 ? `0${position}` : position}${dynamicTile === 'remove' ? ':us' : ''}`
9859                : '';
9860        } else if (this.isSearchResultsPage() && !this.isMarketplaceSearchPage() && digitalData?.pageFilter && digitalData?.pageFlags?.isDynamicFacetsEnabled && !digitalData?.pageFilter?.dynamicFilters) {
9861            const filteredOptions = facets?.options?.filter(option => option.name !== 'Miscellaneous');
9862            const position = filteredOptions?.findIndex(option => option.name === filterSelection) + 1;
9863            digitalData.pageFilter.dynamicFilters = position > 0
9864                ? `${filterType}:${filterSelection}:${position < 10 ? `0${position}` : position}`
9865                : '';
9866        }
9867    }
9868
9869    // Set localStorage item to track navigation using the top nav links
9870    this.setTopNavPreviousPage = function (link, dontSetFilter) {
9871        if (digitalData && digitalData.pageDetails) {
9872            if (dontSetFilter) {
9873                localStorage.setItem('dontsetfilter', true);
9874            }
9875
9876            const isShopOrTopNavLink = link && typeof link === 'object' && link.closest('.shop-flyout-main-nav, .menu-nav__left-container') ? true : false;
9877            const isWeeklyAdOrYourStore = link?.hostname?.startsWith('coupons') || window.location.hostname.startsWith('coupons') || link?.textContent?.toLowerCase()?.includes('weekly ad') || link?.hostname?.startsWith('local') || window.location.hostname.startsWith('local') ? true : false;
9878            let topNavPreviousPage = `${window.isAnalyticsMarketplacePage ? 'mkp|' : ''}${AB.DATALAYER.pathSections.join(':')} (L${AB.DATALAYER.pathSections.length})`;
9879
9880            if (isShopOrTopNavLink && isWeeklyAdOrYourStore) {
9881                const oneTrustLoadedEvent = window['dataLayer'] && window['dataLayer'].find(x => x.event === 'OneTrustGroupsUpdated');
9882                if (oneTrustLoadedEvent?.['OnetrustActiveGroups']?.indexOf('C0002') !== -1) {
9883                    SWY.CONFIGSERVICE.setDomainCookie('topNavPreviousPage', topNavPreviousPage, `${digitalData.pageDetails.banner}.com`, 0);
9884                }
9885                return;
9886            }
9887            if (link && link.hostname && link.hostname !== window.location.hostname) {
9888                return;
9889            }
9890            if (link === 'checkout-minicart' || link === 'checkout-dnf' || link === 'express-checkout-minicart' || link === 'checkout-full-cart') {
9891                topNavPreviousPage = `cta:${link === 'checkout-minicart' ? 'mini-cart' : link === 'checkout-dnf' ? AB.DATALAYER.initPathSections(true).join(':') : (AB.DATALAYER.pathSections.join(':')).replace(/\s+/g, '-').toLowerCase()}|button|${link === 'checkout-dnf' ? 'continue-to-' : ''}${link === 'express-checkout-minicart' ? link : 'checkout'}`;
9892                localStorage.setItem('topNavCheckoutPage', topNavPreviousPage);
9893            } else {
9894                if (isShopOrTopNavLink) {
9895                    this.setLSItem('shopOrTopNavFlag', 'true');
9896                }
9897                localStorage.setItem('topNavPreviousPage', topNavPreviousPage);
9898            }
9899        }
9900    };
9901
9902    // Send the prebook information & event sent from the eRums prebook page
9903    this.initPrebookAEM = function () {
9904        const lsPrebookDl = localStorage.getItem('pageload_hit_buffer');
9905        if (lsPrebookDl) {
9906            const parsedPrebookDl = AB.DATALAYER.safeJSONParse(lsPrebookDl);
9907            this.pushEvent(
9908                parsedPrebookDl.event, parsedPrebookDl
9909            );
9910            localStorage.removeItem('pageload_hit_buffer');
9911        }
9912    }
9913
9914    // Set coupon placement & media-type for coupon carousel and coupon grid
9915    this.setCouponPlacement = function (coupon, nativeElement, calledBy) {
9916        let couponID = coupon?.couponID || coupon?.couponId;
9917        let placement = '';
9918        let contentType = '';
9919        let displayableCRPosition = '';
9920        const currentCoupon = calledBy === 'offer-drawer'
9921            ? nativeElement?.closest('coupon-carousel-item, coupon-card, loyalty-card-al-v1')
9922            : calledBy === 'deals-impressions-carousel' ? nativeElement?.querySelector('coupon-carousel-item, coupon-card, loyalty-card-al-v1')
9923                : (document.getElementById(`coupon-title-${couponID}`)?.closest('coupon-carousel-item, coupon-card') ||
9924                    document.getElementById(`coupon-title-${couponID}`)?.closest('coupon-item') ||
9925                    document.querySelectorAll('loyalty-card-al-v1')?.length > 0 && Array.from(document.querySelectorAll('loyalty-card-al-v1')).find(element => {
9926                        return element.querySelector('a')?.attributes['aria-describedby']?.value?.includes(`${couponID}`);
9927                    }
9928                    ));
9929
9930        if (currentCoupon && currentCoupon?.closest('coupon-carousel, loyalty-card-carousel-al-v1')) {
9931            //Placement for carousel in page and coupon in carousel
9932            const currentCouponCarousel = currentCoupon?.closest('coupon-carousel, loyalty-card-carousel-al-v1');
9933            const couponCarousels = document.querySelectorAll('coupon-carousel, loyalty-card-carousel-al-v1');
9934            const currentCCPosition = couponCarousels && Array.from(couponCarousels).indexOf(currentCouponCarousel) + 1;
9935            displayableCRPosition = currentCCPosition && currentCCPosition < 10 ? `0${currentCCPosition}` : currentCCPosition;
9936            const currentCouponPosition = currentCoupon && Number(currentCoupon?.closest('div.slick-slide:not(.slick-cloned)')?.getAttribute('data-slick-index')) + 1;
9937            const displayableSPosition = currentCouponPosition && currentCouponPosition < 10 ? `0${currentCouponPosition}` : currentCouponPosition;
9938            placement = `R${displayableCRPosition}#S${displayableSPosition}`;
9939            this.setPageFilterPlacement(placement, 'coupon-carousel', 'notRecommended');
9940            contentType = coupon?.carouselSection;
9941        } else if (currentCoupon && currentCoupon?.closest('coupon-grid')) {
9942            // Placement for coupon in grid
9943            const couponGrid = currentCoupon?.closest('coupon-grid');
9944            const gridCoupons = couponGrid?.querySelectorAll('coupon-item, loyalty-card-al-v1');
9945            const couponPosition = gridCoupons && Array.from(gridCoupons).indexOf(currentCoupon) + 1;
9946            let couponRow = couponPosition && couponPosition < 3 ? 1 : Math.ceil(couponPosition / 3);
9947            if (window.innerWidth < 992 && window.innerWidth > 767) {
9948                couponRow = couponPosition && couponPosition < 2 ? 1 : Math.ceil(couponPosition / 2);
9949            } else if (window.innerWidth < 768) {
9950                couponRow = couponPosition && couponPosition;
9951            }
9952            const displayableSPosition = couponPosition && couponPosition < 10 ? `0${couponPosition}` : couponPosition;
9953            const displayablePGPosition = couponRow && couponRow < 10 ? `0${couponRow}` : couponRow;
9954            placement = `R${displayablePGPosition}#S${displayableSPosition}`;
9955            this.setPageFilterPlacement(placement, 'coupon-grid', 'notRecommended');
9956            contentType = 'coupon-grid';
9957        }
9958        if (calledBy === 'clip-coupon') {
9959            if (digitalData && digitalData.pageFilter && digitalData.pageFilter.bentoCouponV218Set) {
9960                digitalData.pageFilter.bentoCouponV218Set = false;
9961                return placement;
9962            }
9963            this.trackAEMZone('coupon_clipped', nativeElement ? nativeElement : currentCoupon, contentType);
9964        }
9965        return calledBy === 'deals-impressions-carousel' ? `R${displayableCRPosition}` : placement;
9966    }
9967
9968    // Initialize banner placement from previous page
9969    this.initBannerPosition = function () {
9970        const lsBannerClicked = localStorage.getItem('bannerClickedDatalayer') || localStorage.getItem('skinnyBannerClickedDatalayer');
9971        if (lsBannerClicked) {
9972            const parsedBannerDl = AB.DATALAYER.safeJSONParse(lsBannerClicked);
9973            digitalData.pageFilter = parsedBannerDl.pageFilter;
9974            this.pushEvent(
9975                parsedBannerDl.event, parsedBannerDl
9976            );
9977            localStorage.removeItem('bannerClickedDatalayer');
9978            localStorage.removeItem('skinnyBannerClickedDatalayer');
9979        }
9980    }
9981
9982    // get the recommendation type for products based on the value from local storage for pdp
9983    this.getRecommendationType = function (recommendation) {
9984        let recommendationType = '';
9985        if (recommendation.indexOf('cross-sell') !== -1) {
9986            recommendationType = 'cross-sell';
9987            if (recommendation.indexOf('sponsored') !== -1) {
9988                recommendationType += ':sponsored';
9989            }
9990        } else if (recommendation.indexOf('sponsored') !== -1) {
9991            recommendationType = 'sponsored';
9992        } else if (recommendation.indexOf('recs') !== -1) {
9993            recommendationType = 'recommended';
9994        } else if (recommendation.indexOf('past-purchase') !== -1) {
9995            recommendationType = 'pastPurchased';
9996        } else if (recommendation.indexOf('#br') !== -1) {
9997            recommendationType = 'br';
9998        } else {
9999            recommendationType = 'notRecommended';
10000        }
10001        return recommendationType;
10002    }
10003
10004    // set pageFilter.recommendationType for product actions
10005    this.recommendationInfo = function (recommendationObj) {
10006        if (digitalData && digitalData.pageFilter) {
10007            let recommendationType = '';
10008            if (this.isRecipesPage()) {
10009                recommendationType = 'recipes';
10010            } else {
10011                if (recommendationObj.isCrossSell === true) {
10012                    recommendationType = 'cross-sell';
10013                    if (recommendationObj.isSponsored === true) {
10014                        recommendationType += ':sponsored';
10015                    }
10016                } else if (recommendationObj.isSponsored === true) {
10017                    recommendationType = 'sponsored';
10018                } else if (recommendationObj.isPastPurchased === true) {
10019                    recommendationType = 'pastPurchased';
10020                } else if (recommendationObj.isRecommended === true) {
10021                    recommendationType = 'recommended';
10022                } else if (recommendationObj.isBrPathway === true) {
10023                    recommendationType = 'br';
10024                } else {
10025                    recommendationType = 'notRecommended';
10026                }
10027            }
10028            digitalData.pageFilter.recommendationType = recommendationType;
10029        }
10030    }
10031
10032    // set info from refunds page
10033    this.initRequestRefund = function () {
10034        const lsRefund = localStorage.getItem('refundContinueDatalayer');
10035        if (lsRefund) {
10036            const refundValue = AB.DATALAYER.safeJSONParse(lsRefund);
10037            this.pushEvent(
10038                refundValue.event, refundValue
10039            );
10040            localStorage.removeItem('refundContinueDatalayer');
10041        }
10042    }
10043
10044    // set info from Order Reschedule page
10045    this.initOrderReschedule = function () {
10046        const lsOrderReschedule = localStorage.getItem('rescheduleOrderDatalayer');
10047        if (lsOrderReschedule) {
10048            const orderRescheduleValue = AB.DATALAYER.safeJSONParse(lsOrderReschedule);
10049            this.pushEvent(
10050                orderRescheduleValue.event, orderRescheduleValue
10051            );
10052            localStorage.removeItem('rescheduleOrderDatalayer');
10053        }
10054    }
10055
10056    /**
10057     * Handle subscription registration/FreshPass SPA flow
10058     */
10059    this.updateAnalyticsSubscriptionInfo = function (subscriptionStep, subscriptionInfoObj, impressions) {
10060        if (digitalData) {
10061            digitalData.modal = {};
10062
10063            if (subscriptionStep === 'landing' || subscriptionStep === 'snaplanding') {
10064                if (!localStorage.getItem('preventAnalyticsLanding')) {
10065                    const pageNamePrefix = `${digitalData.pageDetails.banner}:loyalty`;
10066                    digitalData.pageDetails.subSection1 = 'lp';
10067                    digitalData.pageDetails.subSection2 = 'subscriptions-delivery';
10068                    digitalData.pageDetails.subSection3 = subscriptionStep === 'snaplanding' ? 'government-benefits' : '';
10069                    if (subscriptionInfoObj) {
10070                        this.setFPSPlanType(subscriptionStep, subscriptionInfoObj);
10071                    } else {
10072                        digitalData.pageFilter.subscriptionFunnel = `${subscriptionStep === 'snaplanding' ? 'snap:' : ''}freshpass-landing`;
10073                    }
10074                    digitalData.pageFilter.topNav = this.getLSItem('analyticsGetFreshPass')
10075                        ? this.handleGetLSValue('analyticsGetFreshPass')
10076                        : this.getLSItem('analyticsCTAValue') ? this.handleGetLSValue('analyticsCTAValue')
10077                            : digitalData.pageFilter.topNav ? digitalData.pageFilter.topNav : '';
10078
10079                    digitalData.pageDetails.pageName = `${pageNamePrefix}:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}${digitalData.pageDetails.subSection3 ? `:${digitalData.pageDetails.subSection3}` : ''}`;
10080                    if (subscriptionStep === 'landing') {
10081                        this.setImpression(document.querySelector('app-partnerscarousel') ? 'prtnrs' : 'no-prtnrs');
10082                        if (impressions && typeof impressions === 'object' && Object.keys(impressions).length > 0 && impressions.snapBanner) {
10083                            this.setImpression(impressions.snapBanner);
10084                            digitalData.modal.modalMessage = 'fresh-pass-goverment-programs-get-50-percent-off';
10085                        }
10086                    }
10087                    if (digitalData.crossPageData?.analyticsTrackFPBannerMessage?.data) {
10088                        digitalData.modal.modalMessage = `guest-user|${digitalData.crossPageData?.analyticsTrackFPBannerMessage.data}`;
10089                        this.setAnalyticsCrossPageData({ action: 'remove', name: 'analyticsTrackFPBannerMessage' });
10090                    }
10091                    this.handleAccountEvents();
10092                    this.setPageLoad();
10093                    digitalData.pageFilter.impressions = '';
10094                } else {
10095                    localStorage.removeItem('preventAnalyticsLanding')
10096                }
10097            } else {
10098                let pageNamePrefix = `${digitalData.pageDetails.banner}:loyalty:lp`;
10099                digitalData.pageDetails.subSection1 = 'delivery-subscription';
10100                if (subscriptionStep !== 'step4') {
10101                    switch (subscriptionStep) {
10102                        case 'step1':
10103                            this.setFPSPlanType(subscriptionStep, subscriptionInfoObj);
10104                            digitalData.pageDetails.subSection2 = 'step1_plan-selection';
10105                            digitalData.pageFilter.topNav = '';
10106                            if (subscriptionInfoObj?.campaignType === 'SHEER') {
10107                                this.setImpression('gap');
10108                            }
10109                            break;
10110                        case 'step2':
10111                            digitalData.pageDetails.subSection2 = 'step2_setup-account';
10112                            this.setFPSPlanType(subscriptionStep, subscriptionInfoObj);
10113                            localStorage.setItem('freshpass-analytics-confirmation', JSON.stringify(subscriptionInfoObj));
10114                            break;
10115                        case 'step3':
10116                            digitalData.pageDetails.subSection2 = 'step3_payment-details';
10117                            this.setFPSPlanType(subscriptionStep, subscriptionInfoObj);
10118                            localStorage.setItem('freshpass-analytics-confirmation', JSON.stringify(subscriptionInfoObj));
10119                            break;
10120                        case 'confirmation':
10121                            digitalData.pageDetails.subSection1 = 'freshpass';
10122                            digitalData.pageDetails.subSection2 = 'manage';
10123                            digitalData.pageDetails.subSection3 = 'confirmation';
10124                            pageNamePrefix = `${digitalData.pageDetails.banner}:loyalty`;
10125                            if (impressions && typeof impressions === 'object' && Object.keys(impressions).length > 0 && impressions.partnerCards) {
10126                                this.setImpression(impressions.partnerCards);
10127                            }
10128                            this.setFPSPlanType(subscriptionStep, subscriptionInfoObj);
10129                            if (digitalData.crossPageData?.analyticsTrackFPBannerMessage?.data) {
10130                                digitalData.modal.modalMessage = `fp-${digitalData.user?.subscriptionStatus?.indexOf('annual') != -1 ? 'annual' : 'monthly'}|${digitalData.crossPageData?.analyticsTrackFPBannerMessage.data}`;
10131                                this.setAnalyticsCrossPageData({ action: 'remove', name: 'analyticsTrackFPBannerMessage' });
10132                            }
10133                            break;
10134                        case 'manage':
10135                            digitalData.pageDetails.pageUrl = window.location.pathname;
10136                            digitalData.pageDetails.subSection1 = 'freshpass';
10137                            digitalData.pageDetails.subSection2 = 'manage';
10138                            digitalData.pageDetails.subSection3 = '';
10139                            pageNamePrefix = `${digitalData.pageDetails.banner}:loyalty`;
10140                            digitalData.pageFilter.subscriptionFunnel = '';
10141                            digitalData.user.subscriptionStatus = '';
10142                            if (this.getLSItem('analyticsFPLSitem') === 'changeToA
10142nnual' || this.getLSItem('analyticsFPLSitem') === 'changeToMonthly') {
10143                                this.setFPSPlanType('changePlan');
10144                                this.removeLSItem('analyticsFPLSitem');
10145                            }
10146                            if (digitalData.crossPageData?.analyticsTrackCancelReasonId?.data && digitalData.crossPageData?.analyticsTrackDiscBnftFunnel?.data && digitalData.crossPageData?.analyticsTrackCancelReasonText?.data) {
10147                                digitalData.modal.modalMessage = `${digitalData.crossPageData.analyticsTrackCancelReasonId.data}-${digitalData.crossPageData.analyticsTrackCancelReasonText.data?.toLowerCase()?.replace(/\s/g, '-')}`;
10148                            }
10149                            if (digitalData.crossPageData?.analyticsTrackDiscBnftFunnel?.data) {
10150                                digitalData.pageFilter.subscriptionFunnel = `disc-bnft:freshpass-${digitalData.crossPageData?.analyticsTrackDiscBnftFunnel.data}`;
10151                                digitalData.user.subscriptionStatus = `disc-bnft:freshpass|${digitalData.crossPageData?.analyticsTrackDiscBnftFunnel.data}-success`;
10152                                this.setAnalyticsCrossPageData({ action: 'remove', name: 'analyticsTrackDiscBnftFunnel' })
10153                            }
10154                            this.setAnalyticsCrossPageData({ action: 'remove', name: 'analyticsTrackCancelReasonId' });
10155                            this.setAnalyticsCrossPageData({ action: 'remove', name: 'analyticsTrackCancelReasonText' });
10156                            break;
10157                        case 'change':
10158                            localStorage.removeItem('analyticsChangeSnapPlan');
10159                            digitalData.pageDetails.pageUrl = window.location.pathname;
10160                            digitalData.pageDetails.subSection1 = 'freshpass';
10161                            digitalData.pageDetails.subSection2 = 'manage';
10162                            digitalData.pageDetails.subSection3 = 'change';
10163                            pageNamePrefix = `${digitalData.pageDetails.banner}:loyalty`;
10164                            digitalData.pageFilter.subscriptionFunnel = subscriptionInfoObj?.campaignType === 'SHEER'
10165                                ? `snap-plan-selection:${subscriptionInfoObj?.planCardTitle?.toLowerCase()?.includes('annual') ? 'monthly|annual' : 'annual|monthly'}` : '';
10166                            digitalData.user.subscriptionStatus = '';
10167                            if (subscriptionInfoObj?.campaignType === 'SHEER') {
10168                                localStorage.setItem('analyticsChangeSnapPlan', 'true');
10169                            }
10170                            break;
10171                        case 'service-unavailable':
10172                            digitalData.pageDetails.subSection2 = 'subscription-unavailable';
10173                            digitalData.pageFilter.subscriptionFunnel = 'service not available';
10174                            break;
10175                        case 'cancel':
10176                            digitalData.pageDetails.subSection1 = 'freshpass';
10177                            digitalData.pageDetails.subSection2 = 'manage';
10178                            digitalData.pageDetails.subSection3 = 'cancel-plan';
10179                            this.setFPSPlanType(subscriptionStep, subscriptionInfoObj);
10180                            this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsFeatureTracking', data: 'freshpassDiscountACIP392731', isAcrossPages: false });
10181                            break;
10182                        case 'pre-discount-page':
10183                            digitalData.pageDetails.subSection1 = 'freshpass';
10184                            digitalData.pageDetails.subSection2 = 'manage';
10185                            digitalData.pageDetails.subSection3 = 'pre-discount-page';
10186                            this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsFeatureTracking', data: 'freshpassDiscountACIP392731', isAcrossPages: false });
10187                            break;
10188                        case 'discount-page':
10189                            digitalData.pageDetails.subSection1 = 'freshpass';
10190                            digitalData.pageDetails.subSection2 = 'manage';
10191                            digitalData.pageDetails.subSection3 = 'discount-page';
10192                            this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsFeatureTracking', data: 'freshpassDiscountACIP392731', isAcrossPages: false });
10193                            break;
10194                        case 'update-payment':
10195                            digitalData.pageDetails.subSection1 = 'freshpass';
10196                            digitalData.pageDetails.subSection2 = 'manage';
10197                            digitalData.pageDetails.subSection3 = 'update';
10198                            this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsFeatureTracking', data: 'freshpassDiscountACIP392731', isAcrossPages: false });
10199                            break;
10200                        default:
10201                            break;
10202                    };
10203                    digitalData.pageDetails.pageName = `${pageNamePrefix}:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}${digitalData.pageDetails.subSection3 ? `:${digitalData.pageDetails.subSection3}` : ''}`;
10204                    if (this.getLSItem('analyticsCTAValue')) {
10205                        digitalData.pageFilter.topNav = this.handleGetLSValue('analyticsCTAValue');
10206                    }
10207                    if (subscriptionStep === 'change') {
10208                        setTimeout(function () {
10209                            const userMessage = document.querySelector('.benefits .description.success-color')?.textContent?.trim()?.startsWith('Your eligibility for government assistance has been verified');
10210                            digitalData.modal.modalMessage = userMe
10210ssage ? 'your-eligibility-for-gov-assistance-has-been-verified-your-plan-will-auto-renew' : '';
10211                            AB.DATALAYER.setPageLoad();
10212                        }, 2000);
10213                    } else {
10214                        this.setPageLoad();
10215                    }
10216
10217                    if (this.isFreshpassConfirmationPage()) {
10218                        AB.DATALAYER.pushEvent(
10219                            AB.DATALAYER.EVENTS.DS_CONFIRMATION, {
10220                            page: digitalData?.pageDetails,
10221                            pageFilter: digitalData?.pageFilter,
10222                            user: digitalData?.user
10223                        }
10224                        );
10225                    }
10226                    this.handleAccountEvents();
10227                } else if (subscriptionStep === 'step4') {
10228                    if (digitalData.pageDetails.subSection2 !== 'step4_payment-confirmation') {
10229                        digitalData.pageDetails.subSection2 = 'step4_payment-confirmation';
10230                        this.setFPSPlanType(subscriptionStep, subscriptionInfoObj);
10231                        if (subscriptionInfoObj.planType) {
10232                            localStorage.setItem('freshpass-analytics-confirmation', JSON.stringify(subscriptionInfoObj));
10233                        }
10234                        digitalData.pageDetails.pageName = `${pageNamePrefix}:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}`;
10235                        this.setPageLoad();
10236                    }
10237                }
10238            }
10239            digitalData.modal = {};
10240            digitalData.pageFilter.topNav = '';
10241        }
10242    }
10243    /**
10244     * Function to set the impression value
10245     * @param caller set as the place where the function was called
10246     * set pageFilter.impressions for Buy It Again carousel
10247     */
10248    this.setPastPurchasedImpressions = function (caller) {
10249        let value = '';
10250        switch (caller) {
10251            case 'buyItAgainPdp':
10252                value = '1';
10253                break;
10254            case 'buyItAgainCarousel':
10255                value = 'carousel';
10256                break;
10257            case 'aisles':
10258                if (AB.DATALAYER.isAislesL3Page() || AB.DATALAYER.isAislesL4Page()) {
10259                    this.pastPurchasedProducts += 1;
10260                    value = `${this.pastPurchasedProducts}`;
10261                }
10262                break;
10263            default:
10264                break;
10265        }
10266
10267        if (digitalData?.pageFilter) {
10268            digitalData.pageFilter.impressions = value ? `pastpurchased#${value}` : '';
10269        }
10270    }
10271
10272    // set pageName for just for U Registration
10273    this.justforURegistration = function () {
10274        if (digitalData.pageDetails && digitalData.pageDetails.subSection1 === 'account' && digitalData.pageDetails.subSection2 === 'short-registration') {
10275            if (AB.DATALAYER.analyticsGetURLParameterByName('source') === 'CARDLESS_ENROLLMENT') {
10276                digitalData.pageDetails.pageName += ':cardless_enrollment';
10277            }
10278        }
10279    }
10280
10281    // set pageFilter.metaInfo for multiple images on pdp
10282    this.setPageFilterMetaInfo = function (setMetaInfo, shouldSetLsItem) {
10283        const numberOfImagesClicked = localStorage.getItem('analyticsMetaInfo') || '0';
10284        if (shouldSetLsItem) {
10285            localStorage.setItem('analyticsMetaInfo', parseInt(numberOfImagesClicked) + 1);
10286        }
10287        else {
10288            digitalData.pageFilter.metaInfo = setMetaInfo && numberOfImagesClicked !== '0' ? `PDP-Images|${numberOfImagesClicked}` : '';
10289        }
10290    }
10291
10292    /**
10293     * Sets tracking for Hero Collection/Canvas
10294     * @param element element clicked
10295     */
10296    this.setHeroCollectionsTracking = function (element) {
10297        if (element && digitalData?.pageFilter) {
10298            let cardPlacement = '';
10299            const currentBanner = element.closest('.slick-slide:not(.slick-cloned)')?.querySelector('.hero-canvas');
10300            const currentBannerTitle = currentBanner?.querySelector('.hero-canvas__text-plate-wrapper .hero-canvas__text-plate-title')?.textContent.trim().toLowerCase().replace(/[^a-z0-9|-]/gi, '
10300-');
10301
10302            const currentCarousel = element.closest('.nextgen-abs-carousel-wrapper');
10303            const currentCarouselBanners = currentCarousel?.querySelectorAll('.slick-slide:not(.slick-cloned) .hero-canvas');
10304            const bannerSlot = currentCarouselBanners && currentBanner ? Array.from(currentCarouselBanners).indexOf(currentBanner) + 1 : 0;
10305            const bannerPlacement = bannerSlot > 0 ? `R01#S0${bannerSlot}` : 'R01';
10306
10307            const isWithCollections = currentBanner?.querySelector('div#withCollections') !== null;
10308            let bannerCardCarousel = '';
10309            if (isWithCollections) {
10310                bannerCardCarousel = `z01|banner|hero-banner:${currentBannerTitle}|sp00`;
10311                // element clicked is a card
10312                if (element.classList.contains('hero-collection__link')) {
10313                    const currentCard = element.closest('.hero-collection__card');
10314                    const cardsContainer = element.closest('.hero-collection__wrapper');
10315                    const allCards = cardsContainer?.querySelectorAll('.hero-collection__card');
10316                    cardPlacement = allCards && currentCard ? Array.from(allCards).indexOf(currentCard) + 1 : 0;
10317                    const cardTitle = currentCard?.querySelector('.hero-collection__title')?.textContent.trim().toLowerCase().replace(/[^a-z0-9|-]/gi, '-');
10318                    bannerCardCarousel = `z01|banner|hero-banner-${cardPlacement}:${cardTitle}|sp0${cardPlacement}`;
10319                }
10320            }
10321
10322            digitalData.pageFilter.bannerCardCarousel = bannerCardCarousel;
10323            digitalData.pageFilter.placement = bannerPlacement;
10324            digitalData.pageFilter.mediaType = 'banner';
10325            digitalData.pageFilter.recommendationType = 'notRecommended';
10326            digitalData.pageDetails.bnrName = `${currentBannerTitle}|no-value`;
10327            digitalData.link = {
10328                linkName: `bannerClicked|${currentBannerTitle}`
10329            };
10330
10331            this.trackAEMZone('hero-collections', element, `hero-collections-${isWithCollections ? `card-${cardPlacement}` : 'banner'}`);
10332
10333            this.pushEvent(
10334                this.EVENTS.LINK_CLICK,
10335                {
10336                    link: digitalData.link,
10337                    pageFilter: digitalData.pageFilter,
10338                    page: digitalData.pageDetails
10339                }
10340            );
10341            digitalData.pageFilter.bannerCardCarousel = '';
10342            digitalData.pageFilter.placement = '';
10343            digitalData.pageFilter.mediaType = '';
10344            digitalData.pageFilter.recommendationType = '';
10345            digitalData.pageDetails.bnrName = '';
10346            digitalData.link = {};
10347        }
10348    }
10349
10350    this.setLinkClickViewAll = function ({ linkTarget, carouselTitle, caller, event } = {}) {
10351        const title = carouselTitle ? carouselTitle.trim() : 'not-available';
10352        if (event) {
10353            let element = event instanceof Element ? event : event.target;
10354            this.trackAEMZone('link', element, carouselTitle);
10355            AB.DATALAYER.trackP13nViewAll(element);
10356        }
10357        if (this.isARPage()) {
10358            localStorage.setItem('analyticsARviewAll', 'AR:LP:view-all');
10359        } else if (this.isAccountPage()) {
10360            this.analyticsCTATracking(`cta:${this.pathSections?.join(':')}|link|view-all`);
10361        } else if (linkTarget && linkTarget.indexOf('buy-it-again') !== -1) {
10362            this.setLinkClickEvents(`bia:${title}:view-all`);
10363        } else if (window.isAnalyticsMarketplacePage) {
10364            // Marketplace carousels
10365            if (caller === 'seeAllSellers') {
10366                // Send only one modal view event per page view
10367                let eventSent = false;
10368                // Find the index of the last 'pageLoaded' event in appEventData
10369                const pageLoadedIndex = appEventData.map(eventObj => eventObj?.event).lastIndexOf('pageLoaded');
10370                if (pageLoadedIndex !== -1) {
10371                    // Check if the link event has already been sent after the 'pageLoaded' event
10372                    eventSent = appEventData.slice(pageLoadedIndex).some(eventObj => eventObj?.link?.linkName === 'mkp|sidebar-open');
10373                }
10374                if (!eventSent) {
10375                    digitalData.pageFilter.topNav = `cta:${this.initPathSections(true).join(':')}|link|view-all-side-menu`;
10376                    this.setLinkClickEvents('mkp|sidebar-open');
10377                }
10378            } else {
10379                this.analyticsCTATracking(`cta:${this.initPathSections(true).join(':')}|link|view-all-merch-carousel`);
10380            }
10381        }
10382    }
10383
10384    this.setLinkClickViewAllAEMZone = function (carouselTitle, linkText, zoneId) {
10385        let element = document.querySelector(`#${zoneId}`);
10386        let sanitizedLinkText = linkText ? linkText.toLowerCase().split(' ').join('-').replace(/[^\w-,|#:]/gi, '').replace('--', '-') : 'no-value';
10387        this.trackAEMZone(`link:${sanitizedLinkText}`, element, carouselTitle);
10388    }
10389
10390    this.setLinkClickFreshPassAlert = function ({ messageTitle, messageText, messageShowMore, event } = {}) {
10391        if (messageTitle?.toLowerCase()?.includes('freshpass') || messageText?.toLowerCase()?.includes('freshpass')) {
10392            if (event === 'start' && messageShowMore?.toLowerCase()?.includes('start free trial')) {
10393                AB.DATALAYER.analyticsCTATracking(`cta:${AB.DATALAYER.initPathSections(true).join(':')}|link|freshpass-banner`)
10394            } else if (event === 'close') {
10395                AB.DATALAYER.setLinkClickEvents('fp:banner-closed');
10396            }
10397        }
10398    }
10399
10400    /**
10401     * Handles the BIA page view & instant basket flow
10402     * @param viewType - view type for the BIA page new design
10403     */
10404    this.updateBIAViewType = function (viewType, productsCount) {
10405        if (digitalData && digitalData.pageDetails) {
10406            digitalData.pageDetails.subSection1 = AB.DATALAYER.pathSections[0] || '';
10407            digitalData.pageDetails.subSection2 = AB.DATALAYER.pathSections[1] || '';
10408            digitalData.pageFilter = digitalData.pageFilter || {};
10409            digitalData.pageFilter.topNav = digitalData.pageFilter.topNav ? digitalData.pageFilter.topNav : AB.DATALAYER.initTopNav();
10410
10411            switch (true) {
10412                case (viewType === 'item' || window.location.search.indexOf('view=item') !== -1) && window.biaAnalyticsTrackView !== 'item':
10413                    digitalData.pageDetails.subSection3 = 'item-view';
10414                    digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:delivery:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}:${digitalData.pageDetails.subSection3}`;
10415                    AB.DATALAYER.setPageLoad();
10416                    window.biaAnalyticsTrackView = 'item';
10417                    break;
10418                case (viewType === 'category' || window.location.search.indexOf('view=category') !== -1) && window.biaAnalyticsTrackView !== 'category':
10419                    digitalData.pageDetails.subSection3 = 'category-view';
10420                    digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:delivery:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}:${digitalData.pageDetails.subSection3}`;
10421                    AB.DATALAYER.setPageLoad();
10422                    window.biaAnalyticsTrackView = 'category';
10423                    break;
10424                case (viewType === 'viewAll' || window.location.search.indexOf('view=viewAll') !== -1) && window.biaAnalyticsTrackView !== 'viewAll':
10425                    digitalData.pageDetails.subSection3 = 'view-all';
10426                    digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:delivery:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}:${digitalData.pageDetails.subSection3}`;
10427                    AB.DATALAYER.setPageLoad();
10428                    window.biaAnalyticsTrackView = 'viewAll';
10429                    break;
10430                case (viewType === 'instantCart' || window.location.search.indexOf('view=instantCart') !== -1) && window.biaAnalyticsTrackView !== 'instantCart':
10431                    digitalData.pageDetails.subSection1 = 'smart-basket';
10432                    digitalData.pageDetails.subSection2 = 'quick-start-cart';
10433                    digitalData.pageDetails.subSection3 = '';
10434                    digitalData.modal = digitalData.modal || {};
10435                    digitalData.modal.modalMessage = `quick-start-cart|recs:${productsCount || 'no-value'}`;
10436                    AB.DATALAYER.setPageName(false, true);
10437                    AB.DATALAYER.setPageLoad();
10438                    window.biaAnalyticsTrackView = 'instantCart';
10439                    break;
10440                default:
10441                    break;
10442            }
10443
10444            digitalData.pageDetails.pfmDetail = `${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}:${digitalData.pageDetails.subSection3}`;
10445            AB.DATALAYER.pfmFromCurrentPage = `${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}:${digitalData.pageDetails.subSection3}`;
10446            localStorage.setItem('pfmDetail', digitalData.pageDetails.pfmDetail);
10447            digitalData.pageFilter.topNav = '';
10448        } else {
10449            sessionStorage.setItem('analyticsBIADelayedPageLoad', 'foo');
10450        }
10451        localStorage.removeItem('analyticsBiaLoadMore');
10452    }
10453
10454    // Tracking for BIA instant/quick cart, from the old BIA grid component loading on qsc landing
10455    this.updateBiaQsc = function (viewType) {
10456        if (window.location.search.indexOf('view=instantCart') !== -1 && window.biaAnalyticsTrackView !== 'instantCart') {
10457            if (viewType === 'instantCart') {
10458                digitalData.pageDetails.subSection3 = 'instant-cart';
10459                digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:delivery:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}:${digitalData.pageDetails.subSection3}`;
10460            } else if (viewType === 'quickAdd') {
10461                digitalData.pageDetails.subSection1 = 'quick-start-cart';
10462                digitalData.pageDetails.subSection2 = '';
10463                digitalData.pageDetails.subSection3 = '';
10464                digitalData.pageDetails.channel = 'shop';
10465                digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:${digitalData.pageDetails.channel}:${digitalData.pageDetails.subSection1}`;
10466                let noOfRecommandation = [];
10467                if (localStorage.getItem('quickAddBasket')) {
10468                    noOfRecommandation = AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('quickAddBasket'))?.cartItemsList || [];
10469                }
10470                digitalData.modal.modalMessage = `quick-add|recs:${noOfRecommandation.length > 0 ? noOfRecommandation.length : 0}`;
10471            }
10472            AB.DATALAYER.pfmFromCurrentPage = `${digitalData.pageDetails.subSection1}${digitalData.pageDetails.subSection2 ? `:${digitalData.pageDetails.subSection2}` : ''}${digitalData.pageDetails.subSection3 ? `:${digitalData.pageDetails.subSection3}` : ''}`;
10473            AB.DATALAYER.setPageLoad();
10474            window.biaAnalyticsTrackView = 'instantCart';
10475        }
10476    }
10477
10478    this.setCheckBoxTrackingValues = function (elementId) {
10479        const quickadd = AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('quickAddBasket'))?.cartItemsList || [];
10480        const valueChecked = quickadd.find(item => item.itemId === elementId).selected;
10481        if (valueChecked) {
10482            AB.DATALAYER.setLinkClickEvents('quick-start-cart|check');
10483        } else {
10484            AB.DATALAYER.setLinkClickEvents('quick-start-cart|uncheck');
10485        }
10486    }
10487
10488    /**
10489    * Track the user clicks on checkBox 1 time per action per item per page 
10490    */
10491    this.trackCheckBoxButtonClicks = function () {
10492        document.querySelectorAll('.checkbox__input').forEach(element => {
10493            let clickCount = 0;
10494
10495            const handleCheckBoxClick = () => {
10496                const elementId = element.id?.replace(/[^0-9]/g, '');
10497                AB.DATALAYER.setCheckBoxTrackingValues(elementId);
10498                clickCount++;
10499                if (clickCount === 2) {
10500                    element.removeEventListener('click', handleCheckBoxClick);
10501                }
10502            };
10503
10504            element.addEventListener('click', handleCheckBoxClick);
10505        });
10506    }
10507
10508    this.setAttributionToken = function (attrToken) {
10509        if (digitalData && digitalData.user) {
10510            digitalData.user.googleAttributionToken = attrToken;
10511        }
10512    }
10513
10514    // EDDL migration -
10515    // Init datalayer for Orders Page
10516    this.initOrdersPage = function (reportedIssues, subSection3, subSection4, orderID) {
10517        /*
10518        order history page         /order-account/orders
10519        order details page         /order-account/orders/#orderId
10520        report an issue page       /order-account/orders/#orderId/report-issue
10521        refund confirmation page   /order-account/orders/#orderId/report-issue/confirmation
10522        */
10523        const { pageDetails, pageFilter, user, crossPageData } = digitalData;
10524        this.initPathSections();
10525        /**
10526         * If the pathSections contains 3 elements, the subSection3 should be 'order-details'
10527         * If the pathSections contains more than 3 elements, we remove the orderID and start setting the subSection3 from the the third element in the pathSections
10528         */
10529        if (this.pathSections.length === 3) {
10530            this.pathSections[2] = 'order-details';
10531        } else if (this.pathSections.length > 3) {
10532            this.pathSections.splice(2, 1);
10533        }
10534        for (let i = 0; i < 4; i++) {
10535            pageDetails[`subSection${i + 1}`] = this.pathSections[i] || '';
10536        }
10537
10538        // update subSections for in-store and online purchases
10539        if (subSection3) {
10540            pageDetails.subSection3 = subSection3;
10541            pageDetails.subSection4 = subSection4 ? subSection4 : '';
10542            pageFilter.orderID = orderID ? orderID : '';
10543        }
10544
10545        if (subSection4) {
10546            // set subSection3 to refund status
10547            if (pageDetails.subSection3 === 'refund-status') {
10548                pageDetails.subSection3 = subSection4;
10549                pageDetails.subSection4 = '';
10550            } else {
10551                // set subSection4 to order status
10552                pageDetails.subSection4 = subSection4;
10553            }
10554        }
10555
10556        pageDetails.pageName = [pageDetails.banner, 'loyalty', pageDetails.subSection1, pageDetails.subSection2, pageDetails.subSection3, pageDetails.subSection4].filter(
10556Boolean).join(':');
10557        pageDetails.pageUrl = window.location.pathname;
10558        pageDetails.channel = 'Account';
10559        pageDetails.orderNumber = window.location.pathname.split('/')[3] || '';
10560        /** Page Filter **/
10561        // set report issue
10562        if (reportedIssues) {
10563            let reportedIssuesArray = [];
10564            Object.keys(reportedIssues).map(item => {
10565                if (reportedIssues[item].count > 0 && reportedIssues[item].reasontext) {
10566                    reportedIssuesArray.push(reportedIssues[item].reasontext.replace(' ', '-').toLowerCase());
10567                }
10568            });
10569            if (reportedIssuesArray) {
10570                pageFilter.reportIssue = reportedIssuesArray.join(', ');
10571            }
10572        }
10573
10574        if (!user || (user && Object.keys(user).length === 0)) {
10575            this.initUser();
10576        }
10577
10578        pageFilter.impressions = crossPageData.orderPageSections?.data
10579            ? pageFilter.impressions !== '' ? crossPageData.orderPageSections.data : `${pageFilter.impressions}, ${crossPageData.orderPageSections.data}` : '';
10580
10581        pageFilter.topNav = pageFilter.topNav || AB.DATALAYER.initTopNav();
10582
10583        this.setPageLoad();
10584        pageFilter.topNav = '';
10585
10586        const af_sub1Param = AB.DATALAYER.analyticsGetURLParameterByName('af_sub1');
10587        const cParam = AB.DATALAYER.analyticsGetURLParameterByName('c');
10588        const reviewSubstitutionsParam = AB.DATALAYER.analyticsGetURLParameterByName('reviewSubstitutions');
10589        const setDeeplink = (campaign) => { pageDetails.campaign = campaign; AB.DATALAYER.setLinkClickEvents('deepLink'); }
10590        if (pageDetails.subSection3 === 'item-details' && (af_sub1Param === 'sms_allb_alld_ecom_2waychat' || cParam === 'sms_allb_alld_ecom_2waychat')) {
10591            setDeeplink(af_sub1Param);
10592        } else if (pageDetails.subSection3 === 'order-details' && reviewSubstitutionsParam === 'true') {
10593            if (af_sub1Param === 'sms_allb_alld_ecom_dlvryrdy' || cParam === 'sms_allb_alld_ecom_dlvryrdy') {
10594                setDeeplink('psh_allb_alld_ecom_dlvryrdy');
10595            } else if (af_sub1Param === 'sms_allb_alld_ecom_pkrdy' || cParam === 'sms_allb_alld_ecom_pkrdy') {
10596                setDeeplink('psh_allb_alld_ecom_pkrdy');
10597            }
10598        }
10599
10600    }
10601
10602    this.initOrderStatus = function (data) {
10603        let orderStatus = '';
10604        if (data) {
10605            switch (data.event) {
10606                case 'CREATED':
10607                    orderStatus = 'order-confirmed';
10608                    break;
10609                case 'IN-PROGRESS':
10610                    orderStatus = 'order-processed';
10611                    break;
10612                case 'DRIVER-DELAY-ALERT':
10613                    orderStatus = 'behind-schedule';
10614                    break;
10615                case 'PICKING-BEHIND-SCHEDULE':
10616                    orderStatus = 'picking-behind-schedule';
10617                    break;
10618                case 'PICKED-UP':
10619                    orderStatus = data?.fulfillmentType === 'DELIVERY' ? 'ready-for-delivery' : 'order-complete';
10620                    break;
10621                case 'CREATED-AFTER-CUTOFF':
10622                    orderStatus = 'created-after-cutoff';
10623                    break;
10624                case 'RELEASED':
10625                    orderStatus = 'released';
10626                    break;
10627                case 'PACKED':
10628                    orderStatus = 'packed';
10629                    break;
10630                case 'PICKUP-READY':
10631                    orderStatus = 'ready-for-pickup';
10632                    break;
10633                case 'DELIVERY-CONFIRMED':
10634                    orderStatus = 'ready-for-delivery';
10635                    break;
10636                case 'DELIVERY-ON-THE-WAY':
10637                    orderStatus = 'out-for-delivery';
10638                    break;
10639                case 'DELIVERED':
10640                    orderStatus = 'order-delivered';
10641                    break;
10642                case 'REFUND':
10643                    orderStatus = 'refund';
10644                    break;
10645                case 'LATE-PICK-ALERT':
10646                    orderStatus = 'late-pick-alert';
10647                    break;
10648                case 'DELIVERY-MISSED':
10649                    orderStatus = 'delivery-missed';
10650                    break;
10651                case 'ENROUTE-TO-PICKUP':
10652                    orderStatus = 'drive-on-the-way';
10653                    break;
10654                default:
10655                    break;
10656            }
10657        }
10658        return orderStatus;
10659    }
10660
10661    this.initRefundStatus = function (status) {
10662        let refundStatus = '';
10663        if (status) {
10664            switch (status) {
10665                case 'AWAITING-SHIPPING-LABEL':
10666                    refundStatus = 'refund-requested';
10667                    break;
10668                case 'AWAITING-SHIPPING-RETURN':
10669                    refundStatus = 'return-label-created';
10670                    break;
10671                case 'REFUND-APPROVED':
10672                    refundStatus = 'refund-issued';
10673                    break;
10674                case 'REFUND-PARTIALLY-APPROVED':
10675                    refundStatus = 'partial-refund-issued';
10676                    break;
10677                case 'REFUND-REJECTED':
10678                    refundStatus = 'refund-not-issued';
10679                    break;
10680            }
10681        }
10682        return refundStatus;
10683    }
10684
10685    this.initResetPwdPage = function (subSectionInfo) {
10686        if (this.isResetPasswordPage()) {
10687            if (subSectionInfo === 'expired') {
10688                digitalData.pageDetails.subSection2 = 'reset-password-expired';
10689            } else {
10690                digitalData.pageDetails.subSection2 = `reset-${subSectionInfo}-password`;
10691            }
10692            this.setPageName(false, true);
10693            this.setPageLoad();
10694        }
10695    }
10696
10697    this.initPaymentPage = function () {
10698        if (this.isPaymentPage()) {
10699            digitalData.pageDetails.subSection2 = 'payment';
10700            digitalData.pageDetails.subSection3 = 'add-payment-methods';
10701            digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:loyalty:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}:${digitalData.pageDetails.subSection3}`;
10702        }
10703    }
10704
10705    this.initReceiptPage = function (subSection3, topNav, modalMessage) {
10706        if (this.isPaymentPage()) {
10707            digitalData.pageDetails.channel = 'account'
10708            digitalData.pageDetails.subSection3 = subSection3;
10709            AB.DATALAYER.setPageName(digitalData.pageDetails.channel, true)
10710            digitalData.pageFilter.topNav = topNav;
10711            digitalData.modal = digitalData.modal || {};
10712            digitalData.modal.modalMessage = modalMessage;
10713            digitalData.pageFlags.isPageLoadSent = false;
10714            AB.DATALAYER.setPageLoad()
10715        }
10716    }
10717
10718    /**
10719     * Initializes datalayer info and sets pageLoaded call on Unsubscribe SPA
10720     */
10721    this.initUnsubscribePage = function (screen) {
10722        if (!digitalData.user || (digitalData.user && Object.keys(digitalData.user).length === 0)) {
10723            AB.DATALAYER.initUser();
10724        }
10725        const unsubscribeSubsction3 = screen === 'unsubscribe'
10726            ? 'unsubscribed' : screen === 'we-miss-you' && digitalData?.modal?.modalMessage
10727                ? 'unsubscribed-confirmed-with-response' : screen === 'we-miss-you' && !digitalData?.modal?.modalMessage
10728                    ? 'unsubscribed-confirmed' : screen === 'subscribed'
10729                        ? 'resubscribed' : '';
10730        if (!digitalData?.pageDetails?.subSection3 || digitalData?.pageDetails?.subSection3 && digitalData?.pageDetails?.subSection3 !== unsubscribeSubsction3) {
10731            digitalData.pageDetails.subSection3 = unsubscribeSubsction3;
10732            digitalData.pageDetails.pageName = `${digitalData?.pageDetails?.banner}:account:${digitalData?.pageDetails?.subSection1}:${digitalData?.pageDetails?.subSection2}:${unsubscribeSubsction3}`;
10733            AB.DATALAYER.setPreviousPageName();
10734            AB.DATALAYER.pushEvent(
10735                AB.DATALAYER.EVENTS.PAGE_LOADED, {
10736                page: digitalData.pageDetails,
10737                pageFilter: digitalData.pageFilter,
10738                user: digitalData.user,
10739                modal: digitalData.modal
10740            }
10741            );
10742            digitalData.modal = {};
10743        }
10744    }
10745
10746    /**
10747     * Init datalayer for AR pages
10748     */
10749    this.initARpages = function (isEmptyState) {
10750        if (AB.DATALAYER.isARManagePage()) {
10751            // init pageInfo object
10752            const bannerEl = document.getElementById('banner');
10753            const pageInfo = {
10754                banner: bannerEl ? bannerEl.dataset.banner : '',
10755                platform: 'web',
10756                channel: 'Account',
10757                pageUrl: window.location.pathname,
10758                server: window.location.hostname,
10759                referringURL: AB.DATALAYER.getReferringUrl(),
10760                thirdParty: AB.DATALAYER.getThirdParty(),
10761                sellerId: AB.DATALAYER.getBannerSellerId()
10762            };
10763            const pathSections = (window.location.pathname.indexOf('.') > -1 ? window.location.pathname.substring(0, window.location.pathname.indexOf('.')) : window.location.pathname).split('/').slice(1);
10764            if (pathSections) {
10765                pathSections.length > 0 && (pageInfo.subSection1 = pathSections[0]);
10766                pathSections.length > 1 && (pageInfo.subSection2 = pathSections[1]);
10767                pathSections.length > 2 && (pageInfo.subSection3 = pathSections[2]);
10768                pathSections.length > 3 && (pageInfo.subSection4 = pathSections[3]);
10769            }
10770            pageInfo.pageName = [
10771                pageInfo.banner,
10772                'loyalty',
10773                pageInfo.subSection1,
10774                pageInfo.subSection2,
10775                pageInfo.subSection3,
10776                pageInfo.subSection4
10777            ].filter(Boolean).join(':');
10778            if (isEmptyState) {
10779                pageInfo.pageName += ' - empty state';
10780            }
10781            window.digitalData.page = {
10782                pageInfo: pageInfo
10783            };
10784            window.digitalData.pageDetails = pageInfo;
10785
10786            //init pageFilter object
10787            const pageFilter = {
10788                topNav: digitalData?.pageFilter?.topNav ? digitalData.pageFilter.topNav : AB.DATALAYER.initTopNav()
10789            };
10790            window.digitalData.pageFilter = pageFilter;
10791
10792            AB.DATALAYER.setPageLoad();
10793        }
10794    }
10795
10796    /**
10797     * Init datalayer for Freshpass SPA pages
10798     */
10799    this.initFreshpassPage = function () {
10800        if (AB.DATALAYER.isFreshpassManagePage()) {
10801            // init pageInfo object
10802            const bannerEl = document.getElementById('banner');
10803            const pageInfo = {
10804                banner: bannerEl ? bannerEl.dataset.banner : '',
10805                platform: 'web',
10806                channel: 'Account',
10807                pageUrl: window.location.pathname,
10808                server: window.location.hostname,
10809                referringURL: AB.DATALAYER.getReferringUrl(),
10810                thirdParty: AB.DATALAYER.getThirdParty(),
10811                sellerId: AB.DATALAYER.getBannerSellerId()
10812            };
10813            const pathSections = (window.location.pathname.indexOf('.') > -1 ? window.location.pathname.substring(0, window.location.pathname.indexOf('.')) : window.location.pathname).split('/').slice(1);
10814            if (pathSections) {
10815                pathSections.length > 0 && (pageInfo.subSection1 = pathSections[0]);
10816                pathSections.length > 1 && (pageInfo.subSection2 = pathSections[1]);
10817                pathSections.length > 2 && (pageInfo.subSection3 = pathSections[2]);
10818                pathSections.length > 3 && (pageInfo.subSection4 = pathSections[3]);
10819            }
10820            pageInfo.pageName = [
10821                pageInfo.banner,
10822                'loyalty',
10823                pageInfo.subSection1,
10824                pageInfo.subSection2,
10825                pageInfo.subSection3,
10826                pageInfo.subSection4
10827            ].filter(Boolean).join(':');
10828            window.digitalData.page = {
10829                pageInfo: pageInfo
10830            };
10831            window.digitalData.pageDetails = pageInfo;
10832
10833            //init pageFilter object
10834            const pageFilter = {
10835                topNav: digitalData?.pageFilter?.topNav ? digitalData.pageFilter.topNav : AB.DATALAYER.initTopNav()
10836            };
10837            window.digitalData.pageFilter = pageFilter;
10838        }
10839    }
10840
10841    this.initRewardsPage = function (subsection2) {
10842        // Set page variables
10843        AB.DATALAYER.pathSections = ['rewards', subsection2];
10844        digitalData.pageDetails.subSection1 = AB.DATALAYER.pathSections[0];
10845        digitalData.pageDetails.subSection2 = AB.DATALAYER.pathSections[1] || '';
10846        digitalData.pageDetails.pfmDetail = AB.DATALAYER.pathSections.join(':');
10847        AB.DATALAYER.setPageName();
10848        digitalData.pageFilter.topNav = AB.DATALAYER.initTopNav();
10849
10850        // Send pageLoad event
10851        AB.DATALAYER.setPageLoad();
10852        digitalData.pageFilter.topNav = '';
10853    }
10854
10855    this.initAngularSPA = function (subSection1, subSection2, subSection3, subSection4, impressions) {
10856        // Set page variables
10857        if (subSection1) {
10858            AB.DATALAYER.pathSections = [subSection1, subSection2 || '', subSection3 || '', subSection4 || ''].filter((x) => { return x && x !== '' });
10859        } else {
10860            AB.DATALAYER.initPathSections();
10861        }
10862        digitalData.pageDetails.subSection1 = AB.DATALAYER.pathSections[0];
10863        digitalData.pageDetails.subSection2 = AB.DATALAYER.pathSections[1] || '';
10864        digitalData.pageDetails.subSection3 = AB.DATALAYER.pathSections[2] || '';
10865        digitalData.pageDetails.subSection4 = AB.DATALAYER.pathSections[3] || '';
10866        digitalData.pageDetails.channel = digitalData.pageDetails.subSection1 === 'games' || digitalData.pageDetails.subSection1 === 'rewards' ? 'Banners for you' : digitalData.pageDetails.channel;
10867        if (digitalData.pageDetails.subSection1 === 'games') {
10868            if (digitalData.pageDetails.subSection3 && !digitalData.pageDetails.subSection4) {
10869                AB.DATALAYER.pathSections[2] = `${AB.DATALAYER.pathSections[2]}-landing`;
10870                digitalData.pageDetails.subSection3 = `${digitalData.pageDetails.subSection3}-landing`;
10871            } else if (digitalData.pageDetails.subSection4 && AB.DATALAYER.pathSections[4]) {
10872                AB.DATALAYER.pathSections[3] = `${AB.DATALAYER.pathSections[3]}-${AB.DATALAYER.pathSections[4]}`;
10873                digitalData.pageDetails.subSection4 = `${digitalData.pageDetails.subSection4}-${AB.DATALAYER.pathSections[4]}`;
10874            }
10875        }
10876        digitalData.pageDetails.pfmDetail = AB.DATALAYER.pathSections.join(':');
10877        digitalData.pageDetails.pageUrl = window.location.pathname;
10878        AB.DATALAYER.setPageName(digitalData.pageDetails.channel, true);
10879        digitalData.pageFilter.topNav = digitalData?.pageFilter?.topNav ? digitalData.pageFilter.topNav : AB.DATALAYER.initTopNav();
10880        if (subSection2 === 'partners' && impressions) {
10881            this.setImpression(impressions);
10882        }
10883        digitalData.modal = digitalData.modal || {};
10884        digitalData.modal.modalMessage = subSection2 === 'dashboard' && impressions ? impressions : '';
10885        // Send pageLoad event
10886        AB.DATALAYER.setPageLoad();
10887        digitalData.pageFilter.topNav = '';
10888        digitalData.modal.modalMessage = '';
10889    }
10890
10891    /**
10892     * Init datalayer for OHC pages
10893     */
10894    this.initHelpCenterPages = function () {
10895        const { pageDetails, user } = digitalData;
10896        if (pageDetails) {
10897            AB.DATALAYER.initPathSections();
10898            for (let i = 0; i < 4; i++) {
10899                pageDetails[`subSection${i + 1}`] = AB.DATALAYER.pathSections[i] || '';
10900            }
10901            pageDetails.subSection2 = pageDetails.subSection2 === 'home' ? 'main' : pageDetails.subSection2;
10902            pageDetails.pageName = [pageDetails.banner, 'loyalty', pageDetails.subSection1, pageDetails.subSection2, pageDetails.subSection3, pageDetails.subSection4].filter(
10902Boolean).join(':');
10903            pageDetails.pageUrl = window.location.pathname;
10904            pageDetails.channel = 'help-center';
10905        }
10906        if (!user || (user && Object.keys(user).length === 0)) {
10907            AB.DATALAYER.initUser();
10908        }
10909        AB.DATALAYER.setPageLoad();
10910    }
10911
10912    this.trackWeeklyAd = function (eventName, payload) {
10913        const flyerName = payload?.flyer?.flyerName?.replace(/\s/g, '-').toLowerCase();
10914        const dateRange = payload?.validFrom && payload?.validTo ? `${(new Date(payload.validFrom)).toLocaleDateString('en-GB').split('/').reverse().join('').replace(/^20/, '')}-${(new Date(payload.validTo)).toLocaleDateString('en-GB').split('/').reverse().join('').replace(/^20/, '')}` : '';
10915        let flyerType = 'current';
10916
10917        if (!sessionStorage.getItem('weekly-ad-type-first')) {
10918            sessionStorage.setItem('weekly-ad-type-first', true);
10919        } else {
10920            flyerType = flyerName == 'weekly-ad' ? 'next' : flyerName;
10921        }
10922
10923        if (eventName == 'analyticsOpen') {
10924            window.digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:weekly-ad:weekly-ad:${flyerType}:${dateRange}`;
10925            window.digitalData.pageDetails.subSection2 = flyerType;
10926            window.digitalData.pageDetails.subSection3 = dateRange;
10927            window.digitalData.pageFilter = { topNav: digitalData?.pageFilter?.topNav ? digitalData.pageFilter.topNav : AB.DATALAYER.initTopNav() };
10928            AB.DATALAYER.initTopNavPageFlag();
10929            const pageInfo = {
10930                pageName: `${digitalData.pageDetails.banner}:weekly-ad:weekly-ad:${flyerType}:${dateRange}`,
10931                subsection2: flyerType,
10932                subSection3: dateRange
10933            }
10934            localStorage.setItem('analyticsWeeklyAdPageInfo', JSON.stringify(pageInfo));
10935            AB.DATALAYER.setPageLoad();
10936        } else if (eventName == 'analyticsItemClick') {
10937            this.setLinkClickEvents(`weekly-ad:${flyerType}|item-view`);
10938        }
10939    }
10940
10941    this.initWeeklyAdPages = function (screen) {
10942        const flyerInfo = AB.DATALAYER.safeJSONParse(AB.DATALAYER.handleGetLSValue('analyticsWeeklyAdPageInfo'));
10943        digitalData.pageDetails.subSection1 = 'weekly-ad';
10944        digitalData.pageDetails.subSection2 = screen === 'deals' ? 'your-deals' : flyerInfo.flyerType;
10945        digitalData.pageDetails.subSection3 = screen === 'deals' ? '' : flyerInfo.dateRange;
10946        screen === 'deals' ? AB.DATALAYER.setPageName(digitalData.pageDetails.channel, true) : digitalData.pageDetails.pageName = flyerInfo.pageName;
10947        if (screen === 'deals' || Object.keys(flyerInfo)?.length > 0) {
10948            AB.DATALAYER.setPageLoad();
10949        }
10950    }
10951
10952    this.initSpotlightPages = function (userInfo, pageName, reportId) {
10953        const pageId = AB.DATALAYER.analyticsGetURLParameterByName('Id') || 'no-value';
10954        window.digitalData.pageDetails = {
10955            pageName: pageName?.startsWith('admin-panel') ? pageName : pageName ? `${AB.DATALAYER.sanitizeAnalyticsText(pageName)}:${pageId}` : 'no-value',
10956            pageUrl: reportId ? `${window.location.pathname}?id=${reportId}` : window.location.pathname + window.location.search,
10957            platform: 'web',
10958            previousPageName: this.handleGetLSValue('analyticsPreviousPageName') || '',
10959            portalBanner: 'spotlight'
10960        };
10961        window.digitalData.user = {
10962            userRole: userInfo?.userRole,
10963            userType: userInfo?.userType,
10964            partnerCompany: userInfo?.partnerCompany || 'no-value'
10965        };
10966        this.setLSItem('analyticsPreviousPageName', window.digitalData.pageDetails.pageName);
10967        this.pushEvent(
10968            'pageLoaded_spotlight',
10969            {
10970                page: window.digitalData.pageDetails,
10971                user: window.digitalData.user,
10972            }
10973        );
10974    }
10975
10976    this.initFulfillmentCenterPages = function (userInfo) {
10977        AB.DATALAYER.initPathSections();
10978        if (digitalData?.pageDetails?.pageName !== AB.DATALAYER.pathSections?.join(':')) {
10979            digitalData.pageDetails = {
10980                pageName: AB.DATALAYER.pathSections?.join(':'),
10981                pageUrl: window.location.pathname,
10982                platform: 'web',
10983                previousPageName: this.handleGetLSValue('analyticsPreviousPageName') || '',
10984                portalBanner: 'fulfillment-center'
10985            };
10986            digitalData.user = {
10987                userRole: userInfo?.userRole || 'no-value',
10988                userType: userInfo?.userType || 'no-value',
10989                partnerCompany: userInfo?.partnerCompany || 'no-value'
10990            };
10991            digitalData.pageFilter = {
10992                filterType: '',
10993                filterSelection: '',
10994                filterSelection: ''
10995            };
10996            this.setLSItem('analyticsPreviousPageName', digitalData.pageDetails.pageName);
10997            this.pushEvent(
10998                'pageLoaded_fc',
10999                {
11000                    page: digitalData.pageDetails,
11001                    pageFilter: digitalData.pageFilter,
11002                    user: digitalData.user,
11003                }
11004            );
11005        }
11006    }
11007
11008    /**
11009     * Sets the page load event on albertsonsmediacollective pages
11010     */
11011    this.initMediaCollective = function (userData) {
11012        window.digitalData = window.digitalData || {};
11013        if ((window.digitalData?.pageFlags?.previousPageUrl !== window.location.pathname) || !window.digitalData.pageFlags?.previousPageUrl) {
11014            window.digitalData.pageDetails = {
11015                pageName: document.title,
11016                pageUrl: window.location.pathname,
11017                platform: 'web',
11018                previousPageName: this.handleGetLSValue('analyticsPreviousPageName') || ''
11019            };
11020
11021            let userType = '';
11022            if (userData?.userCompanyRole?.role) {
11023                userType = ['CPG_ADMIN', 'CPG_BUYER', 'AGENCY_ADMIN', 'AGENCY_BUYER'].includes(userData.userCompanyRole.role)
11024                    ? 'external'
11025                    : ['HUB_ADMIN', 'CSM_ADMIN', 'CLIENT_SUCCESS_PARTNER', 'MEDIA_PLANNER_ADMIN', 'MEDIA_PLANNER', 'AUDIENCE_ANALYST', 'PERFORMANCE_ANALYST'].includes(userData.userCompanyRole.role)
11026                        ? 'internal'
11027                        : '';
11028            }
11029            window.digitalData.user = {
11030                userRole: userData?.userCompanyRole?.role ? userData.userCompanyRole.role : window.digitalData.user?.userRole ? window.digitalData.user.userRole : '',
11031                userType: userType ? userType : window.digitalData.user?.userType ? window.digitalData.user.userType : '',
11032                partnerCompany: userData?.userCompanyRole?.partnerCompany ? userData.userCompanyRole.partnerCompany : window.digitalData.user?.partnerCompany ? window.digitalData.user.partnerCompany : ''
11033            };
11034
11035            window.digitalData.pageFilter = {
11036                topNav: AB.DATALAYER.initTopNav(),
11037                filterType: '',
11038                filterSelection: '',
11039                filterZone: ''
11040            };
11041            // use pageFlags.previousPageUrl to prevent duplicate calls
11042            window.digitalData.pageFlags = window.digitalData.pageFlags || {};
11043            window.digitalData.pageFlags.previousPageUrl = window.digitalData.pageDetails.pageUrl;
11044
11045            this.setLSItem('analyticsPreviousPageName', window.digitalData.pageDetails.pageName);
11046            this.pushEvent(
11047                'pageLoaded_mediacollective',
11048                {
11049                    page: window.digitalData.pageDetails,
11050                    user: window.digitalData.user,
11051                    pageFilter: window.digitalData.pageFilter
11052                }
11053            );
11054        }
11055    }
11056
11057    /**
11058    * Sends event when downloading a report from media collective portal
11059    */
11060    this.downloadReportEvent = function (reportName, reportFormat) {
11061        if (window.digitalData?.pageDetails) {
11062            window.digitalData.pageDetails.downloadReportDetails = `${reportName === 'searchReport' ? window.digitalData.search?.searchValue : reportName}:${reportFormat}`;
11063            AB.DATALAYER.pushEvent(
11064                'download',
11065                {
11066                    page: window.digitalData.pageDetails
11067                }
11068            );
11069        }
11070    }
11071
11072    /**
11073     * Tracks download events on Media Hub view wrap reports page
11074     * @param {Object} data 
11075     */
11076    this.downloadWrapReport = function (data) {
11077        if (window.digitalData?.pageDetails && data) {
11078            const docInfo = data?.documents && data?.documents[0] ? data?.documents[0] : {};
11079            const partnerName = data?.company;
11080            const docValuesArray = docInfo.originalFileName?.split('.');
11081            const docFormat = docValuesArray.pop();
11082            const docName = docValuesArray.join('.');
11083
11084            window.digitalData.user = window.digitalData.user || {};
11085            window.digitalData.user.partnerCompany = partnerName;
11086            window.digitalData.pageDetails.downloadReportDetails = `${docName}:${docFormat}`;
11087            AB.DATALAYER.pushEvent(
11088                'download',
11089                {
11090                    page: window.digitalData.pageDetails,
11091                    user: window.digitalData.user
11092                }
11093            );
11094        }
11095    }
11096
11097    /**
11098    * Sends event when selecting a filter on media collective portal
11099    */
11100    this.setFilterEventMediaCollective = function (filterSelection, filterType, pageSection, eventType) {
11101        if (window.digitalData?.pageFilter && filterSelection) {
11102
11103            const eventName = eventType ? eventType : (filterSelection === 'reset' || filterSelection === 'reset_all') ? 'filter_reset' : 'filter';
11104            const { pageFilter } = window.digitalData;
11105            pageFilter.filterType = filterType;
11106            pageFilter.filterZone = pageSection;
11107
11108            const formatFilterDate = (dateString) => {
11109                const date = new Date(dateString);
11110                const month = String(date.getMonth() + 1).padStart(2, '0');
11111                const day = String(date.getDate()).padStart(2, '0');
11112                const year = date.getFullYear();
11113                return `${month}/${day}/${year}`;
11114            }
11115
11116            const updatedFilterSelection = Array.isArray(filterSelection)
11117                ? filterType === 'date range' && filterSelection.length === 2
11118                    ? `${formatFilterDate(filterSelection[0])}-${formatFilterDate(filterSelection[1])}`
11119                    : filterSelection.join(',')
11120                : filterSelection;
11121
11122            const eventSent = filterType === 'date range'
11123                ? appEventData.some(eventObj => eventObj?.pageFilter?.filterSelection === updatedFilterSelection)
11124                : false;
11125            pageFilter.filterSelection = updatedFilterSelection;
11126            if (!eventSent) {
11127                AB.DATALAYER.pushEvent(
11128                    eventName,
11129                    {
11130                        pageFilter: pageFilter
11131                    }
11132                );
11133            }
11134        }
11135    }
11136
11137    /**
11138     * Track filter events on Media Hub wrap reports page
11139     * @param {Object} filterData 
11140     * @param {String} pageType 
11141     * @param {String} eventType 
11142     */
11143    this.setFilterEventWrapReportsMediaCollective = function (filterData, pageType, eventType) {
11144        const { pageFilter } = window.digitalData;
11145        const eventName = eventType === 'reset_all' ? eventType : 'filter';
11146        const filterPairs = [];
11147        const filterTypeArray = [];
11148        pageFilter.filterZone = pageType;
11149        if (filterData) {
11150            Object.entries(filterData)?.forEach(dataPair => {
11151                if (dataPair && dataPair[0] && dataPair[1]) {
11152                    if (dataPair[0] === 'partners') {
11153                        dataPair[0] = 'Advertisers';
11154                    }
11155                    if (dataPair[1] && Array.isArray(dataPair[1]) && dataPair[1].length === 0) {
11156                        dataPair[1] = 'All';
11157                    }
11158                    filterTypeArray.push(dataPair[0]);
11159                    filterPairs.push(dataPair.join(': ')?.toLowerCase());
11160                }
11161            })
11162        }
11163
11164        pageFilter.filterSelection = filterPairs.join(',');
11165        pageFilter.filterType = filterTypeArray.join(',');
11166
11167        AB.DATALAYER.pushEvent(
11168            eventName,
11169            {
11170                pageFilter: pageFilter
11171            }
11172        );
11173    }
11174
11175    /**
11176     * Sets the search results event on Media Collective Portal
11177     */
11178    this.setSearchEventMediaCollective = function (data) {
11179        if (window.digitalData && data) {
11180            const isBasicSearch = data.searchPage === 'help-center' || data.searchPage === 'wrap-reports';
11181            const shouldSetHCSearch = isBasicSearch && data.searchTerm && data.searchTerm != window.digitalData.search?.searchValue;
11182            const eventName = data.searchPage === 'help-center' ? 'search_results_hc' : data.searchPage === 'wrap-reports' ? 'search_results_cwr' : this.EVENTS.SEARCH;
11183            const shouldSendSearchEvent = !isBasicSearch || shouldSetHCSearch;
11184            window.digitalData.search = {};
11185
11186            if (shouldSetHCSearch) {
11187                window.digitalData.search.searchValue = data.searchTerm;
11188                window.digitalData.search.searchType = data.searchType;
11189            } else if (!isBasicSearch) {
11190                window.digitalData.search.searchValue = data.searchBy === 'brand'
11191                    ? `company:${data.company?.toLowerCase()}|brand:${data.brands?.length === 0 ? 'no-value' : data.brands?.join(',').toLowerCase()}`
11192                    : `upc:${data.upcs?.length === 0 ? 'null' : data.upcs?.join(',')}`;
11193                window.digitalData.search.searchType = data.searchBy === 'brand' ? 'company/brand' : 'upc';
11194            }
11195
11196            shouldSendSearchEvent && this.pushEvent(
11197                eventName,
11198                {
11199                    page: window.digitalData.pageDetails,
11200                    user: window.digitalData.user,
11201                    search: window.digitalData.search
11202                }
11203            );
11204        }
11205    }
11206
11207    /**
11208     * Sets the page load event on albertsons partner pages
11209     */
11210    this.initAlbsPartner = function (data) {
11211        window.digitalData = window.digitalData || {};
11212        if (((window.digitalData?.pageFlags?.previousPageUrl !== window.location.pathname) || !window.digitalData.pageFlags?.previousPageUrl) && data?.userProfileData && Object.keys(data.userProfileData).length > 0) {
11213            const eventType = AB.DATALAYER.analyticsGetURLParameterByName('eventType');
11214            const viewType = window.sessionStorage?.viewType;
11215
11216            window.digitalData.pageDetails = {
11217                pageName: document.title,
11218                pageUrl: window.location.pathname,
11219                platform: 'web',
11220                previousPageName: this.handleGetLSValue('analyticsPreviousPageName') || '',
11221                company: data?.userProfileData?.analytics?.companyInfo?.[0]?.companyDetail?.legalBusinessName ? data.userProfileData.analytics.companyInfo[0].companyDetail.legalBusinessName : window.digitalData.pageDetails?.company ? window.digitalData.pageDetails.company : ''
11222            };
11223
11224            window.digitalData.user = {
11225                userAcess: data?.userProfileData?.analytics?.access?.[0] ? data.userProfileData.analytics.access[0] : window.digitalData.user?.userAcess ? window.digitalData.user.userAcess : '',
11226                userEmail: data?.userProfileData?.profileInfo?.emailAddress,
11227                userRole: data?.roleName,
11228                userId: data?.userProfileData?.userId
11229            };
11230
11231            switch (true) {
11232                case digitalData.pageDetails.pageName == 'APP : Promotion - Events':
11233                    digitalData.pageDetails.pageName = 'APP : Promotion-Management:Create-Event';
11234                    break;
11235                case digitalData.pageDetails.pageName == 'APP : Promotion - Create' && eventType == 'DP':
11236                    digitalData.pageDetails.pageName = 'APP : Promotion-Management:Division-Promotion';
11237                    break;
11238                case digitalData.pageDetails.pageName == 'APP : Promotion - Create' && eventType == 'AO':
11239                    digitalData.pageDetails.pageName = 'APP : Promotion-Management:Division-Allowances-Only';
11240                    break;
11241                case digitalData.pageDetails.pageName == 'APP : Promotion - Create' && eventType == 'NDP':
11242                    digitalData.pageDetails.pageName = 'APP : Promotion-Management:National';
11243                    break;
11244                case ((digitalData.pageDetails.pageName == 'APP : Promotion - Meupp' || digitalData.pageDetails.pageName == 'APP : Meupp') && viewType === 'taskView') || ((digitalData.pageDetails.pageName == 'APP : Promotion - Meupp' || digitalData.pageDetails.pageName == 'APP : Meupp') && !viewType):
11245                    digitalData.pageDetails.pageName = 'APP : Promotion-Management:Tasks ';
11246                    break;
11247                case (digitalData.pageDetails.pageName == 'APP : Promotion - Meupp' || digitalData.pageDetails.pageName == 'APP : Meupp') && viewType === 'planningView':
11248                    digitalData.pageDetails.pageName = 'APP : Promotion-Management:Planning ';
11249                    break;
11250                case (digitalData.pageDetails.pageName == 'APP : Promotion - Meupp' || digitalData.pageDetails.pageName == 'APP : Meupp') && viewType === 'allowanceView':
11251                    digitalData.pageDetails.pageName = 'APP : Promotion-Management:Allowances ';
11252                    break;
11253                case (digitalData.pageDetails.pageName == 'APP : Promotion - Meupp' || digitalData.pageDetails.pageName == 'APP : Meupp') && viewType === 'alertView':
11254                    digitalData.pageDetails.pageName = 'APP : Promotion-Management:Alerts ';
11255                    break;
11256                default:
11257                    break;
11258            }
11259
11260            // use pageFlags.previousPageUrl to prevent duplicate calls
11261            window.digitalData.pageFlags = window.digitalData.pageFlags || {};
11262            window.digitalData.pageFlags.previousPageUrl = window.digitalData.pageDetails.pageUrl;
11263
11264            this.setLSItem('analyticsPreviousPageName', window.digitalData.pageDetails.pageName);
11265            this.pushEvent(
11266                'pageLoaded_albspartner',
11267                {
11268                    page: window.digitalData.pageDetails,
11269                    user: window.digitalData.user
11270                }
11271            );
11272        }
11273    }
11274
11275    this.trackTabChangeAlbsPartner = function (tabName) {
11276        digitalData.pageDetails.pageName = `APP : Promotion-Management:${tabName}`
11277        this.setLSItem('analyticsPreviousPageName', window.digitalData.pageDetails.pageName);
11278        this.pushEvent(
11279            'pageLoaded_albspartner',
11280            {
11281                page: window.digitalData.pageDetails,
11282                user: window.digitalData.user
11283            }
11284        );
11285    }
11286
11287    /**
11288     * Sets the search results event on Albertsons Partner - Help Center
11289     */
11290    this.setSearchEventAlbsPartner = function (searchTerm, data) {
11291        if (window.digitalData && data !== undefined) {
11292            window.digitalData.search = {};
11293            window.digitalData.search.searchTerm = searchTerm;
11294            window.digitalData.search.searchResults = data?.count || 0;
11295            this.pushEvent(
11296                this.EVENTS.SEARCH,
11297                {
11298                    page: window.digitalData.pageDetails,
11299                    user: window.digitalData.user,
11300                    search: window.digitalData.search
11301                }
11302            );
11303        }
11304    }
11305
11306    /**
11307     * Subscribes to Firework Video events
11308     */
11309    this.initFireworkEvents = function () {
11310        // Video loads on the page
11311        document.addEventListener('fw:video:impression', (event) => {
11312            this.setFireworkEvents('videoImpression', event.detail);
11313        });
11314
11315        // Video started
11316        document.addEventListener('fw:video:start', (event) => {
11317            this.setFireworkEvents('videoStart', event.detail);
11318        });
11319
11320        // Video reached 25% 
11321        document.addEventListener('fw:video:first-quartile', (event) => {
11322            this.setFireworkEvents('videoFirstQuartile', event.detail, '25');
11323        });
11324
11325        // Video reached at least 90%
11326        document.addEventListener('fw:video:complete', (event) => {
11327            this.setFireworkEvents('videoComplete', event.detail, '100');
11328        });
11329    }
11330
11331    /**
11332     * Sets events for Firework videos
11333     * @param eventName 
11334     * @param eventDetails 
11335     * @param percentage 
11336     */
11337    this.setFireworkEvents = function (eventName, eventDetails, percentage) {
11338        if (eventDetails && eventDetails.video && eventDetails.extra) {
11339
11340            // get playlistName
11341            const currentPlaylist = document.querySelector(`.web-stories [playlist=${eventDetails.playlist}]`);
11342            const currentPlaylistTitle = currentPlaylist?.closest('.web-stories')?.querySelector('.abs-short-videos__cta-title')?.textContent?.trim();
11343
11344            this.pushEvent(
11345                eventName,
11346                {
11347                    video: {
11348                        name: `${currentPlaylistTitle}:${eventDetails.video.caption}`,
11349                        duration: `${eventDetails.extra.duration} seconds`,
11350                        videoId: eventDetails.video.encoded_id,
11351                        percentage: percentage,
11352                        playerName: 'firework'
11353                    },
11354                    page: digitalData?.pageDetails,
11355                    pageFilter: digitalData?.pageFilter
11356                }
11357            );
11358        }
11359    }
11360
11361    /**
11362     * Returns analytics context from a [data-video-enterprise] container element.
11363     */
11364    this._getInHouseVideoContext = function (container) {
11365        return {
11366            campId:      container.dataset.campId || 'no-value',
11367            orientation: container.dataset.orientation || 'vertical',
11368            isSponsored: container.dataset.isSponsored === 'true',
11369            rowIndex:    parseInt(container.dataset.rowIndex) || 1,
11370            slotIndex:   parseInt(container.dataset.slotIndex) || 1,
11371        };
11372    };
11373
11374    /**
11375     * Fires a linkClick event for the in-house enterprise video player, matching the
11376     * full standard payload (page, pageFilter, user, productInfo, modal, cart) from digitalData,
11377     * exactly as setLinkClickEvents does internally.
11378     */
11379    this.setInHouseVideoLinkClickEvent = function (linkName, customData, oncePerPageView) {
11380        try {
11381            const alreadySent = oncePerPageView ? this.setEventOncePerPage(linkName, 'linkClick') : false;
11382            if (alreadySent) return;
11383            const { mediaPlacement, pageFilter: pageFilterOverride, ...rest } = customData || {};
11384            // Adobe Launch reads V80 from pageFilter.mediaPlacementClick — mutate before pushEvent
11385            // so both the EDDL event snapshot and any Launch rules reading digitalData directly see the value.
11386            if (mediaPlacement) {
11387                digitalData = digitalData || {};
11388                digitalData.pageFilter = digitalData.pageFilter || {};
11389                digitalData.pageFilter.mediaPlacementClick = mediaPlacement;
11390            }
11391            this.pushEvent(this.EVENTS.LINK_CLICK, {
11392                link: { linkName },
11393                page: digitalData?.pageDetails,
11394                pageFilter: pageFilterOverride ? { ...digitalData?.pageFilter, ...pageFilterOverride } : digitalData?.pageFilter,
11395                user: digitalData?.user,
11396                productInfo: digitalData?.productInfo || {},
11397                modal: digitalData?.modal,
11398                cart: digitalData?.cart,
11399                ...rest,
11400            });
11401        } catch (e) {
11402            console.error('@AnalyticsTeam - Failed to send in-house video event: ', e);
11403        }
11404    };
11405
11406    /**
11407     * Subscribes to in-house enterprise video player DOM events.
11408     * Analytics context is read from [data-video-enterprise] attributes set by the Angular microapp.
11409     * Follows the same pattern as initFireworkEvents.
11410     */
11411    this.initInHouseVideoEvents = function () {
11412        // Tracks which campId+page combos have already fired a play event this page view.
11413        // Keyed by `${campId}::${pathname}` so SPA navigation to a new URL resets the guard automatically.
11414        const _firedVideoPlay = new Map();
11415
11416        // AC#1 — Track play click on in-house video player (once per page view per video/campId)
11417        document.addEventListener('abs-video-play', (event) => {
11418            const container = event.target.closest('[data-video-enterprise]');
11419            if (!container) return;
11420            const { campId, orientation, isSponsored, rowIndex, slotIndex } = this._getInHouseVideoContext(container);
11421            const deduKey = `${campId}::${window.location.pathname}`;
11422            if (_firedVideoPlay.has(deduKey)) return;
11423            _firedVideoPlay.set(deduKey, true);
11424            const rec        = isSponsored ? 'sponsored' : 'not-recommended';
11425            const row        = `r${String(rowIndex).padStart(2, '0')}`;
11426            const slot       = `s${String(slotIndex).padStart(2, '0')}`;
11427            const placementUC = `R${String(rowIndex).padStart(2, '0')}#S${String(slotIndex).padStart(2, '0')}`;
11428            const mediaPlacementVal = `video-enterprise-${orientation}#${rec}#${row}#${slot}`;
11429            const videoBentoCtx = {
11430                content: `video-enterprise-${orientation}`,
11431                mediaType: `video-enterprise-${orientation}`,
11432                recommendationType: isSponsored ? 'sponsored' : 'not-recommended',
11433                placement: placementUC,
11434                mediaPlacementClick: mediaPlacementVal,
11435            };
11436            digitalData._bentoProductContext = videoBentoCtx;
11437            setTimeout(() => {
11438                if (digitalData._bentoProductContext === videoBentoCtx) {
11439                    delete digitalData._bentoProductContext;
11440                }
11441            }, 5000);
11442            this.setInHouseVideoLinkClickEvent(
11443                `video-enterprise-${orientation}|play`,
11444                {
11445                    video: { name: `video-enterprise:${campId}` },
11446                    page: { ...digitalData?.pageDetails, feature: 'video-enterprise|shp-exp|595549|53801' },
11447                    pageFilter: { mediaType: `video-enterprise-${orientation}`, placement: placementUC, recommendationType: rec },
11448                    mediaPlacement: mediaPlacementVal,
11449                }
11450            );
11451        });
11452
11453        // AC#2 — Track add to cart click — injects _bentoProductContext for ALL products so
11454        // setPfmDetailOnProductAction uses video-enterprise pfmDetail on every page/orientation.
11455        // The cart_add linkClick event fires for the first product only; existing analytics handles the rest.
11456        document.addEventListener('click', (event) => {
11457            const container = event.target.closest('[data-video-enterprise]');
11458            if (!container || !event.target.closest('[data-qa="addbutton"], [data-qa="addwgtBtn"]')) return;
11459            const clickedProduct = event.target.closest('[data-qa="prd-itm"]');
11460            if (!clickedProduct) return;
11461            const { campId, orientation, isSponsored, rowIndex, slotIndex } = this._getInHouseVideoContext(container);
11462            // Horizontal add-to-cart tracking is scoped to the horizontal video grid product list only.
11463            if (orientation === 'horizontal' && !event.target.closest('.horizontal-video-grid__products')) return;
11464            const rec  = isSponsored ? 'sponsored' : 'not-recommended';
11465            const row  = `r${String(rowIndex).padStart(2, '0')}`;
11466            const slot = `s${String(slotIndex).padStart(2, '0')}`;
11467            const placementUC = `R${String(rowIndex).padStart(2, '0')}#S${String(slotIndex).padStart(2, '0')}`;
11468            // Inject bento-style context for ALL products so handleItemEvent → setPfmDetailOnProductAction
11469            // sets the correct video-enterprise evar14 regardless of orientation (vertical/search, horizontal/PDP).
11470            const videoBentoCtx = {
11471                content: `video-enterprise-${orientation}`,
11472                mediaType: `video-enterprise-${orientation}`,
11473                recommendationType: isSponsored ? 'sponsored' : 'not-recommended',
11474                placement: placementUC,
11475                mediaPlacementClick: `video-enterprise-${orientation}#${rec}#${row}#${slot}`,
11476            };
11477            digitalData._bentoProductContext = videoBentoCtx;
11478            // Auto-clear after generous cart API timeout; reference check avoids clobbering a later context.
11479            setTimeout(() => {
11480                if (digitalData._bentoProductContext === videoBentoCtx) {
11481                    delete digitalData._bentoProductContext;
11482                }
11483            }, 5000);
11484            // Only fire the cart_add linkClick for the first product; existing analytics handles the rest.
11485            const firstProduct = container.querySelector('[data-qa="prd-itm"]');
11486            if (clickedProduct !== firstProduct) return;
11487            this.setInHouseVideoLinkClickEvent('cart_add', {
11488                video: { name: `video-enterprise:${campId}` },
11489                page: { ...digitalData?.pageDetails, feature: 'video-enterprise|shp-exp|595549|53801' },
11490                pageFilter: { mediaType: `video-enterprise-${orientation}`, placement: placementUC, recommendationType: rec },
11491                mediaPlacement: `video-enterprise-${orientation}#${rec}#${row}#${slot}`,
11492            });
11493        }, true);
11494
11495        // AC#3 — Track product image click to PDP — stores bentoHeroPdpPfm + mediaPlacementClick for ALL
11496        // products so PDP page load picks up the correct evar14/V80 for any orientation (vertical/search,
11497        // horizontal/PDP). The linkClick event + CTA tracking fire for the first product only.
11498        document.addEventListener('click', (event) => {
11499            const container = event.target.closest('[data-video-enterprise]');
11500            if (!container || !event.target.closest('a.pc__tap-zone, [data-qa="prd-itm-pttl"], [data-qa="prd-itm-img"]')) return;
11501            const clickedProduct = event.target.closest('[data-qa="prd-itm"]');
11502            if (!clickedProduct) return;
11503            const { campId, orientation, isSponsored, rowIndex, slotIndex } = this._getInHouseVideoContext(container);
11504            // Horizontal click-to-PDP tracking is scoped to the horizontal video grid product list only.
11505            if (orientation === 'horizontal' && !event.target.closest('.horizontal-video-grid__products')) return;
11506            const rec        = isSponsored ? 'sponsored' : 'not-recommended';
11507            const row        = `r${String(rowIndex).padStart(2, '0')}`;
11508            const slot       = `s${String(slotIndex).padStart(2, '0')}`;
11509            const placementUC = `R${String(rowIndex).padStart(2, '0')}#S${String(slotIndex).padStart(2, '0')}`;
11510            const subSection = digitalData?.pageDetails?.subSection1 || 'search-results';
11511            const ctaValue   = `cta:${subSection}|link|video-enterprise-${orientation}`;
11512            // Store video-enterprise pfm context for ALL products so PDP page load picks up correct
11513            // evar14/V80 regardless of which product was clicked or what orientation the container uses.
11514            const videoCtxPdp = {
11515                content: `video-enterprise-${orientation}`,
11516                mediaType: `video-enterprise-${orientation}`,
11517                recommendationType: isSponsored ? 'sponsored' : 'not-recommended',
11518                placement: placementUC,
11519            };
11520            this.setBentoPdpPfm(videoCtxPdp, null, null);    // → localStorage.bentoHeroPdpPfm → evar14 on PDP load
11521            this.setBentoMediaPlacement(videoCtxPdp, true);  // → localStorage.mediaPlacementClick → V80 on PDP load
11522            // Only fire linkClick + CTA tracking for the first product; existing analytics handles the rest.
11523            const firstProduct = container.querySelector('[data-qa="prd-itm"]');
11524            if (clickedProduct !== firstProduct) return;
11525            // V171 — save to localStorage so PDP page load picks it up as pageFilter.topNav
11526            this.analyticsCTATracking(ctaValue);
11527            // V95/V208/v80 — immediate linkClick event on click page
11528            this.setInHouseVideoLinkClickEvent(ctaValue, {
11529                video: { name: `video-enterprise:${campId}` },
11530                page: { ...digitalData?.pageDetails, feature: 'video-enterprise|shp-exp|595549|53801' },
11531                pageFilter: { mediaType: `video-enterprise-${orientation}`, placement: placementUC, recommendationType: rec },
11532                mediaPlacement: `video-enterprise-${orientation}#${rec}#${row}#${slot}`,
11533            });
11534        }, true);
11535
11536        // AC#4 — Capture errors from in-house video player
11537        document.addEventListener('abs-video-error', (event) => {
11538            const container = event.target.closest('[data-video-enterprise]');
11539            if (!container) return;
11540            const { campId, orientation, isSponsored, rowIndex, slotIndex } = this._getInHouseVideoContext(container);
11541            const rec4        = isSponsored ? 'sponsored' : 'not-recommended';
11542            const placementUC4 = `R${String(rowIndex).padStart(2, '0')}#S${String(slotIndex).padStart(2, '0')}`;
11543            const { errorId = 'no-value', errorName = 'no-value', errorMessage = 'no-value' } = event.detail || {};
11544            try {
11545                this.pushEvent(this.EVENTS.ERROR, {
11546                    video: { name: `video-enterprise:${campId}` },
11547                    page: { ...digitalData?.pageDetails, feature: 'video-enterprise|shp-exp|595549|53801' },
11548                    pageFilter: { ...digitalData?.pageFilter, mediaType: `video-enterprise-${orientation}`, placement: placementUC4, recommendationType: rec4 },
11549                    error: {
11550                        errorID: `video-enterprise:${errorId}`,
11551                        errorFeature: errorName,
11552                        errorMessage: `video-enterprise:${errorMessage}`,
11553                    },
11554                });
11555            } catch (e) {
11556                console.error('@AnalyticsTeam - Failed to send in-house video event: ', e);
11557            }
11558        });
11559    };
11560
11561    this.analyticsSetLSFPUpdate = function (source, isTrial) {
11562        if (source === 'upgradeBtn') {
11563            this.setLSItem('analyticsFPLSitem', 'clickedBanner');
11564        } else if (source === 'annualBtn' && this.getLSItem('analyticsFPLSitem') === 'clickedBanner') {
11565            this.setLSItem('analyticsFPLSitem', 'clickedAnnualBtn');
11566        } else if (source === 'submitBtn' && this.getLSItem('analyticsFPLSitem') === 'clickedAnnualBtn') {
11567            this.setLSItem('analyticsFPLSitem', 'clickedPaymentSubmit');
11568        }
11569        if (source === 'submitBtn' && this.getLSItem('analyticsChangePlan') === 'annual' || source === 'changePlanToAnnualBtn') {
11570            this.setLSItem('analyticsFPLSitem', 'changeToAnnual');
11571            this.removeLSItem('analyticsChangePlan');
11572        } else if (source === 'submitBtn' && this.getLSItem('analyticsChangePlan') === 'monthly' || source === 'changePlanToMonthlyBtn') {
11573            this.setLSItem('analyticsFPLSitem', 'changeToMonthly');
11574            this.removeLSItem('analyticsChangePlan');
11575        }
11576        if (isTrial === 'TRIAL') {
11577            this.setLSItem('analyticsTrialFPUpdate', true);
11578        }
11579    }
11580
11581    /**
11582     * Returns all visible banners
11583     */
11584    this.getAllBanners = function () {
11585
11586        const selectors = ['.nextgen-banner-unit-proxy', '.banner-unit-proxy',
11587            '.nextgen-abs-carousel-wrapper', '.abs-carousel-wrapper', '.as-hero__carousel',
11588            '.mod-unit-unified-proxy', '.mod-unit-skinny-proxy', '.mod-unit-carousel-container', '.merch-targeted-promo-banner', '.nextgen-banner-unit', '.banner-unit-hero', 'search-grid-merch-banner', '.banner-unit-medium, .abs-carousel'];
11589        const allElements = document.querySelectorAll(selectors.join(', '));
11590
11591        const allBanners = allElements && Array.from(allElements).filter(el => {
11592            return AB.DATALAYER.isVisible(el) &&
11593                ((el.classList.contains('nextgen-banner-unit-proxy') &&
11594                    el.querySelector('.nextgen-banner-unit')?.children?.length > 0 &&
11595                    !el.classList.contains('d-none') &&
11596                    !el.closest('.nextgen-abs-carousel-wrapper')) ||
11597                    (el.classList.contains('nextgen-banner-unit-proxy') &&
11598                        el?.children[0]?.classList?.contains('merch-targeted-promo-banner')) ||
11599                    (el.classList.contains('nextgen-abs-carousel-wrapper') &&
11600                        el.querySelector('.nextgen-banner-unit')?.children?.length > 0) ||
11601                    (el.classList.contains('as-hero__carousel') &&
11602                        el.querySelector('.as-hero__item')?.children?.length > 0) ||
11603                    (el.classList.contains('banner-unit-proxy') &&
11604                        el.querySelector('.banner-unit-regular')?.children?.length > 0 &&
11605                        !el.closest('.abs-carousel-wrapper') &&
11606                        !el.classList.contains('d-none') &&
11607                        !el.classList.contains('collapse')) ||
11608                    (el.classList.contains('nextgen-abs-carousel-wrapper') &&
11609                        el.querySelector('.hero-canvas')?.children?.length > 0) ||
11610                    (el.classList.contains('mod-unit-unified-proxy') &&
11611                        !el.closest('.mod-unit-carousel-container')) ||
11612                    (el.classList.contains('mod-unit-skinny-proxy') &&
11613                        !el.closest('.mod-unit-carousel-container')) ||
11614                    el.classList.contains('mod-unit-carousel-container') ||
11615                    (el.classList.contains('abs-carousel-wrapper') &&
11616                        !el.querySelector('.nextgen-banner-unit-proxy')?.children[0]?.classList?.contains('merch-targeted-promo-banner') && !el.parentElement?.classList?.contains('d-none')) ||
11617                    (el.classList.contains('merch-targeted-promo-banner') && !el.classList.contains('d-none')) ||
11618                    (!el.parentElement?.classList?.contains('nextgen-banner-unit-proxy') && el.parentElement?.querySelector('webgen-banner-unit')) ||
11619                    (el.nodeName == 'SEARCH-GRID-MERCH-BANNER') ||
11620                    (el.classList?.contains('banner-unit-hero')) ||
11621                    (el.classList?.contains('banner-unit-medium')) ||
11622                    (el.classList.contains('abs-carousel') && el.querySelector('.hero-canvas')))
11623        });
11624
11625        return allBanners || [];
11626    };
11627
11628    /**
11629     * Checks if it's a single banner or multiple banners per row
11630     */
11631    this.isMultipleSlotsBanner = function (bannerClassMappings, currentBanner) {
11632        for (const className in bannerClassMappings) {
11633            const wrapper = bannerClassMappings[className];
11634            const unitSelector = `.${className}`;
11635            if (currentBanner.classList.contains(className) && currentBanner.closest(wrapper) && currentBanner.closest(wrapper).querySelector(unitSelector)) {
11636                return true
11637            }
11638        }
11639        return false;
11640    }
11641
11642    /**
11643     * Returns the banner title
11644     */
11645    this.getBannerClickedTitle = function (bannerClicked, selectors, bannerTypeString) {
11646        const currentBanner = bannerClicked?.closest(selectors.currentBanner);
11647        const titleElement = currentBanner?.querySelector(selectors.titleElement);
11648        const targetTitle = titleElement?.querySelector('.target-visually-shown')?.textContent || '';
11649        let titleText = titleElement ? titleElement.textContent?.trim().toLowerCase().replace(/[^a-z0-9|-]/gi, '-').replace(/^-+|-+$/g, '').replace(/-+/g, '-') : '';
11650
11651        if (targetTitle) {
11652            titleText = AB.DATALAYER.sanitizeAnalyticsText(targetTitle);
11653        }
11654
11655        if (bannerTypeString === 'mediumBanner' && !titleText) {
11656            const bannerImageAltAttr = bannerClicked?.querySelector('img')?.getAttribute('alt');
11657            titleText = bannerImageAltAttr ? bannerImageAltAttr.trim().replace(/\s/g, '') : 'no-title';
11658        }
11659
11660        return titleText;
11661    }
11662
11663    /**
11664     * Returns the banner placement
11665     */
11666    this.getBannerPlacement = function (bannerClicked, selectors, bannerClassMappings) {
11667        let currentBanner = bannerClicked?.closest(selectors.currentBanner);
11668        if (!currentBanner) {
11669            return '';
11670        }
11671        let isMultipleSlotsBanner = bannerClassMappings ? AB.DATALAYER.isMultipleSlotsBanner(bannerClassMappings, currentBanner) : false;
11672        const totalBannerSlots = AB.DATALAYER.getAllBanners();
11673        let bannerPlacement = '';
11674        if (isMultipleSlotsBanner) {
11675            if (currentBanner?.classList?.contains('nextgen-banner-unit') && currentBanner.closest('.nextgen-banner-unit-proxy')) {
11676                currentBanner = currentBanner.closest('.nextgen-banner-unit-proxy');
11677            }
11678            const currentBannerContainer = bannerClicked?.closest(selectors.wrapperElement);
11679            const bannerRow = currentBannerContainer ? totalBannerSlots?.indexOf(currentBannerContainer) + 1 : 0;
11680            const currentContainerBanners = currentBannerContainer
11681                ? Array.from(currentBannerContainer.querySelectorAll(selectors.currentBanner))
11682                    .filter(banner => !(banner.classList?.contains('slick-cloned') || banner.closest('.slick-cloned') || banner.classList?.contains('nextgen-banner-unit')))
11683                : [];
11684            const bannerSlot = Array.from(currentContainerBanners)?.indexOf(currentBanner) + 1 || 0;
11685            const displayableBannerRow = bannerRow < 10 ? `R0${bannerRow}` : `R${bannerRow}`;
11686            const displayableBannerSlot = bannerSlot < 10 ? `S0${bannerSlot}` : `S${bannerSlot}`;
11687
11688            bannerPlacement = bannerSlot > 0 && currentContainerBanners.length > 1
11689                ? `${displayableBannerRow}#${displayableBannerSlot}`
11690                : displayableBannerRow;
11691        } else {
11692            if (currentBanner.classList?.contains('nextgen-banner-unit') && currentBanner.closest('.nextgen-banner-unit-proxy')) {
11693                currentBanner = currentBanner.closest('.nextgen-banner-unit-proxy');
11694            }
11695            if (currentBanner.classList?.contains('flex-medium-fw')) {
11696                currentBanner = currentBanner.closest(selectors.wrapperElement);
11697            }
11698            const bannerRow = totalBannerSlots?.indexOf(currentBanner) + 1 || 0;
11699            bannerPlacement = bannerRow < 10 ? `R0${bannerRow}#S00` : `R${bannerRow}#S00`;
11700        }
11701        return bannerPlacement;
11702    }
11703
11704    /**
11705     * Returns the banner recommendation type
11706     */
11707    this.getBannerRecommendationType = function (selectors, currentBanner, bannerType) {
11708        if (!currentBanner) {
11709            return '';
11710        }
11711        let bannerApiSource = '';
11712        if (bannerType === 'hero') {
11713            const sponsoredBannerIndexes = [];
11714            const bannerIndex = currentBanner.getAttribute('data-slick-index');
11715            const heroContainer = currentBanner.closest('.as-hero');
11716            heroContainer?.querySelectorAll('hero-sponsored-wc').forEach(sponsoredBanner => {
11717                sponsoredBannerIndexes.push(sponsoredBanner?.dataset?.bannerPosition);
11718            });
11719            if (sponsoredBannerIndexes.includes(parseInt(bannerIndex))) {
11720                bannerApiSource = heroContainer?.querySelector('hero-sponsored-wc')?.dataset?.bannerApiSource || currentBanner.querySelector('.as-hero__background--desktop .as-hero__item__footer')?.textContent;
11721            }
11722        } else {
11723            bannerApiSource = currentBanner.querySelector(selectors.bannerSource)?.dataset?.bannerApiSource;
11724        }
11725        if (bannerApiSource === 'sponsoredBannerApi' || bannerApiSource === 'sponsoredad
11725api' || bannerApiSource === 'sponsoredadapiviadomainapi' || bannerApiSource === 'sponsoredbannerapi' || bannerApiSource === 'sponsored') {
11726            return 'sponsored';
11727        }
11728        return 'notRecommended';
11729    }
11730
11731    /**
11732     * Sets the link click event when clicking on banners
11733     */
11734    this.setBannerClickedEvent = function (placement, title, recommendationType, mediaType, bannerTitle) {
11735        if (window.digitalData && window.digitalData.pageFilter) {
11736            const payload = {
11737                link: {
11738                    linkName: title,
11739                    oneTagLinkName: 'banner-clicked'
11740                },
11741                pageFilter: structuredClone(digitalData.pageFilter),
11742                page: structuredClone(digitalData.pageDetails)
11743            }
11744            payload.pageFilter.recommendationType = recommendationType;
11745            payload.pageFilter.placement = placement;
11746            payload.pageFilter.mediaType = mediaType;
11747            payload.page.bnrName = `${bannerTitle}|no-value`;
11748
11749            this.pushEvent(
11750                this.EVENTS.LINK_CLICK, payload
11751            );
11752            digitalData.pageFilter.bannerType = '';
11753            if (digitalData.pageFilter.isMerchBanner) {
11754                delete digitalData.pageFilter.isMerchBanner;
11755            }
11756        }
11757    }
11758
11759    /**
11760     * Tracking for medium banner
11761     */
11762    this.setMediumBannerTracking = function (bannerClicked) {
11763        const selectors = {
11764            currentBanner: '.nextgen-banner-unit, .nextgen-banner-unit-proxy, .banner-unit-medium',
11765            titleElement: '.banner-unit-medium__text-plate__title p',
11766            wrapperElement: '.nextgen-abs-carousel-wrapper, .banner-unit-medium',
11767            bannerSource: 'nextgen-banner-unit-wc'
11768        };
11769
11770        const bannerClassMappings = {
11771            'nextgen-banner-unit-proxy': '.nextgen-abs-carousel-wrapper',
11772            'nextgen-banner-unit': '.nextgen-abs-carousel-wrapper'
11773        }
11774
11775        // get banner title
11776        const currentBannerTitle = AB.DATALAYER.getBannerClickedTitle(bannerClicked, selectors, 'mediumBanner');
11777
11778        // get banner placement
11779        const bannerPlacement = AB.DATALAYER.getBannerPlacement(bannerClicked, selectors, bannerClassMappings);
11780
11781        // get recommendation type
11782        const currentBanner = bannerClicked?.closest(selectors.currentBanner);
11783        const recommendationType = AB.DATALAYER.getBannerRecommendationType(selectors, currentBanner);
11784
11785        if (window.isAnalyticsMarketplacePage) {
11786            AB.DATALAYER.analyticsCTATracking(`cta:${AB.DATALAYER.initPathSections(true).join(':')}|link|view-all-from-banner`)
11787        }
11788
11789        AB.DATALAYER.trackAEMZone('banner', currentBanner, `banner:${currentBannerTitle}`);
11790
11791        // send link click event
11792        AB.DATALAYER.setBannerClickedEvent(bannerPlacement, `mediumBannerClicked|${currentBannerTitle}`, recommendationType, 'medium-banner', currentBannerTitle);
11793    }
11794
11795    this.setMerchFlexBannerTracking = function (bannerClicked) {
11796        const selectors = {
11797            currentBanner: '.flex-medium-fw',
11798            titleElement: '.flex-medium-fw__text-plate__heading',
11799            wrapperElement: 'search-grid-merch-banner',
11800        };
11801
11802        // get banner title
11803        const currentBannerTitle = AB.DATALAYER.getBannerClickedTitle(bannerClicked, selectors, 'merch-baner');
11804
11805        // get banner placement
11806        const bannerPlacement = AB.DATALAYER.getBannerPlacement(bannerClicked, selectors, null, 'merch-banner');
11807
11808        // get recommendation type
11809        const currentBanner = bannerClicked?.closest(selectors.currentBanner) || bannerClicked?.closest('webgen-flex-module');
11810        let bannerId = '';
11811        let recommendationType = '';
11812        const bannerData = currentBanner?.closest(selectors.wrapperElement)?.querySelector('webgen-flex-module')?.getAttribute('data-flex-module-content')
11813            || currentBanner?.getAttribute?.('data-flex-module-content');
11814
11815        if (bannerData && typeof bannerData === 'string') {
11816            const parsedBannerData = AB.DATALAYER.safeJSONParse(bannerData);
11817            bannerId = parsedBannerData.promoId ? `|${parsedBannerData.promoId}` : '';
11818            recommendationType = parsedBannerData.program && parsedBannerData.program !== 'abs' ? 'sponsored' : 'notRecommended';
11819        }
11820        digitalData.pageFilter = digitalData.pageFilter || {};
11821        digitalData.pageFilter.isMerchBanner = true;
11822
11823        AB.DATALAYER.trackAEMZone('merch-banner', currentBanner, currentBannerTitle);
11824
11825        // send link click event
11826        AB.DATALAYER.setBannerClickedEvent(bannerPlacement, `bannerclicked|${currentBannerTitle}${bannerId}`, recommendationType, 'medium-banner', currentBannerTitle);
11827    }
11828
11829    /**
11830     * Tracking for banner unit
11831     */
11832    this.setBannerUnitTracking = function (bannerClicked) {
11833        const selectors = {
11834            currentBanner: '.banner-unit-proxy, .nextgen-banner-unit-proxy, .as-hero__item, promo-banner, .merch-targeted-promo-banner, .banner-unit-hero',
11835            titleElement: '.banner-unit-regular__headline p, .banner-unit-hero__text-plate__title, .title, .mod-unit__headline p, .banner-unit-regular__headline .h2, .banner__title p',
11836            wrapperElement: '.abs-carousel-wrapper, .nextgen-abs-carousel-wrapper, .as-hero__carousel, .banner-unit-hero',
11837            bannerSource: 'banner-unit-regular-wc, banner-unit-hero-wc, promo-banner-regular-wc'
11838        };
11839        const bannerClassMappings = {
11840            'banner-unit-proxy': '.abs-carousel-wrapper',
11841            'nextgen-banner-unit-proxy': '.nextgen-abs-carousel-wrapper',
11842            'as-hero__item': '.as-hero__carousel',
11843        };
11844
11845        // get banner title
11846        const currentBannerTitle = AB.DATALAYER.getBannerClickedTitle(bannerClicked, selectors);
11847
11848        // get banner placement
11849        const bannerPlacement = AB.DATALAYER.getBannerPlacement(bannerClicked, selectors, bannerClassMappings);
11850
11851        // get recommendation type
11852        const currentBanner = bannerClicked?.closest(selectors.currentBanner);
11853        let recommendationType = 'notRecommended';
11854        if (currentBanner?.classList.contains('banner-unit-proxy') || currentBanner?.classList.contains('nextgen-banner-unit-proxy') || currentBanner?.classList.contains('merch-targeted-promo-banner')) {
11855            recommendationType = AB.DATALAYER.getBannerRecommendationType(selectors, currentBanner);
11856        } else if (currentBanner?.classList.contains('as-hero__item')) {
11857            recommendationType = AB.DATALAYER.getBannerRecommendationType(selectors, currentBanner, 'hero');
11858        }
11859        if (bannerClicked?.closest('.banner-unit-hero') || currentBanner?.classList.contains('as-hero__item')) {
11860            digitalData.pageFilter.bannerType = 'hero';
11861        }
11862        AB.DATALAYER.trackAEMZone('banner', currentBanner, `${digitalData.pageFilter?.bannerType === 'hero' ? `${AB.DATALAYER.isHomePage() ? 'home-hero' : 'hero'}` : 'large'}-banner:${currentBannerTitle}`);
11863
11864        // Removed restriction to homepage as per request to send metricA across the website
11865        const heroBannerContent = currentBanner?.querySelector(selectors.bannerSource)?.getAttribute('data-hero-banner-content');
11866        const heroBannerContentObj = AB.DATALAYER.safeJSONParse(heroBannerContent);
11867        if (heroBannerContentObj?.p13nAdobeMetrics) {
11868            const abTestDetails = heroBannerContentObj.p13nAdobeMetrics?.metricA || 'generic';
11869            localStorage.setItem('heroBannerAbTestDetails', abTestDetails);
11870        }
11871
11872
11873        // send link click event
11874        AB.DATALAYER.setBannerClickedEvent(bannerPlacement, `bannerClicked|${currentBannerTitle}`, recommendationType, 'banner', currentBannerTitle);
11875    }
11876
11877    /**
11878     * Tracking for sidebar banner
11879     */
11880    this.setSidebarBannerTracking = function (bannerClicked) {
11881        const selectors = {
11882            currentBanner: '.nextgen-banner-unit-proxy',
11883            titleElement: '.banner-unit-sidebar__card__content__headline p',
11884            bannerSource: 'nextgen-banner-unit-sidebar'
11885        };
11886
11887        // get banner title
11888        const currentBannerTitle = AB.DATALAYER.getBannerClickedTitle(bannerClicked, selectors);
11889
11890        // get banner placement
11891        const bannerPlacement = AB.DATALAYER.getBannerPlacement(bannerClicked, selectors);
11892
11893        // get recommendation type
11894        const currentBanner = bannerClicked?.closest(selectors.currentBanner);
11895        const recommendationType = AB.DATALAYER.getBannerRecommendationType(selectors, currentBanner);
11896
11897        // send link click event
11898        AB.DATALAYER.setBannerClickedEvent(bannerPlacement, `sidebarBannerClicked|${currentBannerTitle}`, recommendationType, 'sidebar-banner', currentBannerTitle);
11899    }
11900
11901    /**
11902    * Tracking for ultra skinny banner
11903    */
11904    this.setUltraSkinnyBannerTracking = function (bannerClicked) {
11905        const selectors = {
11906            currentBanner: '.nextgen-banner-unit-proxy',
11907            titleElement: '.banner-unit-ultra-skinny__text-plate__title',
11908            bannerSource: 'nextgen-banner-unit-ultra-skinny'
11909        };
11910
11911        // get banner title
11912        const currentBannerTitle = AB.DATALAYER.getBannerClickedTitle(bannerClicked, selectors);
11913
11914        // get banner placement
11915        const bannerPlacement = AB.DATALAYER.getBannerPlacement(bannerClicked, selectors);
11916
11917        // get recommendation type
11918        const currentBanner = bannerClicked?.closest(selectors.currentBanner);
11919        const recommendationType = AB.DATALAYER.getBannerRecommendationType(selectors, currentBanner);
11920
11921        this.trackAEMZone('banner', currentBanner, `skinny-banner:${currentBannerTitle}`);
11922
11923        // send link click event
11924        AB.DATALAYER.setBannerClickedEvent(bannerPlacement, `ultraSkinnyBannerClicked|${currentBannerTitle}`, recommendationType, 'ultra-skinny-banner', currentBannerTitle);
11925    }
11926
11927    this.setHeroCanvasTracking = function (bannerClicked) {
11928        const selectors = {
11929            currentBanner: '.hero-canvas',
11930            titleElement: '.hero-canvas__text-plate-wrapper, .hero-canvas__text-plate-title, .hero-canvas__text-plate__title',
11931            wrapperElement: '.abs-carousel'
11932        };
11933
11934        const currentBanner = bannerClicked?.closest(selectors.currentBanner);
11935        // get banner title
11936        const currentBannerTitle = AB.DATALAYER.getBannerClickedTitle(bannerClicked, selectors);
11937
11938        const currentCarousel = bannerClicked.closest(selectors.wrapperElement);
11939        const currentCarouselBanners = currentCarousel?.querySelectorAll('.slick-slide:not(.slick-cloned) .hero-canvas');
11940        const bannerRow = AB.DATALAYER.getAllBanners() && currentCarousel ? AB.DATALAYER.getAllBanners().indexOf(currentCarousel) + 1 : 0;
11941        const bannerSlot = currentCarouselBanners && currentBanner ? Array.from(currentCarouselBanners).indexOf(currentBanner) + 1 : 0;
11942        const bannerPlacement = `R${bannerRow < 10 ? `0${bannerRow}` : bannerRow}#S${bannerSlot < 10 ? `0${bannerSlot}` : bannerSlot}`;
11943
11944        // get recommendation type
11945        const recommendationType = AB.DATALAYER.getBannerRecommendationType(selectors, currentBanner);
11946
11947        this.trackAEMZone('banner', currentBanner, `hero-canvas:${currentBannerTitle}`);
11948
11949        // send link click event
11950        AB.DATALAYER.setBannerClickedEvent(bannerPlacement, `bannerclicked|hero-canvas:${currentBannerTitle}`, recommendationType, 'hero-canvas', currentBannerTitle);
11951    }
11952
11953     this.setHeroCardsTracking = function (bannerClicked) {
11954        const selectors = {
11955            currentBanner: '.hero-flex__card',
11956            titleElement: '.hero-flex-full-bleed__text-box__title',
11957            localWrapper: '.hero-canvas-row__flex',
11958            wrapperElement: '#herocanvasflex'
11959        };
11960
11961        // get banner title
11962        const currentBannerTitle = AB.DATALAYER.getBannerClickedTitle(bannerClicked, selectors);
11963
11964        // get recommendation type
11965        const currentBanner = bannerClicked?.closest(selectors.currentBanner);
11966        const allCards = currentBanner.closest(selectors.localWrapper)?.querySelectorAll(selectors.currentBanner);
11967        const currentCardSlot = allCards && currentBanner ? Array.from(allCards)?.filter(card => AB.DATALAYER.isVisible(card))?.indexOf(currentBanner) + 1 : 0;
11968
11969        // get banner placement
11970        const bannerPlacement = `R01#S${currentCardSlot < 10 ? `0${currentCardSlot}` : currentCardSlot}`;
11971
11972        const recommendationType = AB.DATALAYER.getBannerRecommendationType(selectors, currentBanner);
11973        const renderedFlexElement = currentBanner?.closest?.('.hero-flex') || currentBanner?.closest?.(selectors.localWrapper) || currentBanner;
11974        const carouselProxy = renderedFlexElement?.closest?.('.nextgen-abs-carousel-proxy');
11975        const allVisibleFlexRows = document.querySelectorAll('.nextgen-abs-carousel-proxy .flex-medium-fw, .nextgen-abs-carousel-proxy .flex-container, .nextgen-abs-carousel-proxy .hero-flex')?.length > 0
11976            ? Array.from(document.querySelectorAll('.nextgen-abs-carousel-proxy .flex-medium-fw, .nextgen-abs-carousel-proxy .flex-container, .nextgen-abs-carousel-proxy .hero-flex'))
11977            : [];
11978        const flexIndex = allVisibleFlexRows.indexOf(renderedFlexElement) + 1 || 1;
11979        const zoneInfo = AB.DATALAYER.getZoneInfo(renderedFlexElement)?.zone;
11980        const zone = this.normalizeFlexBannerZone(zoneInfo ? `zone${zoneInfo}` : '');
11981        const spotIndex = currentCardSlot > 0 ? currentCardSlot : 1;
11982        const spot = `sp${this.padFlexBannerAnalyticsIndex(spotIndex)}`;
11983        const cardTitle = this.getFlexBannerAnalyticsValue(currentBannerTitle);
11984        const carouselTitle = this.getFlexBannerAnalyticsValue(
11985            carouselProxy?.querySelector?.('h2.flex-title')?.textContent
11986            || renderedFlexElement?.closest?.('.hero-canvas-row')?.querySelector?.('h2.flex-title')?.textContent
11987            || renderedFlexElement?.getAttribute?.('aria-label')
11988        );
11989        const uniqueId = this.getFlexBannerAnalyticsValue(
11990            currentBanner?.getAttribute?.('data-gam-slot-id')
11991            || currentBanner?.getAttribute?.('data-target')
11992        );
11993        const bannerCardCarousel = `${zone}|flex|flex-${this.padFlexBannerAnalyticsIndex(flexIndex)}:${cardTitle}:${carouselTitle}|${spot}|${uniqueId}`;
11994
11995        digitalData.pageFilter.bannerCardCarousel = bannerCardCarousel;
11996        digitalData.pageDetails.feature = 'flex-banner|shop-ex|501655|423334';
11997
11998        this.trackAEMZone('banner', currentBanner, `hero-card${currentCardSlot}
11998:${currentBannerTitle}`);
11999
12000        // send link click event
12001        AB.DATALAYER.setBannerClickedEvent(bannerPlacement, `bannerclicked|hero-card${currentCardSlot}:${currentBannerTitle}`, recommendationType, `hero-card${currentCardSlot}`, currentBannerTitle);
12002        digitalData.pageFilter.bannerCardCarousel = '';
12003        digitalData.pageDetails.feature = '';
12004    }
12005
12006    /**
12007     * Tracking for sponsored banners
12008     */
12009    this.setBannerUnitTrackingGAM = function (eventInfo) {
12010        let data = eventInfo.data ? eventInfo.data : eventInfo;
12011        let element = eventInfo?.target;
12012        let bannerTitle = data.bannerTitle ? data.bannerTitle.trim().toLowerCase().replace(/[^a-z0-9|-]/gi, '-') : '';
12013
12014        // Get only banner title for oneTag tracking
12015        const bnrArr = bannerTitle.split('|');
12016        const oneTagBnrTitle = bnrArr.length === 2 ? bnrArr[1] : bannerTitle;
12017
12018        if (data) {
12019            /** this part is not functional, as we cannot get the element from an iframe, element var is always window object - GAM banners are not currently in scope for AEM zone tracking
12020             *  so there is no need to spend more time on this solution at the moment - to be revisited if the GAM banners are loaded in AEM zone
12021             * */
12022            if (element && element instanceof Element) {
12023                const jsCurrentBanner = element.closest('.banner-unit-proxy, .nextgen-banner-unit-proxy, .as-hero__item');
12024                this.trackAEMZone('banner', jsCurrentBanner, `large-banner:${bannerTitle}`);
12025            }
12026
12027            if (this.isCouponsAndDealsPage() && data.bannerType?.includes('medium-banner')) {
12028                data.bannerType = `advert-${data.bannerType}`;
12029                this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsFeatureTracking', data: 'mediumbannerACIP397009', isAcrossPages: false });
12030            }
12031
12032            // send link click event
12033            AB.DATALAYER.setBannerClickedEvent(data.bannerPlacement, bannerTitle, data.recommendationType, data.bannerType, oneTagBnrTitle);
12034        }
12035    }
12036
12037    /**
12038     * Returns placement for sponsored banners
12039     */
12040    this.getBannerPlacementForGAM = function (data) {
12041        const selectors = {
12042            currentBanner: '.banner-unit-proxy, .nextgen-banner-unit-proxy, .as-hero__item, promo-banner, .hero-flex__card, .hero-canvas',
12043            titleElement: '.banner-unit-regular__headline p, .banner-unit-hero__text-plate__title, .title, .mod-unit__headline p',
12044            wrapperElement: '.abs-carousel-wrapper, .nextgen-abs-carousel-wrapper, .as-hero__carousel, #herocanvasflex, .abs-carousel',
12045            bannerSource: '.banner-unit-regular-wc, .banner-unit-hero-wc'
12046        };
12047        const bannerClassMappings = {
12048            'banner-unit-proxy': '.abs-carousel-wrapper',
12049            'nextgen-banner-unit-proxy': '.nextgen-abs-carousel-wrapper',
12050            'as-hero__item': '.as-hero__carousel',
12051        };
12052        // get banner placement
12053        const currentBanner = data?.closest(selectors.currentBanner);
12054        let bannerPlacement = '';
12055
12056        try {
12057            if (currentBanner?.classList?.contains('hero-flex__card')) {
12058                const allCards = currentBanner.closest(selectors.localWrapper)?.querySelectorAll(selectors.currentBanner);
12059                const currentCardSlot = allCards && currentBanner ? Array.from(allCards)?.filter(card => AB.DATALAYER.isVisible(card))?.indexOf(currentBanner) + 1 : 0;
12060                bannerPlacement = `R01#S${currentCardSlot < 10 ? `0${currentCardSlot}` : currentCardSlot}`;
12061            } else if (currentBanner?.classList?.contains('hero-canvas') && data) {
12062                const currentCarousel = data.closest(selectors.wrapperElement);
12063                const currentCarouselBanners = currentCarousel?.querySelectorAll('.slick-slide:not(.slick-cloned) .hero-canvas');
12064                const bannerRow = AB.DATALAYER.getAllBanners() && currentCarousel ? AB.DATALAYER.getAllBanners().indexOf(currentCarousel) + 1 : 0;
12065                const bannerSlot = currentCarouselBanners && currentBanner ? Array.from(currentCarouselBanners).indexOf(currentBanner) + 1 : 0;
12066                bannerPlacement = `R${bannerRow < 10 ? `0${bannerRow}` : bannerRow}#S${bannerSlot < 10 ? `0${bannerSlot}` : bannerSlot}`;
12067            } else {
12068                bannerPlacement = AB.DATALAYER.getBannerPlacement(data, selectors, bannerClassMappings);
12069            }
12070        } catch (e) {
12071            console.warn('GAM banner placement error: ', e);
12072        }
12073        return bannerPlacement;
12074    }
12075
12076    /**
12077     * Sends impressions event for GAM banners, eventInfo is received from GAM handler functions which anal
12077ytics team doesn't own/update
12078     * @param {*} eventInfo 
12079     */
12080    this.setBannerImpressionsGAM = function (eventInfo) {
12081        let data = eventInfo.data ? eventInfo.data : eventInfo;
12082        let bannerTitle = data.bannerTitle ? AB.DATALAYER.sanitizeAnalyticsText(data?.bannerTitle) : '';
12083
12084        // Get only banner title for oneTag tracking
12085        const bnrArr = bannerTitle.split('|');
12086        const oneTagBnrTitle = bnrArr.length === 2 ? bnrArr[1] : bannerTitle;
12087
12088        if (data) {
12089            // Set GAM impression data
12090            const pageDetails = { ...digitalData.pageDetails };
12091            const pageFilter = { ...digitalData.pageFilter };
12092            const user = { ...digitalData.user };
12093            pageDetails.bnrName = oneTagBnrTitle;
12094            pageFilter.mediaType = data.bannerType;
12095            pageFilter.placement = data.bannerPlacement;
12096            pageFilter.recommendationType = data.recommendationType;
12097            user.gamAdData = {
12098                adUnitPath: data.adUnitPath,
12099                lineItemId: data.lineItemId,
12100                creativeId: data.creativeId,
12101                creativeTemplateId: data.creativeTemplateId,
12102                responseStatus: data.responseStatus,
12103                uniqueID: data.uniqueID || 'no-value',
12104                responseTime: data.responseTime,
12105                targetingMap: data.targetingMap
12106            };
12107
12108            AB.DATALAYER.pushEvent(
12109                AB.DATALAYER.EVENTS.LINK_CLICK, {
12110                link: {
12111                    linkName: `gam-banner-impressions`,
12112                    isSendToSS: true
12113                },
12114                page: pageDetails,
12115                pageFilter: pageFilter,
12116                user: user
12117            }
12118            );
12119            digitalData.pageFilter.placement = '';
12120            digitalData.pageFilter.mediaType = '';
12121            digitalData.pageFilter.recommendationType = '';
12122            digitalData.pageDetails.bnrName = '';
12123        }
12124    }
12125
12126    /**
12127     * Sends exposure event for GAM banners, eventInfo is received from GAM handler functions which analytics team doesn't own/update
12128     * @param {*} eventInfo 
12129     */
12130    this.setExperimentExposureGAM = function (eventInfo) {
12131        let data = eventInfo.data ? eventInfo.data : eventInfo;
12132        let bannerTitle = data.bannerTitle ? AB.DATALAYER.sanitizeAnalyticsText(data?.bannerTitle) : '';
12133
12134        // Get only banner title for oneTag tracking
12135        const bnrArr = bannerTitle.split('|');
12136        const oneTagBnrTitle = bnrArr.length === 2 ? bnrArr[1] : bannerTitle;
12137
12138        if (data) {
12139            // Set GAM impression data
12140            const pageDetails = { ...digitalData.pageDetails };
12141            const pageFilter = { ...digitalData.pageFilter };
12142            const user = { ...digitalData.user };
12143            pageDetails.bnrName = oneTagBnrTitle;
12144            pageFilter.mediaType = data.bannerType;
12145            pageFilter.placement = data.bannerPlacement;
12146            pageFilter.recommendationType = data.recommendationType;
12147            user.gamAdData = {
12148                adUnitPath: data.adUnitPath,
12149                lineItemId: data.lineItemId,
12150                creativeId: data.creativeId,
12151                creativeTemplateId: data.creativeTemplateId,
12152                responseStatus: data.responseStatus,
12153                uniqueID: data.uniqueID || 'no-value',
12154                responseTime: data.responseTime,
12155                targetingMap: data.targetingMap
12156            };
12157
12158            AB.DATALAYER.pushEvent(
12159                AB.DATALAYER.EVENTS.LINK_CLICK, {
12160                link: {
12161                    linkName: `gam-banner-exposure`,
12162                    isSendToSS: true
12163                },
12164                page: pageDetails,
12165                pageFilter: pageFilter,
12166                user: user
12167            }
12168            );
12169            digitalData.pageFilter.placement = '';
12170            digitalData.pageFilter.mediaType = '';
12171            digitalData.pageDetails.bnrName = '';
12172            digitalData.pageFilter.recommendationType = '';
12173        }
12174    }
12175
12176    /**
12177     * Tracking for mod units
12178     * @param  bannerClicked 
12179     */
12180    this.setModUnitTracking = function (banner) {
12181
12182        const bannerClicked = banner instanceof jQuery ? banner[0] : banner;
12183        let isAEMZoneBanner = false;
12184        let isBirthdayBanner = false;
12185        const selectors = {
12186            currentBanner: '.mod-unit-unified-proxy, .mod-unit-skinny-proxy',
12187            titleElement: '.mod-unit__headline, .mod-unit-skinny__headline',
12188            wrapperElement: '.mod-unit-carousel-container'
12189        };
12190        const bannerClassMappings = {
12191            'mod-unit-unified-proxy': '.mod-unit-carousel-container',
12192            'mod-unit-skinny-proxy': '.mod-unit-carousel-container'
12193        };
12194        const currentBanner = bannerClicked?.closest(selectors.currentBanner);
12195
12196        // get banner title
12197        let bannerLinkName = '';
12198        let currentBannerTitle = AB.DATALAYER.getBannerClickedTitle(bannerClicked, selectors);
12199
12200        if (currentBanner.classList.contains('mod-unit-unified-proxy')) {
12201            if (!currentBannerTitle && (currentBanner.parentElement?.querySelectorAll('h3').length > 0 || currentBanner.parentElement?.querySelectorAll('p b').length > 0)) {
12202                currentBannerTitle = currentBanner.parentElement?.querySelector('h3')?.textContent?.trim()?.replace(/\s/g, '') !== ''
12203                    ? currentBanner.parentElement?.querySelector('h3').textContent?.trim()?.replace(/\s/g, '')
12204                    : currentBanner.parentElement?.querySelector('p b')?.textContent?.trim()?.replace(/\s/g, '');
12205                isAEMZoneBanner = true;
12206            }
12207            bannerLinkName = `bannerClicked|${currentBannerTitle}`;
12208
12209        } else if (currentBanner.classList.contains('.mod-unit-skinny-proxy')) {
12210            bannerLinkName = `skinnyBannerClicked|${currentBannerTitle}`;
12211        }
12212        // set custom title for birthday banner
12213        if (currentBannerTitle.toLowerCase() === 'abirthdaytreatonus') {
12214            isBirthdayBanner = true;
12215            bannerLinkName = 'B4U:birthday-banner';
12216        }
12217
12218        // get banner placement
12219        const bannerPlacement = AB.DATALAYER.getBannerPlacement(bannerClicked, selectors, bannerClassMappings);
12220
12221        //get media type
12222        const mediaType = isAEMZoneBanner
12223            ? 'medium-banner'
12224            : currentBanner.classList.contains('mod-unit-unified-proxy')
12225                ? 'banner'
12226                : currentBanner.classList.contains('mod-unit-skinny-proxy')
12227                    ? 'skinny-banner'
12228                    : '';
12229
12230        this.trackAEMZone('banner', currentBanner, `large-banner:${currentBannerTitle}`);
12231
12232        // send link click event
12233        AB.DATALAYER.setBannerClickedEvent(bannerPlacement, bannerLinkName, 'notRecommended', mediaType, isBirthdayBanner ? 'birthday-banner' : currentBannerTitle);
12234    }
12235
12236    /**
12237     * Sets Episodic events
12238     * @param linkClicked 
12239     * @param triggerPageLoad
12240     */
12241    this.episodicOptInEvents = function (linkClicked, triggerPageLoad) {
12242        AB.DATALAYER.setLinkClickEvents(linkClicked);
12243        if (triggerPageLoad && digitalData && digitalData.pageDetails) {
12244            digitalData.pageDetails.subSection3 = 'verify-contact-info';
12245            AB.DATALAYER.setPageLoad();
12246        }
12247    }
12248
12249    /**
12250     * Tracks clicks on the sign in button on the OTP sign in flow for the e-community Sincerely-Food
12251     */
12252    this.setLinkClickSignInEcom = function (source) {
12253        if (window.location.hostname.indexOf('sincerely-food') != -1) {
12254            if (source === 'otp') {
12255                AB.DATALAYER.setLinkClickEvents('passwordless-sign-in|click');
12256            } else if (source === 'sign-in') {
12257                AB.DATALAYER.setLinkClickEvents('ecommunity|signed-in');
12258            } else if (source === 'create-account') {
12259                AB.DATALAYER.setLinkClickEvents('ecommunity|created-account');
12260            }
12261        } else {
12262            if (this.isSubscriptionDeliveryPage()) {
12263                localStorage.setItem('preventAnalyticsLanding', true);
12264            }
12265        }
12266    }
12267
12268    /**
12269     * Sets subsection3 on Episodic pages
12270     */
12271    this.initEpisodicOptInPage = function () {
12272        if (digitalData && digitalData.pageDetails && digitalData.pageDetails.subSection1 === 'flavoradventure') {
12273            if (AB.DATALAYER.analyticsGetURLParameterByName('validate') === 'true') {
12274                digitalData.pageDetails.subSection3 = 'verify-contact-info';
12275            } else {
12276                digitalData.pageDetails.subSection3 = '';
12277            }
12278        }
12279    }
12280
12281    this.isProductInAnalyticsCart = function (productAddedId) {
12282        let existingCart = [];
12283        if (window.location.pathname.startsWith('/schedule-and-save/manage')) {
12284            localStorage.getItem('analyticsOneTimeOrderItems')
12285            existingCart = AB.DATALAYER.getLSItem('analyticsOneTimeOrderItems') ? AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('analyticsOneTimeOrderItems')) : [];
12286        } else {
12287            let carts = AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('abCart'))?.cart;
12288            if (carts && Object.keys(carts)?.length > 0) {
12289                Object.values(carts)?.forEach(cart => {
12290                    if (cart.cartItems) {
12291                        cart.cartItems.forEach(item => {
12292                            existingCart.push(item);
12293                        });
12294                    }
12295                });
12296            } else {
12297                existingCart = AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('abCart'))?.cartItems ? AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('abCart')).cartItems : [];
12298            }
12299        }
12300        let isProductInCart = false;
12301        existingCart.forEach(item => {
12302            let productID = item.itemId || item.id || item.productBpn || item.productID;
12303            if (Number(productID) === Number(productAddedId)) {
12304                isProductInCart = true;
12305            }
12306        });
12307        if (isProductInCart) {
12308            localStorage.setItem('itemsInCartBeforeUpdate', JSON.stringify(existingCart));
12309        }
12310        return isProductInCart;
12311    }
12312
12313    /**
12314     * Sets banner, channel, subSections and pageName for Sincerely,Food
12315     */
12316    this.initSCFPage = function () {
12317        if (digitalData && digitalData.pageDetails && digitalData.pageDetails.banner === 'sincerely-food') {
12318
12319            // get banner from SincerelyFoodBanner cookie
12320            const sincerelyFoodBannerCookie = AB.DATALAYER.getCookie('SincerelyFoodBanner');
12321            if (sincerelyFoodBannerCookie) {
12322                const sincerelyFoodBanner = AB.DATALAYER.safeJSONParse(sincerelyFoodBannerCookie);
12323                if (sincerelyFoodBanner && sincerelyFoodBanner.banner) {
12324                    digitalData.pageDetails.banner = sincerelyFoodBanner.banner;
12325                }
12326            }
12327
12328            switch (digitalData.pageDetails.subSection1) {
12329                case 'home':
12330                    digitalData.pageDetails.subSection1 = 'scf-main';
12331                    digitalData.pageDetails.subSection2 = 'fulfillment';
12332                    break;
12333                case 'registration':
12334                    digitalData.pageDetails.subSection1 = 'scf-create-account';
12335                    digitalData.pageDetails.subSection2 = 'scf-short-registration';
12336                    break;
12337                case 'sign-in':
12338                    digitalData.pageDetails.subSection1 = 'scf-account';
12339                    digitalData.pageDetails.subSection2 = 'scf-sign-in';
12340                    break;
12341                default:
12342                    break;
12343            }
12344
12345            digitalData.pageDetails.channel = 'e-community';
12346            digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:${digitalData.pageDetails.channel}:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}`;
12347        }
12348    }
12349
12350    /**
12351     * Tracks the marketplace sellers' info on search-results page
12352     * @param sellerCount 
12353     * @param sellerResultsString 
12354     * @param pgmResponse
12355     */
12356    this.marketplaceSellerUpdates = function (sellerCount, sellerResultsString, pgmResponse) {
12357        digitalData.search = digitalData.search || {};
12358        if (pgmResponse) {
12359            const mkpData = pgmResponse?.find((data) => data?.pgmName?.includes('mkp'));
12360            const mkpResponse = mkpData?.response ? mkpData?.response : {};
12361            const pgmDocs = mkpResponse?.docs || [];
12362            const sellers = {};
12363            let sellersCount = 0;
12364            let sellerCountResults = [];
12365            pgmDocs.forEach(product => {
12366                const sellerId = product.sellerId || 'sellerIdNotFound'
12367                if (sellers[sellerId]) {
12368                    sellers[sellerId]++;
12369                } else {
12370                    sellersCount++;
12371                    sellers[sellerId] = 1
12372                }
12373            });
12374            for (const key in sellers) {
12375                if (sellers.hasOwnProperty(key)) {
12376                    sellerCountResults.push(`${key}:${sellers[key]}`);
12377                }
12378            }
12379            sellerCount = sellersCount;
12380            sellerResultsString = sellerCountResults.join();
12381            digitalData.search.mkpSearchResultsCount = mkpResponse?.numFound ? mkpResponse?.numFound.toString() : '0';
12382        }
12383        if (sellerCount && sellerCount !== 0) {
12384            digitalData.search.sellerCount = sellerCount ? sellerCount.toString() : '0';
12385            digitalData.search.sellerCountResults = sellerResultsString ? sellerResultsString : 'no-value:0';
12386        }
12387    }
12388
12389    /**
12390     * Tracks the number of products on wineshop carousel and the number of recipes on recipe carousel on search-results page
12391     * @param wineResultsReturn 
12392     * @param recipeResults 
12393     */
12394    this.searchResultsCarouselsProductCount = function (wineResultsReturn, recipeResults, programType) {
12395        if (programType !== 'mkp-carousel') {
12396            digitalData.search = digitalData.search || {};
12397            digitalData.search.wineResultsReturn = digitalData.search.wineResultsReturn || '0';
12398            digitalData.search.recipeResults = digitalData.search.recipeResults || '0';
12399
12400            if (wineResultsReturn) {
12401                digitalData.search.wineResultsReturn = wineResultsReturn.toString();
12402            }
12403            if (recipeResults) {
12404                digitalData.search.recipeResults = recipeResults.toString();
12405            }
12406        }
12407    }
12408
12409    /**
12410     * Capture the carousel, total items added (not unique) and the total value of the products added on DFTA page
12411     * expected output: prodctCarouselValue = [CAROUSEL]|[TOTAL PRODUCT COUNT]|[VALUE OF PRODUCTS ADDED]
12412     */
12413    this.setCarouselValueDFTA = function (eventName, productInfo) {
12414        if (this.isDFTAPage() && productInfo) {
12415
12416            const currentProductID = productInfo.productID;
12417            const currentProductCarousel = document.querySelector(`a[data-bpn="${currentProductID}"]`)?.closest('.slick-product-carousel');
12418            const currentTitle = currentProductCarousel?.previousElementSibling?.textContent?.trim()?.replace(/\s/g, '-');
12419
12420            if (currentTitle) {
12421                let carouselValueArray = [];
12422                let updatedCarouselValueArray = [];
12423
12424                const listPrice = Number(productInfo.listPrice);
12425                const previousUnits = Number(productInfo.previousQty) || 0;
12426                const currentLbs = (productInfo.unitType == 'LB' && productInfo.lbs !== '0') ? (productInfo.lbs === '' ? 0 : Number(productInfo.lbs)) : 0;
12427                const currentUnits = productInfo.units ? Number(productInfo.units) : currentLbs;
12428
12429                let units = 1;
12430                if (previousUnits > currentUnits) {
12431                    units = previousUnits - currentUnits;
12432                } else if (previousUnits < currentUnits) {
12433                    units = currentUnits - previousUnits;
12434                } else {
12435                    // for 'remove_cart' productinfo.units is not updated with the new value(0)?
12436                    units = previousUnits;
12437                }
12438                const totalPrice = listPrice * units;
12439
12440                const carouselName = currentTitle.replace(' - ', ' ').replace(/\s/g, '-');
12441                this.setCarouselName(`shop|${currentTitle}`);
12442                digitalData.productInfo.carouselSection = this.sanitizeAnalyticsText(currentTitle);
12443
12444                AB.DATALAYER.pfmFromCurrentPage = `${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}:${digitalData.pageDetails.subSection3}`;
12445
12446                if (localStorage.getItem('analyticsDFTACarouselValue')) {
12447                    const carouselValueLS = localStorage.getItem('analyticsDFTACarouselValue');
12448                    carouselValueArray = carouselValueLS.split(',');
12449                }
12450
12451                // we already have one ore more products added
12452                if (carouselValueArray.length > 0) {
12453
12454                    let found = false;
12455
12456                    carouselValueArray.forEach((carouselInfo) => {
12457
12458                        let carousel = carouselInfo.split('|')[0];
12459                        let totalProductCount = Number(carouselInfo.split('|')[1]);
12460                        let totalValue = Number(carouselInfo.split('|')[2]);
12461                        let updatedCarouselInfo = '';
12462
12463                        if (carousel.toLowerCase() === carouselName.toLowerCase()) {
12464                            switch (eventName) {
12465                                case 'cart_add':
12466                                case 'add_quantity':
12467                                    totalProductCount = totalProductCount + units;
12468                                    totalValue = (Math.round((totalValue + totalPrice) * 100) / 100).toFixed(2);
12469                                    updatedCarouselInfo = `${carousel}|${totalProductCount}|${totalValue}`;
12470                                    updatedCarouselValueArray.push(updatedCarouselInfo);
12471                                    break;
12472                                case 'remove_quantity':
12473                                    totalProductCount = totalProductCount - units;
12474                                    totalValue = (Math.round((totalValue - totalPrice) * 100) / 100).toFixed(2);
12475                                    updatedCarouselInfo = `${carousel}|${totalProductCount}|${totalValue}`;
12476                                    updatedCarouselValueArray.push(updatedCarouselInfo);
12477                                    break;
12478                                case 'remove_cart':
12479                                    totalProductCount = totalProductCount - units;
12480                                    totalValue = (Math.round((totalValue - totalPrice) * 100) / 100).toFixed(2);
12481                                    updatedCarouselInfo = `${carousel}|${totalProductCount}|${totalValue}`;
12482                                    if (totalProductCount > 0) {
12483                                        updatedCarouselValueArray.push(updatedCarouselInfo);
12484                                    }
12485                                    break;
12486                                default:
12487                                    break
12488                            }
12489                            found = true;
12490                        } else {
12491                            updatedCarouselValueArray.push(carouselInfo);
12492                        }
12493                    });
12494
12495                    if (!found && eventName === 'cart_add') {
12496                        updatedCarouselValueArray.push(`${carouselName}|${units}|${totalPrice.toFixed(2)}`);
12497                    }
12498
12499                } else {
12500                    // first product added
12501                    if (eventName === 'cart_add') {
12502                        updatedCarouselValueArray.push(`${carouselName}|${units}|${totalPrice.toFixed(2)}`);
12503                    }
12504                }
12505                if (updatedCarouselValueArray.length > 0) {
12506                    const updatedCarouselString = updatedCarouselValueArray.filter(
12506Boolean).join(',');
12507                    localStorage.setItem('analyticsDFTACarouselValue', updatedCarouselString);
12508                } else {
12509                    localStorage.removeItem('analyticsDFTACarouselValue');
12510                }
12511            }
12512        }
12513    }
12514
12515    this.initDFTACarousel = function () {
12516        if (this.getLSItem('analyticsDFTACarouselValue') && digitalData) {
12517            digitalData.productInfo = digitalData.productInfo || {};
12518            digitalData.productInfo.productCarouselValue = this.handleGetLSValue('analyticsDFTACarouselValue');
12519        }
12520    }
12521
12522    this.setPreviousQuantityDFTA = function (productUpdatedID) {
12523        const cartItems = window.digitalData && window.digitalData.cart && window.digitalData.cart.item && window.digitalData.cart.item.length > 0 ? window.digitalData.cart.item : AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('abCart'))?.cartItems ? AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('abCart')).cartItems : [];
12524
12525        if (productUpdatedID && cartItems.length > 0) {
12526            cartItems.forEach(item => {
12527                let productID = item.itemId || item.id || item.productID;
12528                if (productID == productUpdatedID) {
12529                    digitalData.productInfo.previousQty = item.qty || item.units;
12530                }
12531            });
12532        }
12533    }
12534
12535    this.setFeaturedFacetsFilter = function () {
12536        if (localStorage.getItem('analyticsFeaturedFacet')) {
12537            const featureSelection = localStorage.getItem('analyticsFeaturedFacet');
12538            window['AB']['DATALAYER'].addFilterSelection(`featured: ${featureSelection}`);
12539            window['AB']['DATALAYER'].addFilterType('featured');
12540            window['AB']['DATALAYER'].setPageFilter();
12541            localStorage.removeItem('analyticsFeaturedFacet');
12542        }
12543    }
12544
12545    this.initMarketplaceSellerListing = function () {
12546        if (digitalData.pageDetails && (digitalData.pageDetails.subSection1 === 'marketplace' || digitalData.pageDetails.subSection1 === 'm') && digitalData.pageDetails.subSection2 && !digitalData.pageDetails.subSection3) {
12547            if (digitalData.pageDetails.subSection2 === 'seller-listing') {
12548                const marketType = document.querySelector('.mktp-ship-info')?.getAttribute('data-mktp-type');
12549                digitalData.pageDetails.subSection1 = marketType ? `${marketType.toLowerCase()}-mart` : '';
12550            } else {
12551                digitalData.pageDetails.subSection1 = digitalData.pageDetails.subSection2;
12552            }
12553            digitalData.pageDetails.subSection1 = 'marketplace-landing';
12554            digitalData.pageDetails.subSection2 = 'seller-listing';
12555            digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:${digitalData.pageDetails.channel}:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}`;
12556        }
12557    }
12558
12559    this.initPharmacyRx = function (subSection2) {
12560        if (digitalData && digitalData.pageDetails) {
12561            digitalData.pageDetails.subSection1 = 'household';
12562            digitalData.pageDetails.subSection2 = subSection2;
12563            digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:${digitalData.pageDetails.channel}:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}`;
12564            this.setPageLoad();
12565            this.handleAccountEvents();
12566        }
12567    }
12568
12569    this.initMarketplacePDP = function () {
12570        if (digitalData.productInfo && digitalData.productInfo.sellerId && digitalData.productInfo.sellerId !== '22222222') {
12571            digitalData.pageDetails.sellerId = digitalData.productInfo.sellerId;
12572            digitalData.pageDetails.channel = 'marketplace';
12573            digitalData.pageDetails.subSection1 = 'product-details';
12574            digitalData.pageDetails.subSection2 = '';
12575            digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:${digitalData.pageDetails.channel}:${digitalData.pageDetails.subSection1}`;
12576        }
12577    }
12578
12579    this.initMarketplaceCategory = function () {
12580        let newSubsections = digitalData.pageDetails.pageUrl.split('/');
12581        let sellerId = localStorage.getItem('sellerId') ? localStorage.getItem('sellerId') : AB.DATALAYER.analyticsGetURLParameterByName('sellerId') ? AB.DATALAYER.analyticsGetURLParameterByName('sellerId') : newSubsections[6] ? newSubsections[6].split('.')[1] : '';
12582        if (!sellerId && AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('mkpSeller'))) {
12583            if (AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('mkpSeller'))?.sellerInfo) {
12584                sellerId = Object.keys(AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('mkpSeller')).sellerInfo)[0];
12585            }
12586        }
12587        if (digitalData.pageDetails.subSection2 === 'aisles') {
12588            digitalData.pageDetails.subSection1 = newSubsections[3];
12589            digitalData.pageDetails.subSection2 = newSubsections[4];
12590            digitalData.pageDetails.subSection3 = newSubsections[5];
12591            digitalData.pageDetails.subSection4 = newSubsections[6] ? newSubsections[6].split('.')[0] : '';
12592            digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:${digitalData.pageDetails.channel}:${digitalData.pageDetails.subSection1}${digitalData.pageDetails.subSection2 ? `:${digitalData.pageDetails.subSection2}` : ''}${digitalData.pageDetails.subSection3 ? `:${digitalData.pageDetails.subSection3}` : ''}${digitalData.pageDetails.subSection4 ? `:${digitalData.pageDetails.subSection4}` : ''}`;
12593        }
12594        digitalData.pageDetails.channel = 'marketplace';
12595        digitalData.pageDetails.sellerId = sellerId;
12596    }
12597
12598    this.initMarketplaceSellerLanding = function () {
12599        let sellerId = '';
12600        if (document.querySelector('.mktp__seller-info')?.attributes?.getNamedItem('data-seller-id')?.textContent) {
12601            sellerId = document.querySelector('.mktp__seller-info')?.attributes?.getNamedItem('data-seller-id')?.textContent;
12602        } else if (AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('mkpSeller'))?.sellerInfo) {
12603            sellerId = Object.keys(AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('mkpSeller')).sellerInfo)[0];
12604        }
12605        digitalData.pageDetails.subSection1 = 'landing';
12606        digitalData.pageDetails.subSection2 = digitalData.pageDetails.subSection3 = digitalData.pageDetails.subSection4 = '';
12607        digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:${digitalData.pageDetails.channel}:${digitalData.pageDetails.subSection1}`;
12608        digitalData.pageDetails.channel = 'marketplace';
12609        digitalData.pageDetails.sellerId = sellerId;
12610    }
12611
12612    this.setTopNavMarketplace = function () {
12613        if (digitalData.pageDetails && digitalData.pageDetails.subSection1 === 'landing') {
12614            this.setTopNavPreviousPage();
12615        }
12616    }
12617
12618    // To be removed
12619    this.updateCartIdMarketplace = function (allItems, newItem) {
12620        if (((newItem && newItem.sellerName) || (digitalData.productInfo && digitalData.productInfo.sellerName)) && digitalData.cart && digitalData.cart.cartInfo) {
12621            const cartId = digitalData.cart.cartInfo.cartId;
12622            const cartType = digitalData.cart.cartInfo.cartType || '';
12623            const marketplaceCartTotal = digitalData.cart.transaction?.subTotal;
12624            const marketplaceCartItems = allItems || [];
12625            let marketplaceCartSKUs = [];
12626            marketplaceCartItems.forEach(item => {
12627                marketplaceCartSKUs.push(item.id);
12628            });
12629            const marketplaceCartSKUsString = marketplaceCartSKUs.join(',');
12630            const marketplaceCartInfo = `${cartId}|${cartType}|${marketplaceCartSKUsString}|${marketplaceCartTotal}`;
12631
12632            const sellerName = newItem?.sellerName || digitalData.productInfo?.sellerName;
12633            if (sellerName.toLowerCase().indexOf('kehe') !== -1) {
12634                digitalData.cart.cartInfo.cartIDkehe = marketplaceCartInfo;
12635            } else {
12636                digitalData.cart.cartInfo.cartIDnaturalcommerce = marketplaceCartInfo;
12637            }
12638        }
12639    }
12640
12641    this.initContactUs = function () {
12642        if (digitalData.pageDetails.subSection1 === 'inquiry' && digitalData.pageDetails.subSection2 === 'contact-us') {
12643            digitalData.pageDetails.subSection1 = 'help';
12644            digitalData.pageDetails.subSection2 = 'inquiry';
12645            digitalData.pageDetails.subSection3 = 'contact-us';
12646            digitalData.pageDetails.channel = 'help-center';
12647            digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:${digitalData.pageDetails.channel}:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}:${digitalData.pageDetails.subSection3}`;
12648        }
12649    }
12650
12651    this.setLinkClickRemoveAll = function (linkClicked, productIdsList) {
12652        digitalData.cart = digitalData.cart || {};
12653        digitalData.cart.unavailableItemsIds = productIdsList;
12654        AB.DATALAYER.pushEvent(
12655            this.EVENTS.LINK_CLICK, {
12656            link: {
12657                linkName: linkClicked
12658            },
12659            cart: digitalData.cart,
12660            page: digitalData?.pageDetails,
12661            pageFilter: digitalData?.pageFilter
12662        }
12663        );
12664    }
12665
12666    this.setWalletLinkClick = function (linkName, key) {
12667        if (AB.DATALAYER.isPaymentPage()) {
12668            AB.DATALAYER.pushEvent(
12669                this.EVENTS.LINK_CLICK, {
12670                link: {
12671                    linkName: linkName
12672                },
12673                page: digitalData?.pageDetails,
12674                pageFilter: digitalData?.pageFilter
12675            }
12676            );
12677            let newSubsection3 = key === 'addCreditOrDebitCard' ? 'add-card-details' : key === 'addEBTCard' ? 'add-ebt-card-details' : 'add-payment-methods';
12678            if (digitalData && digitalData.pageDetails) {
12679                digitalData.pageDetails.subSection3 = newSubsection3;
12680            }
12681        }
12682    }
12683
12684    this.setWalletOtherClicks = function (linkName, subSection3, subSection4, topNav, moodalMessage) {
12685        if (AB.DATALAYER.isPaymentPage()) {
12686            if (digitalData && digitalData.pageDetails) {
12687                digitalData.pageDetails.subSection3 = subSection3;
12688                digitalData.pageDetails.subSection4 = subSection4;
12689            }
12690            if (digitalData && digitalData.pageFilter) {
12691                digitalData.pageFilter.topNav = topNav;
12692            }
12693            if (digitalData && digitalData.modal) {
12694                digitalData.modal.modalMessage = moodalMessage;
12695            }
12696            AB.DATALAYER.pushEvent(
12697                this.EVENTS.LINK_CLICK, {
12698                link: {
12699                    linkName: linkName
12700                },
12701                page: digitalData?.pageDetails,
12702                pageFilter: digitalData?.pageFilter,
12703                modal: digitalData?.modal
12704            }
12705            );
12706        }
12707    }
12708
12709    /**
12710    * PayPal tracking - my account screen
12711    */
12712    this.payPalLinkClicks = function (linkName, userMessage) {
12713        if (AB.DATALAYER.isPaymentPage() && digitalData?.pageDetails) {
12714            const subSections = [digitalData.pageDetails.subSection1, digitalData.pageDetails.subSection2, digitalData.pageDetails.subSection3, digitalData.pageDetails.subSection4].filter(
12714Boolean).join(':');
12715            digitalData.modal = digitalData.modal || {};
12716            digitalData.modal.modalMessage = userMessage ? `toast-message|${userMessage.toLowerCase().replace(/ /g, '-')}` : `cta:${subSections}|button|paypal`;
12717
12718            const eventSent = userMessage ? false : appEventData.some(eventObj => eventObj?.link?.linkName === linkName);
12719            if (!eventSent) {
12720                AB.DATALAYER.setLinkClickEvents(linkName);
12721            }
12722        }
12723    }
12724
12725
12726    this.trackP13nCarousel = function (lazyWrapper, products, carouselAction, p13nData) {
12727        // AMC tracking
12728        if (products && Array.isArray(products) && products.length > 0 && lazyWrapper?.localName === 'product-carousel-al-v1') {
12729            AB.DATALAYER.setAMCImpressionsCarousel(lazyWrapper, products, carouselAction);
12730        }
12731
12732        // PZN tracking
12733        if (products && lazyWrapper && (lazyWrapper.dataset?.carouselDriven === 'featured-products' || lazyWrapper.dataset?.carouselDriven === 'featured-items' || lazyWrapper.dataset?.carouselDriven === 'picked-for-you' || lazyWrapper.dataset?.carouselDriven === 'p13n-generic' || AB.DATALAYER.safeJSONParse(lazyWrapper.closest('targeted-wrapper')?.dataset?.products)?.apiDriven === 'p13n-generic') && !AB.DATALAYER.isDFTAPage() && !AB.DATALAYER.isBIAPage()) {
12734            let currentCarouselParent = lazyWrapper.closest('.master-product-carousel') || lazyWrapper.closest('.slick-product-carousel') || lazyWrapper.querySelector('.carousel-content-wrapper') || lazyWrapper;
12735            let currentCarouselTitle = currentCarouselParent?.querySelector('.carousel-header-text') ? currentCarouselParent.querySelector('.carousel-header-text').textContent : currentCarouselParent?.querySelector('.carousel-nav__header-title') ? currentCarouselParent.querySelector('.carousel-nav__header-title').textContent : 'Picked for You';
12736            let curatedCarouselTitle = currentCarouselParent?.querySelector('.carousel-header-text') ? currentCarouselParent.querySelector('.carousel-header-text').textContent.trim().toLowerCase().split(' ').join('-').replace(/[^\w-,|#:]/gi, '').replace('--', '-') : currentCarouselParent?.querySelector('.carousel-nav__header-title') ? currentCarouselParent.querySelector('.carousel-nav__header-title').textContent.trim().toLowerCase().split(' ').join('-').replace(/[^\w-,|#:]/gi, '').replace('--', '-') : 'picked-for-you';
12737
12738            if (curatedCarouselTitle === 'picks-for-you') {
12739                curatedCarouselTitle = 'picked-for-you';
12740            }
12741            window.slideNumber = window.slideNumber || {};
12742            if (carouselAction && carouselAction !== 'back') {
12743                setTimeout(function () {
12744                    AB.DATALAYER.sendProductImpressionsCarousel(products, p13nData, currentCarouselParent, currentCarouselTitle, curatedCarouselTitle);
12745                }, 200)
12746            } else if (carouselAction && carouselAction === 'back') {
12747                if (window.slideNumber?.hasOwnProperty(curatedCarouselTitle)) {
12748                    window.slideNumber[curatedCarouselTitle]--;
12749                }
12750            }
12751        } else if (((AB.DATALAYER.isDFTAPage() && (lazyWrapper?.dataset?.carouselDriven === 'p13n-generic' || AB.DATALAYER.safeJSONParse(lazyWrapper?.closest('targeted-wrapper')?.dataset?.products)?.apiDriven === 'p13n-generic')) || (AB.DATALAYER.isBIAPage() && lazyWrapper?.dataset?.carouselBehaviour === 'bia-spaCarousel')) && p13nData && products) {
12752
12753            const currentCarouselParent = lazyWrapper.closest('.slick-product-carousel');
12754            const carouselTitle = AB.DATALAYER.isDFTAPage()
12755                ? currentCarouselParent?.previousElementSibling?.textContent?.trim()
12756                : currentCarouselParent?.closest('.bia-spa-carousel-container')?.querySelector('.bia-spa-carousel-container-header')?.textContent?.trim();
12757            const formattedCarouselTitle = carouselTitle?.toLowerCase().split(' ').join('-').replace(/[^\w-,|#:]/gi, '').replace('--', '-');
12758            window.slideNumber = window.slideNumber || {};
12759
12760            if (carouselAction === 'load') {
12761                const options = {
12762                    root: null,
12763                    rootMargin: '0px',
12764                    threshold: 0.5
12765                };
12766                const observer = new IntersectionObserver((entries, observer) => {
12767                    entries.forEach(entry => {
12768                        if (entry.isIntersecting) {
12769                            AB.DATALAYER.sendProductImpressionsCarousel(products, p13nData, currentCarouselParent, carouselTitle, formattedCarouselTitle);
12770                            observer.unobserve(lazyWrapper.children[0]);
12771                        }
12772                    });
12773                }, options);
12774                observer.observe(lazyWrapper.children[0]);
12775            } else if (carouselAction === 'forward') {
12776                AB.DATALAYER.sendProductImpressionsCarousel(products, p13nData, currentCarouselParent, carouselTitle, formattedCarouselTitle);
12777            } else if (carouselAction === 'back') {
12778                if (window.slideNumber?.hasOwnProperty(formattedCarouselTitle)) {
12779                    window.slideNumber[formattedCarouselTitle]--;
12780                }
12781            }
12782        } else if (lazyWrapper && lazyWrapper.localName === 'meals-carousel' && products && Array.isArray(products) && products.length > 0 && lazyWrapper.closest('targeted-wrapper')?.dataset?.meals && typeof lazyWrapper.closest('targeted-wrapper')?.dataset?.meals === 'string' && AB.DATALAYER.safeJSONParse(lazyWrapper.closest('targeted-wrapper').dataset.meals)?.dataSource === 'p13n') {
12783            const currentCarouselParent = lazyWrapper.closest('.slick-meal-carousel');
12784            const currentCarouselTitle = currentCarouselParent?.querySelector('.meal-carousel-title')?.textContent?.trim()?.toLowerCase()?.split(' ')?.join('-')?.replace(/[^\w-,|#:]/gi, '')?.replace('--', '-');
12785            window.slideNumber = window.slideNumber || {};
12786            if (carouselAction && carouselAction !== 'back') {
12787                setTimeout(function () {
12788                    AB.DATALAYER.sendRecipeImpressions(products, currentCarouselParent, currentCarouselTitle);
12789                }, 200)
12790            } else if (carouselAction && carouselAction === 'back') {
12791                if (window.slideNumber.hasOwnProperty(currentCarouselTitle)) {
12792                    window.slideNumber[currentCarouselTitle]--;
12793                }
12794            }
12795        } else if (lazyWrapper && lazyWrapper.dataset?.lazyComponent === 'coupon-carousel' && lazyWrapper.dataset?.carouselFilter === 'p13n' && products && Array.isArray(products) && products.length > 0) {
12796            const currentCarouselParent = lazyWrapper.closest('.coupon-carousel');
12797            const currentCarouselTitle = lazyWrapper.dataset?.carouselTitle?.trim()?.toLowerCase()?.split(' ')?.join('-')?.replace(/[^\w-,|#:]/gi, '')?.replace('--', '-');
12798            window.slideNumber = window.slideNumber || {};
12799            if (carouselAction && carouselAction !== 'back') {
12800                setTimeout(function () {
12801                    AB.DATALAYER.sendCouponImpressions(products, currentCarouselParent, currentCarouselTitle);
12802                }, 200)
12803            } else if (carouselAction && carouselAction === 'back') {
12804                if (window.slideNumber?.hasOwnProperty(currentCarouselTitle)) {
12805                    window.slideNumber[currentCarouselTitle]--;
12806                }
12807            }
12808        }
12809
12810        if (carouselAction === 'load' && lazyWrapper && lazyWrapper.closest) {
12811            var mktTileWrapper = lazyWrapper.closest('[data-mt-includeMarketingTile="true"]');
12812            if (mktTileWrapper) {
12813                var mktTileJson = mktTileWrapper.getAttribute('data-mt-marketingTileJson');
12814                var mktTile = mktTileJson && AB.DATALAYER.safeJSONParse(mktTileJson);
12815                if (mktTile) {
12816                    var mktCarouselTitle = mktTileWrapper.getAttribute('data-carousel-title') || '';
12817                    if (lazyWrapper.dataset?.lazyComponent === 'coupon-carousel') {
12818                        AB.DATALAYER.sendDealsCarouselMarketingCardImpression(mktTile, mktCarouselTitle, lazyWrapper, null);
12819                    } else {
12820                        AB.DATALAYER.sendMarketingCardImpression(mktTile, mktCarouselTitle, mktTileWrapper);
12821                    }
12822                }
12823            } else {
12824                // deals-carousel-wrapper path: marketing tile data lives in data-deals-carousel-content JSON
12825                var dealsContentEl = lazyWrapper.hasAttribute && lazyWrapper.hasAttribute('data-deals-carousel-content')
12826                    ? lazyWrapper
12827                    : lazyWrapper.closest('[data-deals-carousel-content]');
12828                if (dealsContentEl) {
12829                    var dealsCarouselData = AB.DATALAYER.safeJSONParse(dealsContentEl.getAttribute('data-deals-carousel-content'));
12830                    if (dealsCarouselData && dealsCarouselData.includeMarketingTile === 'true' && dealsCarouselData.marketingTile) {
12831                        var dealsCarouselTitle = dealsContentEl.getAttribute('data-carousel-title') || dealsCarouselData.title || '';
12832                        AB.DATALAYER.sendDealsCarouselMarketingCardImpression(dealsCarouselData.marketingTile, dealsCarouselTitle, dealsContentEl, null);
12833                    }
12834                }
12835                if (!dealsContentEl) {
12836                    var _twWrapper = lazyWrapper.closest('targeted-wrapper');
12837                    if (_twWrapper) {
12838                        var _twData = AB.DATALAYER.safeJSONParse(_twWrapper.getAttribute('data-products')) || {};
12839                        if (_twData.includeMarketingTile === 'true' && _twData.marketingTile) {
12840                            var _twTitle = _twWrapper.getAttribute('data-carousel-title') || _twData.carouselTitle || _twData.title || '';
12841                            AB.DATALAYER.sendMarketingCardImpression(_twData.marketingTile, _twTitle, _twWrapper);
12842                        }
12843                    }
12844                }
12845            }
12846        }
12847    }
12848
12849    this.trackP13nGrid = function (wrapper, response) {
12850        const products = response?.products || [];
12851        if (products && Array.isArray(products) && products.length > 0 && (wrapper?.parentElement?.dataset?.driven === 'p13n' || wrapper?.closest('dynamic-product-grid-wrapper')?.getAttribute('data-driven') === 'p13n')) {
12852            const gridTitle = wrapper.parentElement?.parentElement?.parentElement?.querySelector('.simple-page-title')?.textContent?.trim() || 'no-value';
12853            AB.DATALAYER.sendProductImpressionsGrid(products, gridTitle);
12854            AB.DATALAYER.setP13nExperimentExposure(response);
12855        }
12856    }
12857
12858    /**
12859     * Sends the product impressions event
12860     */
12861    this.sendProductImpressionsCarousel = function (products, p13nData, currentCarouselParent, carouselTitle, formattedCarouselTitle) {
12862        if (!window.slideNumber?.hasOwnProperty(formattedCarouselTitle)) {
12863            window.slideNumber[formattedCarouselTitle] = 1;
12864        }
12865        let carouselVisibleWidth = currentCarouselParent?.offsetWidth * window.slideNumber[formattedCarouselTitle] - 100;
12866        let visibleProductsNotSent = [];
12867        window.analyticsDietPrefSent = window.analyticsDietPrefSent || [];
12868        window.digitalData.dietPrefItems = window.digitalData.dietPrefItems || [];
12869
12870        let impressionAdditionalDetail = typeof p13nData === 'object' && Object.keys(p13nData).length > 0
12871            ? AB.DATALAYER.returnImpressionAdditionalDetail(p13nData)
12872            : '';
12873
12874        if (p13nData?.experimentData?.experimentGroup && p13nData?.experimentData?.experimentId) {
12875            digitalData.pageDetails.expVariant = `${digitalData.pageDetails.subSection1}#${p13nData.experimentData.experimentGroup.toLowerCase()}#${p13nData.experimentData.experimentId}`;
12876        }
12877
12878        products.forEach(product => {
12879            if (AB.DATALAYER.isAlcoholAdTrackingDisabled(product)) {
12880                return;
12881            }
12882            if (product.name && product.price) {
12883                const isSpImpFixOn = !window?.SWY?.CONFIGSERVICE?.featureToggleConfig?.isSponsoredImpressionFixDisabled;
12884                const placement = isSpImpFixOn
12885                    ? (AB.DATALAYER.setCarouselPosition({ productId: product.id, carouselSection: carouselTitle, nativeElement: currentCarouselParent }) || 'R00#S00')
12886                    : AB.DATALAYER.setCarouselPosition({ productId: product.id, carouselSection: carouselTitle });
12887                AB.DATALAYER.pfmFromCurrentPage = AB.DATALAYER.isDFTAPage() ? `${digitalData.pageDetails?.subSection1}:${digitalData.pageDetails?.subSection2}:${digitalData.pageDetails?.subSection3}` : AB.DATALAYER.pfmFromCurrentPage;
12888                const isSponsored = !!(product.adId || product.featured);
12889                const recType = isSponsored ? 'sponsored' : 'recs';
12890                const rTyp = isSponsored ? 'sponsored' : 'recommended';
12891                const currentProductPfm = `${AB.DATALAYER.pfmFromCurrentPage}#${formattedCarouselTitle}#${this.isSearchResultsPage() ? digitalData.search?.searchTerm : 'non-search'}#${recType}#${placement}`;
12892                impressionAdditionalDetail = product.adobeMetrics?.metricA ? product.adobeMetrics?.metricA : impressionAdditionalDetail;
12893                const productInfo = {
12894                    productID: product.id,
12895                    units: isSpImpFixOn
12896                        ? AB.DATALAYER.getProductCartUnits(product.id)
12897                        : (product.quantity ? product.quantity : product.qty ? product.qty : 0),
12898                    listPrice: product.price,
12899                    carouselSection: formattedCarouselTitle,
12900                    pfmImpression: currentProductPfm,
12901                    impressionAdditionalDetail: impressionAdditionalDetail,
12902                    isImpTrackEnabled: typeof p13nData === 'object' && p13nData?.isImpTrackEnabled ? p13nData.isImpTrackEnabled : 'no-value',
12903                    placement: placement,
12904                    display: 'carousel',
12905                    badge: AB.DATALAYER.getUIBadge(currentCarouselParent, product.id)
12906                };
12907                if (isSpImpFixOn) {
12908                    productInfo.rTyp = rTyp;
12909                }
12910                const currentProductCard = currentCarouselParent?.querySelector(`a[data-bpn="${product.id}"]`)?.closest('.slick-slide');
12911                const currentProductPosition = currentProductCard && currentProductCard.offsetLeft ? currentProductCard.offsetLeft : 0;
12912
12913                if (carouselVisibleWidth > currentProductPosition && window.analyticsDietPrefSent.indexOf(product.id) === -1 && currentProductCard) {
12914                    visibleProductsNotSent.push(productInfo);
12915                    window.analyticsDietPrefSent.push(product.id);
12916                    window.digitalData.dietPrefItems.push(productInfo);
12917                }
12918            }
12919        });
12920        if (visibleProductsNotSent.length > 0) {
12921            if (!window?.SWY?.CONFIGSERVICE?.featureToggleConfig?.isSponsoredImpressionFixDisabled) {
12922                // Drive eVar14 (rTyp) from the first visible product's classification.
12923                const firstRTyp = visibleProductsNotSent[0]?.rTyp;
12924                if (firstRTyp && digitalData?.pageFilter) {
12925                    digitalData.pageFilter.recommendationType = firstRTyp;
12926                }
12927            }
12928            AB.DATALAYER.pushEvent(
12929                AB.DATALAYER.EVENTS.LINK_CLICK, {
12930                link: {
12931                    linkName: 'product-impressions'
12932                },
12933                page: digitalData?.pageDetails,
12934                pageFilter: digitalData?.pageFilter,
12935                carousel: visibleProductsNotSent
12936
12937            }
12938            );
12939        }
12940        if (window.slideNumber) {
12941            window.slideNumber[formattedCarouselTitle]++;
12942        }
12943    }
12944
12945    this.sendProductImpressionsGrid = function (products, gridTitle) {
12946        let visibleProductsNotSent = [];
12947        window.analyticsProductImpressionsSent = window.analyticsProductImpressionsSent || [];
12948
12949        products.forEach(product => {
12950            if (AB.DATALAYER.isAlcoholAdTrackingDisabled(product)) {
12951                return;
12952            }
12953            if (product?.name && product?.price) {
12954                const placement = AB.DATALAYER.setProductGridPosition({ productId: product.id });
12955                const recType = `${product.adId || product.featured ? '' : 'not-'}recommended`;
12956                digitalData.pageFilter.recommendationType = `${product.adId || product.featured ? '' : 'not'}Recommended`;
12957                const currentProductPfm = `${AB.DATALAYER.pfmFromCurrentPage}#product-grid#non-search#${recType}#${placement}`;
12958                const impressionDetail = product.adobeMetrics?.metricA || 'generic';
12959
12960                const productInfo = {
12961                    productID: product.id,
12962                    units: product.quantity ? product.quantity : product.qty ? product.qty : 0,
12963                    listPrice: product.price,
12964                    carouselSection: gridTitle ? AB.DATALAYER.sanitizeAnalyticsText(gridTitle) : '',
12965                    pfmImpression: currentProductPfm,
12966                    impressionAdditionalDetail: impressionDetail,
12967                    placement: placement,
12968                    display: 'grid',
12969                    pageNumber: '1'
12970                };
12971
12972                if (window.analyticsProductImpressionsSent.indexOf(product.id) === -1) {
12973                    visibleProductsNotSent.push(productInfo);
12974                    window.analyticsProductImpressionsSent.push(product.id);
12975                }
12976            }
12977        });
12978        if (visibleProductsNotSent.length > 0) {
12979            AB.DATALAYER.pushEvent(
12980                AB.DATALAYER.EVENTS.LINK_CLICK, {
12981                link: {
12982                    linkName: 'product-impressions'
12983                },
12984                page: digitalData?.pageDetails,
12985                pageFilter: digitalData?.pageFilter,
12986                carousel: visibleProductsNotSent
12987            }
12988            );
12989        }
12990    }
12991
12992    this.sendRecipeImpressions = function (recipes, currentCarouselParent, formattedCarouselTitle) {
12993        if (!window.slideNumber?.hasOwnProperty(formattedCarouselTitle)) {
12994            window.slideNumber[formattedCarouselTitle] = 1;
12995        }
12996        let carouselVisibleWidth = currentCarouselParent.offsetWidth * window.slideNumber[formattedCarouselTitle] - 100;
12997        let visibleRecipesNotSent = [];
12998        window.analyticsRecipesImpressionsSent = window.analyticsRecipesImpressionsSent || [];
12999        window.digitalData.analyticsRecipesImpressionsSent = window.digitalData.analyticsRecipesImpressionsSent || [];
13000
13001        recipes.forEach(recipe => {
13002            if (recipe.id) {
13003                const recipeInfo = {
13004                    recipeId: recipe.id,
13005                    detail: recipe.adobeMetrics?.metricA || 'no-value'
13006                };
13007                const currentRecipeCard = currentCarouselParent?.querySelector(`a[id='meal${recipe.id}']`)?.closest('.slick-slide');
13008                const currentRecipePosition = currentRecipeCard && currentRecipeCard.offsetLeft ? currentRecipeCard.offsetLeft : 0;
13009
13010                if (carouselVisibleWidth > currentRecipePosition && window.analyticsRecipesImpressionsSent.indexOf(recipe.id) === -1 && currentRecipeCard) {
13011                    visibleRecipesNotSent.push(recipeInfo);
13012                    window.analyticsRecipesImpressionsSent.push(recipe.id);
13013                    window.digitalData.analyticsRecipesImpressionsSent.push(recipeInfo);
13014                }
13015            }
13016        });
13017        if (visibleRecipesNotSent.length > 0) {
13018            AB.DATALAYER.pushEvent(
13019                AB.DATALAYER.EVENTS.LINK_CLICK, {
13020                link: {
13021                    linkName: 'recipes-impressions'
13022                },
13023                page: digitalData?.pageDetails,
13024                pageFilter: digitalData?.pageFilter,
13025                recipeCarouselItems: visibleRecipesNotSent
13026            }
13027            );
13028        }
13029        if (window.slideNumber) {
13030            window.slideNumber[formattedCarouselTitle]++;
13031        }
13032    }
13033
13034    this.sendCouponImpressions = function (coupons, currentCarouselParent, formattedCarouselTitle, isGrid) {
13035        if (!isGrid && !window.slideNumber?.hasOwnProperty(formattedCarouselTitle)) {
13036            window.slideNumber[formattedCarouselTitle] = 1;
13037        }
13038        let carouselVisibleWidth = !isGrid ? currentCarouselParent.offsetWidth * window.slideNumber[formattedCarouselTitle] - 100 : 0;
13039        let visibleCouponsNotSent = [];
13040        let metricA = [];
13041        let carouselPlacement = '';
13042
13043        window.analyticsCouponsImpressionsSent = window.analyticsCouponsImpressionsSent || [];
13044        digitalData.analyticsCouponsImpressionsSent = digitalData.analyticsCouponsImpressionsSent || [];
13045        digitalData.couponTrackingInfo = digitalData.couponTrackingInfo || {};
13046        digitalData.couponTrackingInfo.couponMetricAList = digitalData.couponTrackingInfo.couponMetricAList || [];
13047
13048        coupons.forEach(coupon => {
13049            if (coupon.offerId) {
13050                const currentCouponCard = !isGrid && currentCarouselParent?.querySelector(`button[id='couponAddBtn${coupon.offerId}']`)?.closest('.slick-slide');
13051                const currentCouponPosition = !isGrid && currentCouponCard && currentCouponCard.offsetLeft ? currentCouponCard.offsetLeft : 0;
13052                if (!carouselPlacement && !isGrid) {
13053                    carouselPlacement = AB.DATALAYER.setCouponPlacement(coupon, currentCouponCard, 'deals-impressions-carousel');
13054                }
13055
13056                if ((isGrid || (carouselVisibleWidth > currentCouponPosition && currentCouponCard)) && window.analyticsCouponsImpressionsSent.indexOf(coupon.offerId) === -1) {
13057                    const metricAValue = coupon?.adobeMetrics?.metricA ? `impdeals#${coupon?.adobeMetrics?.metricA}` : 'impdeals#no-value';
13058                    metricA.push(metricAValue);
13059                    digitalData.couponTrackingInfo.couponMetricAList[coupon.offerId] = metricAValue;
13060                    visibleCouponsNotSent.push(coupon.offerId);
13061                    window.analyticsCouponsImpressionsSent.push(coupon.offerId);
13062                    digitalData.analyticsCouponsImpressionsSent.push(coupon.offerId);
13063                }
13064            }
13065        });
13066        if (visibleCouponsNotSent.length > 0) {
13067            const payload = {
13068                link: {
13069                    linkName: 'deals-impressions'
13070                },
13071                page: structuredClone(digitalData?.pageDetails),
13072                pageFilter: structuredClone(digitalData?.pageFilter),
13073                dealsCouponIds: visibleCouponsNotSent.join(',')
13074            }
13075            payload.page.abTestDetails = metricA.join(',');
13076            payload.pageFilter.placement = carouselPlacement;
13077
13078            AB.DATALAYER.pushEvent(
13079                AB.DATALAYER.EVENTS.LINK_CLICK, payload
13080            );
13081            digitalData.pageFilter.placement = '';
13082            digitalData.pageFilter.recommendationType = '';
13083            digitalData.pageFilter.mediaType = '';
13084        }
13085        if (!isGrid && window.slideNumber) {
13086            window.slideNumber[formattedCarouselTitle]++;
13087        }
13088    }
13089
13090    this.setTopNavCategoriesPage = function () {
13091        if (this.isCategoriesPage()) {
13092            const topNav = digitalData.pageFilter && digitalData.pageFilter.topNav ? digitalData.pageFilter.topNav.toLowerCase().trim() : '';
13093            if (topNav === 'aisles-view all-home' || topNav === 'aisles-view all-pdp') {
13094                const previousPage = topNav === 'aisles-view all-home' ? 'home' : 'pdp';
13095                document.querySelectorAll('a.aisle-two')?.forEach(element => {
13096                    element.addEventListener('click', () => {
13097                        const title = element.querySelector('.product-title')?.textContent;
13098                        const aisleName = `aisles-${title}-${previousPage}`;
13099                        localStorage.setItem('aislesPreviousPage', aisleName);
13100                    });
13101                });
13102                document.querySelectorAll('.product-subcats a, a.view-all-subcats')?.forEach(element => {
13103                    element.addEventListener('click', () => {
13104                        const title = element.textContent;
13105                        const aisleName = `aisles-${title}-${previousPage}`;
13106                        localStorage.setItem('aislesPreviousPage', aisleName);
13107                    });
13108                });
13109            } else if (topNav.indexOf('> aisles (l1)') !== -1) {
13110                document.querySelectorAll('a.aisle-two, .product-subcats a, a.view-all-subcats')?.forEach(element => {
13111                    element.addEventListener('click', () => {
13112                        AB.DATALAYER.setTopNavPreviousPage();
13113                    });
13114                });
13115            }
13116        }
13117    }
13118
13119    this.setPfmSourceCategories = function () {
13120        if (this.isAislesL2Page() || this.isAislesL3Page()) {
13121            const pfmSource = this.returnPfmSource();
13122            if (pfmSource) {
13123                digitalData.pageFilter.pfmSource = pfmSource;
13124            }
13125        } else if (this.isMarketplaceCategoryPage() && this.pfmSourceMktpCategories) {
13126            digitalData.pageFilter.pfmSource = this.pfmSourceMktpCategories;
13127        }
13128    }
13129
13130    this.setPfmSourceCategoriesPDP = function () {
13131        if (this.isAislesL2Page() || this.isAislesL3Page()) {
13132            const pfmSource = this.returnPfmSource();
13133            if (pfmSource) {
13134                localStorage.setItem('pfmSourceCategories', pfmSource)
13135            }
13136        }
13137    }
13138
13139    this.returnPfmSource = function () {
13140        let pfmSource = '';
13141        if (digitalData.pageFilter && digitalData.pageFilter.topNav && digitalData.pageDetails) {
13142            const topNav = digitalData.pageFilter.topNav;
13143            if (topNav.indexOf('aisles-') !== -1) {
13144                pfmSource = topNav.toLowerCase().replace(/,/g, ' -');
13145            } else if (topNav.toLowerCase().indexOf('aisles (l1) >') !== -1 || topNav.toLowerCase().indexOf('> aisles:') !== -1) {
13146                const category = digitalData.pageDetails.subSection3 || digitalData.pageDetails.subSection2;
13147                pfmSource = `aisles-${category}-flyout`;
13148            }
13149        }
13150        return pfmSource;
13151    }
13152
13153    this.initWineShopPDP = function () {
13154        if (digitalData.productInfo && digitalData.productInfo.sellerId === '22222222') {
13155            digitalData.pageDetails.sellerId = '22222222';
13156            digitalData.pageDetails.channel = 'wine-shop';
13157            digitalData.pageDetails.subSection1 = 'product-details';
13158            digitalData.pageDetails.subSection2 = '';
13159            digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:vineandcellar:${digitalData.pageDetails.subSection1}`;
13160        }
13161    }
13162
13163    this.initPetProgramHandlers = function () {
13164        // Handles page loads on Pet Savings and My Pets section dropdowns
13165        let petCardAccordion = document.querySelectorAll('pet-card span[data-toggle="collapse"]')[0];
13166        let petProfileAccordion = document.querySelectorAll('pet-profile span[data-toggle="collapse"]')[0];
13167        function handleAccordionClick(element) {
13168            if (element.classList.contains('collapsed')) {
13169                if (digitalData.pageDetails) {
13170                    digitalData.pageDetails.subSection2 = element.closest('pet-card') ? 'pet-health-savings-card' : element.closest('pet-profile') ? 'my-pets' : '';
13171                    digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:loyalty:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}`;
13172                }
13173                AB.DATALAYER.setPageLoad();
13174            }
13175        }
13176        if (petProfileAccordion) {
13177            petProfileAccordion.addEventListener('click', (event) => {
13178                handleAccordionClick(event.target);
13179            });
13180        }
13181        if (petCardAccordion) {
13182            petCardAccordion.addEventListener('click', (event) => {
13183                handleAccordionClick(event.target);
13184            });
13185        }
13186    }
13187
13188    /**
13189     * Sets impressionAdditionalDetail on add to cart
13190     */
13191    this.setP13nData = function () {
13192        if (digitalData && digitalData.productInfo) {
13193            let currentCarousel;
13194            if (this.isDFTAPage() || this.isBIAPage()) {
13195                currentCarousel = document.querySelector(`a[data-bpn="${digitalData.productInfo.productID}"]`)?.closest('.slick-product-carousel');
13196            } else {
13197                const carousels = document.querySelectorAll('.slick-product-carousel');
13198                currentCarousel = Array.from(carousels).filter(carousel => {
13199                    return (carousel.querySelector('h2')?.textContent?.trim()?.includes(`${digitalData.productInfo.carouselSectionUncurated}`)
13200                        || carousel.querySelector(`lazy-wrapper[data-carousel-title="${digitalData.productInfo.carouselSectionUncurated}"]`));
13201                })[0];
13202            }
13203            const p13nCarousel = this.isBIAPage()
13204                ? currentCarousel?.querySelector('[data-carousel-behaviour="bia-spaCarousel"]')
13205                : currentCarousel?.querySelector('[data-carousel-driven="p13n-generic"]');
13206            if (p13nCarousel) {
13207                const currentDietPrefItem = digitalData.dietPrefItems?.find(item => item.productID === digitalData.productInfo.productID);
13208                const isImpTrackEnabled = this.isDFTAPage() ? currentDietPrefItem?.isImpTrackEnabled : p13nCarousel.getAttribute('data-impression-tracking') ? p13nCarousel.getAttribute('data-impression-tracking') : 'no-value';
13209                digitalData.productInfo.impressionAdditionalDetail = `${currentDietPrefItem?.impressionAdditionalDetail}#${isImpTrackEnabled}`;
13210            } else if (this.isPdp() && this.p13nData && !digitalData.productInfo.carouselSection) {
13211                digitalData.productInfo.impressionAdditionalDetail = this.p13nData;
13212            }
13213        }
13214    }
13215
13216    this.returnImpressionAdditionalDetail = function (p13nData) {
13217        const modelData = p13nData.modelData;
13218        const experimentData = p13nData.experimentData;
13219        return `${modelData?.modelConfigurationId || 'no-value'}#${modelData?.modelId || 'no-value'}#${modelData?.modelName || 'no-value'}#${experimentData?.experimentId || 'no-value'}#${experimentData?.experimentGroup || 'no-value'}#${experimentData?.eligible?.toString() || 'no-value'}`;
13220    }
13221
13222    /**
13223     * Duplicate of setP13nExperimentExposure, changing function name to better show its functionality
13224     * TO BE REMOVED after moving all function calls to the setP13nExperimentExposure
13225     */
13226    this.setP13nImpressions = function (response, caller) {
13227        if (response?.p13nAdobeMetrics?.msgExperiment && digitalData?.pageDetails) {
13228            const pageDetails = { ...digitalData.pageDetails };
13229            if ((caller === 'banner' || caller === 'hero-banner' || caller === 'hero-canvas') && response?.optionalAttributes?.segments) {
13230                pageDetails.bnrName = `web-home-engagement-ladder|${response?.optionalAttributes?.segments}`
13231                digitalData.pageFilter.mediaType = caller === 'hero-banner' ? 'hero-banner' : caller === 'hero-canvas' ? 'hero-canvas' : 'medium-banner';
13232                caller = 'banner';
13233            }
13234            const modelId = response.p13nData?.modelData?.modelConfigurationId || response.modelData?.modelConfigurationId;
13235
13236            if (caller === 'deals' && modelId) {
13237                digitalData.couponTrackingInfo = digitalData.couponTrackingInfo || {};
13238                digitalData.couponTrackingInfo[modelId] = digitalData.couponTrackingInfo[modelId] || {};
13239                digitalData.couponTrackingInfo[modelId].msgExperiment = response?.p13nAdobeMetrics?.msgExperiment;
13240                digitalData.couponTrackingInfo.msgExperiment = response?.p13nAdobeMetrics?.msgExperiment;
13241            } else if (!caller && modelId) {
13242                digitalData.productTrackingInfo = digitalData.productTrackingInfo || {};
13243                digitalData.productTrackingInfo[modelId] = digitalData.productTrackingInfo[modelId] || {};
13244                digitalData.productTrackingInfo[modelId].msgExperiment = response?.p13nAdobeMetrics?.msgExperiment;
13245                if (response.p13nData?.experimentData?.experimentGroup && response.p13nData?.experimentData?.experimentId) {
13246                    pageDetails.expVariant = `${pageDetails.subSection1}#${response.p13nData.experimentData.experimentGroup.toLowerCase()}#${response.p13nData.experimentData.experimentId}`;
13247                }
13248            }
13249            pageDetails.abTestDetails = response.p13nAdobeMetrics.msgExperiment;
13250            AB.DATALAYER.pushEvent(
13251                AB.DATALAYER.EVENTS.LINK_CLICK, {
13252                link: {
13253                    linkName: `experiment-exposure-loaded${caller ? `-${caller}` : ''}`
13254                },
13255                page: pageDetails,
13256                pageFilter: digitalData?.pageFilter,
13257                user: digitalData?.user
13258            });
13259            pageDetails.bnrName = ''
13260        }
13261    }
13262
13263    /**
13264     * This function is used to track a specific set of impressions/exposure for p13n team only when p13nAdobeMetrics.msgExperiment has a value in the API response
13265     */
13266    this.setP13nExperimentExposure = function (response, caller) {
13267        if (!caller && response?.includeMarketingTile === 'true' && response?.marketingTile && digitalData?.pageDetails) {
13268            var mktCarouselTitle = response.p13nData?.metadata?.carouselTitle || '';
13269            AB.DATALAYER.sendMarketingCardImpression(response.marketingTile, mktCarouselTitle, null);
13270        }
13271
13272        if (caller === 'deals' && digitalData?.pageDetails) {
13273            var mktDealsCarouselTitle = response.p13nData?.metadata?.carouselTitle || '';
13274            var mktDealsTileData = response?.marketingTile;
13275            if (response?.includeMarketingTile !== 'true' || !mktDealsTileData) {
13276                var mktDealsDomEl = mktDealsCarouselTitle
13277                    ? document.querySelector('[data-carousel-title="' + mktDealsCarouselTitle + '"]')
13278                    : document.querySelector('[data-deals-carousel-content]');
13279                if (mktDealsDomEl) {
13280                    var mktDealsDomData = AB.DATALAYER.safeJSONParse(mktDealsDomEl.getAttribute('data-deals-carousel-content'));
13281                    if (mktDealsDomData && mktDealsDomData.includeMarketingTile === 'true' && mktDealsDomData.marketingTile) {
13282                        mktDealsTileData = mktDealsTileData || mktDealsDomData.marketingTile;
13283                        if (!mktDealsCarouselTitle) {
13284                            mktDealsCarouselTitle = mktDealsDomEl.getAttribute('data-carousel-title') || mktDealsDomData.title || '';
13285                        }
13286                    }
13287                }
13288            }
13289            if (mktDealsTileData) {
13290                var mktDealsCarouselEl = mktDealsCarouselTitle ? document.querySelector('[data-carousel-title="' + mktDealsCarouselTitle + '"]') : null;
13291                // Fallback: data-carousel-title stores raw title; API carouselTitle may differ in case/format — compare sanitized
13292                if (!mktDealsCarouselEl && mktDealsCarouselTitle) {
13293                    var _impSanitizedTarget = AB.DATALAYER.sanitizeAnalyticsText(mktDealsCarouselTitle);
13294                    var _impDealEls = document.querySelectorAll('[data-deals-carousel-content]');
13295                    for (var _impDi = 0; _impDi < _impDealEls.length; _impDi++) {
13296                        var _impEl = _impDealEls[_impDi];
13297                        var _impAttrTitle = _impEl.getAttribute('data-carousel-title') || '';
13298                        var _impDcd = AB.DATALAYER.safeJSONParse(_impEl.getAttribute('data-deals-carousel-content')) || {};
13299                        if (
13300                            AB.DATALAYER.sanitizeAnalyticsText(_impAttrTitle) === _impSanitizedTarget ||
13301                            AB.DATALAYER.sanitizeAnalyticsText(_impDcd.title || '') === _impSanitizedTarget ||
13302                            _impDcd.itemName === mktDealsCarouselTitle
13303                        ) {
13304                            mktDealsCarouselEl = _impEl;
13305                            break;
13306                        }
13307                    }
13308                }
13309                // Only fire from this path when the element is found — if null, initDealsCarouselMktCardTracking handles it
13310                if (mktDealsCarouselEl) {
13311                    AB.DATALAYER.sendDealsCarouselMarketingCardImpression(mktDealsTileData, mktDealsCarouselTitle, mktDealsCarouselEl, {
13312                        msgExperiment: response.p13nAdobeMetrics?.msgExperiment
13313                    });
13314                }
13315            }
13316        }
13317
13318        if ((response?.p13nAdobeMetrics?.msgExperiment || response?.response?.p13nAdobeMetrics?.msgExperiment || (!response?.p13nAdobeMetrics?.msgExperiment && response?.containerItems?.some(item => item?.p13nAdobeMetrics?.msgExperiment))) && digitalData?.pageDetails) {
13319            const pageDetails = { ...digitalData.pageDetails };
13320            if ((caller === 'banner' || caller === 'hero-banner' || caller === 'hero-canvas') && response?.optionalAttributes?.segments) {
13321                pageDetails.bnrName = `web-home-engagement-ladder|${response?.optionalAttributes?.segments}`
13322                digitalData.pageFilter.mediaType = caller === 'hero-banner' ? 'hero-banner' : caller === 'hero-canvas' ? 'hero-canvas' : 'medium-banner';
13323                caller = 'banner';
13324            }
13325            const modelId = response.p13nData?.modelData?.modelConfigurationId || response.modelData?.modelConfigurationId;
13326
13327            if (caller === 'deals' && modelId) {
13328                digitalData.couponTrackingInfo = digitalData.couponTrackingInfo || {};
13329                digitalData.couponTrackingInfo[modelId] = digitalData.couponTrackingInfo[modelId] || {};
13330                digitalData.couponTrackingInfo[modelId].msgExperiment = response?.p13nAdobeMetrics?.msgExperiment;
13331                digitalData.couponTrackingInfo.msgExperiment = response?.p13nAdobeMetrics?.msgExperiment;
13332            } else if (!caller && modelId) {
13333                digitalData.productTrackingInfo = digitalData.productTrackingInfo || {};
13334                digitalData.productTrackingInfo[modelId] = digitalData.productTrackingInfo[modelId] || {};
13335                digitalData.productTrackingInfo[modelId].msgExperiment = response?.p13nAdobeMetrics?.msgExperiment;
13336                if (response.p13nData?.experimentData?.experimentGroup && response.p13nData?.experimentData?.experimentId) {
13337                    pageDetails.expVariant = `${pageDetails.subSection1}#${response.p13nData.experimentData.experimentGroup.toLowerCase()}#${response.p13nData.experimentData.experimentId}`;
13338                }
13339            }
13340            if (caller === 'bundle' && !response?.p13nAdobeMetrics?.msgExperiment && response?.bannerViewType === 'carousel' && response?.containerItems?.some(item => item?.p13nAdobeMetrics?.msgExperiment)) {
13341                response?.containerItems?.forEach(bundle => {
13342                    if (bundle.p13nAdobeMetrics?.msgExperiment) {
13343                        AB.DATALAYER.setP13nExperimentExposure(bundle, 'bundle');
13344                    }
13345                })
13346                return;
13347            }
13348            pageDetails.abTestDetails = response.p13nAdobeMetrics?.msgExperiment || response?.response?.p13nAdobeMetrics?.msgExperiment;
13349            AB.DATALAYER.pushEvent(
13350                AB.DATALAYER.EVENTS.LINK_CLICK, {
13351                link: {
13352                    linkName: `experiment-exposure-loaded${caller ? `-${caller}` : ''}`
13353                },
13354                page: pageDetails,
13355                pageFilter: digitalData?.pageFilter,
13356                user: digitalData?.user
13357            });
13358            pageDetails.bnrName = ''
13359
13360            if (!caller && response?.includeMarketingTile === 'true' && response?.marketingTile) {
13361                var mktCarouselTitle = response.p13nData?.metadata?.carouselTitle || '';
13362                AB.DATALAYER.sendMarketingCardExposure(response.marketingTile, mktCarouselTitle, null, {
13363                    msgExperiment: response.p13nAdobeMetrics?.msgExperiment
13364                });
13365            }
13366
13367            if (caller === 'deals') {
13368                var mktDealsExpCarouselTitle = response.p13nData?.metadata?.carouselTitle || '';
13369                var mktDealsExpTileData = response?.marketingTile;
13370                if (response?.includeMarketingTile !== 'true' || !mktDealsExpTileData) {
13371                    var mktDealsExpDomEl = mktDealsExpCarouselTitle
13372                        ? document.querySelector('[data-carousel-title="' + mktDealsExpCarouselTitle + '"]')
13373                        : document.querySelector('[data-deals-carousel-content]');
13374                    if (mktDealsExpDomEl) {
13375                        var mktDealsExpDomData = AB.DATALAYER.safeJSONParse(mktDealsExpDomEl.getAttribute('data-deals-carousel-content'));
13376                        if (mktDealsExpDomData && mktDealsExpDomData.includeMarketingTile === 'true' && mktDealsExpDomData.marketingTile) {
13377                            mktDealsExpTileData = mktDealsExpTileData || mktDealsExpDomData.marketingTile;
13378                            if (!mktDealsExpCarouselTitle) {
13379                                mktDealsExpCarouselTitle = mktDealsExpDomEl.getAttribute('data-carousel-title') || mktDealsExpDomData.title || '';
13380                            }
13381                        }
13382                    }
13383                }
13384                if (mktDealsExpTileData) {
13385                    var mktDealsExpCarouselEl = mktDealsExpCarouselTitle ? document.querySelector('[data-carousel-title="' + mktDealsExpCarouselTitle + '"]') : null;
13386                    if (!mktDealsExpCarouselEl && mktDealsExpCarouselTitle) {
13387                        var _expSanitizedTarget = AB.DATALAYER.sanitizeAnalyticsText(mktDealsExpCarouselTitle);
13388                        var _expDealEls = document.querySelectorAll('[data-deals-carousel-content]');
13389                        for (var _expDi = 0; _expDi < _expDealEls.length; _expDi++) {
13390                            var _expEl = _expDealEls[_expDi];
13391                            var _expAttrTitle = _expEl.getAttribute('data-carousel-title') || '';
13392                            var _expDcd = AB.DATALAYER.safeJSONParse(_expEl.getAttribute('data-deals-carousel-content')) || {};
13393                            if (
13394                                AB.DATALAYER.sanitizeAnalyticsText(_expAttrTitle) === _expSanitizedTarget ||
13395                                AB.DATALAYER.sanitizeAnalyticsText(_expDcd.title || '') === _expSanitizedTarget ||
13396                                _expDcd.itemName === mktDealsExpCarouselTitle
13397                            ) {
13398                                mktDealsExpCarouselEl = _expEl;
13399                                break;
13400                            }
13401                        }
13402                    }
13403                    if (mktDealsExpCarouselEl) {
13404                        AB.DATALAYER.sendDealsCarouselMarketingCardExposure(mktDealsExpTileData, mktDealsExpCarouselTitle, mktDealsExpCarouselEl, {
13405                            msgExperiment: response.p13nAdobeMetrics?.msgExperiment
13406                        });
13407                    }
13408                }
13409            }
13410        }
13411    }
13412
13413    this.setP13nHeroBannerImpressions = function (bannerUnitWrapper) {
13414        const getParsedBannerContent = (slide) => {
13415            const heroBannerContent = slide?.querySelector('banner-unit-hero-wc')?.getAttribute('data-hero-banner-content') || slide?.querySelector('webgen-hero-canvas-card')?.getAttribute('data-hero-canvas-content');
13416            const heroBannerContentObj = AB.DATALAYER.safeJSONParse(heroBannerContent);
13417            return heroBannerContentObj;
13418        }
13419
13420        const selectors = {
13421            currentBanner: '.banner-unit-proxy, .nextgen-banner-unit-proxy, .as-hero__item, promo-banner, .merch-targeted-promo-banner, .hero-canvas',
13422            titleElement: '.banner-unit-regular__headline p, .banner-unit-hero__text-plate__title, .title, .mod-unit__headline p, .banner-unit-regular__headline .h2, .banner__title p',
13423            wrapperElement: '.abs-carousel-wrapper, .nextgen-abs-carousel-wrapper, .as-hero__carousel, .abs-carousel',
13424            bannerSource: 'banner-unit-regular-wc, banner-unit-hero-wc, promo-banner-regular-wc'
13425        };
13426        const bannerClassMappings = {
13427            'banner-unit-proxy': '.abs-carousel-wrapper',
13428            'nextgen-banner-unit-proxy': '.nextgen-abs-carousel-wrapper',
13429            'as-hero__item': '.as-hero__carousel',
13430        };
13431
13432        const options = {
13433            root: null,
13434            rootMargin: '0px',
13435            threshold: 0.5
13436        };
13437        const observer = new IntersectionObserver((entries, self) => {
13438            entries.forEach(entry => {
13439                if (entry?.isIntersecting) {
13440                    const slide = entry?.target;
13441                    const heroBannerContentObj = getParsedBannerContent(slide);
13442                    const currentBanner = slide.querySelector(selectors.currentBanner);
13443                    if (heroBannerContentObj?.p13nAdobeMetrics?.metricA) {
13444                        const pageDetails = { ...digitalData.pageDetails };
13445                        pageDetails.msgDetail = heroBannerContentObj?.p13nAdobeMetrics?.metricA || 'generic';
13446                        pageDetails.bnrName = heroBannerContentObj?.bannerTitle
13447                            && heroBannerContentObj?.campaign
13448                            && `${AB.DATALAYER.sanitizeAnalyticsText(heroBannerContentObj.bannerTitle.replace(/[<]\/?[a-z]*[>]/gi, ''))}|${heroBannerContentObj.campaign}`;
13449                        const zoneInfo = AB.DATALAYER.getZoneInfo(currentBanner)?.zone || '0';
13450                        digitalData.pageFilter.mediaType = currentBanner?.classList?.contains('hero-canvas') ? 'hero-canvas' : 'hero-banner';
13451                        digitalData.pageFilter.placement = `${AB.DATALAYER.getBannerPlacement(currentBanner, selectors, bannerClassMappings)}#Z${zoneInfo < 10 ? `0${zoneInfo}` : zoneInfo}`;
13452                        AB.DATALAYER.pushEvent(
13453                            AB.DATALAYER.EVENTS.LINK_CLICK, {
13454                            link: {
13455                                linkName: 'banner-impressions',
13456                                isSendToSS: true
13457                            },
13458                            page: pageDetails,
13459                            pageFilter: digitalData?.pageFilter,
13460                            user: digitalData?.user
13461                        }
13462                        );
13463                        digitalData.pageFilter.placement = '';
13464                        digitalData.pageFilter.mediaType = '';
13465                        digitalData.pageDetails.bnrName = '';
13466                        digitalData.pageFilter.recommendationType = '';
13467                        self.unobserve(slide);
13468                    }
13469                }
13470            });
13471        }, options);
13472        const heroBannerSlides = bannerUnitWrapper?.[0]?.querySelectorAll('.slick-slide:not(.slick-cloned)');
13473        heroBannerSlides?.forEach(slide => {
13474            const bannerContentObj = getParsedBannerContent(slide);
13475            if (bannerContentObj?.p13nAdobeMetrics?.metricA) {
13476                observer.observe(slide);
13477            }
13478        });
13479    }
13480
13481    this.heroBannnerExposureLoaded = function (response, type) {
13482        if (response && Array.isArray(response) && response.length > 0) {
13483            let uniqueItems = [];
13484            response.forEach(item => {
13485                const msgExperiment = item.p13nAdobeMetrics?.msgExperiment;
13486                if (msgExperiment && !uniqueItems.includes(msgExperiment)) {
13487                    uniqueItems.push(msgExperiment);
13488                    this.setP13nExperimentExposure(item, type === 'hero-canvas' ? 'hero-canvas' : 'hero-banner');
13489                }
13490            });
13491        }
13492    }
13493
13494    /**
13495     * Hero Bento carousel experiment-exposure (React component, drop-in replacement
13496     * for hero-canvas). Dedupes by msgExperiment - same rule as heroBannnerExposureLoaded -
13497     * so a given experiment fires at most once even if multiple cards share it.
13498     * cards: Array<{ element: <DOM node inside the slide>, info: { msgExperiment, title, subTitle, promotionId } }>
13499     */
13500    this.heroBentoExposureLoaded = function (cards) {
13501        if (!Array.isArray(cards) || cards.length === 0) {
13502            return;
13503        }
13504        const uniqueExperiments = [];
13505        cards.forEach(card => {
13506            const msgExperiment = card?.info?.msgExperiment;
13507            if (msgExperiment && !uniqueExperiments.includes(msgExperiment)) {
13508                uniqueExperiments.push(msgExperiment);
13509                AB.DATALAYER.setHeroBentoExposure(card.element, card.info);
13510            }
13511        });
13512    }
13513
13514    /**
13515     * Fires a single experiment-exposure-loaded-banner event for one Bento card.
13516     * Placement follows the hero-canvas derivation: row is fixed to 01 (Bento is always
13517     * the top hero), slot = card index among non-cloned slick slides, zone via getZoneInfo.
13518     */
13519    this.setHeroBentoExposure = function (bannerEl, info) {
13520        if (!info?.msgExperiment || !bannerEl || !digitalData?.pageDetails) {
13521            return;
13522        }
13523        const pad = (value) => (Number(value) < 10 ? `0${value}` : `${value}`);
13524
13525        const carousel = bannerEl.closest('.abs-carousel');
13526        const currentSlide = bannerEl.closest('.slick-slide');
13527        const allSlides = carousel ? carousel.querySelectorAll('.slick-slide:not(.slick-cloned)') : [];
13528        const bannerSlot = (allSlides.length && currentSlide) ? Array.from(allSlides).indexOf(currentSlide) + 1 : 0;
13529        const zoneInfo = AB.DATALAYER.getZoneInfo(bannerEl)?.zone || '0';
13530
13531        // bnrName: "<title>-<subTitle>|<promotionId>". Titles from textPlateModule can be
13532        // rich text (e.g. "<p><b>..</b></p>"), so strip HTML tags BEFORE sanitizing -
13533        // otherwise the tag letters leak in ("pb..bp"). Spaces -> "-" via sanitizeAnalyticsText.
13534        // Empty title+subTitle => "no-value"; no promotionId => "no-value".
13535        const stripHtml = (value) => (value || '').replace(/<[^>]*>/g, '');
13536        const titlePart = [info.title, info.subTitle]
13537            .map(part => AB.DATALAYER.sanitizeAnalyticsText(stripHtml(part)))
13538            .filter(Boolean)
13539            .join('-') || 'no-value';
13540        const bnrName = `${titlePart}|${info.promotionId || 'no-value'}`;
13541
13542        const pageDetails = { ...digitalData.pageDetails };
13543        pageDetails.abTestDetails = info.msgExperiment;
13544        pageDetails.bnrName = bnrName;
13545
13546        digitalData.pageFilter.mediaType = 'vertical-hero-banner';
13547        digitalData.pageFilter.placement = `R01#S${pad(bannerSlot)}#Z${pad(zoneInfo)}`;
13548
13549        AB.DATALAYER.pushEvent(
13550            AB.DATALAYER.EVENTS.LINK_CLICK, {
13551            link: {
13552                linkName: 'experiment-exposure-loaded-banner'
13553            },
13554            page: pageDetails,
13555            pageFilter: digitalData.pageFilter,
13556            user: digitalData.user
13557        });
13558
13559        pageDetails.bnrName = '';
13560        digitalData.pageFilter.placement = '';
13561        digitalData.pageFilter.mediaType = '';
13562    }
13563
13564    // Fires the Vertical Hero unit Banner impression (banner-impressions); mirrors the vertical-hero exposure setHeroBentoExposure.
13565    this.setVerticalHeroBannerImpressions = function (bannerEl, info) {
13566        if (!info || !digitalData?.pageDetails) return;
13567        const pad = (value) => (Number(value) < 10 ? `0${value}` : `${value}`);
13568        const stripHtml = (value) => `${value || ''}`.replace(/<[^>]*>/g, '');
13569        const metricA = info.metricA || 'generic';
13570
13571        const carousel = bannerEl?.closest?.('.abs-carousel');
13572        const currentSlide = bannerEl?.closest?.('.slick-slide');
13573        const allSlides = carousel ? carousel.querySelectorAll('.slick-slide:not(.slick-cloned)') : [];
13574        const domSlot = (allSlides.length && currentSlide) ? Array.from(allSlides).indexOf(currentSlide) + 1 : 0;
13575        const bannerSlot = domSlot || info.slideIndex || 1;
13576        const placementInfo = AB.DATALAYER.getZoneInfo(bannerEl) || {};
13577        const rowInfo = Number(placementInfo.row) > 0 ? placementInfo.row : 1;
13578        const zoneInfo = placementInfo.zone || '0';
13579
13580        const normalizedTitle = AB.DATALAYER.sanitizeAnalyticsText(stripHtml(info.title));
13581        const normalizedSubTitle = AB.DATALAYER.sanitizeAnalyticsText(stripHtml(info.subTitle));
13582        const titlePart = normalizedTitle || normalizedSubTitle
13583            ? `${normalizedTitle || 'no-value'}-${normalizedSubTitle || 'no-value'}`
13584            : 'no-value';
13585
13586        const pageDetails = { ...digitalData.pageDetails };
13587        pageDetails.msgDetail = metricA;
13588        pageDetails.abTestDetails = metricA;
13589        pageDetails.bnrName = `${titlePart}|${info.promotionId || 'no-value'}`;
13590
13591        if (info.variant === 'deals') {
13592            pageDetails.dlsCpnIds = Array.isArray(info.dealsCouponIds)
13593                ? info.dealsCouponIds
13594                    .map(couponId => `${couponId ?? ''}`.trim())
13595                    .filter(Boolean)
13596                    .join(',')
13597                : '';
13598        } else {
13599            // dlsCpnIds belongs only to coupon/deals banner impressions.
13600            delete pageDetails.dlsCpnIds;
13601        }
13602
13603        digitalData.pageFilter.mediaType = 'vertical-hero-banner';
13604        digitalData.pageFilter.placement = `R${pad(rowInfo)}#S${pad(bannerSlot)}#Z${pad(zoneInfo)}`;
13605
13606        const payload = {
13607            link: {
13608                linkName: 'banner-impressions',
13609                isSendToSS: true
13610            },
13611            page: pageDetails,
13612            pageFilter: digitalData?.pageFilter,
13613            user: digitalData?.user
13614        };
13615
13616        if (info.variant === 'products') {
13617            payload.carousel = Array.isArray(info.products) ? info.products : [];
13618        }
13619
13620        AB.DATALAYER.pushEvent("banner-impressions", payload);
13621
13622        digitalData.pageFilter.placement = '';
13623        digitalData.pageFilter.mediaType = '';
13624        digitalData.pageDetails.bnrName = '';
13625        digitalData.pageFilter.recommendationType = '';
13626    }
13627
13628    // Bento Hero Card click tracking. React passes info { contentType, title, subTitle, promotionId, recommendationType, ctaValue, msg }; content prefix is `bento-hero-card`.
13629
13630    // Resolve zone/row/slot + `bento-hero-card:<contentType>:<title>`; bannerEl may be null (falls back to the current/first bento slide).
13631    this.getBentoClickContext = function (bannerEl, info) {
13632        const pad = (v) => (Number(v) < 10 ? `0${v}` : `${v}`);
13633        const stripHtml = (v) => `${v || ''}`.replace(/<[^>]*>/g, '');
13634
13635        const el = bannerEl
13636            || document.querySelector('.abs-carousel .slick-current .hero-canvas')
13637            || document.querySelector('.abs-carousel .hero-canvas');
13638
13639        const carousel = el?.closest?.('.abs-carousel');
13640        const currentSlide = el?.closest?.('.slick-slide');
13641        const allSlides = carousel ? carousel.querySelectorAll('.slick-slide:not(.slick-cloned)') : [];
13642        const carouselSlot = (allSlides.length && currentSlide) ? Array.from(allSlides).indexOf(currentSlide) + 1 : (info?.slideIndex || 1);
13643        const slot = Number(info?.slot) > 0 ? Number(info.slot) : carouselSlot;
13644        const row = Number(info?.row) > 0 ? Number(info.row) : 1;
13645
13646        const title = [info?.title, info?.subTitle]
13647            .map((p) => AB.DATALAYER.sanitizeAnalyticsText(stripHtml(p)))
13648            .filter(Boolean).join('-') || 'no-value';
13649
13650        const designType = info?.contentType || 'full-bleed';
13651        const suppliedRecommendationType = `${info?.recommendationType || ''}`.trim();
13652        const recommendationType = !suppliedRecommendationType || suppliedRecommendationType === 'no-value'
13653            ? 'not-recommended'
13654            : suppliedRecommendationType;
13655
13656        // Cap content + uniqueId so the assembled value (z|action|content|sp|id) stays within 256 chars.
13657        const V218_MAX = 256;
13658        const V218_WRAPPER_RESERVE = 32;
13659        const uniqueId = (info?.promotionId ? `${info.promotionId}` : 'no-value').slice(0, 64);
13660        const contentBudget = V218_MAX - V218_WRAPPER_RESERVE - uniqueId.length;
13661        const rawContent = `bento-hero-card:${designType}:${title}`;
13662        const content = rawContent.length > contentBudget ? rawContent.slice(0, contentBudget) : rawContent;
13663
13664        return {
13665            element: el,
13666            placement: `R${pad(row)}#S${pad(slot)}`,             // V80 row#slot (matches hero-card convention; no zone suffix)
13667            mediaType: `bento-hero-card:${designType}`,          // V80 MEDIA TYPE / V218 content prefix
13668            content,                                             // V218 CONTENT value (capped to keep V218 <= 256)
13669            title,
13670            uniqueId,
13671            recommendationType
13672        };
13673    };
13674
13675    // L2 (MSG): onetag maps `page.msgDetail`; set before a push, reset after so it doesn't leak into other events.
13676    this.setBentoMsgDetail = function (msg) {
13677        if (!msg || !digitalData?.pageDetails) return;
13678        this._bentoPrevMsgDetail = digitalData.pageDetails.msgDetail;
13679        digitalData.pageDetails.msgDetail = msg;
13680    };
13681    this.resetBentoMsgDetail = function () {
13682        if (this._bentoPrevMsgDetail !== undefined && digitalData?.pageDetails) {
13683            digitalData.pageDetails.msgDetail = this._bentoPrevMsgDetail;
13684        }
13685        this._bentoPrevMsgDetail = undefined;
13686    };
13687
13688    // Writes the V218 aemZoneAnalytics string (read on the next page load
13688) with a literal action, mirroring trackAEMZone's z<section>|action|content|sp<row>|id format but without its 'link' -> 'link:<textContent>' rewrite.
13689    this.setBentoAemZone = function (el, action, content, id) {
13690        const zi = AB.DATALAYER.getZoneInfo(el) || {};
13691        if (!zi.section || zi.section === '' || !zi.row || zi.row === '') return;
13692        const pad = (v) => (Number(v) < 10 ? `0${v}` : `${v}`);
13693        const value = `z${pad(zi.section)}|${action}|${this.sanitizeAnalyticsText(content) || 'no-value'}|sp${pad(zi.row)}|${id || 'no-value'}`;
13694        try { localStorage.setItem('aemZoneAnalytics', value); } catch { /* no-op */ }
13695    };
13696
13697    this.getBentoV80 = function (c) {
13698        const rec = `${c.recommendationType || ''}`;
13699        if (!rec || rec === 'no-value') return '';
13700        return `${c.mediaType}#${rec}#${String(c.placement).toLowerCase()}`;
13701    };
13702    this.setBentoMediaPlacement = function (c, crossPage) {
13703        const v80 = this.getBentoV80(c);
13704        if (!v80) return '';
13705        if (crossPage) {
13706            try { localStorage.setItem('mediaPlacementClick', v80); } catch (e) { /* no-op */ }
13707            try { localStorage.setItem('bentoHeroMediaPlacement', v80); } catch (e) { /* no-op */ }
13708        } else if (digitalData?.pageFilter) {
13709            digitalData.pageFilter.mediaPlacementClick = v80;
13710        }
13711        return v80;
13712    };
13713
13714    this.setBentoPdpPfm = function (c, badge, msg) {
13715        const b = this.sanitizeAnalyticsText(badge) || 'no-badge';
13716        const bentoPdpPfm = `${c.content}#non-search#${this.getBentoPfmRecSegment(c.recommendationType)}#${c.placement}#${b}`;
13717        try {
13718            localStorage.setItem('bentoHeroPdpPfm', bentoPdpPfm);
13719            localStorage.setItem('analyticsMediaType', c.mediaType);
13720            localStorage.setItem('analyticsProductPlacement', c.placement);
13721            if (msg) localStorage.setItem('analyticsProductMsg', msg);
13722        } catch { /* no-op */ }
13723        return bentoPdpPfm;
13724    };
13725
13726    this.buildBentoV218 = function (action, c) {
13727        const zi = AB.DATALAYER.getZoneInfo(c.element) || {};
13728        const pad = (v) => (Number(v) < 10 ? `0${Number(v) || 0}` : `${v}`);
13729        const zone = pad(Number(zi.section) > 0 ? Number(zi.section) : 0);
13730        const spot = pad(Number(zi.row) > 0 ? Number(zi.row) : 1);
13731        return `z${zone}|${action}|${c.content}|sp${spot}|${c.uniqueId}`;
13732    };
13733
13734    this.setBentoBannerClick = function (bannerEl, info) {
13735        if (!info) return;
13736        const c = this.getBentoClickContext(bannerEl, info);
13737        // V218 -> localStorage.aemZoneAnalytics (next page). Built via buildBentoV218 (sp01 fallback) so the
13738        // spot is consistent with cart_add/coupon when the React grid's AEM zone can't be resolved (sp00).
13739        const v218 = this.buildBentoV218('banner', c);
13740        try { localStorage.setItem('aemZoneAnalytics', v218); } catch { /* no-op */ }
13741        this.setBentoMediaPlacement(c, true);                                       // V80 -> localStorage.mediaPlacementClick (next page)
13742        if (info.destinationIsPdp) {
13743            this.setBentoPdpPfm(c, info.badge, info.msg);                           // main-CTA -> PDP: eVar14/V80/L2 source (AC4 "any design type")
13744        }
13745        this.setBentoMsgDetail(info.msg);                                           // L2 (before push)
13746        const previousV218 = digitalData?.pageFilter?.bannerCardCarousel;
13747        if (digitalData?.pageFilter) digitalData.pageFilter.bannerCardCarousel = v218;
13748        try {
13749            this.setBannerClickedEvent(c.placement, `bannerclicked|${c.content}`,   // single immediate banner-clicked with V218 + L2 + media type
13750                c.recommendationType, c.mediaType, c.title);
13751        } finally {
13752            if (digitalData?.pageFilter) digitalData.pageFilter.bannerCardCarousel = previousV218 || '';
13753            this.resetBentoMsgDetail();
13754        }
13755    };
13756
13757    // Text-link CTA (e.g. T&C): V171 only, no V218/V80; subsections from existing page values via initPathSections.
13758    this.setBentoTextLinkClick = function (info) {
13759        const subs = (AB.DATALAYER.initPathSections(true) || []).join(':') || 'no-value';
13760        const ctaValue = AB.DATALAYER.sanitizeAnalyticsText(info?.ctaValue) || 'no-value'; // self-sanitize (consistent with setBentoDealLineClick) so the emitter is correct regardless of caller
13761        AB.DATALAYER.setLinkClickEvents(`cta:${subs}|link|bento-hero-card:${ctaValue}`); 
13762    };
13763
13764    // Add to cart in banner: fires the canonical cart_add (products string + V218 + L2) via handleItemEvent; call AFTER the cart update succeeds. info.product from the card, info.cart optional.
13765    this.setBentoAddToCart = function (bannerEl, info) {
13766        if (!info || !info.product) return;
13767        const c = this.getBentoClickContext(bannerEl, info);
13768        const v218 = this.buildBentoV218('cart_add', c);
13769        digitalData.pageFilter.bannerCardCarousel = v218;
13770        digitalData._bentoProductContext = {
13771            content: c.content,                 // bento-hero-card:product-grid:<title>
13772            mediaType: c.mediaType,             // bento-hero-card:product-grid   
13773            placement: c.placement,                        
13774            bannerCardCarousel: v218,           
13775            mediaPlacementClick: this.getBentoV80(c), // (same-page cart_add rides pageFilter.mediaPlacementClick)
13776            recommendationType: c.recommendationType
13777        };
13778        this.setBentoMsgDetail(info.msg);                                          // L2 (page.msgDetail)
13779        try {
13780            this.handleItemEvent('cart_add', info.product, undefined, 'bento-hero-card', info.cart); // fires the single cart_add + products string
13781        } finally {
13782            // Always clear so a throw in handleItemEvent can't leak bento context into a later non-bento product action.
13783            delete digitalData._bentoProductContext;
13784        }
13785        if (String(c.recommendationType).includes('sponsored')) {
13786            this.setBannerClickedEvent(c.placement, `bannerclicked|${c.content}`, c.recommendationType, c.mediaType, c.title);
13787        }
13788        this.resetBentoMsgDetail();
13789    };
13790
13791    // Maps the bento recommendationType to the eVar14 pfm segment (mirrors createPaPfmBasedOnRecType).
13792    this.getBentoPfmRecSegment = function (recommendationType) {
13793        const rec = `${recommendationType || ''}`;
13794        if (rec.includes('sponsored')) return 'sponsored';
13795        if (rec === 'recommended') return 'recs';
13796        return 'not-recommended';
13797    };
13798
13799    this.setBentoProductClick = function (bannerEl, info) {
13800        if (!info) return;
13801        const c = this.getBentoClickContext(bannerEl, info);
13802        // V218 -> localStorage.aemZoneAnalytics (next page). buildBentoV218 (sp01 fallback) keeps the spot
13803        // consistent with cart_add/coupon when the React grid's AEM zone can't be resolved (sp00).
13804        try { localStorage.setItem('aemZoneAnalytics', this.buildBentoV218('pdp-card', c)); } catch { /* no-op */ }
13805        this.setBentoMediaPlacement(c, true);
13806        this.setBentoMsgDetail(info.msg);
13807        // eVar14 tail (PDP prefixes the page pfm): <content>#non-search#<rec>#<placement>#<badge>.
13808        this.setBentoPdpPfm(c, info.badge, info.msg);
13809        if (String(c.recommendationType).includes('sponsored')) {
13810            this.setBannerClickedEvent(c.placement, `bannerclicked|${c.content}`, c.recommendationType, c.mediaType, c.title); // immediate banner-clicked
13811        }
13812        this.resetBentoMsgDetail();
13813    };
13814
13815    this.setBentoDealLineClick = function (bannerEl, info) {
13816        if (!info) return;
13817        const c = this.getBentoClickContext(bannerEl, info);
13818        const subs = (AB.DATALAYER.initPathSections(true) || []).join(':') || 'no-value';
13819        this.setBentoMsgDetail(info.msg);                                          // L2 (page.msgDetail)
13820        AB.DATALAYER.setLinkClickEvents(
13821            `cta:${subs}|link|${c.content}:${AB.DATALAYER.sanitizeAnalyticsText(info.ctaValue) || 'no-value'}`); 
13822        this.setBentoAemZone(c.element, 'link', `${c.mediaType}:offer details`, c.uniqueId);   
13823        this.setBentoMediaPlacement(c, true);                                      
13824        if (String(c.recommendationType).includes('sponsored')) {
13825            this.setBannerClickedEvent(c.placement, `bannerclicked|${c.content}`, c.recommendationType, c.mediaType, c.title); // immediate banner-clicked
13826        }
13827        this.resetBentoMsgDetail();
13828    };
13829
13830    this.setBentoCouponClipContext = function (couponEl, info) {
13831        if (!info || !digitalData.pageFilter) return;
13832        const c = this.getBentoClickContext(couponEl, { ...info, contentType: info.contentType || 'deals-grid' });
13833        digitalData.pageFilter.bentoCarouselTitle = c.content;
13834        const v218 = this.buildBentoV218('coupon_clipped', c);
13835        digitalData._bentoCouponV218 = v218;                 // consumed by clipCoupon's re-assert (always set now)
13836        digitalData.pageFilter.bannerCardCarousel = v218;
13837        // Flag makes setCouponPlacement skip its no-value overwrite so the bento V218 content survives.
13838        digitalData.pageFilter.bentoCouponV218Set = true;
13839    };
13840
13841    this.resetBentoCouponClipContext = function () {
13842        if (!digitalData || !digitalData.pageFilter) return;
13843        if (digitalData.pageFilter.bannerCardCarousel === digitalData._bentoCouponV218) {
13844            digitalData.pageFilter.bannerCardCarousel = '';
13845        }
13846        delete digitalData._bentoCouponV218;
13847        digitalData.pageFilter.bentoCouponV218Set = false;
13848    };
13849
13850    this.initHeroBannerAbTestDetails = function () {
13851        const heroBannerAbTestDetails = AB.DATALAYER.handleGetLSValue('heroBannerAbTestDetails');
13852        if (digitalData?.pageDetails && heroBannerAbTestDetails) {
13853            digitalData.pageDetails.abTestDetails = heroBannerAbTestDetails;
13854        }
13855    }
13856
13857    this.initBundleAbTestDetails = function () {
13858        const bundleAbTestDetails = AB.DATALAYER.handleGetLSValue('bundleAbTestDetails');
13859        if (digitalData?.pageDetails && bundleAbTestDetails) {
13860            digitalData.pageDetails.abTestDetails = bundleAbTestDetails;
13861        }
13862    }
13863
13864    /**
13865    * This function is used to track a specific set of impressions for p13n banner team only when p13nAdobeMetrics.msgExperiment has a value in the API response
13866    */
13867    this.setP13nEngagementLadderImpressions = function (data, bannerWrapper) {
13868        const bannerInfo = data && data['banners'] && data['banners'][0];
13869        const metricA = bannerInfo?.p13nAdobeMetrics?.metricA || 'generic';
13870        const pageDetails = { ...digitalData.pageDetails };
13871        pageDetails.msgDetail = metricA;
13872        pageDetails.bnrName = bannerInfo?.optionalAttributes?.title
13873            && bannerInfo?.optionalAttributes?.segments
13874            && `${AB.DATALAYER.sanitizeAnalyticsText(bannerInfo.optionalAttributes.title.replace(/[<]\/?[a-z]*[>]/gi, ''))}|${bannerInfo.optionalAttributes.segments}`;
13875        const selectors = {
13876            currentBanner: '.nextgen-banner-unit, .nextgen-banner-unit-proxy',
13877            titleElement: '.banner-unit-medium__text-plate__title p',
13878            wrapperElement: '.nextgen-abs-carousel-wrapper',
13879            bannerSource: 'nextgen-banner-unit-wc'
13880        };
13881
13882        const bannerClassMappings = {
13883            'nextgen-banner-unit-proxy': '.nextgen-abs-carousel-wrapper',
13884            'nextgen-banner-unit': '.nextgen-abs-carousel-wrapper'
13885        }
13886        const bannerSource = bannerWrapper?.querySelector('nextgen-banner-unit-wc')?.getAttribute('data-banner-data-source');
13887        const currentBanner = bannerWrapper.closest('.nextgen-banner-unit, .nextgen-banner-unit-proxy');
13888        const zoneInfo = AB.DATALAYER.getZoneInfo(currentBanner)?.zone || '0';
13889        digitalData.pageFilter.mediaType = bannerSource && bannerSource == 'MediumBanner' ? 'medium-banner' : '';
13890        digitalData.pageFilter.placement = `${AB.DATALAYER.getBannerPlacement(currentBanner, selectors, bannerClassMappings)}#Z${zoneInfo < 10 ? `0${zoneInfo}` : zoneInfo}`;
13891        AB.DATALAYER.pushEvent(
13892            AB.DATALAYER.EVENTS.LINK_CLICK, {
13893            link: {
13894                linkName: `banner-impressions`,
13895                isSendToSS: true
13896            },
13897            page: pageDetails,
13898            pageFilter: digitalData?.pageFilter,
13899            user: digitalData?.user
13900        }
13901        );
13902        digitalData.pageFilter.placement = '';
13903        digitalData.pageFilter.mediaType = '';
13904        digitalData.pageDetails.bnrName = '';
13905    }
13906
13907    /**
13908    * This function is used to track a specific set of headline impressions for p13n team
13909    */
13910    this.setP13nHeadlineImpressions = function (data, caller) {
13911        if (data?.dataSource === 'p13n') {
13912            const metricA = data?.p13nAdobeMetrics?.metricA || 'generic';
13913            const pageDetails = { ...digitalData.pageDetails };
13914            pageDetails.msgDetail = metricA;
13915            AB.DATALAYER.pushEvent(
13916                AB.DATALAYER.EVENTS.LINK_CLICK, {
13917                link: {
13918                    linkName: `${caller}-impressions`,
13919                    isSendToSS: true
13920                },
13921                page: pageDetails,
13922                pageFilter: digitalData?.pageFilter,
13923                user: digitalData?.user
13924            }
13925            );
13926        }
13927    }
13928
13929    /**
13930    * This function is used to track a specific set of bundles impressions for p13n team
13931    */
13932    this.setP13nBundleImpressions = function ({ data, caller, wrapper, action } = {}) {
13933        const pageDetails = { ...digitalData.pageDetails };
13934        const bundlesToSend = [];
13935        window.digitalData.bundlesTrackedIds = window.digitalData.bundlesTrackedIds || [];
13936        const bundleDataContainer = wrapper?.querySelector('webgen-bundles-carousel')?.getAttribute('data-bundles-carousel-content');
13937
13938        if (data && Object.keys(data)?.length > 0 && caller === 'bundle') {
13939            if (data.p13nAdobeMetrics?.metricA) {
13940                const allSingleBundles = document.querySelectorAll('div:has(>webgen-bundles)') && Array.from(document.querySelectorAll('div:has(>webgen-bundles)'))?.filter(bundle => AB.DATALAYER.isVisible(bundle));
13941                const bundleRow = wrapper && allSingleBundles ? allSingleBundles.indexOf(wrapper) + 1 : '0';
13942                const currentBundle = wrapper?.querySelector('.bundles-box');
13943                const sectionInfo = AB.DATALAYER.getZoneInfo(currentBundle);
13944                const bundlePlacement = `R${bundleRow < 10 ? `0${bundleRow}` : bundleRow}#S01#ZONE${sectionInfo?.zone ? (sectionInfo?.zone < 10 ? `0${sectionInfo?.zone}` : sectionInfo?.zone) : '00'}`;
13945                const bundleInfo = {
13946                    section: data.bannerTitle,
13947                    detail: data.p13nAdobeMetrics.metricA,
13948                    placement: bundlePlacement,
13949                    type: 'bundle',
13950                    name: AB.DATALAYER.sanitizeAnalyticsText(data.bannerTitle)
13951                }
13952                bundlesToSend.push(bundleInfo);
13953            }
13954        }
13954 else if (caller === 'bundle-carousel' && bundleDataContainer) {
13955            const parsedData = AB.DATALAYER.safeJSONParse(bundleDataContainer);
13956
13957            if (parsedData?.containerItems?.length > 0) {
13958                parsedData?.containerItems.forEach((bundle) => {
13959                    if (bundle.p13nAdobeMetrics?.metricA && bundle.bundleSlugId && window.digitalData.bundlesTrackedIds.indexOf(bundle.bundleSlugId) === -1) {
13960                        const currentBundle = wrapper?.querySelector(`.bundles-box[data-analytics-id="${bundle.bundleSlugId}"]`);
13961                        if (currentBundle?.closest('.slick-active')) {
13962                            const allBundleCarousels = document.querySelectorAll('div:has(>webgen-bundles)') && Array.from(document.querySelectorAll('div:has(>webgen-bundles-carousel)'))?.filter(bundle => AB.DATALAYER.isVisible(bundle));
13963                            const allBundles = wrapper?.querySelectorAll('.bundles-box') && Array.from(wrapper?.querySelectorAll('.bundles-box')) || [];
13964                            const bundleRow = wrapper && allBundleCarousels ? allBundleCarousels?.indexOf(wrapper) + 1 : '0';
13965                            const bundleSlot = allBundles.indexOf(currentBundle) + 1;
13966                            const sectionInfo = AB.DATALAYER.getZoneInfo(currentBundle);
13967                            const bundlePlacement = `R${bundleRow < 10 ? `0${bundleRow}` : bundleRow}#S${bundleSlot < 10 ? `0${bundleSlot}` : bundleSlot}#ZONE${sectionInfo?.zone ? (sectionInfo?.zone < 10 ? `0${sectionInfo?.zone}` : sectionInfo?.zone) : '00'}`;
13968                            const bundleInfo = {
13969                                section: parsedData.headerTitle,
13970                                detail: bundle.p13nAdobeMetrics.metricA,
13971                                placement: bundlePlacement,
13972                                type: 'carousel-bundle',
13973                                name: AB.DATALAYER.sanitizeAnalyticsText(bundle.bannerTitle)
13974                            }
13975                            bundlesToSend.push(bundleInfo);
13976                            window.digitalData.bundlesTrackedIds.push(bundle.bundleSlugId);
13977                        }
13978                    }
13979                })
13980            }
13981        }
13982        const payload = {
13983            link: {
13984                linkName: 'bundle-impressions',
13985                isSendToSS: true
13986            },
13987            page: pageDetails,
13988            pageFilter: { ...digitalData?.pageFilter },
13989            user: { ...digitalData?.user },
13990            component: bundlesToSend
13991        }
13992        if (bundlesToSend.length > 0) {
13993            AB.DATALAYER.pushEvent(AB.DATALAYER.EVENTS.LINK_CLICK, payload);
13994        }
13995    }
13996
13997    this.setAMCProductsExposed = function (response, carousel, element) {
13998        if (((this.isSearchResultsPage() || this.isAislesPage() || this.isPdp()) && !this.isWineShopPage() && !window.isAnalyticsMarketplacePage) && carousel?.dataDriven === 'featured-products') {
13999            if (response?.products && response?.products?.length > 0) {
14000                let carouselProducts = [];
14001
14002                // get carousel row
14003                const parentCarousel = element?.closest('.slick-product-carousel, .bia-carousel-list-item');
14004                const visibleCarousels = this.findVisibleElement(document.querySelectorAll('.slick-product-carousel, .bia-carousel-list-item'));
14005                const carouselIndex = visibleCarousels?.indexOf(parentCarousel) + 1;
14006                const carouselRow = carouselIndex < 10 ? `R0${carouselIndex}` : `R${carouselIndex}`;
14007
14008                response.products.forEach((product, index) => {
14009                    if (AB.DATALAYER.isAlcoholAdTrackingDisabled(product)) {
14010                        return;
14011                    }
14012                    if (product.adId || product.featured || product.eventTracking) {
14013                        const productSlot = (index + 1) < 10 ? `S0${index + 1}` : `S${index + 1}`;
14014                        const placement = `${carouselRow}#${productSlot}`;
14015                        const currentProductPfm = `${AB.DATALAYER.pfmFromCurrentPage}#${this.sanitizeAnalyticsText(carousel?.title)}#${this.isSearchResultsPage() ? digitalData.search?.internalSearchTerm : 'non-search'}#sponsored#${placement}`;
14016                        carouselProducts.push({
14017                            section: carousel?.title ? AB.DATALAYER.sanitizeAnalyticsText(carousel.title) : '',
14018                            detail: product?.adobeMetrics?.metricA,
14019                            lp: product.price,
14020                            pfm: currentProductPfm,
14021                            pId: product.id,
14022                            units: product.quantity || product.qty || 0,
14023                            sponsored: true,
14024                            placement: placement,
14025                            pName: AB.DATALAYER.isPdp() ? product.name : undefined
14026                        });
14027                    }
14028                });
14029                if (carouselProducts.length > 0) {
14030                    let payload = {
14031                        link: {
14032                            linkName: `${digitalData.pageDetails.subSection1}-product-exposed`
14033                        },
14034                        page: digitalData?.pageDetails,
14035                        user: digitalData?.user,
14036                        pageFilter: digitalData?.pageFilter,
14037                        carousel: carouselProducts
14038                    };
14039                    if (AB.DATALAYER.isSearchResultsPage()) {
14040                        payload.search = digitalData.search;
14041                    }
14042                    if (AB.DATALAYER.isPdp()) {
14043                        payload.productInfo = AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('analyticsAMCPDPInfo'));
14044                    }
14045                    payload.pageFilter.mediaType = 'product-carou
14045sel';
14046                    payload.pageFilter.placement = '';
14047                    AB.DATALAYER.pushEvent('product-exposed', payload);
14048                    digitalData.pageFilter.mediaType = '';
14049                }
14050            }
14051        }
14052    }
14053
14054    /**
14055     * Sets LS item for marketplace categories
14056     */
14057    this.setMktpCategoriesLinkClick = function (category, level) {
14058        if (category) {
14059            if (this.isMarketplaceCategoryPage() && level) {
14060                const aislesPreviousPage = `aisles-${category}-${level}`;
14061                localStorage.setItem('aislesPreviousPage', aislesPreviousPage);
14062            } else if (window.location.pathname.indexOf('/marketplace/landing') !== -1) {
14063                const categoryName = document.querySelector(category)?.querySelector('.marketplace-header__categories-item-text')?.textContent;
14064                const aislesPreviousPage = `aisles-${categoryName}-home`;
14065                localStorage.setItem('aislesPreviousPage', aislesPreviousPage);
14066            }
14067        }
14068    }
14069
14070    /**
14071     * Sets topNav when filter is selected on L1, L2 and L3 marketplace
14072     */
14073    this.setTopNavMktpFilters = function (filter) {
14074        if (this.isMarketplaceCategoryPage() && window.digitalData.pageDetails) {
14075            if (!window.digitalData.pageDetails.subSection3 && !window.digitalData.pageDetails.subSection4) {
14076                digitalData.pageFilter.topNav = `aisles-${filter}-l1`;
14077            } else if (window.digitalData.pageDetails.subSection3 && !window.digitalData.pageDetails.subSection4) {
14078                digitalData.pageFilter.topNav = `aisles-${filter}-l2`;
14079            } else if (window.digitalData.pageDetails.subSection3 && window.digitalData.pageDetails.subSection4) {
14080                digitalData.pageFilter.topNav = `aisles-${filter}-l3`;
14081            }
14082        }
14083    }
14084
14085    /**
14086     * Sets custom page name and subSections on Games pages
14087     */
14088    this.initGamesPages = function () {
14089        if (!digitalData.pageDetails.subSection3) {
14090            if (digitalData.pageDetails.subSection1 === 'foru') {
14091                digitalData.pageDetails.subSection2 = 'games-landing';
14092            }
14093            digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:${digitalData.pageDetails.channel}:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}`;
14094        } else if (digitalData.pageDetails.subSection3 === 'game-details' || digitalData.pageDetails.subSection3 === 'prize-details') {
14095            digitalData.pageDetails.subSection2 = 'games';
14096            const subSection3 = digitalData.pageDetails.subSection3;
14097            const gameName = subSection3 === 'game-details' ? document.querySelector('game-grid')?.getAttribute('data-selected-game') : document.querySelector('prize-details')?.getAttribute('data-game-id');
14098            digitalData.pageDetails.subSection3 = `${gameName}${subSection3 === 'game-details' ? '-landing' : '-prize-details'}`;
14099            digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:${digitalData.pageDetails.channel}:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}:${digitalData.pageDetails.subSection3}`;
14100        }
14101        if (localStorage.getItem('analyticsPlayNow')) {
14102            digitalData.modal = digitalData.modal || {};
14103            digitalData.modal.modalMessage = localStorage.getItem('analyticsPlayNow');
14104            localStorage.removeItem('analyticsPlayNow');
14105        }
14106    }
14107
14108    /**
14109     * Sets modal click and modal view events for Games modals
14110     */
14111    this.setGamesModalEvents = function (gameName, action, event) {
14112        const eventType = event === 'view' ? this.EVENTS.MODAL_VIEW : this.EVENTS.MODAL_CLICK;
14113        this.pushEvent(
14114            eventType,
14115            {
14116                modal: {
14117                    modalAction: `${gameName}:${action}`,
14118                },
14119                page: digitalData?.pageDetails,
14120                pageFilter: digitalData?.pageFilter
14121            }
14122        );
14123    }
14124
14125    /**
14126     * Sets game_point_redeemed event when a user redeems game points
14127     */
14128    this.clipGamePoints = function (prize) {
14129        if (digitalData && prize) {
14130            digitalData.rewards = {
14131                perkPointID: `${prize.programCode}|${prize.prizeId}|${prize.name}`,
14132                perkPointsRedeemed: `${prize.programCode}|${prize.burnPoints}`
14133            }
14134            this.pushEvent(
14135                'perk_point_redeemed', {
14136                rewards: digitalData.rewards,
14137                page: digitalData?.pageDetails,
14138                pageFilter: digitalData?.pageFilter
14139            }
14140            );
14141        }
14142    }
14143
14144    /**
14145     * Sets top nav when a user clicks on 'start playing' or 'connect to play' to land on the Sign page and clicks on create account
14146     */
14147    this.createAcountHandler = function () {
14148        if (digitalData.pageFilter && digitalData.pageFilter.topNav && digitalData.pageFilter.topNav.startsWith('foru:games:')) {
14149            document.querySelector('.sign-in-wrapper.sign-in-page .btn-create-account')?.addEventListener('click', () => {
14150                this.setTopNavPreviousPage();
14151            });
14152        }
14153    }
14154
14155    this.gamesModalHandler = function (gameName, action) {
14156        document.querySelector('modal-container')?.addEventListener('click', event => {
14157            if (event.target.classList.contains('modal') && !event.target.classList.contains('shown')) {
14158                this.setGamesModalEvents(gameName, action, 'click');
14159            }
14160        });
14161    }
14162
14163    this.trackEngagementLadder = function (data, bannerWrapper) {
14164        if (data) {
14165            const bannerInfo = data['banners'] && data['banners'][0] && data['banners'][0]['optionalAttributes'];
14166            const p13nData = data['p13nData'];
14167            const campaign = data['analyticsCampaign'];
14168            if (this.isHomePage()) {
14169                let bannerP13nInfo = '';
14170                if (p13nData) {
14171                    // [MODEL CONFIGURATION ID]#[EXPERIMENT ID]#[EXPERIMENT GROUP]#[ELIGIBLE]#[MODEL ID]#[MODEL VERSION]#[FALL BACK MODEL]#[BANNERID]#[RANK]#[CAMPAIGN]
14172                    bannerP13nInfo = `${p13nData?.modelData?.modelConfigurationId || 'no-value'}#${p13nData?.experimentData?.experimentId || 'no-value'}#${p13nData?.experimentData?.experimentGroup || 'no-value'}#${p13nData?.experimentData?.eligible}#${p13nData?.modelData?.modelId || 'no-value'}#${p13nData?.modelData?.modelVersion || 'no-value'}#${p13nData?.modelData?.fallbackModel === false ? 'false' : p13nData?.modelData?.fallbackModel ? p13nData?.modelData.fallbackModel : 'no-value'}#${bannerInfo?.name || 'no-value'}#${p13nData?.recommendationData?.rank || 'no-value'}#${campaign || 'no-value'}`;
14173                }
14174                if (bannerInfo && bannerInfo.segments) {
14175                    localStorage.setItem('analyticsEngagementLadder', bannerInfo.segments);
14176                    if (bannerP13nInfo) {
14177                        localStorage.setItem('analyticsEngagementLadderAbTestInfo', bannerP13nInfo);
14178                    }
14179                    document.querySelectorAll('.banner-unit-medium__text-plate__cta, .banner-unit-medium__image')?.forEach(element => {
14180                        element.addEventListener('click', event => {
14181                            const bannerApiSource = event.target.closest('.nextgen-banner-unit-wrapper')?.querySelector('nextgen-banner-unit-wc')?.dataset?.bannerApiSource;
14182                            if (bannerApiSource === 'p13nSegmentedApi') {
14183                                localStorage.setItem('analyticsEngagementLadderClicked', bannerInfo.segments);
14184                                if (bannerP13nInfo) {
14185                                    localStorage.setItem('analyticsEngagementLadderAbTestInfo', bannerP13nInfo);
14186                                }
14187                            }
14188                        });
14189                    });
14190                }
14191                const isP13nBanner = bannerWrapper?.closest('.nextgen-banner-unit-wrapper')?.querySelector('nextgen-banner-unit-wc')?.dataset?.bannerApiSource === 'p13nSegmentedApi';
14192                if (isP13nBanner) {
14193                    this.setP13nEngagementLadderImpressions(data, bannerWrapper)
14194                }
14195            }
14196        }
14197    }
14198
14199    this.initEngagementLadderImpressions = function () {
14200        let analyticsEngagementLadder = AB.DATALAYER.handleGetLSValue('analyticsEngagementLadder');
14201        let analyticsEngagementLadderAbTestInfo = AB.DATALAYER.handleGetLSValue('analyticsEngagementLadderAbTestInfo');
14202        let analyticsEngagementLadderClicked = AB.DATALAYER.handleGetLSValue('analyticsEngagementLadderClicked');
14203
14204        if (analyticsEngagementLadder) {
14205            digitalData.pageDetails.engagementLadderImpressions = `web-home-engagement-ladder|${analyticsEngagementLadder}`;
14206        } else if (this.isBIAPage() && digitalData.pageDetails?.engagementLadderImpressions) {
14207            digitalData.pageDetails.engagementLadderImpressions = '';
14208        }
14209        if (analyticsEngagementLadderAbTestInfo) {
14210            digitalData.pageDetails.abTestDetails = analyticsEngagementLadderAbTestInfo;
14211        }
14212        if (analyticsEngagementLadderClicked) {
14213            digitalData.pageDetails.engagementLadderImpressions = `web-home-engagement-ladder|${analyticsEngagementLadderClicked}`;
14214            digitalData.pageFilter.topNav = `cta:home|engagement-ladder|${analyticsEngagementLadderClicked}`;
14215        }
14216    }
14217
14218    this.initCartPromoBannerImpressions = function () {
14219        if (this.getLSItem('analyticsCartPromoBanner')) {
14220            digitalData.pageFilter.impressions = `${digitalData.pageFilter.impressions ? `${digitalData.pageFilter.impressions},` : ''}${this.handleGetLSValue('analyticsCartPromoBanner')}`;
14221        }
14222    }
14223
14224
14225    this.getFlexBannerAnalyticsValue = function (value, fallback = 'no-value') {
14226        return this.sanitizeAnalyticsText(value?.trim() || fallback) || fallback;
14227    }
14228
14229    this.padFlexBannerAnalyticsIndex = function (value) {
14230        const parsedValue = Number(value);
14231        if (!Number.isFinite(parsedValue)) {
14232            return '01';
14233        }
14234        return parsedValue < 10 ? `0${parsedValue}` : `${parsedValue}`;
14235    }
14236
14237    this.normalizeFlexBannerZone = function (zone) {
14238        const zoneValue = zone?.trim();
14239        const zoneNumber = zoneValue?.match(/^zone(\d+)$/i)?.[1];
14240
14241        return zoneNumber ? `z${this.padFlexBannerAnalyticsIndex(zoneNumber)}` : zoneValue || 'z01';
14242    }
14243
14244    this.setFlexBannerClickTracking = function (linkElement) {
14245        if (!window.digitalData || !linkElement) {
14246            return false;
14247        }
14248
14249        const clickedElement = linkElement;
14250        const moduleElement = clickedElement?.closest?.('webgen-flex-module');
14251        const renderedFlexElement = clickedElement?.closest?.('.flex-medium-fw, .flex-container, .hero-flex') || moduleElement?.querySelector?.('.flex-medium-fw, .flex-container, .hero-flex') || moduleElement;
14252        const carouselProxy = renderedFlexElement?.closest?.('.nextgen-abs-carousel-proxy');
14253        const allVisibleFlexRows = document.querySelectorAll('.nextgen-abs-carousel-proxy .flex-medium-fw, .nextgen-abs-carousel-proxy .flex-container, .nextgen-abs-carousel-proxy .hero-flex')?.length > 0
14254            ? Array.from(document.querySelectorAll('.nextgen-abs-carousel-proxy .flex-medium-fw, .nextgen-abs-carousel-proxy .flex-container, .nextgen-abs-carousel-proxy .hero-flex'))
14255            : [];
14256        const flexIndex = allVisibleFlexRows.indexOf(renderedFlexElement) + 1 || 1;
14257        const currentCard = clickedElement?.closest?.('.flex-card, .hero-flex__card');
14258        const availableSpots = renderedFlexElement?.querySelectorAll?.('.flex-card, .hero-flex__card')?.length > 0
14259            ? Array.from(renderedFlexElement.querySelectorAll('.flex-card, .hero-flex__card'))
14260            : [];
14261        const derivedSpotIndex = currentCard && availableSpots.length > 0 ? availableSpots.indexOf(currentCard) + 1 : 1;
14262        const spotIndex = derivedSpotIndex > 0 ? derivedSpotIndex : 1;
14263        const parsedFlexData = this.safeJSONParse(moduleElement?.getAttribute?.('data-flex-module-content')) || {};
14264        const containerItems = Array.isArray(parsedFlexData?.containerItems) ? parsedFlexData.containerItems : [];
14265        const currentItemData = containerItems[spotIndex - 1] || {};
14266        const zoneInfo = AB.DATALAYER.getZoneInfo(renderedFlexElement)?.zone;
14267        const zone = this.normalizeFlexBannerZone(zoneInfo ? `zone${zoneInfo}` : '');
14268        const spot = `sp${this.padFlexBannerAnalyticsIndex(spotIndex)}`;
14269        const placement = `r${this.padFlexBannerAnalyticsIndex(flexIndex)}#s${this.padFlexBannerAnalyticsIndex(spotIndex)}`;
14270        const cardTitle = this.getFlexBannerAnalyticsValue(
14271            currentCard?.querySelector?.('.flex-card__title')?.textContent
14272            || renderedFlexElement?.querySelector?.('.flex-medium-fw__text-plate__heading')?.textContent
14273            || currentCard?.querySelector?.('.hero-flex-full-bleed__text-box__title, .hero-flex-color-block__text-box__title')?.textContent
14274            || currentItemData?.title
14275            || parsedFlexData?.title
14276            || parsedFlexData?.bannerTitle
14277            || parsedFlexData?.heading
14278        );
14279        const carouselTitle = this.getFlexBannerAnalyticsValue(
14280            carouselProxy?.querySelector?.('h2.flex-title')?.textContent
14281            || renderedFlexElement?.closest?.('.hero-canvas-row')?.querySelector?.('h2.flex-title')?.textContent
14282            || renderedFlexElement?.getAttribute?.('aria-label')
14283            || parsedFlexData?.headerText
14284            || parsedFlexData?.containerHeading
14285            || parsedFlexData?.sectionHeading
14286            || parsedFlexData?.name
14287        );
14288        const uniqueId = this.getFlexBannerAnalyticsValue(
14289            currentItemData?.promotionId
14290            || currentItemData?.promoId
14291            || currentItemData?.id
14292            || currentCard?.getAttribute?.('data-gam-slot-id')
14293            || clickedElement?.getAttribute?.('data-target')
14294            || parsedFlexData?.promotionId
14295            || parsedFlexData?.promoId
14296            || parsedFlexData?.id
14297        );
14298        const metricA = parsedFlexData?.p13nAdobeMetrics?.metricA
14299            || parsedFlexData?.adobeMetrics?.metricA
14300            || currentItemData?.p13nAdobeMetrics?.metricA
14301            || currentItemData?.adobeMetrics?.metricA
14302            || 'generic';
14303        const bannerCardCarousel = `${zone}|flex|flex-${this.padFlexBannerAnalyticsIndex(flexIndex)}:${cardTitle}:${carouselTitle}|${spot}|${uniqueId}`;
14304        const isSponsoredFlexBanner = (parsedFlexData?.program && parsedFlexData.program !== 'abs') || (currentItemData?.program && currentItemData.program !== 'abs');
14305        const recommendationType = isSponsoredFlexBanner
14306            ? 'sponsored'
14307            : 'not-sponsored';
14308
14309        digitalData.pageFilter = digitalData.pageFilter || {};
14310        digitalData.pageFilter.bannerCardCarousel = bannerCardCarousel;
14311        digitalData.pageFilter.mediaType = 'flex-sponsored';
14312        digitalData.pageFilter.recommendationType = recommendationType;
14313        digitalData.pageFilter.placement = placement;
14314
14315        this.pushEvent(
14316            this.EVENTS.LINK_CLICK,
14317            {
14318                link: {
14319                    linkName: `bannerclicked|${cardTitle}`,
14320                    oneTagLinkName: 'banner-clicked'
14321                },
14322                pageFilter: structuredClone(digitalData.pageFilter),
14323                page: {
14324                    ...structuredClone(digitalData.pageDetails),
14325                    feature: 'flex-banner|shop-ex|501655|423334',
14326                    bnrName: `${cardTitle}|no-value`,
14327                    abTestDetails: metricA
14328                }
14329            }
14330        );
14331
14332        return true;
14333    };
14334
14335    this.setFlexCardDetails = function (element) {
14336        const currentParent = element?.closest('.flex-container');
14337        const flexZones = document.querySelectorAll('.nextgen-abs-carousel-proxy .flex-container')?.length > 0 ? Array.from(document.querySelectorAll('.nextgen-abs-carousel-proxy .flex-container')) : [];
14338        const currentZonePosition = flexZones.indexOf(currentParent) + 1 < 10 ? `0${flexZones.indexOf(currentParent) + 1}` : `${flexZones.indexOf(currentParent) + 1}`;
14339        const availableSpots = currentParent.querySelectorAll('.flex-card').length > 0 ? Array.from(currentParent.querySelectorAll('.flex-card')) : [];
14340        const currentCard = element?.closest('.flex-card');
14341        const currentSpot = availableSpots.indexOf(currentCard) + 1;
14342        const currentTitle = currentCard?.querySelector('.flex-card__title') ? this.sanitizeAnalyticsText(currentCard.querySelector('.flex-card__title').textContent?.trim()) : 'Error - Cannot find title element';
14343        const currentParentTitle = this.sanitizeAnalyticsText(element.closest('.nextgen-abs-carousel-proxy')?.querySelector('h2.flex-title')?.textContent?.trim()) || 'no-value';
14344        const contentType = `flex-card-${currentSpot}:${currentTitle}:${currentParentTitle}`;
14345        const flexPosition = `z${currentZonePosition}|flex|${contentType}|sp${currentSpot < 10 ? `0${currentSpot}` : currentSpot}`;
14346        // localStorage.setItem('flexCardAnalytics', flexPosition);
14347
14348        this.trackAEMZone('flex', element, contentType);
14349    }
14350
14351    this.trackCRSHomeModuleImpression = function ({ element, mediaType, placement, component } = {}) {
14352        if (!AB.DATALAYER.isCESEventsEnabled() || !element || element.dataset?.crsImpressionTracked === 'true' || !AB.DATALAYER.isHomePage()) {
14353            return; 
14354        }
14355
14356        AB.DATALAYER.setCRSClickEvent({
14357            linkName: 'item-click',
14358            mTyp: mediaType,
14359            element: element,
14360            placement: placement,
14361            caasEnbld: AB.DATALAYER.isCRSHomeCaasEnabled(element),
14362            component: component
14363        });
14364        element.dataset.crsImpressionTracked = 'true';
14365    }
14366
14367    this.trackFlexModuleImpression = function (moduleElement) {
14368        if (!moduleElement || !digitalData) {
14369            return;
14370        }
14371
14372        const renderedFlexElement = moduleElement.querySelector('.flex-medium-fw, .flex-container') || moduleElement;
14373        if (!renderedFlexElement || renderedFlexElement.dataset?.flexImpressionTracked === 'true') {
14374            return;
14375        }
14376
14377        const carouselProxy = renderedFlexElement.closest('.nextgen-abs-carousel-proxy');
14378        const allVisibleFlexRows = document.querySelectorAll('.nextgen-abs-carousel-proxy .flex-medium-fw, .nextgen-abs-carousel-proxy .flex-container')?.length > 0
14379            ? Array.from(document.querySelectorAll('.nextgen-abs-carousel-proxy .flex-medium-fw, .nextgen-abs-carousel-proxy .flex-container'))
14380            : [];
14381
14382        const parsedFlexData = this.safeJSONParse(moduleElement.getAttribute('data-flex-module-content')) || {};
14383        const rowIndex = allVisibleFlexRows.indexOf(renderedFlexElement) + 1;
14384        const row = rowIndex > 0 ? rowIndex : 1;
14385        const sectionTitle = this.sanitizeAnalyticsText(
14386            carouselProxy?.querySelector('h2.flex-title')?.textContent?.trim()
14387            || renderedFlexElement?.querySelector('.flex-medium-fw__text-plate__heading, .flex-title, [class*="heading"]')?.textContent?.trim()
14388            || parsedFlexData?.title
14389            || parsedFlexData?.bannerTitle
14390            || parsedFlexData?.heading
14391            || parsedFlexData?.containerHeading
14392            || parsedFlexData?.sectionHeading
14393            || parsedFlexData?.name
14394            || ''
14395        ) || 'flex-module';
14396        const containerItems = Array.isArray(parsedFlexData?.containerItems) ? parsedFlexData.containerItems : [];
14397        const type = containerItems.length > 1 ? 'flex-tiles' : 'flex-no-tile';
14398        const metricA = parsedFlexData?.p13nAdobeMetrics?.metricA
14399            || parsedFlexData?.adobeMetrics?.metricA
14400            || containerItems.find(item => item?.p13nAdobeMetrics?.metricA || item?.adobeMetrics?.metricA)?.p13nAdobeMetrics?.metricA
14401            || containerItems.find(item => item?.p13nAdobeMetrics?.metricA || item?.adobeMetrics?.metricA)?.adobeMetrics?.metricA;
14402        const detail = metricA || 'generic';
14403        const zoneInfo = AB.DATALAYER.getZoneInfo(renderedFlexElement)?.zone;
14404        const placement = `r${row < 10 ? `0${row}` : row}#s01#z${zoneInfo && zoneInfo > 0 ? (zoneInfo < 10 ? `0${zoneInfo}` : zoneInfo) : '00'}`;
14405
14406        const payload = {
14407            link: {
14408                linkName: 'flex-impressions',
14409                isSendToSS: true
14410            },
14411            page: {
14412                ...digitalData?.pageDetails,
14413                deviceType: digitalData?.pageDetails?.deviceType
14414            },
14415            pageFilter: {
14416                ...digitalData?.pageFilter,
14417                mediaType: 'flex-module',
14418                placement: placement
14419            },
14420            user: digitalData?.user,
14421            component: [{
14422                section: sectionTitle,
14423                detail: detail,
14424                placement: placement,
14425                type: type,
14426                name: 'flex-module'
14427            }]
14428        };
14429
14430        AB.DATALAYER.pushEvent(AB.DATALAYER.EVENTS.LINK_CLICK, payload);
14431        if (AB.DATALAYER.isCESEventsEnabled() || AB.DATALAYER.isHomePage()) {
14432                AB.DATALAYER.trackCRSHomeModuleImpression({
14433                element: renderedFlexElement,
14434                mediaType: 'flex-module',
14435                placement: placement,
14436                component: payload.component
14437            });
14438        }
14439
14440        renderedFlexElement.dataset.flexImpressionTracked = 'true';
14441    }
14442
14443    this.trackFlexModuleExposureOnLoad = function (moduleElement) {
14444        if (!moduleElement || !digitalData) {
14445            return;
14446        }
14447
14448        if (moduleElement.dataset?.flexExposureLoadedTracked === 'true') {
14449            return;
14450        }
14451
14452        const parsedFlexData = this.safeJSONParse(moduleElement.getAttribute('data-flex-module-content')) || {};
14453        if (!parsedFlexData || Object.keys(parsedFlexData).length === 0) {
14454            return;
14455        }
14456
14457        const renderedFlexElement = moduleElement.querySelector('.flex-medium-fw, .flex-container') || moduleElement;
14458        const allVisibleFlexRows = document.querySelectorAll('.nextgen-abs-carousel-proxy .flex-medium-fw, .nextgen-abs-carousel-proxy .flex-container')?.length > 0
14459            ? Array.from(document.querySelectorAll('.nextgen-abs-carousel-proxy .flex-medium-fw, .nextgen-abs-carousel-proxy .flex-container'))
14460            : [];
14461
14462        const rowIndex = allVisibleFlexRows.indexOf(renderedFlexElement) + 1;
14463        const zoneInfoObj = AB.DATALAYER.getZoneInfo(renderedFlexElement);
14464        const rowFromZone = Number(zoneInfoObj?.row) > 0 ? Number(zoneInfoObj.row) : 0;
14465        const row = rowFromZone || (rowIndex > 0 ? rowIndex : 1);
14466        const zoneFromInfo = Number(zoneInfoObj?.zone) > 0 ? Number(zoneInfoObj.zone) : 0;
14467        const zoneSource = renderedFlexElement?.getAttribute('data-zone')
14468            || moduleElement?.getAttribute('data-zone')
14469            || renderedFlexElement?.closest?.('[data-zone]')?.getAttribute?.('data-zone')
14470            || moduleElement?.closest?.('[data-zone]')?.getAttribute?.('data-zone')
14471            || '';
14472        const zoneMatch = `${zoneSource}`.match(/(\d+)/);
14473        const zoneFromData = zoneMatch && zoneMatch[1] ? Number(zoneMatch[1]) : 0;
14474        const zone = zoneFromInfo || zoneFromData || row || 1;
14475        const slotSource = renderedFlexElement?.getAttribute('data-abs-carousel-slot')
14476            || moduleElement?.getAttribute('data-abs-carousel-slot')
14477            || parsedFlexData?.slot
14478            || parsedFlexData?.position
14479            || '';
14480        const slotMatch = `${slotSource}`.match(/(\d+)/);
14481        const slot = slotMatch && slotMatch[1] ? Number(slotMatch[1]) : 1;
14482        const placement = `r${row < 10 ? `0${row}` : row}#s${slot < 10 ? `0${slot}` : slot}#z${zone < 10 ? `0${zone}` : zone}`;
14483
14484        const containerItems = Array.isArray(parsedFlexData?.containerItems) ? parsedFlexData.containerItems : [];
14485        const sectionTitle = this.sanitizeAnalyticsText(
14486            renderedFlexElement?.querySelector('.flex-medium-fw__text-plate__heading, .flex-title, [class*="heading"]')?.textContent?.trim()
14487            || parsedFlexData?.title
14488            || parsedFlexData?.bannerTitle
14489            || parsedFlexData?.heading
14490            || parsedFlexData?.containerHeading
14491            || parsedFlexData?.sectionHeading
14492            || parsedFlexData?.name
14493            || ''
14494        ) || 'flex-module';
14495        const type = containerItems.length > 1 ? 'flex-tiles' : 'flex-no-tile';
14496        const normalizeMsgExperiment = (value) => {
14497            if (value === undefined || value === null) {
14498                return '';
14499            }
14500            const normalized = `${value}`.trim();
14501            if (!normalized) {
14502                return '';
14503            }
14504            const lowered = normalized.toLowerCase();
14505            if (lowered === 'undefined' || lowered === 'null' || lowered === 'no-value') {
14506                return '';
14507            }
14508            return normalized;
14509        };
14510
14511        const itemWithMsgExperiment = containerItems.find(item => item?.p13nAdobeMetrics?.msgExperiment
14512            || item?.p13adobemetric?.msgExperiment
14513            || item?.adobeMetrics?.msgExperiment
14514            || item?.response?.p13nAdobeMetrics?.msgExperiment
14515            || item?.response?.p13adobemetric?.msgExperiment
14516            || item?.response?.adobeMetrics?.msgExperiment) || {};
14517        const msgExperimentCandidates = [
14518            parsedFlexData?.p13nAdobeMetrics?.msgExperiment,
14519            parsedFlexData?.p13adobemetric?.msgExperiment,
14520            parsedFlexData?.adobeMetrics?.msgExperiment,
14521            parsedFlexData?.response?.p13nAdobeMetrics?.msgExperiment,
14522            parsedFlexData?.response?.p13adobemetric?.msgExperiment,
14523            parsedFlexData?.response?.adobeMetrics?.msgExperiment,
14524            itemWithMsgExperiment?.p13nAdobeMetrics?.msgExperiment,
14525            itemWithMsgExperiment?.p13adobemetric?.msgExperiment,
14526            itemWithMsgExperiment?.adobeMetrics?.msgExperiment,
14527            itemWithMsgExperiment?.response?.p13nAdobeMetrics?.msgExperiment,
14528            itemWithMsgExperiment?.response?.p13adobemetric?.msgExperiment,
14529            itemWithMsgExperiment?.response?.adobeMetrics?.msgExperiment
14530        ];
14531        const msgExperiment = msgExperimentCandidates
14532            .map(candidate => normalizeMsgExperiment(candidate))
14533            .find(candidate => !!candidate) || 'generic';
14534
14535        const payload = {
14536            event: {
14537                name: 'pageAction',
14538                subEvent: 'experiment-exposure'
14539            },
14540            link: {
14541                name: 'flex-experiment-exposure-loaded',
14542                linkName: 'flex-experiment-exposure-loaded',
14543                isSendToSS: true
14544            },
14545            page: {
14546                ...digitalData?.pageDetails,
14547                abTestDetails: msgExperiment,
14548                deviceType: digitalData?.pageDetails?.deviceType
14549            },
14550            pageFilter: {
14551                ...digitalData?.pageFilter,
14552                mediaType: 'flex-module',
14553                placement: placement
14554            },
14555            user: digitalData?.user,
14556            component: [{
14557                section: sectionTitle,
14558                detail: msgExperiment,
14559                placement: placement,
14560                type: type,
14561                name: 'flex-module'
14562            }]
14563        };
14564
14565        AB.DATALAYER.pushEvent(AB.DATALAYER.EVENTS.LINK_CLICK, payload);
14566        moduleElement.dataset.flexExposureLoadedTracked = 'true';
14567    }
14568
14569    this.initFlexModuleExposureOnLoad = function () {
14570        const flexModules = document.querySelectorAll('webgen-flex-module');
14571        if (!flexModules || flexModules.length === 0) {
14572            return;
14573        }
14574
14575        flexModules.forEach(moduleElement => {
14576            AB.DATALAYER.trackFlexModuleExposureOnLoad(moduleElement);
14577        });
14578    }
14579
14580    this.initFlexModuleImpressions = function () {
14581        const flexModules = document.querySelectorAll('webgen-flex-module');
14582        if (!flexModules || flexModules.length === 0) {
14583            return;
14584        }
14585
14586        if (!this.flexImpressionObserver && typeof IntersectionObserver !== 'undefined') {
14587            this.flexImpressionObserver = new IntersectionObserver((entries, observer) => {
14588                entries.forEach(entry => {
14589                    if (entry?.isIntersecting && entry.intersectionRatio >= 0.75) {
14590                        AB.DATALAYER.trackFlexModuleImpression(entry.target);
14591                        observer.unobserve(entry.target);
14592                    }
14593                });
14594            }, {
14595                root: null,
14596                rootMargin: '0px',
14597                threshold: [0.75]
14598            });
14599        }
14600
14601        flexModules.forEach(moduleElement => {
14602            if (moduleElement?.dataset?.flexObserverAttached === 'true') {
14603                return;
14604            }
14605
14606            if (this.flexImpressionObserver) {
14607                this.flexImpressionObserver.observe(moduleElement);
14608                moduleElement.dataset.flexObserverAttached = 'true';
14609            } else {
14610                AB.DATALAYER.trackFlexModuleImpression(moduleElement);
14611            }
14612        });
14613    }
14614
14615    this.getCollectionTrackingData = function (collectionElement) {
14616        const hostElement = collectionElement?.closest?.('webgen-bundles, webgen-bundles-carousel') || collectionElement;
14617        const wrapper = hostElement?.parentElement || hostElement;
14618        const isCarousel = hostElement?.tagName?.toLowerCase?.() === 'webgen-bundles-carousel';
14619        const rawData = hostElement?.getAttribute?.(isCarousel ? 'data-bundles-carousel-content' : 'data-bundles-content')
14620            || hostElement?.getAttribute?.('data-bundles-content')
14621            || hostElement?.getAttribute?.('data-bundles-carousel-content');
14622        const parsedData = AB.DATALAYER.safeJSONParse(rawData) || {};
14623
14624        return {
14625            hostElement: hostElement,
14626            wrapper: wrapper,
14627            isCarousel: isCarousel,
14628            data: parsedData
14629        };
14630    }
14631
14632    this.getCollectionImpressionItems = function (collectionElement) {
14633        const trackingData = AB.DATALAYER.getCollectionTrackingData(collectionElement);
14634        const hostElement = trackingData.hostElement;
14635        const wrapper = trackingData.wrapper;
14636        const data = trackingData.data;
14637        const itemsToSend = [];
14638
14639        if (!hostElement || hostElement.dataset?.collectionImpressionTracked === 'true') {
14640            return itemsToSend;
14641        }
14642
14643        window.digitalData.bundlesTrackedIds = window.digitalData.bundlesTrackedIds || [];
14644
14645        if (trackingData.isCarousel && Array.isArray(data?.containerItems) && data.containerItems.length > 0) {
14646            const allBundleCarousels = Array.from(document.querySelectorAll('webgen-bundles-carousel'))
14647                .map(element => element.parentElement || element)
14648                .filter(element => AB.DATALAYER.isVisible(element));
14649            const allBundles = wrapper?.querySelectorAll?.('.bundles-box') ? Array.from(wrapper.querySelectorAll('.bundles-box')) : [];
14650            const row = Math.max(allBundleCarousels.indexOf(wrapper) + 1, 1);
14651
14652            data.containerItems.forEach((bundle, index) => {
14653                const bundleId = bundle?.bundleSlugId || `${hostElement.id || 'bundle-carousel'}-${index}`;
14654                if (window.digitalData.bundlesTrackedIds.indexOf(bundleId) !== -1) {
14655                    return;
14656                }
14657
14658                const currentBundle = bundle?.bundleSlugId ? wrapper?.querySelector?.(`.bundles-box[data-analytics-id="${bundle.bundleSlugId}"]`) : allBundles[index];
14659                if (currentBundle && !currentBundle.closest('.slick-active') && !AB.DATALAYER.isVisible(currentBundle)) {
14660                    return;
14661                }
14662
14663                const slot = allBundles.indexOf(currentBundle) + 1 > 0 ? allBundles.indexOf(currentBundle) + 1 : index + 1;
14664                const sectionInfo = AB.DATALAYER.getZoneInfo(currentBundle || hostElement);
14665                const placement = `R${row < 10 ? `0${row}` : row}#S${slot < 10 ? `0${slot}` : slot}#ZONE${sectionInfo?.zone ? (sectionInfo.zone < 10 ? `0${sectionInfo.zone}` : sectionInfo.zone) : '00'}`;
14666                const title = bundle?.bannerTitle || bundle?.title || data?.headerTitle || 'collection';
14667                itemsToSend.push({
14668                    section: data?.headerTitle || title,
14669                    detail: bundle?.p13nAdobeMetrics?.metricA || bundle?.adobeMetrics?.metricA || data?.p13nAdobeMetrics?.metricA || data?.adobeMetrics?.metricA || 'generic',
14670                    placement: placement,
14671                    type: 'carousel-bundle',
14672                    name: AB.DATALAYER.sanitizeAnalyticsText(title)
14673                });
14674                window.digitalData.bundlesTrackedIds.push(bundleId);
14675            });
14676        } else if (data && Object.keys(data).length > 0) {
14677            const allSingleBundles = Array.from(document.querySelectorAll('webgen-bundles'))
14678                .map(element => element.parentElement || element)
14679                .filter(element => AB.DATALAYER.isVisible(element));
14680            const row = Math.max(allSingleBundles.indexOf(wrapper) + 1, 1);
14681            const currentBundle = wrapper?.querySelector?.('.bundles-box') || hostElement;
14682            const sectionInfo = AB.DATALAYER.getZoneInfo(currentBundle);
14683            const placement = `R${row < 10 ? `0${row}` : row}#S01#ZONE${sectionInfo?.zone ? (sectionInfo.zone < 10 ? `0${sectionInfo.zone}` : sectionInfo.zone) : '00'}`;
14684            const title = data?.bannerTitle || data?.title || data?.headerTitle || 'collection';
14685            const bundleId = data?.bundleSlugId || hostElement.id || `${title}-${placement}`;
14686
14687            if (window.digitalData.bundlesTrackedIds.indexOf(bundleId) === -1) {
14688                itemsToSend.push({
14689                    section: title,
14690                    detail: data?.p13nAdobeMetrics?.metricA || data?.adobeMetrics?.metricA || 'generic',
14691                    placement: placement,
14692                    type: 'bundle',
14693                    name: AB.DATALAYER.sanitizeAnalyticsText(title)
14694                });
14695                window.digitalData.bundlesTrackedIds.push(bundleId);
14696            }
14697        }
14698
14699        return itemsToSend;
14700    }
14701
14702    this.trackCollectionImpression = function (collectionElement) {
14703        if (!AB.DATALAYER.isCESEventsEnabled() || !collectionElement || !digitalData) {
14704            return;
14705        }
14706
14707        const trackingData = AB.DATALAYER.getCollectionTrackingData(collectionElement);
14708        const hostElement = trackingData.hostElement;
14709        const component = AB.DATALAYER.getCollectionImpressionItems(collectionElement);
14710
14711        if (!hostElement || hostElement.dataset?.collectionImpressionTracked === 'true' || component.length === 0) {
14712            return;
14713        }
14714
14715        const firstPlacement = component[0]?.placement || '';
14716        const payload = {
14717            link: {
14718                linkName: 'bundle-impressions',
14719                isSendToSS: true
14720            },
14721            page: {
14722                ...digitalData?.pageDetails,
14723                deviceType: digitalData?.pageDetails?.deviceType
14724            },
14725            pageFilter: {
14726                ...digitalData?.pageFilter,
14727                mediaType: 'collections',
14728                placement: firstPlacement
14729            },
14730            user: digitalData?.user,
14731            component: component
14732        };
14733
14734        AB.DATALAYER.pushEvent(AB.DATALAYER.EVENTS.LINK_CLICK, payload);
14735        AB.DATALAYER.trackCRSHomeModuleImpression({
14736            element: hostElement,
14737            mediaType: 'collections',
14738            placement: firstPlacement,
14739            component: component
14740        });
14741        hostElement.dataset.collectionImpressionTracked = 'true';
14742    }
14743
14744    this.initCollectionImpressions = function () {
14745        const collectionModules = document.querySelectorAll('webgen-bundles, webgen-bundles-carousel');
14746        if (!collectionModules || collectionModules.length === 0) {
14747            return;
14748        }
14749
14750        if (!this.collectionImpressionObserver && typeof IntersectionObserver !== 'undefined') {
14751            this.collectionImpressionObserver = new IntersectionObserver((entries, observer) => {
14752                entries.forEach(entry => {
14753                    if (entry?.isIntersecting && entry.intersectionRatio >= 0.75) {
14754                        AB.DATALAYER.trackCollectionImpression(entry.target);
14755                        observer.unobserve(entry.target);
14756                    }
14757                });
14758            }, {
14759                root: null,
14760                rootMargin: '0px',
14761                threshold: [0.75]
14762            });
14763        }
14764
14765        collectionModules.forEach(moduleElement => {
14766            if (moduleElement?.dataset?.collectionObserverAttached === 'true') {
14767                return;
14768            }
14769
14770            if (this.collectionImpressionObserver) {
14771                this.collectionImpressionObserver.observe(moduleElement);
14772                moduleElement.dataset.collectionObserverAttached = 'true';
14773            } else {
14774                AB.DATALAYER.trackCollectionImpression(moduleElement);
14775            }
14776        });
14777    }
14778
14779    /**
14780     * Maps a Blog component designType (imageBlog | textBlog | recipeBlog) to the
14781     * analytics "type" token used for the [TYPE]-impressions subEvent.
14782     */
14783    this.getBlogImpressionType = function (designType) {
14784        const normalized = (designType || '').toString().toLowerCase();
14785        if (normalized.indexOf('image') !== -1) {
14786            return 'image';
14787        }
14788        if (normalized.indexOf('recipe') !== -1) {
14789            return 'recipe';
14790        }
14791        if (normalized.indexOf('text') !== -1) {
14792            return 'text';
14793        }
14794        return '';
14795    }
14796
14797    /**
14798     * Tracks a single Blog component (image / text / recipe variation) impression once it
14799     * reaches the 75% in-viewport threshold. Sends a [TYPE]-impressions linkClick event
14800     * which is routed by the OneTag layer to /ocat/impression/serversidetag/event/.
14801     */
14802    this.trackBlogComponentImpression = function (blogElement) {
14803        if (!blogElement || !digitalData) {
14804            return;
14805        }
14806        if (blogElement.dataset?.blogImpressionTracked === 'true') {
14807            return;
14808        }
14809
14810        const parsedBlogData = this.safeJSONParse(
14811            blogElement.getAttribute('data-blog-component')
14812            || blogElement.getAttribute('data-blog-component-content')
14813        ) || {};
14814
14815        const blogType = AB.DATALAYER.getBlogImpressionType(parsedBlogData?.designType);
14816        if (!blogType) {
14817            return;
14818        }
14819
14820        const allBlogElements = Array.from(document.querySelectorAll('webgen-blog-component'))
14821            .filter(element => AB.DATALAYER.isVisible(element));
14822        const rowIndex = allBlogElements.indexOf(blogElement) + 1;
14823        const row = rowIndex > 0 ? rowIndex : 1;
14824        const zoneInfo = AB.DATALAYER.getZoneInfo(blogElement)?.zone;
14825        const placement = `r${row < 10 ? `0${row}` : row}#s01#z${zoneInfo && zoneInfo > 0 ? (zoneInfo < 10 ? `0${zoneInfo}` : zoneInfo) : '00'}`;
14826
14827        const sectionTitle = AB.DATALAYER.sanitizeAnalyticsText(parsedBlogData?.title || parsedBlogData?.eyebrow || '') || 'blog';
14828        const detail = parsedBlogData?.p13nAdobeMetrics?.metricA
14829            || parsedBlogData?.adobeMetrics?.metricA
14830            || 'no-value';
14831
14832        // Name: itemName/title slugified per spec (lowercase, spaces -> hyphens).
14833        const rawName = parsedBlogData?.itemName || parsedBlogData?.title || `${blogType}-blog`;
14834        const name = `${rawName}`
14835            .toString()
14836            .toLowerCase()
14837            .replace(/[^a-z0-9]+/g, '-')
14838            .replace(/^-+|-+$/g, '');
14839
14840        // Sponsored: derived from disclaimer/secondaryDisclaimer fields.
14841        const sponsoredText = `${parsedBlogData?.secondaryWebDisclaimerText || parsedBlogData?.secondaryDisclaimerText || parsedBlogData?.disclaimerText || ''}`.toLowerCase();
14842        const sponsored = sponsoredText.indexOf('sponsor') !== -1 ? 'true' : 'false';
14843
14844        const linkName = `${blogType}-impressions`;
14845
14846        const payload = {
14847            event: {
14848                name: 'pageAction',
14849                subEvent: linkName
14850            },
14851            link: {
14852                linkName: linkName,
14853                name: linkName,
14854                isSendToSS: true
14855            },
14856            page: { ...digitalData?.pageDetails },
14857            pageFilter: {
14858                ...digitalData?.pageFilter,
14859                mediaType: 'collections',
14860                placement: placement
14861            },
14862            user: { ...digitalData?.user },
14863            component: [{
14864                section: sectionTitle,
14865                detail: detail,
14866                placement: placement,
14867                type: blogType,
14868                name: name,
14869                sponsored: sponsored
14870            }]
14871        };
14872
14873        AB.DATALAYER.pushEvent(AB.DATALAYER.EVENTS.LINK_CLICK, payload);
14874        blogElement.dataset.blogImpressionTracked = 'true';
14875    }
14876
14877    this.initBlogImpressions = function () {
14878        const blogElements = document.querySelectorAll('webgen-blog-component');
14879        if (!blogElements || blogElements.length === 0) {
14880            return;
14881        }
14882
14883        if (!this.blogImpressionObserver && typeof IntersectionObserver !== 'undefined') {
14884            this.blogImpressionObserver = new IntersectionObserver((entries, observer) => {
14885                entries.forEach(entry => {
14886                    if (entry?.isIntersecting && entry.intersectionRatio >= 0.75) {
14887                        AB.DATALAYER.trackBlogComponentImpression(entry.target);
14888                        observer.unobserve(entry.target);
14889                    }
14890                });
14891            }, {
14892                root: null,
14893                rootMargin: '0px',
14894                threshold: [0.75]
14895            });
14896        }
14897
14898        blogElements.forEach(blogElement => {
14899            if (blogElement?.dataset?.blogObserverAttached === 'true') {
14900                return;
14901            }
14902
14903            if (this.blogImpressionObserver) {
14904                this.blogImpressionObserver.observe(blogElement);
14905                blogElement.dataset.blogObserverAttached = 'true';
14906            } else {
14907                AB.DATALAYER.trackBlogComponentImpression(blogElement);
14908            }
14909        });
14910    }
14911
14912    /**
14913     * Reads and parses the JSON payload authored on a blog component host element.
14914     * Supports both `data-blog-component` (publish render) and `data-blog-component-content`.
14915     */
14916    this.getBlogComponentParsedData = function (blogElement) {
14917        if (!blogElement) {
14918            return {};
14919        }
14920        const host = blogElement.tagName && blogElement.tagName.toLowerCase() === 'webgen-blog-component'
14921            ? blogElement
14922            : (blogElement.querySelector?.('webgen-blog-component') || blogElement);
14923        return this.safeJSONParse(
14924            host.getAttribute?.('data-blog-component')
14925            || host.getAttribute?.('data-blog-component-content')
14926        ) || {};
14927    }
14928
14929    /**
14930     * Per spec there is no `isSponsored` API attribute. Sponsorship is inferred from
14931     * authored AEM disclaimer fields containing the substring "sponsor".
14932     */
14933    this.isBlogComponentSponsored = function (parsedBlogData) {
14934        const sponsoredText = `${parsedBlogData?.secondaryWebDisclaimerText
14935            || parsedBlogData?.secondaryDisclaimerText
14936            || parsedBlogData?.disclaimerText
14937            || ''}`.toLowerCase();
14938        return sponsoredText.indexOf('sponsor') !== -1;
14939    }
14940
14941    /**
14942     * Builds the V218 bannerCardCarousel string for a blog CTA click per spec:
14943     * [ZONE]|banner|[blog-type]-blog:[BANNER TITLE/SUBTITLE]|[SPOT]|[UNIQUE ID]
14944     * e.g. "z01|banner|recipe-blog:shop-recipe|sp01|no-value"
14945     */
14946    this.getBlogComponentBannerLocation = function (options) {
14947        const blogElement = options?.blogElement;
14948        const parsedBlogData = options?.parsedBlogData || {};
14949        const blogType = options?.blogType || '';
14950        const spot = options?.spot || 1;
14951
14952        const zoneInfo = AB.DATALAYER.getZoneInfo(blogElement)?.zone;
14953        const zoneNumber = zoneInfo && zoneInfo > 0 ? zoneInfo : 1;
14954        const zoneToken = `z${zoneNumber < 10 ? `0${zoneNumber}` : zoneNumber}`;
14955        const spotToken = `sp${spot < 10 ? `0${spot}` : spot}`;
14956
14957        const titleSource = parsedBlogData?.title
14958            || parsedBlogData?.subTitle
14959            || parsedBlogData?.eyebrow
14960            || `${blogType}-blog`;
14961        const titleToken = AB.DATALAYER.sanitizeAnalyticsText(`${titleSource}`) || `${blogType}-blog`;
14962
14963        const uniqueIdSource = parsedBlogData?.modelConfigurationId
14964            || parsedBlogData?.analyticsTag
14965            || parsedBlogData?.itemId
14966            || parsedBlogData?.id;
14967        const uniqueIdToken = uniqueIdSource
14968            ? (AB.DATALAYER.sanitizeAnalyticsText(`${uniqueIdSource}`) || 'no-value')
14969            : 'no-value';
14970
14971        const value = `${zoneToken}|banner|${blogType}-blog:${titleToken}|${spotToken}|${uniqueIdToken}`;
14972        return value.length > 256 ? value.substring(0, 256) : value;
14973    }
14974
14975    /**
14976     * Persists V218 (bannerCardCarousel) and V80 (mediaPlacementClick) to localStorage
14977     * for a Blog component CTA click that navigates to a new page. The next pageLoaded
14978     * event picks these values up via initAEMZoneTracking, so no additional linkClick
14979     * is fired and existing V151-V154 values on the outbound click are preserved.
14980     * Per ACIP-576827 spec. Same-page clicks (empty/hash href) are skipped by the caller.
14981     */
14982    this.setBlogComponentClickAnalytics = function (blogElement, anchorElement) {
14983        if (!blogElement) {
14984            return;
14985        }
14986
14987        const parsedBlogData = AB.DATALAYER.getBlogComponentParsedData(blogElement);
14988        const blogType = AB.DATALAYER.getBlogImpressionType(parsedBlogData?.designType);
14989        if (!blogType) {
14990            return;
14991        }
14992
14993        const hostElement = blogElement.tagName && blogElement.tagName.toLowerCase() === 'webgen-blog-component'
14994            ? blogElement
14995            : (blogElement.querySelector?.('webgen-blog-component') || blogElement);
14996
14997        const allBlogElements = Array.from(document.querySelectorAll('webgen-blog-component, .blog-component-wrapper_left-align, .blog-component-wrapper_right-align, .blog-component-recipe'))
14998            .filter(element => AB.DATALAYER.isVisible(element));
14999        const rowIndex = allBlogElements.indexOf(hostElement);
15000        const row = rowIndex >= 0 ? rowIndex + 1 : 1;
15001        const slot = 1;
15002
15003        const isSponsored = AB.DATALAYER.isBlogComponentSponsored(parsedBlogData);
15004        const recommendationType = isSponsored ? 'sponsored' : 'notRecommended';
15005        const mediaType = `${blogType}-blog`;
15006        const v80 = `${mediaType}#${recommendationType}#r${row < 10 ? `0${row}` : row}#s${slot < 10 ? `0${slot}` : slot}`;
15007
15008        const bannerLocation = AB.DATALAYER.getBlogComponentBannerLocation({
15009            blogElement: hostElement,
15010            parsedBlogData: parsedBlogData,
15011            blogType: blogType,
15012            spot: slot
15013        });
15014
15015        try {
15016            if (bannerLocation) {
15017                localStorage.setItem('aemZoneAnalytics', bannerLocation);
15018            }
15019            if (v80) {
15020                localStorage.setItem('mediaPlacementClick', v80);
15021            }
15022        } catch (e) { /* no-op */ }
15023    }
15024
15025    this.initCaasModuleTracking = function () {
15026        this.initFlexModuleExposureOnLoad();
15027        this.initFlexModuleImpressions();
15028        this.initCollectionImpressions();
15029        this.initBlogTracking();
15030
15031        if (this.caasModuleTrackingObserver || !document?.body || typeof MutationObserver === 'undefined') {
15032            return;
15033        }
15034
15035        this.caasModuleTrackingObserver = new MutationObserver(() => {
15036            clearTimeout(this.caasModuleTrackingTimer);
15037            this.caasModuleTrackingTimer = setTimeout(() => {
15038                AB.DATALAYER.initFlexModuleExposureOnLoad();
15039                AB.DATALAYER.initFlexModuleImpressions();
15040                AB.DATALAYER.initCollectionImpressions();
15041                AB.DATALAYER.initBlogTracking();
15042            }, 100);
15043        });
15044        this.caasModuleTrackingObserver.observe(document.body, { childList: true, subtree: true });
15045    }
15046
15047    /**
15048     * Page-agnostic entry point for Blog component analytics (impressions only).
15049     * Blog CTA V218/V80 tracking piggybacks on the existing CRS-Home universal
15050     * click layer (see crsHomeUniversalClickHandler); no dedicated click listener
15051     * is registered here. Owns a lightweight MutationObserver so late-injected blog
15052     * components (SPA route changes, lazy loads on pages that do not run
15053     * initCaasModuleTracking) still get impression tracking.
15054     */
15055    this.initBlogTracking = function () {
15056        this.initBlogImpressions();
15057
15058        if (this.blogTrackingObserver || !document?.body || typeof MutationObserver === 'undefined') {
15059            return;
15060        }
15061
15062        this.blogTrackingObserver = new MutationObserver((mutations) => {
15063            const hasRelevantChange = mutations.some(mutation => {
15064                if (!mutation.addedNodes || mutation.addedNodes.length === 0) {
15065                    return false;
15066                }
15067                return Array.from(mutation.addedNodes).some(node => {
15068                    if (node?.nodeType !== 1) {
15069                        return false;
15070                    }
15071                    return node.matches?.('webgen-blog-component, .blog-component-wrapper_left-align, .blog-component-wrapper_right-align, .blog-component-recipe')
15072                        || node.querySelector?.('webgen-blog-component, .blog-component-wrapper_left-align, .blog-component-wrapper_right-align, .blog-component-recipe');
15073                });
15074            });
15075            if (!hasRelevantChange) {
15076                return;
15077            }
15078            clearTimeout(this.blogTrackingTimer);
15079            this.blogTrackingTimer = setTimeout(() => {
15080                AB.DATALAYER.initBlogImpressions();
15081            }, 100);
15082        });
15083        this.blogTrackingObserver.observe(document.body, { childList: true, subtree: true });
15084    }
15085
15086    this.initFlexCardDetails = function () {
15087        if (this.getLSItem('flexCardAnalytics') && digitalData?.pageFilter) {
15088            digitalData.pageFilter.bannerCardCarousel = this.handleGetLSValue('flexCardAnalytics');
15089        }
15090
15091        this.initCaasModuleTracking();
15092    }
15093
15094    this.getStickyBannerData = function (stickyBannerElement) {
15095        const stickyBannerHost = stickyBannerElement?.closest('webgen-sticky-banner') || document.querySelector('webgen-sticky-banner');
15096        const parsedAttributeData = this.safeJSONParse(stickyBannerHost?.getAttribute('data-sticky-banner-content'))
15097            || this.safeJSONParse(stickyBannerHost?.getAttribute('data-sticky-banner'))
15098            || this.safeJSONParse(stickyBannerHost?.getAttribute('data-content'))
15099            || this.safeJSONParse(stickyBannerHost?.getAttribute('data'))
15100            || {};
15101        const bannerData = stickyBannerHost?.currentBanner || parsedAttributeData;
15102
15103        return {
15104            host: stickyBannerHost,
15105            data: bannerData && typeof bannerData === 'object' ? bannerData : {}
15106        };
15107    }
15108
15109    this.getStickyBannerPlacement = function (stickyBannerElement) {
15110        const sectionInfo = AB.DATALAYER.getZoneInfo(stickyBannerElement);
15111        const section = Number(sectionInfo?.section) > 0 ? Number(sectionInfo.section) : 1;
15112        const row = Number(sectionInfo?.row) > 0 ? Number(sectionInfo.row) : 1;
15113        const zone = Number(sectionInfo?.zone) > 0 ? Number(sectionInfo.zone) : 99;
15114        return `r${section < 10 ? `0${section}` : section}#s${row < 10 ? `0${row}` : row}#z${zone < 10 ? `0${zone}` : zone}`;
15115    }
15116
15117    this.getStickyBannerMetricA = function (stickyBannerData) {
15118        const responseData = stickyBannerData?.response || {};
15119        const metricA = stickyBannerData?.p13nAdobeMetrics?.metricA
15120            || stickyBannerData?.adobeMetrics?.metricA
15121            || responseData?.p13nAdobeMetrics?.metricA
15122            || responseData?.adobeMetrics?.metricA
15123            || '';
15124
15125        const normalizedMetricA = typeof metricA === 'string' ? metricA.trim() : '';
15126        if (!normalizedMetricA) {
15127            return '';
15128        }
15129
15130        const metricAParts = normalizedMetricA.split('#').map(part => (part || '').trim());
15131        const hasEmptyCarouselToken = metricAParts.some(part => part.toLowerCase() === 'empty_carousel');
15132
15133        // Requirement: when MetricA is empty (empty_carousel variant), send generic instead.
15134        return hasEmptyCarouselToken ? '' : normalizedMetricA;
15135    }
15136
15137    this.getStickyBannerAbTestDetails = function (stickyBannerData) {
15138        const responseData = stickyBannerData?.response || {};
15139        const modelData = stickyBannerData?.p13nData?.modelData || stickyBannerData?.modelData || responseData?.p13nData?.modelData || responseData?.modelData || {};
15140        const experimentData = stickyBannerData?.p13nData?.experimentData || stickyBannerData?.experimentData || responseData?.p13nData?.experimentData || responseData?.experimentData || {};
15141        const recommendationData = stickyBannerData?.p13nData?.recommendationData || stickyBannerData?.recommendationData || responseData?.p13nData?.recommendationData || responseData?.recommendationData || {};
15142        const msgExperiment = stickyBannerData?.p13nAdobeMetrics?.msgExperiment
15143            || stickyBannerData?.adobeMetrics?.msgExperiment
15144            || responseData?.p13nAdobeMetrics?.msgExperiment
15145            || responseData?.adobeMetrics?.msgExperiment
15146            || '';
15147        const metricA = AB.DATALAYER.getStickyBannerMetricA(stickyBannerData);
15148        const metricAParts = metricA ? metricA.split('#').map(part => (part || '').trim()) : [];
15149        const msgExperimentParts = msgExperiment ? msgExperiment.split('#').map(part => (part || '').trim()) : [];
15150        const successfullyServed = stickyBannerData?.p13nAdobeMetrics?.successfullyServed
15151            || stickyBannerData?.adobeMetrics?.successfullyServed
15152            || responseData?.p13nAdobeMetrics?.successfullyServed
15153            || responseData?.adobeMetrics?.successfullyServed
15154            || stickyBannerData?.successfullyServed
15155            || metricAParts[2];
15156
15157        const normalizePart = (value) => {
15158            if (value === false) {
15159                return 'false';
15160            }
15161            if (value === true) {
15162                return 'true';
15163            }
15164            if (value === null || value === undefined || value === '') {
15165                return 'no-value';
15166            }
15167            return AB.DATALAYER.sanitizeAnalyticsText(String(value)) || 'no-value';
15168        };
15169
15170        return [
15171            normalizePart(msgExperimentParts[0] || modelData?.modelConfigurationId || metricAParts[0]),
15172            normalizePart(msgExperimentParts[1] || experimentData?.experimentId || metricAParts[1]),
15173            normalizePart(msgExperimentParts[2] || experimentData?.experimentGroup),
15174            normalizePart(msgExperimentParts[3] || modelData?.modelId || metricAParts[3]),
15175            normalizePart(msgExperimentParts[4] || modelData?.modelVersion || metricAParts[4]),
15176            normalizePart(msgExperimentParts[5] || modelData?.fallbackModel),
15177            normalizePart(msgExperimentParts[6] || recommendationData?.rank),
15178            normalizePart(msgExperimentParts[7] || successfullyServed)
15179        ].join('#');
15180    }
15181
15182    this.getStickyBannerLocation = function (stickyBannerElement, stickyBannerData) {
15183        const title = AB.DATALAYER.sanitizeAnalyticsText(stickyBannerData?.title || stickyBannerData?.bannerTitle || 'sticky-banner');
15184        const subTitle = AB.DATALAYER.sanitizeAnalyticsText(stickyBannerData?.subTitle || stickyBannerData?.bannerSubTitle || '');
15185        const promotionId = AB.DATALAYER.sanitizeAnalyticsText((stickyBannerData?.promotionId || '').toString()) || 'no-value';
15186        const bannerName = `${title}${subTitle ? `-${subTitle}` : ''}`;
15187
15188        return `z99|banner|sticky-banner:${bannerName}|sp99|${promotionId}`;
15189    }
15190
15191    this.setStickyBannerClickedEvent = function (stickyBannerElement, title) {
15192        if (!window.digitalData || !window.digitalData.pageFilter || !stickyBannerElement) {
15193            return;
15194        }
15195
15196        const stickyBannerInfo = AB.DATALAYER.getStickyBannerData(stickyBannerElement);
15197        const stickyBannerData = stickyBannerInfo?.data || {};
15198        const msgDetail = AB.DATALAYER.getStickyBannerMetricA(stickyBannerData) || 'generic';
15199        const abTestDetails = AB.DATALAYER.getStickyBannerAbTestDetails(stickyBannerData);
15200        const bannerTitle = AB.DATALAYER.sanitizeAnalyticsText(stickyBannerData?.title || stickyBannerData?.bannerTitle || 'sticky-banner');
15201        const subTitle = AB.DATALAYER.sanitizeAnalyticsText(stickyBannerData?.subTitle || stickyBannerData?.bannerSubTitle || '');
15202        const promotionId = AB.DATALAYER.sanitizeAnalyticsText((stickyBannerData?.promotionId || '').toString()) || 'no-value';
15203        const bannerName = `${bannerTitle}${subTitle ? `-${subTitle}` : ''}`;
15204        const placement = AB.DATALAYER.getStickyBannerPlacement(stickyBannerElement);
15205        const bannerLocation = AB.DATALAYER.getStickyBannerLocation(stickyBannerElement, stickyBannerData);
15206        const pageDetails = {
15207            ...structuredClone(digitalData?.pageDetails || {}),
15208            msgDetail: msgDetail,
15209            abTestDetails: abTestDetails,
15210            bnrName: `${bannerName}|${promotionId}`
15211        };
15212        const pageFilter = {
15213            ...structuredClone(digitalData?.pageFilter || {}),
15214            recommendationType: 'notRecommended',
15215            placement: placement,
15216            mediaType: 'sticky-banner',
15217            bannerCardCarousel: bannerLocation
15218        };
15219        const payload = {
15220            link: {
15221                linkName: title,
15222                oneTagLinkName: 'banner-clicked'
15223            },
15224            page: pageDetails,
15225            pageFilter: pageFilter,
15226            user: structuredClone(digitalData?.user || {}),
15227            modal: {
15228                ...structuredClone(digitalData?.modal || {}),
15229                modalMessage: msgDetail
15230            }
15231        };
15232
15233        this.pushEvent(this.EVENTS.LINK_CLICK, payload);
15234    }
15235
15236    this.trackStickyBannerExposure = function (stickyBannerElement) {
15237        if (!stickyBannerElement || digitalData?.pageFlags?.isStickyBannerExposureSent) {
15238            return;
15239        }
15240
15241        const stickyBannerInfo = AB.DATALAYER.getStickyBannerData(stickyBannerElement);
15242        const stickyBannerData = stickyBannerInfo?.data || {};
15243        const hasStickyBannerData = Object.keys(stickyBannerData).length > 0;
15244        if (!hasStickyBannerData) {
15245            return;
15246        }
15247
15248        const title = AB.DATALAYER.sanitizeAnalyticsText(stickyBannerData?.title || stickyBannerData?.bannerTitle || 'sticky-banner');
15249        const subTitle = AB.DATALAYER.sanitizeAnalyticsText(stickyBannerData?.subTitle || stickyBannerData?.bannerSubTitle || '');
15250        const promotionId = AB.DATALAYER.sanitizeAnalyticsText((stickyBannerData?.promotionId || '').toString()) || 'no-value';
15251        const placement = AB.DATALAYER.getStickyBannerPlacement(stickyBannerElement);
15252        const pageDetails = {
15253            ...digitalData?.pageDetails,
15254            abTestDetails: AB.DATALAYER.getStickyBannerAbTestDetails(stickyBannerData),
15255            bnrName: `${title}${subTitle ? `-${subTitle}` : ''}|${promotionId}`
15256        };
15257
15258        AB.DATALAYER.pushEvent(
15259            AB.DATALAYER.EVENTS.LINK_CLICK,
15260            {
15261                link: {
15262                    linkName: 'experiment-exposure-loaded-banner',
15263                    isSendToSS: true
15264                },
15265                page: pageDetails,
15266                pageFilter: {
15267                    ...digitalData?.pageFilter,
15268                    mediaType: 'sticky-banner',
15269                    placement: placement
15270                },
15271                user: digitalData?.user
15272            }
15273        );
15274
15275        digitalData.pageFlags.isStickyBannerExposureSent = true;
15276    }
15277
15278    this.trackStickyBannerImpression = function (stickyBannerElement) {
15279        if (!AB.DATALAYER.isCESEventsEnabled() || !stickyBannerElement || digitalData?.pageFlags?.isStickyBannerImpressionSent) {
15280            return;
15281        }
15282
15283        const stickyBannerInfo = AB.DATALAYER.getStickyBannerData(stickyBannerElement);
15284        const stickyBannerData = stickyBannerInfo?.data || {};
15285        const msgDetail = AB.DATALAYER.getStickyBannerMetricA(stickyBannerData) || 'generic';
15286        const title = AB.DATALAYER.sanitizeAnalyticsText(stickyBannerData?.title || stickyBannerData?.bannerTitle || 'sticky-banner');
15287        const subTitle = AB.DATALAYER.sanitizeAnalyticsText(stickyBannerData?.subTitle || stickyBannerData?.bannerSubTitle || '');
15288        const promotionId = AB.DATALAYER.sanitizeAnalyticsText((stickyBannerData?.promotionId || '').toString()) || 'no-value';
15289        const placement = AB.DATALAYER.getStickyBannerPlacement(stickyBannerElement);
15290        const pageDetails = {
15291            ...digitalData?.pageDetails,
15292            msgDetail: msgDetail,
15293            bnrName: `${title}${subTitle ? `-${subTitle}` : ''}|${promotionId}`
15294        };
15295
15296        AB.DATALAYER.pushEvent(
15297            AB.DATALAYER.EVENTS.LINK_CLICK,
15298            {
15299                link: {
15300                    linkName: 'banner-impressions',
15301                    isSendToSS: true
15302                },
15303                page: pageDetails,
15304                pageFilter: {
15305                    ...digitalData?.pageFilter,
15306                    mediaType: 'sticky-banner',
15307                    placement: placement
15308                },
15309                user: digitalData?.user
15310            }
15311        );
15312
15313        digitalData.pageFlags.isStickyBannerImpressionSent = true;
15314        stickyBannerElement.dataset.stickyBannerImpressionTracked = 'true';
15315
15316        if (AB.DATALAYER.stickyBannerImpressionObserver) {
15317            AB.DATALAYER.stickyBannerImpressionObserver.disconnect();
15318            AB.DATALAYER.stickyBannerImpressionObserver = null;
15319        }
15320        if (AB.DATALAYER.stickyBannerMutationObserver) {
15321            AB.DATALAYER.stickyBannerMutationObserver.disconnect();
15322            AB.DATALAYER.stickyBannerMutationObserver = null;
15323        }
15324    }
15325
15326    this.observeStickyBannerImpression = function (stickyBannerElement) {
15327        if (!stickyBannerElement || digitalData?.pageFlags?.isStickyBannerImpressionSent || stickyBannerElement?.dataset?.stickyBannerObserverAttached === 'true') {
15328            return;
15329        }
15330
15331        if (typeof IntersectionObserver === 'undefined') {
15332            AB.DATALAYER.trackStickyBannerImpression(stickyBannerElement);
15333            return;
15334        }
15335
15336        if (!AB.DATALAYER.stickyBannerImpressionObserver) {
15337            AB.DATALAYER.stickyBannerImpressionObserver = new IntersectionObserver((entries, observer) => {
15338                entries.forEach(entry => {
15339                    if (entry?.isIntersecting && entry?.intersectionRatio >= 0.5) {
15340                        AB.DATALAYER.trackStickyBannerImpression(entry.target);
15341                        observer.unobserve(entry.target);
15342                    }
15343                });
15344            }, {
15345                root: null,
15346                rootMargin: '0px',
15347                threshold: [0.5]
15348            });
15349        }
15350
15351        AB.DATALAYER.stickyBannerImpressionObserver.observe(stickyBannerElement);
15352        stickyBannerElement.dataset.stickyBannerObserverAttached = 'true';
15353    }
15354
15355    this.initStickyBannerImpressions = function () {
15356        if (digitalData?.pageFlags?.isStickyBannerImpressionSent && digitalData?.pageFlags?.isStickyBannerExposureSent) {
15357            return;
15358        }
15359
15360        const stickyBannerElement = document.querySelector('webgen-sticky-banner .sticky-banner__container, .sticky-banner__container');
15361        if (stickyBannerElement) {
15362            AB.DATALAYER.trackStickyBannerExposure(stickyBannerElement);
15363            AB.DATALAYER.observeStickyBannerImpression(stickyBannerElement);
15364            return;
15365        }
15366
15367        if (AB.DATALAYER.stickyBannerMutationObserver || typeof MutationObserver === 'undefined') {
15368            return;
15369        }
15370
15371        AB.DATALAYER.stickyBannerMutationObserver = new MutationObserver(() => {
15372            const stickyElement = document.querySelector('webgen-sticky-banner .sticky-banner__container, .sticky-banner__container');
15373            if (stickyElement) {
15374                AB.DATALAYER.trackStickyBannerExposure(stickyElement);
15375                AB.DATALAYER.observeStickyBannerImpression(stickyElement);
15376            }
15377        });
15378
15379        AB.DATALAYER.stickyBannerMutationObserver.observe(document.body, {
15380            childList: true,
15381            subtree: true
15382        });
15383    }
15384
15385    /**
15386     * Set the subscription / plan change / conffirmation pages values for subscriptionFunnel and subscription status
15387     * @param fpsObject - The object which contains the properties properties are going to be used to change the values in the subscriptionFunnel and subscriptionStatus
15388     * @param subscriptionStep - A string type variable which hold the information about the current step in ther page
15389    */
15390    this.setFPSPlanType = function (analyticsStep, fpsObject) {
15391        const isPrebook = fpsObject?.isPrebookReq === 'prebook';
15392
15393        const FPSConfirmationStep = this.getLSItem('freshpass-analytics-confirmation') && this.isFreshpassConfirmationPage();
15394        const FPSConfirmationLanding = !this.getLSItem('freshpass-analytics-confirmation') && this.isFreshpassConfirmationPage();
15395
15396        if (FPSConfirmationStep) {
15397            fpsObject = this.safeJSONParse(this.handleGetLSValue('freshpass-analytics-confirmation'));
15398        }
15399
15400        let isDiscounted = this.getLSItem('analyticsFPDiscountPlan') || (fpsObject?.isMonthlyDiscounted || fpsObject?.isAnnualDiscounted || fpsObject?.isDiscounted);
15401        let isTrial = this.getLSItem('analyticsTrialFPUpdate') || fpsObject?.isTrialElligible;
15402        let isExtTrial = this.getLSItem('analyticsFPExtPlan') || fpsObject?.isExtendedTrial;
15403        const isSnap = fpsObject?.campaignType === 'SHEER' ? true : false;
15404        const isSnapChangePlan = this.getLSItem('analyticsChangeSnapPlan') ? this.handleGetLSValue('analyticsChangeSnapPlan') : false;
15405
15406        const planType = fpsObject?.planType === 'monthlyplan' ? 'monthly' : 'annual';
15407
15408        const changePlan = (this.getLSItem('analyticsFPLSitem') === 'changeToAnnual')
15409            ? 'monthly|annual' : (this.getLSItem('analyticsFPLSitem') === 'changeToMonthly' ? 'annual|monthly' : '');
15410
15411        let stepChange = analyticsStep === 'step1' ? '-plan-selection' : (analyticsStep === 'landing' ? '-landing'
15412            : (analyticsStep === 'changePlan' ? `${changePlan}`
15413                : `${(isTrial ? '-trial' : '')}-${planType}`));
15414
15415
15416        if (analyticsStep === 'step2' || analyticsStep === 'step3' || FPSConfirmationStep) {
15417            digitalData.pageFilter.freshPassPlanPrice = planType === 'monthly' ? fpsObject?.monthlyPlanPrice : fpsObject?.annualPlanPrice;
15418        }
15419
15420        if (analyticsStep !== 'changePlan') {
15421            digitalData.pageFilter.freshPassDiscountedMonths = fpsObject?.monthlyDiscountMonths;
15422        }
15423
15424        const setEmployeeSubscription = function () {
15425            return `emp:freshpass${stepChange}`;
15426        }
15427
15428        const setSnapSubscription = function () {
15429            return `snap:freshpass${stepChange}`;
15430        }
15431
15432        const setSubscription = function (preebookStatus) {
15433            if (preebookStatus) {
15434                return `prebook:freshpass${isExtTrial ? `-${fpsObject.trialExtDuration}-extd` : ''}${stepChange}`;
15435            } else {
15436                return `${isDiscounted ? 'disc:' : ''}freshpass${isExtTrial ? `-${fpsObject.trialExtDuration}-extd` : ''}${stepChange}`;
15437            }
15438        }
15439
15440        const setChangePlan = function () {
15441            return isExtTrial ? `extd-plan-changed:${stepChange}`
15442                : `${(isDiscounted ? 'disc-' : isSnapChangePlan ? 'snap-' : '')}plan-changed:${(isTrial ? 'trial-' : '')}${stepChange}`;
15443        }
15444
15445        if (analyticsStep === 'confirmation') {
15446            digitalData.pageFilter.subscriptionFunnel = FPSConfirmationStep
15447                ? fpsObject.isEmployee
15448                    ? `${setEmployeeSubscription()}-confirmation`
15449                    : isSnap ? `${setSnapSubscription()}-confirmation` : `${setSubscription(isPrebook)}-confirmation`
15450                : 'freshpass-manage-plan';
15451        } else if (analyticsStep === 'changePlan') {
15452            digitalData.pageFilter.subscriptionFunnel = setChangePlan();
15453        } else {
15454            digitalData.pageFilter.subscriptionFunnel = fpsObject.isEmployee ? setEmployeeSubscription() : isSnap ? setSnapSubscription() : setSubscription(isPrebook);
15455        }
15456
15457        digitalData.user.subscriptionStatus = FPSConfirmationStep
15458            ? `${isSnap ? 'snap:' : ''}freshpass|${(!!fpsObject.isTrialElligible ? 'trial-' : '')}${planType}-success` : analyticsStep === 'changePlan'
15459                ? `freshpass|${(isTrial ? 'trial-' : '')}${changePlan === 'monthly|annual' ? 'monthly-to-annual-success' : 'annual-to-monthly-success'}` : FPSConfirmationLanding
15460                    ? 'freshpass-manage-plan' : 'not-available';
15461    }
15462
15463    this.initFPSItems = function () {
15464        if (!window.location.pathname.startsWith('/freshpass/manage/subscribe') && !this.isFreshpassConfirmationPage()) {
15465            this.removeLSItem('freshpass-analytics-confirmation');
15466        }
15467        if (this.getLSItem('analyticsFPLSitem') === 'clickedBanner' && (!window.location.pathname.startsWith('/freshpass/manage'))) {
15468            this.removeLSItem('analyticsFPLSitem');
15469        }
15470        if (this.getLSItem('analyticsFPLSitem') === 'clickedAnnualBtn' && (!window.location.pathname.startsWith('/freshpass/manage'))) {
15471            this.removeLSItem('analyticsFPLSitem');
15472        }
15473        if (!window.location.pathname.startsWith('/delivery-subscription') || !window.location.pathname.startsWith('/freshpass')) {
15474            this.removeLSItem('analyticsTrialFPUpdate');
15475            this.removeLSItem('analyticsFPDiscountPlanAnnual');
15476            this.removeLSItem('analyticsFPDiscountPlan');
15477            this.removeLSItem('analyticsFPExtPlan');
15478            this.removeLSItem('analyticsFPExtPlanAnnual');
15479            this.removeLSItem('analyticsFPDiscountPlanMonthly');
15480            this.removeLSItem('analyticsFPExtPlanMonthly');
15481            this.removeLSItem('analyticsChangePlan');
15482        }
15483    }
15484
15485    this.initPetDetails = function () {
15486        if (localStorage.getItem('analyticsEditPetDetails') && digitalData?.pageDetails) {
15487            digitalData.pageDetails.subSection2 = 'edit-pet-details';
15488            digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:loyalty:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}`;
15489            localStorage.removeItem('analyticsEditPetDetails');
15490        }
15491    }
15492
15493    this.similarItemsTrackingBIA = function () {
15494        if (this.isBIAPage()) {
15495            localStorage.setItem('topNavSimilarItemsBIA', 'cta:purchases:buy-it-again|view-similar-items|similar-items');
15496            localStorage.setItem('analyticsSimilarItemsBIA', 'similar-items_buy-it-again');
15497        }
15498    }
15499
15500    this.setPfmSourceBiaPDP = function () {
15501        if (digitalData.pageFilter && digitalData.pageFilter.topNav === 'cta:purchases:buy-it-again|view-similar-items|similar-items') {
15502            localStorage.setItem('pfmSourceSimilarItemsBIA', 'similar-items_buy-it-again');
15503        }
15504    }
15505
15506    this.setEmailAndSmsOptIn = function () {
15507        const emailOptIn = document.querySelector('.terms-text-unified #terms-email')?.checked;
15508        const smsOptIn = document.querySelector('.terms-text-unified #terms-sms')?.checked;
15509        const userObj = {
15510            emailOptIn: emailOptIn,
15511            smsOptIn: smsOptIn
15512        };
15513        localStorage.setItem('analyticsEmailAndSmsOptIn', JSON.stringify(userObj));
15514    }
15515
15516    this.initEmailAndSmsOptIn = function () {
15517        if (window.digitalData && localStorage.getItem('analyticsEmailAndSmsOptIn')) {
15518            const userObj = AB.DATALAYER.safeJSONParse(AB.DATALAYER.handleGetLSValue('analyticsEmailAndSmsOptIn'));
15519            window.digitalData.user = window.digitalData.user || {};
15520            window.digitalData.user.smsOptIn = userObj.smsOptIn;
15521            window.digitalData.user.emailOptIn = userObj.emailOptIn;
15522        }
15523    }
15524
15525    this.progressiveProfilingTracking = function ({ subSection1, subSection2, topNav } = {}) {
15526        const profileCompletionShown = document.querySelector('#profile-completion')?.classList?.contains('show');
15527        if (digitalData && digitalData.pageDetails && digitalData.pageFilter && !profileCompletionShown) {
15528            digitalData.pageDetails.subSection1 = subSection1 ? subSection1 : AB.DATALAYER.pathSections[0] ? AB.DATALAYER.pathSections[0] : '';
15529            digitalData.pageDetails.subSection2 = subSection2 ? subSection2 : AB.DATALAYER.pathSections[1] ? AB.DATALAYER.pathSections[1] : '';
15530            digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:loyalty:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}`;
15531            digitalData.pageFilter.topNav = topNav ? topNav : AB.DATALAYER.initTopNav();
15532            digitalData.pageFlags.isPageLoadSent = false;
15533            AB.DATALAYER.setPageLoad();
15534        }
15535    }
15536
15537    this.setTopNavMealsCard = function (mealCard, mealId) {
15538        const currentMealSlot = Number(mealCard?.closest('div.slick-slide')?.getAttribute('data-slick-index')) + 1;
15539        const currentCarouselTitle = mealCard?.closest('.slick-meal-carousel')?.querySelector('h2.meal-carousel-title')?.textContent?.trim()?.replace(/\s/g, '');
15540        localStorage.setItem('analyticsMealsCarouselTopNav', `cta:${AB.DATALAYER.pathSections?.join(':')}|meals-carousel|${currentCarouselTitle}-variantID:${mealId}-${currentMealSlot}`);
15541        if (AB.DATALAYER.isHomePage()) {
15542            const currentCarousel = mealCard?.closest('.slick-meal-carousel');
15543            const mealCarousels = AB.DATALAYER.isVisible(document.querySelectorAll('.slick-meal-carousel'));
15544            const carouselRow = mealCarousels && Array.from(mealCarousels).indexOf(currentCarousel) + 1;
15545            const placement = `R${carouselRow && carouselRow < 10 ? `0${carouselRow}` : carouselRow || '00'}#S${currentMealSlot && currentMealSlot < 10 ? `0${currentMealSlot}` : currentMealSlot || '00'}`;
15546            AB.DATALAYER.setCRSRecipeClick({
15547                element: mealCard,
15548                placement: placement,
15549                component: AB.DATALAYER.getCRSComponent({
15550                    element: mealCard,
15551                    section: currentCarouselTitle,
15552                    spot: currentMealSlot,
15553                    placement: placement
15554                })
15555            });
15556        }
15557    }
15558
15559    this.getCRSPlacementParts = function (placement) {
15560        const placementValue = placement || digitalData?.pageFilter?.placement || '';
15561        const rowMatch = placementValue.match(/R(\d+)/i);
15562        const spotMatch = placementValue.match(/S(\d+)/i);
15563        const zoneMatch = placementValue.match(/Z(?:ONE)?(\d+)/i);
15564        return {
15565            row: rowMatch ? parseInt(rowMatch[1], 10) : 0,
15566            spot: spotMatch ? parseInt(spotMatch[1], 10) : 0,
15567            zone: zoneMatch ? parseInt(zoneMatch[1], 10) : 0
15568        };
15569    }
15570
15571    this.isCRSHomeAEMComponent = function (element) {
15572        return !!element?.closest?.('[data-zone-response], [data-api-driven], [data-carousel-driven], [data-abs-carousel-position], [data-abs-carousel-slot], lazy-wrapper[data-model-configuration-id], lazy-wrapper[data-carousel-filter="p13n"], targeted-wrapper, webgen-flex-module, webgen-bundles, webgen-bundles-carousel');
15573    }
15574
15575    this.getCRSFrontendAPIZone = function (element) {
15576        const dataElement = element?.closest?.('[data-zone-response]');
15577        const zoneData = AB.DATALAYER.safeJSONParse(dataElement?.getAttribute?.('data-zone-response')) || {};
15578        return zoneData?.zone || null;
15579    }
15580
15581    this.getCRSAbsPlacement = function ({ element, placement, caasEnbld } = {}) {
15582        const placementParts = this.getCRSPlacementParts(placement);
15583        const zoneInfo = element ? AB.DATALAYER.getZoneInfo(element) : {};
15584        const isAEMComponent = element ? AB.DATALAYER.isCRSHomeAEMComponent(element) : true;
15585        
15586        let zoneNumber = placementParts.zone || parseInt(zoneInfo?.zone, 10) || 0;
15587        let zoneValue;
15588        let slotValue;
15589        
15590        if (isAEMComponent) {
15591            const apiZone = AB.DATALAYER.getCRSFrontendAPIZone(element);
15592            zoneValue = apiZone || `zone${zoneNumber}`;
15593            slotValue = placementParts.row || parseInt(zoneInfo?.row, 10) || 0;
15594        } else {
15595            zoneValue = `nzone${zoneNumber}`;
15596            slotValue = undefined;
15597        }
15598        
15599        return {
15600            zone: zoneValue,
15601            zSlot: slotValue,
15602            absLoc: placementParts.spot || 0,
15603            caasEnbld: caasEnbld === undefined ? true : !!caasEnbld
15604        };
15605    }
15606
15607    this.getCRSComponent = function ({ element, section, detail, type, name, spot, sponsored, placement } = {}) {
15608        const placementParts = this.getCRSPlacementParts(placement);
15609        const componentSection = section || AB.DATALAYER.getAnalyticsCarouselTitle(element) || '';
15610        return [{
15611            section: componentSection ? AB.DATALAYER.sanitizeAnalyticsText(componentSection) : '',
15612            detail: detail || 'generic',
15613            type: type || 'no-val',
15614            name: name || 'no-val',
15615            spot: spot === undefined ? placementParts.spot || 0 : spot,
15616            sponsored: sponsored === undefined || sponsored === '' ? 'no-val' : sponsored
15617        }];
15618    }
15619
15620    this.getCRSProduct = function (product) {
15621        const productData = product || digitalData?.productInfo || {};
15622        return {
15623            pId: productData.productID || productData.id || productData.itemId?.toString(),
15624            pName: productData.productName || productData.name,
15625            units: productData.units || productData.quantity || productData.qty,
15626            uTyp: productData.unitType || productData.unitQuantity,
15627            lp: productData.listPrice || productData.price,
15628            bp: productData.basePrice?.toString(),
15629            pType: productData.pricingType || productData.promoDescription || 'not available',
15630            cpnFlg: productData.couponFlag || 'not available',
15631            cpnClpd: productData.couponClipped || 'not available',
15632            cpnId: productData.couponID || 'not available',
15633            aId: productData.aisleId || '',
15634            upc: productData.upc,
15635            pfmDtl: productData.pfmDetail,
15636            mto: productData.mto || (!!productData.isMTO).toString(),
15637            deptNam: productData.departmentName,
15638            each: productData.each,
15639            aisle: productData.aisleName,
15640            shelf: productData.shelfName,
15641            iv: productData.listPrice?.toString() || productData.price?.toString(),
15642            isMHMD: !!productData.isProductTrackingDisabled
15643        };
15644    }
15645
15646    this.getCRSCoupon = function (coupon) {
15647        return {
15648            type: coupon?.couponType,
15649            name: coupon?.couponName,
15650            id: coupon?.couponId,
15651            clipMthd: coupon?.couponclipmethod,
15652            carouselSec: coupon?.carouselSection,
15653            clipCnt: coupon?.numberofcouponsclipped,
15654            clipID: coupon?.clipID || coupon?.serverData?.eventId,
15655            clipTime: coupon?.clipTime || coupon?.serverData?.currentTime,
15656            divisionName: coupon?.divisionName,
15657            msgData: coupon?.msgData,
15658            savings: coupon?.couponSavings || '0'
15659        };
15660    }
15661
15662    this.isCESEventsEnabled = function () {
15663        return window['SWY']?.CONFIGSERVICE?.featureToggleConfig?.enableCESEvents === true;
15664    };
15665
15666    this.setCRSClickEvent = function ({ linkName, mTyp, element, placement, component, product, batchCouponsClipped, caasEnbld } = {}) {
15667        if (!AB.DATALAYER.isCESEventsEnabled() || !AB.DATALAYER.isHomePage() || !linkName) {
15668            return;
15669        }
15670        const resolvedPlacement = placement || digitalData?.pageFilter?.placement;
15671        const payload = {
15672            link: { linkName: linkName, isCRSClick: true, isSendToSS: true },
15673            page: digitalData?.pageDetails,
15674            pageFilter: { mediaType: mTyp },
15675            absPlacement: AB.DATALAYER.getCRSAbsPlacement({ element: element, placement: resolvedPlacement, caasEnbld: caasEnbld }),
15676            component: component || AB.DATALAYER.getCRSComponent({ element: element, placement: resolvedPlacement }),
15677            user: digitalData?.user
15678        };
15679        if (product) {
15680            payload.product = AB.DATALAYER.getCRSProduct(product);
15681        }
15682        if (Array.isArray(batchCouponsClipped)) {
15683            payload.batchCouponsClipped = batchCouponsClipped.map(coupon => AB.DATALAYER.getCRSCoupon(coupon));
15684        }
15685        this.pushEvent(this.EVENTS.LINK_CLICK, payload);
15686    }
15687
15688    this.setCRSAddToListClick = function ({ product, element, placement, component } = {}) {
15689        AB.DATALAYER.setCRSClickEvent({
15690            linkName: 'add-to-list-click',
15691            mTyp: '',
15692            element: element,
15693            placement: placement,
15694            component: component,
15695            product: product
15696        });
15697    }
15698
15699    this.setCRSPausePlayClick = function ({ action, element, placement, component } = {}) {
15700        AB.DATALAYER.setCRSClickEvent({
15701            linkName: action === 'pause' ? 'pause-click' : 'play-click',
15702            mTyp: 'product-carousel',
15703            element: element,
15704            placement: placement,
15705            component: component
15706        });
15707    }
15708
15709    this.setCRSRecipeClick = function ({ element, placement, component } = {}) {
15710        AB.DATALAYER.setCRSClickEvent({
15711            linkName: 'item-click',
15712            mTyp: 'product-carousel',
15713            element: element,
15714            placement: placement,
15715            component: component
15716        });
15717    }
15718
15719    this.getCRSHomeCarouselSelector = function () {
15720        return '.nextgen-abs-carousel-wrapper, .abs-carousel-wrapper, .abs-carousel, .mod-unit-carousel, .mod-unit-carousel-container, .slick-slider, coupon-carousel, loyalty-card-carousel-al-v1, .slick-coupon-carousel, .slick-product-carousel, .master-product-carousel, product-carousel-al-v1, meals-carousel, .slick-meal-carousel, .meal-carousel, .horizontal-video-carousel-wrapper, .marketplace-search-carousel-container, .nextgen-abs-carousel-proxy, .nextgen-banner-carousel, webgen-hero-canvas-carousel, .hero-carousel, webgen-bundles-carousel';
15721    }
15722
15723    this.getCRSHomeCarouselElement = function (element) {
15724        return element?.closest?.(AB.DATALAYER.getCRSHomeCarouselSelector());
15725    }
15726
15727    this.getCRSHomeArrowDirection = function (element) {
15728        const ariaLabel = element?.getAttribute?.('aria-label') || '';
15729        const className = element?.className?.toString() || '';
15730        const controlText = `${ariaLabel} ${className} ${element?.textContent || ''}`.toLowerCase();
15731        return /prev|previous|back|left|slick-prev|carousel-control-prev|</.test(controlText) ? 'left' : 'right';
15732    }
15733
15734    this.getCRSCarouselControlPlacement = function (element) {
15735        const carousel = AB.DATALAYER.getCRSHomeCarouselElement(element);
15736        const zoneInfo = AB.DATALAYER.getZoneInfo(carousel || element);
15737        let carouselRow = parseInt(zoneInfo?.row, 10) || 0;
15738        const zoneNumber = parseInt(zoneInfo?.zone, 10) || 0;
15739
15740        if (!carouselRow && carousel) {
15741            const allCarousels = Array.from(document.querySelectorAll(AB.DATALAYER.getCRSHomeCarouselSelector()))
15742                .filter(item => !item.parentElement?.closest?.(AB.DATALAYER.getCRSHomeCarouselSelector()));
15743            const visibleCarousels = AB.DATALAYER.findVisibleElement(allCarousels);
15744            carouselRow = visibleCarousels?.indexOf(carousel) + 1 || 1;
15745        }
15746
15747        const controlSpot = AB.DATALAYER.getCRSHomeArrowDirection(element) === 'left' ? 1 : 2;
15748        return `R${carouselRow < 10 ? `0${carouselRow}` : carouselRow}#S0${controlSpot}#ZONE${zoneNumber < 10 ? `0${zoneNumber}` : zoneNumber}`;
15749    }
15750
15751    this.getCRSCarouselControlTitle = function (element) {
15752        const carousel = AB.DATALAYER.getCRSHomeCarouselElement(element);
15753        return AB.DATALAYER.getAnalyticsCarouselTitle(element)
15754            || carousel?.closest?.('.master-product-carousel, .slick-product-carousel, .slick-coupon-carousel, .coupon-carousel, .meal-carousel, .nextgen-abs-carousel-wrapper, .abs-carousel-wrapper, .mod-unit-carousel, .nextgen-abs-carousel-proxy, .nextgen-banner-carousel, webgen-hero-canvas-carousel, .hero-carousel')?.querySelector?.('.hero-canvas__text-plate-title, .carousel-header-text, .carousel-nav__header-title, .meal-carousel-title, .flex-title, h2, h3')?.textContent?.trim()
15755            || carousel?.querySelector?.('.hero-canvas__text-plate-title, .carousel-header-text, .carousel-nav__header-title, .meal-carousel-title, .flex-title, h2, h3')?.textContent?.trim()
15756            || '';
15757    }
15758
15759    this.getCRSHomeClickText = function (element) {
15760        const visibleText = element?.textContent?.replace(/\s+/g, ' ')?.trim();
15761        const rawText = visibleText
15762            || element?.value
15763            || element?.getAttribute?.('aria-label')
15764            || element?.getAttribute?.('title')
15765            || element?.getAttribute?.('alt')
15766            || '';
15767        return `${rawText}`.replace(/\s+/g, ' ').trim();
15768    }
15769
15770    this.getCRSHomeClickLinkName = function (element) {
15771        const clickText = AB.DATALAYER.getCRSHomeClickText(element);
15772        const sanitizedText = AB.DATALAYER.sanitizeAnalyticsText(clickText);
15773        return `${sanitizedText || 'cta'}-click`;
15774    }
15775
15776    this.getCRSHomeArrowLinkName = function (element) {
15777        return AB.DATALAYER.getCRSHomeArrowDirection(element) === 'left' ? 'swipe-left-click' : 'swipe-right-click';
15778    }
15779
15780    this.isCRSHomeCarouselArrow = function (element) {
15781        const carousel = AB.DATALAYER.getCRSHomeCarouselElement(element);
15782        if (!carousel) {
15783            return false;
15784        }
15785        const ariaLabel = element?.getAttribute?.('aria-label') || '';
15786        const className = element?.className?.toString() || '';
15787        const controlText = `${ariaLabel} ${className} ${element?.textContent || ''}`.toLowerCase();
15788        return /slick-prev|slick-next|carousel-control-prev|carousel-control-next|\bprevious\b|\bnext\b|swipe-left|swipe-right|^<$|^>$/.test(controlText.trim());
15789    }
15790
15791    this.getCRSHomeMediaType = function (element) {
15792        if (element?.closest?.('coupon-carousel, loyalty-card-carousel-al-v1, .slick-coupon-carousel, coupon-grid, .cms-coupon-grid')) {
15793            return 'deals-carousel';
15794        }
15795        if (element?.closest?.('.slick-product-carousel, .master-product-carousel, product-carousel, product-carousel-v2, product-carousel-al-v1')) {
15796            return 'product-carousel';
15797        }
15798        if (element?.closest?.('meals-carousel, .slick-meal-carousel, .meal-carousel')) {
15799            return 'meals-carousel';
15800        }
15801        if (element?.closest?.('.horizontal-video-carousel-wrapper, horizontal-video-carousel-wrapper')) {
15802            return 'video-carousel';
15803        }
15804        if (element?.closest?.('webgen-flex-module, .flex-container, .flex-card')) {
15805            return 'flex-module';
15806        }
15807        if (element?.closest?.('webgen-bundles, webgen-bundles-carousel, .bundles-box, .shopbycategory, .hero-collections')) {
15808            return 'collections';
15809        }
15810        if (element?.closest?.('.nextgen-banner-carousel, webgen-hero-canvas-carousel, .hero-carousel, .nextgen-banner-unit, .nextgen-banner-unit-proxy, .banner-unit, .mod-unit, .mod-unit-carousel, .mod-unit-carousel-container, .nextgen-abs-carousel-wrapper, .abs-carousel-wrapper, .abs-carousel')) {
15811            return 'banner';
15812        }
15813        if (element?.closest?.('utility-bar-wrapper, utility-bar, .utility-bar-wrapper, .utility-bar, .special-occasions-modal__banner, .profile-completion-bar')) {
15814            return 'utility-bar';
15815        }
15816        if (element?.closest?.('webgen-sticky-banner .sticky-banner__container, .sticky-banner__container')) {
15817            return 'sticky-banner';
15818        }
15819        return 'collections';
15820    }
15821
15822    this.getCRSHomeClickSpot = function (element) {
15823        const rowElement = element?.closest?.('.nextgen-abs-carousel-wrapper, .abs-carousel-wrapper, .mod-unit-carousel, .slick-slider, .slick-product-carousel, .master-product-carousel, .slick-coupon-carousel, coupon-carousel, loyalty-card-carousel-al-v1, .nextgen-banner-unit, .nextgen-banner-unit-proxy, .flex-card, .flex-container, webgen-bundles, webgen-bundles-carousel, .bundles-box, .shopbycategory, .title-header, .button.section, .image.section, .marker-component');
15824        const interactiveSelector = 'a, button, [role="button"], input[type="button"], input[type="submit"]';
15825        const clickables = rowElement ? Array.from(rowElement.querySelectorAll(interactiveSelector)).filter(item => item.offsetHeight > 0 && item.offsetWidth > 0) : [];
15826        const spot = clickables.indexOf(element) + 1;
15827        return spot > 0 ? spot : -1;
15828    }
15829
15830    this.getCRSHomeClickPlacement = function (element) {
15831        const isUtilityBar = !!element?.closest?.('utility-bar-wrapper, utility-bar, .utility-bar-wrapper, .utility-bar, .special-occasions-modal__banner, .profile-completion-bar');
15832        const zoneInfo = AB.DATALAYER.getZoneInfo(element);
15833        const row = parseInt(zoneInfo?.row, 10) || 1;
15834        const spot = AB.DATALAYER.getCRSHomeClickSpot(element);
15835        const zone = isUtilityBar ? 99 : (parseInt(zoneInfo?.zone, 10) || 0);
15836        return `R${row < 10 ? `0${row}` : row}#S${spot < 10 ? `0${spot}` : spot}#ZONE${zone < 10 ? `0${zone}` : zone}`;
15837    }
15838
15839    this.getCRSHomeMetricDetail = function (element) {
15840        const dataElement = element?.closest?.('[data-zone-response], [data-flex-module-content], [data-bundles-content], [data-bundles-carousel-content], lazy-wrapper[data-impression-tracking], [data-impression-tracking]');
15841        const zoneData = AB.DATALAYER.safeJSONParse(dataElement?.getAttribute?.('data-zone-response')) || {};
15842        const flexData = AB.DATALAYER.safeJSONParse(dataElement?.getAttribute?.('data-flex-module-content')) || {};
15843        const bundleData = AB.DATALAYER.safeJSONParse(dataElement?.getAttribute?.('data-bundles-content'))
15844            || AB.DATALAYER.safeJSONParse(dataElement?.getAttribute?.('data-bundles-carousel-content'))
15845            || {};
15846        const containerItems = Array.isArray(flexData?.containerItems) ? flexData.containerItems : [];
15847        const bundleItems = Array.isArray(bundleData?.containerItems) ? bundleData.containerItems : [];
15848        const currentBundleId = element?.closest?.('.bundles-box')?.getAttribute?.('data-analytics-id');
15849        const currentBundle = currentBundleId ? bundleItems.find(bundle => bundle?.bundleSlugId == currentBundleId) : null;
15850        return zoneData?.p13nAdobeMetrics?.metricA
15851            || zoneData?.adobeMetrics?.metricA
15852            || flexData?.p13nAdobeMetrics?.metricA
15853            || flexData?.adobeMetrics?.metricA
15854            || containerItems.find(item => item?.p13nAdobeMetrics?.metricA || item?.adobeMetrics?.metricA)?.p13nAdobeMetrics?.metricA
15855            || containerItems.find(item => item?.p13nAdobeMetrics?.metricA || item?.adobeMetrics?.metricA)?.adobeMetrics?.metricA
15856            || currentBundle?.p13nAdobeMetrics?.metricA
15857            || currentBundle?.adobeMetrics?.metricA
15858            || bundleData?.p13nAdobeMetrics?.metricA
15859            || bundleData?.adobeMetrics?.metricA
15860            || bundleItems.find(item => item?.p13nAdobeMetrics?.metricA || item?.adobeMetrics?.metricA)?.p13nAdobeMetrics?.metricA
15861            || bundleItems.find(item => item?.p13nAdobeMetrics?.metricA || item?.adobeMetrics?.metricA)?.adobeMetrics?.metricA
15862            || dataElement?.getAttribute?.('data-impression-tracking')
15863            || 'no-val';
15864    }
15865
15866    this.getCRSHomeComponentSection = function (element) {
15867        const componentContainer = element?.closest?.('.nextgen-banner-unit, .nextgen-banner-unit-proxy, .flex-card, .mod-unit, .shopbycategory, .title-header, .button.section, .image.section, webgen-bundles, webgen-bundles-carousel, .bundles-box, .slick-product-carou
15867sel, .master-product-carousel, .slick-coupon-carousel, coupon-carousel, loyalty-card-carousel-al-v1, .meal-carousel, .nextgen-abs-carousel-wrapper, .abs-carousel-wrapper, .mod-unit-carousel, .nextgen-abs-carousel-proxy, .nextgen-banner-carousel, webgen-hero-canvas-carousel, .hero-carousel');
15868        return AB.DATALAYER.getAnalyticsCarouselTitle(element)
15869            || element?.closest?.('[data-carousel-title]')?.getAttribute?.('data-carousel-title')
15870            || componentContainer?.querySelector?.('.hero-canvas__text-plate-title, .carousel-header-text, .carousel-nav__header-title, .meal-carousel-title, .flex-title, .flex-card__title, .bundles-content-header, [class*="title"], h1, h2, h3')?.textContent?.trim()
15871            || 'no-val';
15872    }
15873
15874    this.getCRSHomeComponentName = function (element) {
15875        const componentContainer = element?.closest?.('.nextgen-banner-unit, .nextgen-banner-unit-proxy, .flex-card, .mod-unit, .shopbycategory, .title-header, .button.section, .image.section, webgen-bundles, webgen-bundles-carousel, .bundles-box, .slick-product-carousel, .master-product-carousel, .slick-coupon-carousel, coupon-carousel, loyalty-card-carousel-al-v1, .meal-carousel, .nextgen-abs-carousel-wrapper, .abs-carousel-wrapper, .mod-unit-carousel, .nextgen-abs-carousel-proxy, .nextgen-banner-carousel, webgen-hero-canvas-carousel, .hero-carousel');
15876        const subtitle = componentContainer?.querySelector?.('.carousel-header-subtitle, .carousel-subtitle, .carousel-nav__subtitle, .carousel-nav .body-text-xs, .meal-carousel-subtitle, .hero-canvas__text-plate-subtitle, .flex-card__subtitle, .flex-subtitle, .bundles-content-description, .sub-title, .subtitle, [class*="subtitle"], [class*="sub-title"], p')?.textContent?.trim();
15877        return subtitle ? AB.DATALAYER.sanitizeAnalyticsText(subtitle) : 'no-val';
15878    }
15879
15880    this.isCRSHomeCaasEnabled = function (element) {
15881        return !!element?.closest?.('[data-api-driven], [data-carousel-driven], [data-abs-carousel-position], [data-abs-carousel-slot], [data-zone-response], [data-flex-module-content], [data-bundles-content], [data-bundles-carousel-content], lazy-wrapper[data-model-configuration-id], lazy-wrapper[data-carousel-filter="p13n"], targeted-wrapper, webgen-flex-module, webgen-bundles, webgen-bundles-carousel');
15882    }
15883
15884    this.isCRSHomeMainContentClick = function (element) {
15885        const mainWrapper = document.querySelector('.nextgen-main-wrapper');
15886        const isInMainWrapper = !!(mainWrapper && element && mainWrapper.contains(element) && !element?.closest?.('.unified-header, header, footer, .modal, [role="dialog"]'));
15887        const isUtilityBar = !!element?.closest?.('utility-bar-wrapper, utility-bar, .utility-bar-wrapper, .utility-bar, .special-occasions-modal__banner, .profile-completion-bar');
15888        return isInMainWrapper || isUtilityBar;
15889    }
15890
15891    this.shouldSkipCRSGenericHomeClick = function (element) {
15892        const text = AB.DATALAYER.getCRSHomeClickText(element).toLowerCase();
15893        const isKnownCTA = /^add\b|view\s*all|shop\s*now|learn\s*more|schedule|sign\s*in\s*to\s*add|sign\s*up|subscribe|see\s*all|reserve|join|start|explore|browse|save/.test(text);
15894        const isProductOrCouponCard = !!element?.closest?.('product-item, product-item-v2, product-item-al-v1, product-item-al-v2, product-carousel-item, product-carousel-item-v2, product-carousel-item-al-v1, product-carousel-item-al-v2, coupon-carousel-item, coupon-card, coupon-item, loyalty-card-al-v1');
15895        return isProductOrCouponCard && !isKnownCTA;
15896    }
15897
15898    this.shouldSkipCRSAddToListClick = function (element) {
15899        return !!element?.closest?.('coupon-carousel-item, coupon-card, coupon-item, loyalty-card-al-v1, loyalty-non-digital-coupon-card-al-v1, ndc-offer-detail-al-v1');
15900    }
15901
15902    this.setCRSHomeGenericClick = function (element) {
15903        const placement = AB.DATALAYER.getCRSHomeClickPlacement(element);
15904        AB.DATALAYER.setCRSClickEvent({
15905            linkName: AB.DATALAYER.getCRSHomeClickLinkName(element),
15906            mTyp: AB.DATALAYER.getCRSHomeMediaType(element),
15907            element: element,
15908            placement: placement,
15909            caasEnbld: AB.DATALAYER.isCRSHomeCaasEnabled(element),
15910            component: AB.DATALAYER.getCRSComponent({
15911                element: element,
15912                section: AB.DATALAYER.getCRSHomeComponentSection(element),
15913                detail: AB.DATALAYER.getCRSHomeMetricDetail(element),
15914                name: AB.DATALAYER.getCRSHomeComponentName(element),
15915                spot: -1,
15916                placement: placement
15917            })
15918        });
15919    }
15920
15921    this.getCRSHomeDomPath = function (element) {
15922        const path = [];
15923        let currentElement = element;
15924        while (currentElement && currentElement.nodeType === 1 && path.length < 5 && currentElement !== document.body) {
15925            const tagName = currentElement.tagName?.toLowerCase();
15926            const dataQa = currentElement.getAttribute?.('data-qa');
15927            const id = currentElement.id;
15928            if (id) {
15929                path.unshift(`${tagName}#${id}`);
15930                break;
15931            }
15932            if (dataQa) {
15933                path.unshift(`${tagName}[data-qa="${dataQa}"]`);
15934                break;
15935            }
15936            const parent = currentElement.parentElement;
15937            const siblings = parent ? Array.from(parent.children).filter(child => child.tagName === currentElement.tagName) : [];
15938            const index = siblings.indexOf(currentElement) + 1;
15939            path.unshift(`${tagName}${index > 1 ? `:nth-of-type(${index})` : ''}`);
15940            currentElement = parent;
15941        }
15942        return path.join('>');
15943    }
15944
15945    this.getCRSHomeElementIdentifier = function (element) {
15946        const href = (element?.getAttribute?.('href') || '').split('?')[0];
15947        return element?.id
15948            || element?.getAttribute?.('data-qa')
15949            || element?.getAttribute?.('data-analytics-id')
15950            || element?.getAttribute?.('aria-label')
15951            || href
15952            || AB.DATALAYER.getCRSHomeDomPath(element)
15953            || 'no-val';
15954    }
15955
15956    this.getCRSHomeComponentDetails = function (element) {
15957        const accordionContainer = element?.closest?.('.accordion-v2-pds__top-level-header, webgen-accordion');
15958        const accordionItem = element?.closest?.('.pds-accordion');
15959        if (accordionItem && accordionContainer && !element?.closest?.('.accordion-v2-pds__top-level-header')) {
15960            return { name: 'Accordion Item', element: accordionItem };
15961        }
15962        const componentRules = [
15963            { name: 'Accordion Container', selector: 'webgen-accordion, .accordion-v2-pds' },
15964            { name: 'Rich Text Editor', selector: 'webgen-rich-text, .rte-content' },
15965            { name: 'Blog Component', selector: 'webgen-blog-component, .blog-component-wrapper_left-align, .blog-component-wrapper_right-align, .blog-component-recipe' },
15966            { name: 'Bundle', selector: 'webgen-bundles, webgen-bundles-carousel, .bundles-box' },
15967            { name: 'Collection', selector: 'webgen-hero-canvas-collections, .promo-container, .promo__card, .hero-collections, .shopbycategory' },
15968            { name: 'Container Unit', selector: 'webgen-container-unit, .container-unit, .hero-canvas-flex' }
15969        ];
15970        const matchingRule = componentRules.find(rule => element?.closest?.(rule.selector));
15971        if (matchingRule) {
15972            return { name: matchingRule.name, element: element.closest(matchingRule.selector) };
15973        }
15974        const closestHost = element?.closest?.('webgen-flex-module, webgen-hero-canvas-carousel, .nextgen-banner-unit, .nextgen-banner-unit-proxy, .flex-card, .mod-unit, .slick-product-carou
15974sel, .slick-coupon-carousel, .meal-carousel');
15975        return {
15976            name: closestHost?.tagName?.toLowerCase?.() || closestHost?.className?.toString?.()?.split(' ')?.[0] || 'Home Content',
15977            element: closestHost || element
15978        };
15979    }
15980
15981    this.getCRSHomeSafeCSSValue = function (element, attrName, cssProperty) {
15982        const rawValue = element?.getAttribute?.(attrName) || element?.style?.getPropertyValue?.(cssProperty) || '';
15983        if (!rawValue) {
15984            return '';
15985        }
15986        try {
15987            return window.CSS?.supports?.(cssProperty, rawValue) ? rawValue : '';
15988        } catch (error) {
15989            return '';
15990        }
15991    }
15992
15993    this.getCRSHomeUniversalPayload = function ({ element, action, linkName, placement, elementIdentifier } = {}) {
15994        const targetElement = element?.nodeType === 1 ? element : element?.parentElement;
15995        if (!targetElement) {
15996            return null;
15997        }
15998        const componentDetails = AB.DATALAYER.getCRSHomeComponentDetails(targetElement);
15999        const componentElement = componentDetails.element || targetElement;
16000        const isStickyBannerElement = targetElement?.closest?.('webgen-sticky-banner .sticky-banner__container, .sticky-banner__container');
16001        const resolvedPlacement = isStickyBannerElement ? AB.DATALAYER.getStickyBannerPlacement(targetElement) : placement || AB.DATALAYER.getCRSHomeClickPlacement(targetElement);
16002        const mediaType = AB.DATALAYER.getCRSHomeMediaType(targetElement);
16003        const componentSection = AB.DATALAYER.getCRSHomeComponentSection(componentElement);
16004        const componentName = componentDetails.name || 'Home Content';
16005        const contentText = AB.DATALAYER.getCRSHomeClickText(targetElement).substring(0, 120);
16006        const identifier = `${elementIdentifier || AB.DATALAYER.getCRSHomeElementIdentifier(targetElement)}`.substring(0, 160);
16007        const href = (targetElement?.closest?.('a')?.getAttribute?.('href') || targetElement?.getAttribute?.('href') || '').split('?')[0];
16008        const timestamp = AB.DATALAYER.generateCurrentTime();
16009
16010        return {
16011            link: {
16012                linkName: `${mediaType}-${linkName}` || (action === 'impression' ? 'impression' : 'click'),
16013                isCRSClick: true,
16014                isSendToSS: true
16015            },
16016            page: { ...digitalData?.pageDetails },
16017            pageFilter: {
16018                ...digitalData?.pageFilter,
16019                mediaType: mediaType
16020            },
16021            absPlacement: AB.DATALAYER.getCRSAbsPlacement({
16022                element: targetElement,
16023                placement: resolvedPlacement,
16024                caasEnbld: AB.DATALAYER.isCRSHomeCaasEnabled(targetElement)
16025            }),
16026            component: AB.DATALAYER.getCRSComponent({
16027                element: componentElement,
16028                section: componentSection,
16029                detail: AB.DATALAYER.getCRSHomeMetricDetail(targetElement),
16030                type: componentName,
16031                name: AB.DATALAYER.getCRSHomeComponentName(componentElement),
16032                placement: resolvedPlacement,
16033                section: this.getCRSPlacementParts(placement).spot
16034            }),
16035            user: { ...digitalData?.user }
16036        };
16037    }
16038
16039    this.isCRSHomeAuthorMode = function () {
16040        const wcmmode = new URLSearchParams(window.location?.search || '').get('wcmmode');
16041        return wcmmode === 'edit'
16042            || (wcmmode !== 'disabled' && !!document.querySelector('.cq-Editor, .editor-GlobalBar, [data-cq-editor]'));
16043    }
16044
16045    this.isCRSHomeTrackingDisabledElement = function (element) {
16046        return !!element?.closest?.('[data-tracking-disabled]');
16047    }
16048
16049    this.isHandledByExistingCRSLayer = function (element) {
16050        if (!element) {
16051            return false;
16052        }
16053        const pausePlayElement = element.closest?.('.svg-slick-play-icon, .svg-slick-pause-icon, .abs-carousel-wrapper__items__play-button, .abs-carousel-wrapper__items__pause-button, .mod-unit-play-button, .mod-unit-pause-button, .hero-carousel__control--play, .hero-carousel__control--pause, .svg-play-icon-with-background, .svg-pause-icon-with-background');
16054        if (pausePlayElement) {
16055            return true;
16056        }
16057        const arrowElement = element.closest?.('.slick-prev, .slick-next, .carousel-control-prev, .carousel-control-next, button, a, [role="button"]');
16058        if (arrowElement && AB.DATALAYER.isCRSHomeCarouselArrow(arrowElement)) {
16059            return true;
16060        }
16061        const productOrCouponElement = element.closest?.('product-item, product-item-v2, product-item-al-v1, product-item-al-v2, product-carou
16061sel-item, product-carousel-item-v2, product-carousel-item-al-v1, product-carousel-item-al-v2, coupon-carousel-item, coupon-card, coupon-item, loyalty-card-al-v1');
16062        if (productOrCouponElement) {
16063            return true;
16064        }
16065        const addToListElement = element.closest?.('button, a, [role="button"]');
16066        const addToListText = `${addToListElement?.getAttribute?.('aria-label') || ''} ${addToListElement?.textContent || ''}`.trim().toLowerCase();
16067        if (addToListElement && /add\s+to\s+(my\s+)?list/.test(addToListText) && !AB.DATALAYER.shouldSkipCRSAddToListClick(addToListElement)) {
16068            return true;
16069        }
16070        const genericClickElement = element.closest?.('a, button, [role="button"], input[type="button"], input[type="submit"]');
16071        return !!(genericClickElement
16072            && AB.DATALAYER.isCRSHomeMainContentClick(genericClickElement)
16073            && !AB.DATALAYER.shouldSkipCRSGenericHomeClick(genericClickElement));
16074    }
16075
16076    this.pushCRSHomeUniversalEvent = function ({ element, action, linkName, placement, elementIdentifier } = {}) {
16077        if (!AB.DATALAYER.isCESEventsEnabled()
16078            || !AB.DATALAYER.isHomePage()
16079            || AB.DATALAYER.isB2BPage()
16080            || AB.DATALAYER.isCRSHomeAuthorMode()
16081            || AB.DATALAYER.isCRSHomeTrackingDisabledElement(element)) {
16082            return;
16083        }
16084        const payload = AB.DATALAYER.getCRSHomeUniversalPayload({ element: element, action: action, linkName: linkName, placement: placement, elementIdentifier: elementIdentifier });
16085        if (payload) {
16086            AB.DATALAYER.pushEvent(AB.DATALAYER.EVENTS.CRS_CLICK, payload);
16087        }
16088    }
16089
16090    this.initCRSHomeUniversalClickLayer = function () {
16091        if (this.crsHomeUniversalClickLayerInitialized || !AB.DATALAYER.isHomePage()) {
16092            return;
16093        }
16094        this.crsHomeUniversalClickLayerInitialized = true;
16095        this.crsHomeUniversalClickHandler = function (event) {
16096            const originalTarget = event.target?.nodeType === 1 ? event.target : event.target?.parentElement;
16097            if (!AB.DATALAYER.isHomePage()) {
16098                AB.DATALAYER.cleanupCRSHomeUniversalTracking();
16099                return;
16100            }
16101            const trackedElement = originalTarget?.closest?.('a, button, [role="button"], input, select, textarea, label, summary, [tabindex]') || originalTarget;
16102            if (!AB.DATALAYER.isCRSHomeMainContentClick(originalTarget)
16103                || AB.DATALAYER.isCRSHomeAuthorMode()
16104                || AB.DATALAYER.isCRSHomeTrackingDisabledElement(trackedElement)
16105                || AB.DATALAYER.isHandledByExistingCRSLayer(trackedElement)) {
16106                return;
16107            }
16108            const placement = AB.DATALAYER.getCRSHomeClickPlacement(trackedElement);
16109            const elementIdentifier = AB.DATALAYER.getCRSHomeElementIdentifier(trackedElement);
16110            const dedupeKey = `click|${elementIdentifier}|${placement}`;
16111            const currentTime = Date.now();
16112            if (AB.DATALAYER.lastCRSHomeUniversalClick?.key === dedupeKey && currentTime - AB.DATALAYER.lastCRSHomeUniversalClick.time < 500) {
16113                return;
16114            }
16115            AB.DATALAYER.lastCRSHomeUniversalClick = { key: dedupeKey, time: currentTime };
16116            // ACIP-576827: piggyback on the existing CRS-Home click (which carries V151-V154)
16117            // to persist V218/V80 for the next pageLoaded when a blog CTA navigates away.
16118            // Same-page (empty/hash) hrefs are skipped per spec.
16119            const blogHost = trackedElement?.closest?.('webgen-blog-component, .blog-component-wrapper_left-align, .blog-component-wrapper_right-align, .blog-component-recipe');
16120            if (blogHost) {
16121                const blogHref = (trackedElement?.getAttribute?.('href') || '').trim();
16122                const isNavigating = trackedElement?.tagName?.toLowerCase?.() === 'a'
16123                    && blogHref && blogHref !== '#' && !blogHref.startsWith('#')
16124                    && !trackedElement.hasAttribute?.('disabled');
16125                if (isNavigating) {
16126                    AB.DATALAYER.setBlogComponentClickAnalytics(blogHost, trackedElement);
16127                }
16128            }
16129            AB.DATALAYER.pushCRSHomeUniversalEvent({
16130                element: trackedElement,
16131                action: 'click',
16132                linkName: 'click',
16133                placement: placement,
16134                elementIdentifier: elementIdentifier
16135            });
16136        };
16137        document.addEventListener('click', this.crsHomeUniversalClickHandler, true);
16138    }
16139
16140    this.getCRSHomeUniversalImpressionKey = function (element) {
16141        const pageKey = this.crsHomeUniversalImpressionPageKey || digitalData?.pageDetails?.pageUrl || window.location?.pathname || 'home';
16142        const elementKey = AB.DATALAYER.getCRSHomeElementIdentifier(element);
16143        return `${pageKey}|${elementKey}`;
16144    }
16145
16146    this.initCRSHomeUniversalImpressions = function () {
16147        if (!AB.DATALAYER.isCESEventsEnabled() || !AB.DATALAYER.isHomePage() || AB.DATALAYER.isCRSHomeAuthorMode()) {
16148            return;
16149        }
16150        const mainWrapper = document.querySelector('.nextgen-main-wrapper');
16151        if (!mainWrapper) {
16152            return;
16153        }
16154        const impressionElements = mainWrapper.querySelectorAll('webgen-accordion, .accordion-v2-pds, .accordion-v2-pds .pds-accordion, webgen-rich-text, webgen-blog-component, .blog-component-wrapper_left-align, .blog-component-wrapper_right-align, webgen-container-unit');
16155        if (!impressionElements || impressionElements.length === 0) {
16156            return;
16157        }
16158        if (!this.crsHomeUniversalImpressionObserver && typeof IntersectionObserver !== 'undefined') {
16159            this.crsHomeUniversalImpressionObserver = new IntersectionObserver((entries, observer) => {
16160                if (!AB.DATALAYER.isHomePage()) {
16161                    AB.DATALAYER.cleanupCRSHomeUniversalTracking();
16162                    return;
16163                }
16164                entries.forEach(entry => {
16165                    if (entry?.isIntersecting && entry.intersectionRatio >= 0.5) {
16166                        const element = entry.target;
16167                        const impressionKey = AB.DATALAYER.getCRSHomeUniversalImpressionKey(element);
16168                        if (element?.dataset?.crsUniversalImpressionTracked === impressionKey
16169                            || AB.DATALAYER.isCRSHomeTrackingDisabledElement(element)
16170                            || AB.DATALAYER.isCRSHomeAuthorMode()) {
16171                            observer.unobserve(element);
16172                            return;
16173                        }
16174                        AB.DATALAYER.pushCRSHomeUniversalEvent({
16175                            element: element,
16176                            action: 'impression',
16177                            linkName: 'impressions',
16178                            placement: AB.DATALAYER.getCRSHomeClickPlacement(element),
16179                            elementIdentifier: AB.DATALAYER.getCRSHomeElementIdentifier(element)
16180                        });
16181                        element.dataset.crsUniversalImpressionTracked = impressionKey;
16182                        observer.unobserve(element);
16183                    }
16184                });
16185            }, {
16186                root: null,
16187                rootMargin: '0px',
16188                threshold: [0.5]
16189            });
16190        }
16191        impressionElements.forEach(element => {
16192            const impressionKey = AB.DATALAYER.getCRSHomeUniversalImpressionKey(element);
16193            if (element?.dataset?.crsUniversalObserverAttached === impressionKey
16194                || element?.dataset?.crsUniversalImpressionTracked === impressionKey
16195                || AB.DATALAYER.isCRSHomeTrackingDisabledElement(element)) {
16196                return;
16197            }
16198            if (this.crsHomeUniversalImpressionObserver) {
16199                this.crsHomeUniversalImpressionObserver.observe(element);
16200                element.dataset.crsUniversalObserverAttached = impressionKey;
16201            } else {
16202                AB.DATALAYER.pushCRSHomeUniversalEvent({
16203                    element: element,
16204                    action: 'impression',
16205                    linkName: 'impressions',
16206                    placement: AB.DATALAYER.getCRSHomeClickPlacement(element),
16207                    elementIdentifier: AB.DATALAYER.getCRSHomeElementIdentifier(element)
16208                });
16209                element.dataset.crsUniversalImpressionTracked = impressionKey;
16210            }
16211        });
16212    }
16213
16214    this.cleanupCRSHomeUniversalTracking = function () {
16215        if (this.crsHomeUniversalClickHandler) {
16216            document.removeEventListener('click', this.crsHomeUniversalClickHandler, true);
16217            this.crsHomeUniversalClickHandler = null;
16218        }
16219        this.crsHomeUniversalClickLayerInitialized = false;
16220
16221        if (this.crsHomeUniversalImpressionObserver) {
16222            this.crsHomeUniversalImpressionObserver.disconnect();
16223            this.crsHomeUniversalImpressionObserver = null;
16224        }
16225        if (this.crsHomeUniversalMutationObserver) {
16226            this.crsHomeUniversalMutationObserver.disconnect();
16227            this.crsHomeUniversalMutationObserver = null;
16228        }
16229        clearTimeout(this.crsHomeUniversalMutationTimer);
16230        this.crsHomeUniversalMutationTimer = null;
16231        this.crsHomeUniversalImpressionPageKey = null;
16232        document.querySelectorAll('[data-crs-universal-observer-attached]').forEach(element => {
16233            delete element.dataset.crsUniversalObserverAttached;
16234        });
16235    }
16236
16237    this.initCRSHomeUniversalRouteLifecycle = function () {
16238        if (this.crsHomeUniversalRouteLifecycleInitialized) {
16239            return;
16240        }
16241        this.crsHomeUniversalRouteLifecycleInitialized = true;
16242        this.crsHomeUniversalRouteHandler = function () {
16243            clearTimeout(AB.DATALAYER.crsHomeUniversalRouteTimer);
16244            AB.DATALAYER.crsHomeUniversalRouteTimer = setTimeout(() => {
16245                if (AB.DATALAYER.isHomePage()) {
16246                    AB.DATALAYER.initCRSHomeUniversalTracking();
16247                } else {
16248                    AB.DATALAYER.cleanupCRSHomeUniversalTracking();
16249                }
16250            }, 0);
16251        };
16252        window.addEventListener('popstate', this.crsHomeUniversalRouteHandler);
16253
16254        if (window.history && !window.history.crsHomeUniversalWrapped) {
16255            const originalPushState = history.pushState;
16256            const originalReplaceState = history.replaceState;
16257            history.pushState = function () {
16258                const result = originalPushState.apply(this, arguments);
16259                AB.DATALAYER.crsHomeUniversalRouteHandler?.();
16260                return result;
16261            };
16262            history.replaceState = function () {
16263                const result = originalReplaceState.apply(this, arguments);
16264                AB.DATALAYER.crsHomeUniversalRouteHandler?.();
16265                return result;
16266            };
16267            window.history.crsHomeUniversalWrapped = true;
16268        }
16269    }
16270
16271    this.initCRSHomeUniversalTracking = function () {
16272        AB.DATALAYER.initCRSHomeUniversalRouteLifecycle();
16273        if (!AB.DATALAYER.isHomePage()) {
16274            AB.DATALAYER.cleanupCRSHomeUniversalTracking();
16275            return;
16276        }
16277        if (AB.DATALAYER.isCRSHomeAuthorMode()) {
16278            AB.DATALAYER.cleanupCRSHomeUniversalTracking();
16279            return;
16280        }
16281        this.crsHomeUniversalImpressionPageKey = this.crsHomeUniversalImpressionPageKey
16282            || `${digitalData?.pageDetails?.pageUrl || window.location?.pathname || 'home'}|${Date.now()}`;
16283        AB.DATALAYER.initCRSHomeUniversalClickLayer();
16284        AB.DATALAYER.initCRSHomeUniversalImpressions();
16285        const mainWrapper = document.querySelector('.nextgen-main-wrapper');
16286        if (this.crsHomeUniversalMutationObserver || !mainWrapper || typeof MutationObserver === 'undefined') {
16287            return;
16288        }
16289        this.crsHomeUniversalMutationObserver = new MutationObserver(() => {
16290            if (!AB.DATALAYER.isHomePage()) {
16291                AB.DATALAYER.cleanupCRSHomeUniversalTracking();
16292                return;
16293            }
16294            clearTimeout(this.crsHomeUniversalMutationTimer);
16295            this.crsHomeUniversalMutationTimer = setTimeout(() => {
16296                if (!AB.DATALAYER.isHomePage()) {
16297                    AB.DATALAYER.cleanupCRSHomeUniversalTracking();
16298                    return;
16299                }
16300                AB.DATALAYER.initCRSHomeUniversalImpressions();
16301            }, 100);
16302        });
16303        this.crsHomeUniversalMutationObserver.observe(mainWrapper, { childList: true, subtree: true });
16304    }
16305
16306    this.setCRSHomeArrowClick = function (element) {
16307        const placement = AB.DATALAYER.getCRSCarouselControlPlacement(element);
16308        const linkName = AB.DATALAYER.getCRSHomeArrowLinkName(element);
16309        const dedupeKey = `${linkName}|${placement}|${AB.DATALAYER.getCRSHomeMediaType(element)}`;
16310        const currentTime = Date.now();
16311        if (AB.DATALAYER.lastCRSHomeArrowClick?.key === dedupeKey && currentTime - AB.DATALAYER.lastCRSHomeArrowClick.time < 500) {
16312            return;
16313        }
16314        AB.DATALAYER.lastCRSHomeArrowClick = { key: dedupeKey, time: currentTime };
16315
16316        AB.DATALAYER.setCRSClickEvent({
16317            linkName: linkName,
16318            mTyp: AB.DATALAYER.getCRSHomeMediaType(element),
16319            element: element,
16320            placement: placement,
16321            caasEnbld: AB.DATALAYER.isCRSHomeCaasEnabled(element),
16322            component: AB.DATALAYER.getCRSComponent({
16323                element: element,
16324                section: AB.DATALAYER.getCRSCarouselControlTitle(element),
16325                detail: AB.DATALAYER.getCRSHomeMetricDetail(element),
16326                spot: -1,
16327                placement: placement
16328            })
16329        });
16330    }
16331
16332    this.initCRSHomeClickLayer = function () {
16333        // Keep this legacy CRS layer document-bound across SPA navigation; only the universal layer is cleaned up per route.
16334        if (this.crsHomeClickLayerInitialized || !AB.DATALAYER.isHomePage()) {
16335            return;
16336        }
16337        this.crsHomeClickLayerInitialized = true;
16338        document.addEventListener('click', function (event) {
16339            if (!AB.DATALAYER.isHomePage()) {
16340                return;
16341            }
16342            const target = event.target;
16343            if (!AB.DATALAYER.isCRSHomeMainContentClick(target)) {
16344                return;
16345            }
16346
16347            const pausePlayElement = target?.closest?.('.svg-slick-play-icon, .svg-slick-pause-icon, .abs-carousel-wrapper__items__play-button, .abs-carousel-wrapper__items__pause-button, .mod-unit-play-button, .mod-unit-pause-button, .hero-carousel__control--play, .hero-carousel__control--pause, .svg-play-icon-with-background, .svg-pause-icon-with-background');
16348            if (pausePlayElement) {
16349                const ariaLabel = pausePlayElement.getAttribute('aria-label') || '';
16350                const className = pausePlayElement.className?.toString() || '';
16351                const action = ariaLabel.toLowerCase().indexOf('play') !== -1 || className.indexOf('play') !== -1 ? 'play' : 'pause';
16352                const placement = AB.DATALAYER.getCRSCarouselControlPlacement(pausePlayElement);
16353                AB.DATALAYER.setCRSPausePlayClick({
16354                    action: action,
16355                    element: pausePlayElement,
16356                    placement: placement,
16357                    component: AB.DATALAYER.getCRSComponent({
16358                        element: pausePlayElement,
16359                        section: AB.DATALAYER.getCRSCarouselControlTitle(pausePlayElement),
16360                        placement: placement
16361                    })
16362                });
16363                return;
16364            }
16365
16366            const arrowElement = target?.closest?.('.slick-prev, .slick-next, .carousel-control-prev, .carousel-control-next, button, a, [role="button"]');
16367            if (arrowElement && AB.DATALAYER.isCRSHomeCarouselArrow(arrowElement)) {
16368                AB.DATALAYER.setCRSHomeArrowClick(arrowElement);
16369                return;
16370            }
16371
16372            const addToListElement = target?.closest?.('button, a, [role="button"]');
16373            const addToListText = `${addToListElement?.getAttribute?.('aria-label') || ''} ${addToListElement?.textContent || ''}`.trim().toLowerCase();
16374            if (addToListElement && /add\s+to\s+(my\s+)?list/.test(addToListText) && !AB.DATALAYER.shouldSkipCRSAddToListClick(addToListElement)) {
16375                const placement = localStorage.getItem('analyticsProductPlacement') || digitalData?.pageFilter?.placement || AB.DATALAYER.setCouponPlacement({}, addToListElement, 'add-to-list');
16376                AB.DATALAYER.setCRSAddToListClick({
16377                    product: digitalData?.productInfo,
16378                    element: addToListElement,
16379                    placement: placement,
16380                    component: AB.DATALAYER.getCRSComponent({
16381                        element: addToListElement,
16382                        placement: placement
16383                    })
16384                });
16385                return;
16386            }
16387
16388            const genericClickElement = target?.closest?.('a, button, [role="button"], input[type="button"], input[type="submit"]');
16389            if (genericClickElement && AB.DATALAYER.isCRSHomeMainContentClick(genericClickElement) && !AB.DATALAYER.shouldSkipCRSGenericHomeClick(genericClickElement)) {
16390                AB.DATALAYER.setCRSHomeGenericClick(genericClickElement);
16391            }
16392        });
16393    }
16394
16395    /**
16396     * Global click layer for flex banner tracking 
16397     * Server-rendered templates (AEM HTML / handlebars) already wire these
16398     * handlers via inline onclick attributes, so we skip any anchor that
16399     * already has one to avoid double-firing on those pages.
16400     */
16401    this.initFlexBannerClickLayer = function () {
16402        if (this.flexBannerClickLayerInitialized) {
16403            return;
16404        }
16405        this.flexBannerClickLayerInitialized = true;
16406
16407        document.addEventListener('click', function (event) {
16408            const target = event.target;
16409            const link = target && target.closest ? target.closest('a') : null;
16410            if (!link) {
16411                return;
16412            }
16413
16414            // Server-rendered templates already call the legacy handlers via
16415            // inline onclick. Skip those anchors to prevent duplicate events.
16416            if (typeof link.hasAttribute === 'function' && link.hasAttribute('onclick')) {
16417                return;
16418            }
16419
16420            const inMerch = link.closest('.flex-medium-fw') || link.closest('search-grid-merch-banner');
16421            const inHero = link.closest('.hero-flex__card') || link.closest('.hero-canvas-row__flex');
16422            const inFlexCard = link.closest('.flex-container') || link.closest('.flex-card');
16423
16424            if (!inMerch && !inHero && !inFlexCard) {
16425                return;
16426            }
16427
16428            if (inHero) {
16429                AB.DATALAYER.setHeroCardsTracking(link);
16430            } else if (inMerch) {
16431                AB.DATALAYER.setMerchFlexBannerTracking(link);
16432            } else {
16433                AB.DATALAYER.setFlexBannerClickTracking(link);
16434            }
16435        });
16436    };
16437
16438
16439    /**
16440    * Manage add to seller for both matrketplace and wineshop
16441    * @param {*} sellerType Marketplace or Wineshop 
16442    */
16443    this.addedToSellerTypeModalTracking = function (sellerType) {
16444        this.setModalViewEvents(`${sellerType === 'marketplace' ? 'mkp:added-to-seller-order' : 'added-to-wine-shop'}|view`);
16445        document.querySelector('.modal-footer__action-btn__cart')?.addEventListener('click', () => {
16446            sellerType === 'marketplace' ?
16447                this.setLSItem('analyticsMkpGoToCart', 'mkp:added-to-seller-order|go-to-cart') :
16448                this.setModalClickEvents('added-to-wine-shop|go-to-cart');
16449        });
16450    }
16451
16452    this.mkpCrossSellersNoResultsClicks = function () {
16453        document.querySelector('search-grid .mkp-cross-seller-no-results a')?.addEventListener('click', function () {
16454            localStorage.setItem('analyticsCrossSellersNoResults', 'cta:cross-sellers-null-search|button|search-on-banner');
16455        });
16456    }
16457
16458    this.sanitizeTitlePicksForYouAndP13n = function (title) {
16459        const transformedTitle = title.trim().toLowerCase().split(' ').join('-').replace(/[^\w-,|#:]/gi, '').replace('--', '-');
16460        return transformedTitle === 'picks-for-you' ? 'picked-for-you' : transformedTitle;
16461    }
16462
16463    /**
16464     * Sets link click event when clicking on View Similar Items for Out of stock products
16465     * @param product 
16466     */
16467    this.setViewSimilarItemsClick = function (product) {
16468        if (product?.itemNotAvailableTxt?.toLowerCase() === 'out of stock') {
16469            this.setLinkClickEvents('bia-oos:similar-items');
16470        } else {
16471            this.removeLSItem('aaBiaSimilarItemsMetrics');
16472        }
16473    }
16474
16475    /**
16476     * Check if a BIA product is OOS
16477     * @param product 
16478     * @returns true is the product is OOS, false otherwise
16479     */
16480    this.isBiaItemOos = function (product) {
16481        const { status, price, channelEligibility, channelInventory } = product;
16482        const userChannel = this.getUserChannel();
16483        const channelKeyName = userChannel === 'pickup' ? 'pickUp' : userChannel === 'instore' ? 'inStore' : userChannel;
16484        const isProductEligible = channelEligibility && channelEligibility[channelKeyName]
16485            ? channelEligibility[channelKeyName]
16486            : false;
16487
16488        if (status === 'inactive' || price <= 0) {
16489            return true;
16490        }
16491        if (isProductEligible && channelInventory?.[userChannel]) {
16492            return ['', null, undefined, '0'].includes(channelInventory[userChannel]) && ['pickup', 'delivery', 'shipping'].includes(userChannel);
16493        } else {
16494            return !(channelEligibility?.['delivery'] || channelEligibility?.['inStore'] || channelEligibility?.['pickUp'])
16495        }
16496    }
16497
16498    /**
16499     * Gets adobeMetrics for cross sell component on BIA landing page and stores them in local storage for later use in cart add actions
16500     * @param products 
16501     */
16502    this.getBiaOosAdobeMetrics = function (products) {
16503        if (products && products.length) {
16504            const productsObj = {};
16505            products.forEach(product => {
16506                if (product.adobeMetrics) {
16507                    const productId = product.id;
16508                    productsObj[productId] = product.adobeMetrics;
16509                }
16510            });
16511
16512            if (Object.keys(productsObj).length > 0) {
16513                const productsString = JSON.stringify(productsObj);
16514                this.setLSItem('aaBiaSimilarItemsMetrics', productsString);
16515            }
16516        }
16517    }
16518
16519    /**
16520     * Sets impressionAdditionalDetail, subsAdditionalDetail and pfmSorce for Similar Items on BIA on add to cart
16521     */
16522    this.similarItemsBiaAddToCart = function () {
16523        if (this.isBIAPage()) {
16524            const lsAdobeMetrics = this.getLSItem('aaBiaSimilarItemsMetrics');
16525            if (lsAdobeMetrics && digitalData?.productInfo?.isCrossSell) {
16526                const currentProductId = digitalData.productInfo.productID;
16527                const lsAdobeMetricsParsed = this.safeJSONParse(lsAdobeMetrics);
16528                const adobeMetrics = currentProductId ? lsAdobeMetricsParsed[currentProductId] : '';
16529                digitalData.productInfo.impressionAdditionalDetail = adobeMetrics?.metricA || 'no-value#no-value#no-value#no-value#no-value#no-value';
16530                digitalData.productInfo.subsAdditionalDetail = adobeMetrics?.metricB || 'no-value#no-value#no-value#no-value#no-value#no-value#no-value#no-value#no-value#no-value';
16531                digitalData.pageFilter.pfmSource = 'similar-items_buy-it-again';
16532            }
16533        }
16534    }
16535
16536    /**
16537     * Sets impressionAdditionalDetail, and pfmSorce for BIA carousal product on PDP add to cart
16538     */
16539    this.biaCarousalProductPDPAddToCart = function () {
16540        if (this.isPdp() && this.getLSItem('analyticsBIAPfmSource') && this.getLSItem('analyticsBIAPfmSource') !== 'undefined' && this.getLSItem('analyticsBIAProductImpressionAdDetail') && this.getLSItem('analyticsBIAProductImpressionAdDetail') !== 'undefined' && this.getLSItem('analyticsIsBIACarousal') && this.getLSItem('analyticsIsBIACarousal') !== 'undefined' && this.getLSItem('analyticsBIACarousalProductId') == digitalData?.productInfo?.productID) {
16541            digitalData.pageFilter.pfmSource = this.getLSItem('analyticsBIAPfmSource');
16542            digitalData.productInfo.impressionAdditionalDetail = this.getLSItem('analyticsBIAProductImpressionAdDetail');
16543            digitalData.productInfo.isBIACarousalProduct = this.getLSItem('analyticsIsBIACarousal') === 'true' ? true : false;
16544        }
16545    }
16546
16547    // add carousel name to LS 
16548    this.setCarouselNameRecipes = function (element) {
16549        const carouselName = element?.querySelector('.recipe-carousel')?.querySelector('h2.carousel-header-text')?.textContent || element?.querySelector('.related-recipe-carousel')?.querySelector('.coupons-text-wrapper h2')?.textContent || '';
16550        if (carouselName) {
16551            localStorage.setItem('analyticsCarouselName', 'recipes|' + carouselName);
16552        }
16553    }
16554
16555    // set digitalData.recipes on recipe details pages
16556    this.initRecipeDetails = function () {
16557        if (digitalData?.pageDetails?.subSection2 && digitalData?.pageDetails?.subSection2?.indexOf('detail') != -1) {
16558            const recipeTitle = document.querySelector('h2#recipeTitle')?.textContent.trim();
16559            digitalData.recipes = {
16560                name: recipeTitle || '',
16561                source: digitalData.pageDetails.subSection3
16562            }
16563        }
16564    }
16565
16566    /**
16567     * Sets ls item when clicking on sns link from product cards
16568     * Used for setting topNav on the next page
16569     * @param snsOffer 
16570     */
16571    this.setSnsLinkClick = function (snsOffer) {
16572        if (digitalData?.pageDetails) {
16573            const subSections = [digitalData.pageDetails.subSection1, digitalData.pageDetails.subSection2, digitalData.pageDetails.subSection3, digitalData.pageDetails.subSection4].filter(
16573Boolean).join(':');
16574            const snsLink = `cta:${subSections}|link|schdule-and-save-${snsOffer?.replace('%', '')}-percent`;
16575            if (window.location?.pathname?.startsWith('/rewards/point-reward-details')) {
16576                AB.DATALAYER.setLinkClickEvents('cta:rewards-dashboard|link|rewards:schedule-and-save');
16577            }
16578            this.setLSItem('analyticsSNSlink', snsLink);
16579        }
16580    }
16581
16582    /**
16583     * Sets ls item when clicking on FAQs link on sns modals on PDP
16584     * Used for setting topNav on the next page
16585     * @param dataConfig 
16586     */
16587    this.setSnsModalLinkClick = function (link, dataConfig) {
16588        if (this.isPdp() && digitalData?.pageDetails) {
16589            const subSections = [digitalData.pageDetails.subSection1, digitalData.pageDetails.subSection2, digitalData.pageDetails.subSection3, digitalData.pageDetails.subSection4].filter(Boolean).join(':');
16590            if (link === 'manage') {
16591                this.setLSItem('analyticsSNSlink', `cta:${subSections}|link|modal-manage-ss`);
16592            } else {
16593                const linkName = dataConfig?.modal === 'infoModal'
16594                    ? 'link'
16595                    : dataConfig?.modal === 'freqModal' ? 'frequency:link' : 'adding-to-recurring-order:link';
16596                const faqsLink = `cta:${subSections}|${linkName}|faq-and-terms`;
16597                this.setLSItem('analyticsSNSlink', faqsLink);
16598            }
16599        }
16600    }
16601
16602    /**
16603     * Sets modalView event for S&S modals on PDP
16604     * @param data 
16605     * @param product 
16606     * @param isChecked 
16607     */
16608    this.setSnsModalViewEvents = function (data, product, isChecked, selectedFrequency) {
16609        if (data) {
16610            const { modal, productInfo } = digitalData;
16611            let subscribe = '';
16612            let frequency = '';
16613            switch (data.modal) {
16614                case 'infoModal':
16615                    if (this.isPdp() || this.isCartAndCheckoutPage('erums/cart')) {
16616                        modal.modalAction = 'ar:learn-more|view';
16617                        subscribe = 'unsubscribe';
16618                        frequency = isChecked === false
16619                            ? 'no-frequency'
16620                            : selectedFrequency === 1 ? 'every-week' : `every-${selectedFrequency}-weeks`;
16621                        this.setLSItem('analyticsInfoModalSubscribe', subscribe);
16622                    }
16623                    break;
16624                case 'freqModal':
16625                    if (this.isPdp()) {
16626                        modal.modalAction = 'ar:frequency|view';
16627                        frequency = data.selectedFrequency === 1 ? 'every-week' : `every-${data.selectedFrequency}-weeks`;
16628                    }
16629                    subscribe = 'unsubscribe';
16630                    break;
16631                case 'addRecurringModal':
16632                    modal.modalAction = `ar:adding-to-recurring-order${this.isPdp() ? '-pdp' : '-plp'}|view`;
16633                    subscribe = 'unsubscribe';
16634                    frequency = 'every-week';
16635                    modal.modalMessage = `cta:schedule-and-save-5-percent|button|${this.isPdp() ? 'pdp' : 'plp'}`;
16636                    break;
16637                case 'successModal':
16638                    modal.modalAction = `ar:item-scheduled${this.isPdp() ? '' : '-plp'}|view`;
16639                    subscribe = 'subscribe';
16640                    frequency = data.selectedFrequency === 1 ? 'every-week' : `every-${data.selectedFrequency}-weeks`;
16641                    modal.modalMessage = this.isPdp() ? 'cta:schedule-and-save-5-percent|schedule-it|pdp' : '';
16642                    break;
16643                default:
16644                    break;
16645            }
16646            productInfo.productID = product ? product.id : data.productId;
16647            productInfo.scheduleandSaveSource = `${this.isPdp() ? 'pdp' : 'plp'}#${subscribe}#${frequency}`;
16648            const eventSent = this.setEventOncePerPage(modal.modalAction, 'modalView', this.isPdp() ? undefined : productInfo.productID);
16649            // on PDP don't send 'ar:item-scheduled|view' event
16650            const shouldSendEvent = !(this.isPdp() && modal.modalAction === 'ar:item-scheduled|view');
16651            if (!eventSent && shouldSendEvent) {
16652                this.pushEvent(
16653                    this.EVENTS.MODAL_VIEW,
16654                    {
16655                        modal: digitalData?.modal,
16656                        productInfo: digitalData?.productInfo,
16657                        page: digitalData?.pageDetails,
16658                        pageFilter: digitalData?.pageFilter
16659                    }
16660                );
16661            }
16662        }
16663    }
16664
16665    /**
16666     * Sets linkClick event when user checks/unchecks the S&S checkbox on PDP
16667     * @param isChecked 
16668     * @param product 
16669     * @param frequency
16670     */
16671    this.snsCheckboxClick = function (isChecked, product, frequency) {
16672        if (this.isPdp()) {
16673            const subscribe = 'unsubscribe';
16674            const linkName = `ar:${isChecked ? '' : 'un'}subscribe-schedule-and-save`;
16675            const snsFrequency = frequency === 1 ? 'every-week' : `every-${frequency}-weeks`;
16676            digitalData.crossPageData.snsAnalyticsFrequency = digitalData.crossPageData.snsAnalyticsFrequency || {};
16677            digitalData.crossPageData.snsAnalyticsFrequency.data = digitalData.crossPageData.snsAnalyticsFrequency.data || {};
16678            digitalData.crossPageData.snsAnalyticsFrequency.data[product?.id] = snsFrequency;
16679            AB.DATALAYER.setAnalyticsCrossPageData({ action: 'set', name: `snsAnalyticsFrequency`, data: digitalData.crossPageData.snsAnalyticsFrequency.data, isAcrossPages: true });
16680            const eventSent = this.setEventOncePerPage(linkName, 'linkCl
16680ick');
16681            if (!eventSent) {
16682                this.pushEvent(
16683                    this.EVENTS.LINK_CLICK,
16684                    {
16685                        link: {
16686                            linkName: linkName
16687                        },
16688                        productInfo: {
16689                            productID: product?.id,
16690                            scheduleandSaveSource: `pdp#${subscribe}#${snsFrequency}`
16691                        },
16692                        page: digitalData?.pageDetails,
16693                        pageFilter: digitalData?.pageFilter
16694                    }
16695                );
16696            }
16697        }
16698    }
16699
16700    /**
16701     * Sets modalClick events for S&S modals on PDP
16702     * @param modalAction 
16703     * @param data 
16704     * @param formModel 
16705     * @param recurringFrequency 
16706     */
16707    this.setSnsModalClickEvents = function (modalAction, data, formModel, recurringFrequency) {
16708        const { modal, productInfo } = digitalData;
16709        const eventSent = this.isPdp() ? this.setEventOncePerPage(modalAction, 'modalClick') : false;
16710        modal.modalAction = (modalAction === 'ar:item-scheduled|continue-shopping' && !this.isPdp() && data?.source !== 'full-cart')
16711            ? 'ar:item-scheduled-plp|continue-shopping'
16712            : modalAction.indexOf('ar:item-scheduled') !== -1 && this.isPdp()
16713                ? modalAction.replace('ar:item-scheduled', 'ar:subscription-confirmed-pdp')
16714                : modalAction;
16715        // on PLP only send 'ar:item-scheduled-plp|continue-shopping' and 'ar:subscribe-schedule-and-save-plp|subscribed' events
16716        const shouldSendAction = this.isPdp()
16717            ? true
16718            : modal.modalAction === 'ar:item-scheduled-plp|continue-shopping' || modal.modalAction === 'ar:subscribe-schedule-and-save-plp|subscribed' ? true : data?.source === 'full-cart' ? true : false;
16719
16720        if (!eventSent && shouldSendAction) {
16721
16722            let productId;
16723            if (this.isPdp()) {
16724                if (data?.product?.id) {
16725                    productId = data?.product?.id;
16726                } else {
16727                    const urlParts = window.location.pathname.split('.');
16728                    productId = urlParts[urlParts.length - 2];
16729                }
16730            } else {
16731                productId = data?.product?.id;
16732            }
16733
16734            let subscribe = 'subscribe';
16735            let frequencyValue;
16736
16737            if (data?.modal === 'infoModal') {
16738                subscribe = this.handleGetLSValue('analyticsInfoModalSubscribe');
16739                frequencyValue = subscribe === 'subscribe' ? data?.selectedFrequency ? data.selectedFrequency : 1 : '';
16740            } else if (data?.modal === 'addRecurringModal') {
16741                frequencyValue = recurringFrequency;
16742                if (this.isPdp()) {
16743                    modal.modalAction = modal.modalAction === 'ar:subscribe-schedule-and-save-plp|subscribed'
16744                        ? 'ar:adding-to-recurring-order-pdp|subscribed'
16745                        : modal.modalAction.replace('|', '-pdp|');
16746                }
16747            } else {
16748                frequencyValue = modal.modalAction === 'ar:frequency|save' ? formModel?.frequency : data?.selectedFrequency;
16749            }
16750            const frequency = !frequencyValue
16751                ? 'no-frequency'
16752                : frequencyValue == 1 ? 'every-week' : `every-${frequencyValue}-weeks`;
16753
16754            modal.modalMessage = (modal.modalAction === 'ar:subscribe-schedule-and-save-plp|subscribed' || modal.modalAction === 'ar:adding-to-recurring-order-pdp|subscribed')
16755                ? frequency === 'every-week' ? 'frequency-not-modified' : 'frequency-modified'
16756                : '';
16757
16758            if (['ar:frequency|save', 'ar:frequency|close', 'ar:subscribe-schedule-and-save|close', 'ar:subscribe-schedule-and-save-rpt|remove', 'ar:subscribe-schedule-and-save|not-now'].indexOf(modal.modalAction) !== -1) {
16759                subscribe = 'unsubscribe';
16760            }
16761
16762            productInfo.productID = productId;
16763            productInfo.scheduleandSaveSource = `${this.isPdp() ? 'pdp' : data?.source === 'full-cart' ? data.source : 'plp'}#${subscribe}#${frequency}`;
16764
16765            if (modal.modalAction === 'ar:frequency|save' && this.isPdp()) {
16766                digitalData.crossPageData.snsAnalyticsFrequency = digitalData.crossPageData.snsAnalyticsFrequency || {};
16767                digitalData.crossPageData.snsAnalyticsFrequency.data = digitalData.crossPageData.snsAnalyticsFrequency.data || {};
16768                digitalData.crossPageData.snsAnalyticsFrequency.data[productId] = frequency;
16769                AB.DATALAYER.setAnalyticsCrossPageData({ action: 'set', name: `snsAnalyticsFrequency`, data: digitalData.crossPageData.snsAnalyticsFrequency.data, isAcrossPages: true });
16770            }
16771
16772            this.pushEvent(
16773                this.EVENTS.MODAL_CLICK,
16774                {
16775                    modal: digitalData?.modal,
16776                    productInfo: digitalData?.productInfo,
16777                    page: digitalData?.pageDetails,
16778                    pageFilter: digitalData?.pageFilter
16779                }
16780            );
16781        }
16782    }
16783
16784    /**
16785     * initialize the modalAction, modalMessage, linklName, productId and scheduleandSaveSource
16786     */
16787    this.SNSValInitialize = function () {
16788        digitalData.modal = {
16789            modalAction: '',
16790            modalMessage: ''
16791        };
16792        digitalData.link = {
16793            linkName: ''
16794        };
16795        digitalData.productInfo = digitalData.productInfo || {};
16796        digitalData.productInfo.productID = '';
16797        digitalData.productInfo.scheduleandSaveSource = '';
16798        digitalData.pageFilter = digitalData.pageFilter || {};
16799    }
16800
16801    /**
16802     * Sets page load event when clicking on 'Scheduled Items' tab on Manage Schedule & Save page
16803     */
16804    this.SNSInit = function (pageView, SNSObject) {
16805        if (digitalData?.pageDetails) {
16806            this.SNSValInitialize();
16807            localStorage.removeItem('analyticsOneTimeOrderItems');
16808            digitalData.pageFlags.isSnSItemsListExpanded = false;
16809            digitalData.pageDetails.subSection1 = 'customer-account';
16810            digitalData.pageDetails.subSection2 = 'manage-schedule-and-save';
16811            if (pageView === 'upcoming-orders') {
16812                const userState = `${SNSObject?.isNewUser ? 'never-enrolled' : (SNSObject?.userWithNoActiveSubscriptions ? 'previous-enrolled' : 'enrolled')}`;
16813                digitalData.pageDetails.subSection3 = `upcoming-orders-${userState}`;
16814                if (SNSObject?.upcomingOrder?.orderStatus === 'Created') {
16815                    digitalData.modal.modalMessage = 'upcoming-orders-enrolled-t1-state';
16816                }
16817            } else if (pageView === 'scheduled-items') {
16818                digitalData.pageDetails.subSection3 = 'scheduled-items';
16819                // Set number of ss active and canceled items
16820                digitalData.modal.modalMessage = `ss#${SNSObject?.activeItems?.length || '0'}|cancelled#${SNSObject?.cancelledItems?.length || '0'}`;
16821            } else if (pageView === 'preferences-tab') {
16822                digitalData.pageDetails.subSection3 = 'preferences-tab';
16823                // Set the message on the preference tab as modalMessage
16824                digitalData.modal.modalMessage = SNSObject?.preferenceTabMessage ? SNSObject?.preferenceTabMessage?.toLowerCase().replace(/ /g, '-') : '';
16825            } else if (pageView === 'bia' || pageView === 'bia-no-results') {
16826                if (SNSObject?.upcomingOrder?.oneTimeOrderItems) {
16827                    localStorage.setItem('analyticsOneTimeOrderItems', JSON.stringify(SNSObject.upcomingOrder.oneTimeOrderItems));
16828                }
16829                const todayDate = new Date();
16830                const nextOrderDate = new Date(SNSObject?.upcomingOrder?.orderDate);
16831                const todayDateUtc = Date.UTC(todayDate.getFullYear(), todayDate.getMonth(), todayDate.getDate());
16832                const nextOrderDateUtc = Date.UTC(
16833                    nextOrderDate.getFullYear(),
16834                    nextOrderDate.getMonth(),
16835                    nextOrderDate.getDate(),
16836                );
16837                const numOfDays = (nextOrderDateUtc - todayDateUtc) / (1000 * 60 * 60 * 24);
16838                digitalData.pageDetails.subSection2 = 'ota';
16839                digitalData.pageDetails.subSection3 = pageView;
16840                digitalData.pageFilter.topNav = this.handleGetLSValue('analyticsCTAValue');
16841                digitalData.modal.modalMessage = numOfDays ? numOfDays : '';
16842
16843                const modal = document.querySelector('#snsOneTimeAddModal');
16844                if (modal) {
16845                    modal.addEventListener('click', event => {
16846                        if (digitalData.pageDetails.subSection3 !== 'upcoming-orders-enrolled' && ((!event.target?.closest('.sns-modal-content-wrapper') && event.target !== document.querySelector('.sns-modal-content-wrapper')?.parentElement && !event.target?.closest('button') && !event.target?.closest('quantity-stepper-al-v2') && !event.target?.classList?.contains('dropdown-item')) || event.target?.closest('button')?.getAttribute('aria-label') === 'Close')) {
16847                            digitalData.pageDetails.subSection1 = 'customer-account';
16848                            digitalData.pageDetails.subSection2 = 'manage-schedule-and-save';
16849                            digitalData.pageDetails.subSection3 = 'upcoming-orders-enrolled';
16850                            digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:loyalty:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}:${digitalData.pageDetails.subSection3}`;
16851                            digitalData.pageFilter.topNav = '';
16852                            digitalData.modal.modalMessage = '';
16853                            AB.DATALAYER.setPageLoad();
16854                        }
16855                    });
16856                }
16857            }
16858            digitalData.pageDetails.pageName = `${digitalData.pageDetails.banner}:loyalty:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}:${digitalData.pageDetails.subSection3}`;
16859            this.removeLSItem('analyticsSNSProdAction');
16860        }
16861        AB.DATALAYER.setPageLoad();
16862        digitalData.pageFilter.topNav = '';
16863    }
16864
16865    this.setOtaSnsSearch = function (response, keyword) {
16866        const searchInfo = {
16867            searchType: 'internalsearch:typeahead:suggestion',
16868            typedSearchTerm: '',
16869            autoSearchFlag: 'true',
16870            typedSearchCount: '',
16871            internalSearchTerm: keyword,
16872            searchResults: response?.numFound ? response.numFound.toString() : '0',
16873        };
16874        if (localStorage.getItem('analyticsSearchTerm')) {
16875            searchInfo.typedSearchTerm = this.handleGetLSValue('analyticsSearchTerm');
16876            searchInfo.typedSearchCount = searchInfo.typedSearchTerm?.length?.toString();
16877        }
16878        digitalData.modal = {};
16879        digitalData.modal.modalMessage = response?.docs?.length <= 0 || response?.numFound === 0 ? `sorry-we-couldn't-find-any-products-matching-${keyword}` : '';
16880        this.setSearch(searchInfo);
16881    }
16882
16883    this.snsProdAction = function (action) {
16884        AB.DATALAYER.setPfmDetailOnProductAction();
16885        AB.DATALAYER.setLinkClickEvents(action);
16886        let analyticsOneTimeOrderItems = AB.DATALAYER.getLSItem('analyticsOneTimeOrderItems') ? AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('analyticsOneTimeOrderItems')) : [];
16887        let updatedItems = analyticsOneTimeOrderItems;
16888        if (action === 'cart_add') {
16889            updatedItems.push(digitalData.productInfo);
16890        } else if (action === 'remove_cart') {
16891            updatedItems = analyticsOneTimeOrderItems.filter(item => item?.productID !== digitalData?.productInfo?.productID);
16892        } else {
16893            updatedItems = analyticsOneTimeOrderItems.map(item => item?.productID === digitalData?.productInfo?.productID ? digitalData?.productInfo : item);
16894        }
16895        localStorage.setItem('analyticsOneTimeOrderItems', JSON.stringify(updatedItems));
16896    }
16897
16898    /**
16899     * Sets linkClick events on Manage Schedule & Save page, Scheduled Items Tab
16900     */
16901    this.scheduledAndSaveItemsLinkClick = function (linkClicked, data, orderDate) {
16902        this.SNSValInitialize();
16903        let linkName;
16904        if (linkClicked === 'ar:subscribe-schedule-and-save|confirm-substitutions-for-cancel-items' || linkClicked === 'ota-remove-item|yes-remove-item' || linkClicked === 'ota-remove-item|never-mind') {
16905            linkName = linkClicked;
16906        } else {
16907            const prefix = 'ar:subscribe-schedule-and-save';
16908            linkName = data?.item?.otaToSnsFlag || data?.item?.isReplinishItem === false
16909                ? `${prefix}-ota|${linkClicked}`
16910                : data?.item?.isActiveSubscription || data?.item?.nextOrderItemId ? `${prefix}|${linkClicked}` : `${prefix}|cancel-${linkClicked}`;
16911        }
16912        const subscribe = linkName === 'ar:subscribe-schedule-and-save' ? 'unsubscribe' : 'subscribe';
16913
16914        if (['quantity-increase', 'quantity-decrease', 'ar:subscribe-schedule-and-save|confirm-substitutions-for-cancel-items', 'ota-remove-item|yes-remove-item', 'ota-remove-item|never-mind'].indexOf(linkClicked) !== -1) {
16915            digitalData.productInfo.productID = data?.item?.productBpn || '';
16916            digitalData.productInfo.scheduleandSaveSource = data?.item?.frequency?.displayFrequency ?
16917                `${digitalData.pageDetails.pageName}#${subscribe}#every-${data?.item?.frequency?.displayFrequency?.replace(/ /g, '-')}` : '';
16918            digitalData.productInfo.units = data?.item?.quantity?.toString();
16919            digitalData.productInfo.listPrice = data?.item?.itemPrice;
16920
16921            // for ota get numOfDays = next order date - date when user clicks the cta
16922            let numOfDays = '';
16923            if ((data?.item?.otaToSnsFlag || data?.item?.isReplinishItem === false) && orderDate) {
16924                const todayDate = new Date();
16925                const nextOrderDate = new Date(orderDate);
16926                const todayDateUtc = Date.UTC(todayDate.getFullYear(), todayDate.getMonth(), todayDate.getDate());
16927                const nextOrderDateUtc = Date.UTC(nextOrderDate.getFullYear(), nextOrderDate.getMonth(), nextOrderDate.getDate());
16928                numOfDays = (nextOrderDateUtc - todayDateUtc) / (1000 * 60 * 60 * 24);
16929            }
16930
16931            this.setLinkClickEvents(linkName, false, numOfDays);
16932        } else {
16933            this.setLinkClickEvents(linkName, true);
16934        }
16935    }
16936
16937    /**
16938     * Sets modalClick and modalView events on Manage Schedule & Save page, Scheduled Items Tab
16939     */
16940    this.scheduledAndSaveItemsModalEvents = function (eventType, modalAction, data, modalMessage) {
16941        this.SNSValInitialize();
16942        const subSections = [digitalData.pageDetails.subSection1, digitalData.pageDetails.subSection2, digitalData.pageDetails.subSection3, digitalData.pageDetails.subSection4].filter(
16942Boolean).join(':');
16943        digitalData.modal.modalMessage = modalMessage ? `cta:${subSections}|button|${modalMessage.toLowerCase().replace(/ /g, '-')}` : '';
16944        digitalData.productInfo.productID = data?.productID || '';
16945        digitalData.productInfo.scheduleandSaveSource = data?.updatedFrequency ? `${digitalData.pageDetails.pageName}#subscribe#${data.updatedFrequency.toLowerCase().replace(/ /g, '-')}` : '';
16946        if (eventType === 'view') {
16947            this.setModalViewEvents(modalAction);
16948        } else {
16949            this.setModalClickEvents(modalAction, undefined, false);
16950        }
16951    }
16952
16953    this.snsNextPickupDeliveryClick = function (event, calledBy, productFulfillType, productFulfillDate) {
16954        if ((AB.DATALAYER.isHomePage() || AB.DATALAYER.isSearchResultsPage() || AB.DATALAYER.isLpPage()) && productFulfillDate && productFulfillType) {
16955            let ctaValue = 'product-card';
16956            if (calledBy === 'product-carousel-item') {
16957                ctaValue = event?.target?.closest('.slick-product-carousel')?.querySelector('.carousel-header-text')
16958                    ? event?.target?.closest('.slick-product-carousel')?.querySelector('.carousel-header-text')?.textContent?.toLowerCase()?.trim()?.replace(/\s/g, '-')
16959                    : event?.target?.closest('.slick-product-carousel')?.querySelector('.carousel-nav__header-title')
16960                        ? event?.target?.closest('.slick-product-carousel')?.querySelector('.carousel-nav__header-title').textContent?.toLowerCase()?.trim()?.replace(/\s/g, '-')
16961                        : 'no-value';
16962            }
16963            const formattedDate = new Date(productFulfillDate)?.toLocaleDateString('en-US', { timeZone: 'UTC', month: 'short', day: '2-digit' });
16964            const updatedFulfillType = productFulfillType === 'dug' ? 'pickup' : productFulfillType;
16965            AB.DATALAYER.analyticsCTATracking(`cta:${AB.DATALAYER.initPathSections(true).join(':')}|${ctaValue}-link|${updatedFulfillType}-${formattedDate.replace(' ', '-')}`);
16966        } else if (AB.DATALAYER.isLpPage()) {
16967            AB.DATALAYER.analyticsCTATracking(`cta:${AB.DATALAYER.initPathSections(true).join(':')}|link|manage-scheduled-${productFulfillType === 'dug' ? 'pickup' : productFulfillType}`);
16968        }
16969    }
16970
16971    /**
16972     * Sets modalView and modalClick events for new sign in flow
16973     */
16974    this.setSignInModalEvents = function (eventType, modalAction, modalMessage, topNav) {
16975        if (digitalData) {
16976            const subSections = [digitalData.pageDetails.subSection1, digitalData.pageDetails.subSection2, digitalData.pageDetails.subSection3, digitalData.pageDetails.subSection4].filter(
16976Boolean).join(':');
16977            digitalData.pageFilter.topNav = topNav ? `cta:${subSections}|button|${topNav}` : '';
16978            digitalData.modal.modalMessage = modalMessage ? modalMessage.toLowerCase().replace(/ /g, '-') : '';
16979            const isOncePerPage = modalAction?.includes('use-existing-account') ? false : true;
16980            if (eventType === 'click') {
16981                // if action = 'shopped-with-us-before|close' send only one modal click event per page
16982                AB.DATALAYER.setModalClickEvents(modalAction, undefined, isOncePerPage);
16983            } else {
16984                AB.DATALAYER.setModalViewEvents(modalAction, true);
16985            }
16986        }
16987    }
16988
16989    /**
16990     * Sets modalView and modalClick events for new sign in flow
16991     */
16992    this.setConvertAccountModalEvents = function (eventType, action) {
16993        if (digitalData) {
16994            const banner = digitalData.pageDetails.banner && digitalData.pageDetails.banner.indexOf('business') !== -1 ?
16995                digitalData.pageDetails.banner.replace('business-', '') : digitalData.pageDetails.banner;
16996            const modalAction = eventType && `${eventType === 'view' ? 'view' : eventType === 'goToBanner' ? banner : eventType === 'new' || eventType === 'convert' ? 'continue' : ''}`;
16997            if (action === 'click') {
16998                digitalData.modal.modalMessage = eventType === 'new' || eventType === 'convert' ?
16999                    document.getElementsByTagName('login-wrapper')?.[0]?.getAttribute(`data-${eventType === 'convert' ? 'convert-to' : 'create-new'}-business-acct`)?.toLowerCase()?.replace(/ /g, '-') : '';
17000                AB.DATALAYER.setModalClickEvents(`use-existing-account|${modalAction}`);
17001            } else {
17002                AB.DATALAYER.setModalViewEvents(`use-existing-account|${modalAction}`);
17003            }
17004
17005        }
17006    }
17007
17008    this.initSignInMessage = function () {
17009        const signInMessage = this.handleGetLSValue('analyticsSignInMessage');
17010        if (signInMessage && digitalData?.modal) {
17011            digitalData.modal.modalMessage = signInMessage;
17012        }
17013    }
17014
17015    this.accountInputErrorTracking = function (element) {
17016        let checkInput = element?.getAttribute('aria-describedby')
17017            && element?.getAttribute('aria-describedby') === 'error-username'
17018            && element?.getAttribute('formcontrolname') === 'phoneNumber' ? 'error-phoneNumber' : element?.getAttribute('aria-describedby');
17019        const inputFieldError = document.querySelector(`#${checkInput}`)?.innerText;
17020        const featureError = (element?.getAttribute('formcontrolname') === 'username' || element?.getAttribute('formcontrolname') === 'password') ? 'OTP-error' : 'create-account-error';
17021        if (!digitalData.pageFlags[checkInput] && inputFieldError) {
17022            AB.DATALAYER.setError('7814', featureError, inputFieldError);
17023            digitalData.pageFlags[checkInput] = true;
17024        }
17025    }
17026
17027    /**
17028     * Sets modalView and modaClick events for splash screen
17029     */
17030    this.setSplashScreenEvents = function (modalAction, event, analyticsData) {
17031        if (digitalData?.pageDetails) {
17032            digitalData.pageDetails.abTestDetails = analyticsData?.abTestDetails;
17033            if (event === 'view') {
17034                this.setModalViewEvents(modalAction);
17035                this.splashModalHandler();
17036            } else {
17037                this.setModalClickEvents(modalAction);
17038            }
17039        }
17040    }
17041
17042    /**
17043     * Sets modalClick event when clicking outside splash modal
17044     */
17045    this.splashModalHandler = function () {
17046        const modal = document.querySelector('#splashModal');
17047        if (modal) {
17048            modal.addEventListener('click', event => {
17049                if (!event.target.closest('.modal-content') && !event.target.classList.contains('show')) {
17050                    AB.DATALAYER.setModalClickEvents('splash-screen-deals-for-you|close');
17051                }
17052            });
17053        }
17054    }
17055
17056    this.snsExpandButtonClick = function (element) {
17057        const allOrders = document?.querySelector('div#tabpanel-0 div')?.childNodes;
17058        const nextOrder = allOrders?.[0]?.querySelectorAll('button[aria-label="expand"]')?.length > 0 ? Array.from(allOrders?.[0]?.querySelectorAll('button[aria-label="expand"]')) : [];
17059        const futureOrder = allOrders?.[1]?.querySelectorAll('button[aria-label="expand"]')?.length > 0 ? Array.from(allOrders?.[1]?.querySelectorAll('button[aria-label="expand"]')) : [];
17060        if (nextOrder?.indexOf(element) !== -1) {
17061            this.setLinkClickEvents('upcoming-orders|next-order', true);
17062        } else if (futureOrder?.indexOf(element) !== -1) {
17063            this.setLinkClickEvents(`upcoming-orders|future-orders-[${(futureOrder?.indexOf(element)) + 1}]`, true);
17064        }
17065    }
17066
17067
17068    this.trackAEMZone = function (action, nativeElement, content, id) {
17069        try {
17070            // Set zone number
17071            let element = nativeElement;
17072            // This is exclusively for carousel links, as the element received is the actual zone component, not the link
17073            if (nativeElement?.classList && Array.from(nativeElement.classList).includes('zone-component')) {
17074                element = nativeElement.querySelector(`[data-carousel-title="${content}"]`);
17075            }
17076
17077            const sectionInfo = AB.DATALAYER.getZoneInfo(element);
17078
17079            if (action === 'link') {
17080                action = `link:${element?.textContent?.trim() ? AB.DATALAYER.sanitizeAnalyticsText(element?.textContent?.trim()) : 'no-value'}`
17081            }
17082            if (action === 'campaign-link') {
17083                sectionInfo.section = 1;
17084                sectionInfo.row = 1;
17085                action = 'campaign';
17086            }
17087            if (action === 'campaign-banner') {
17088                sectionInfo.section = 1;
17089                sectionInfo.row = 1;
17090                action = 'banner';
17091                content = `small-banner:${content}`;
17092            }
17093            if (action === 'merch-banner') {
17094                action = 'banner';
17095                content = `merch-banner:${content}`;
17096            }
17097
17098            if (action === 'banner' && typeof content === 'string' && content.indexOf('sticky-banner:') === 0) {
17099                sectionInfo.section = '99';
17100                sectionInfo.row = '99';
17101            }
17102
17103            const currentZonePosition = sectionInfo.section < 10 ? `0${sectionInfo.section}` : sectionInfo.section;
17104            const currentSpot = sectionInfo.row < 10 ? `0${sectionInfo.row}` : sectionInfo.row;
17105
17106            // currently set to no-value due to lack of implementation on UMA
17107            const uniqueId = id ? id : 'no-value';
17108
17109            content = content ? this.sanitizeAnalyticsText(content) : 'no-value';
17110
17111            if (sectionInfo.section && sectionInfo.section != '' && sectionInfo.row && sectionInfo.row != '') {
17112                // Set tracking string
17113                const aemZone = `z${currentZonePosition}|${action}|${content}|sp${currentSpot}|${uniqueId}`;
17114
17115                if (['pdp-card', 'banner', 'hero-collections', 'flex', 'hero-canvas', 'collections', 'disclaimer', 'view', 'link', 'campaign', 'carousel'].filter((x) => { return action ? action.indexOf(x) != -1 : false }).length > 0) {
17116                    localStorage.setItem('aemZoneAnalytics', aemZone);
17117                } else if (['remove_cart', 'cart_add', 'add_quantity', 'remove_quantity', 'coupon_clipped', 'offer-drawer'].filter((x) => { return action ? action.indexOf(x) != -1 : false }).length > 0) {
17118                    digitalData.pageFilter.bannerCardCarousel = aemZone;
17119                }
17120                return aemZone;
17121            }
17122        } catch (error) {
17123            console.error('@AnalyticsTeam: graceful failure, error in trackAEMZone: ', error);
17124        }
17125    }
17126
17127    this.setFreshpassPageFilterValues = function () {
17128        const { pageFilter, user } = digitalData;
17129        let subscriptionInfoObj;
17130        if (this.getLSItem('freshpass-analytics-confirmation') && this.isCartAndCheckoutPage('prebook')) {
17131            subscriptionInfoObj = this.safeJSONParse(this.getLSItem('freshpass-analytics-confirmation'));
17132        }
17133
17134        const subscriptionPlanLS = !this.isCartAndCheckoutPage('prebook') ? this.getLSItem('analyticsSubscriptionPlan') : subscriptionInfoObj ? `prebook:freshpass-${subscriptionInfoObj?.isExtendedTrial
17135            ? `${subscriptionInfoObj?.trialExtDuration}-extd-` : ''}${(!!subscriptionInfoObj?.isTrialElligible
17136                ? 'trial-' : '')}${subscriptionInfoObj?.planType?.includes('monthlyplan') ? 'monthly-' : 'annual-'}confirmation` : '';
17137        const subscriptionPlanPrice = !this.isCartAndCheckoutPage('prebook') ? this.getLSItem('analyticsFPPlanPrice') : (subscriptionInfoObj?.monthlyPlanPrice || subscriptionInfoObj?.annualPlanPrice || '');
17138        const subscriptionDiscountedMonths = !this.isCartAndCheckoutPage('prebook') ? this.getLSItem('analyticsFPDiscountedMonths') : (subscriptionInfoObj?.monthlyDiscountMonths || subscriptionInfoObj?.annualDiscountMonths || '');
17139
17140        if (subscriptionPlanLS) {
17141            pageFilter.subscriptionFunnel = this.isCartAndCheckoutPage('order/confirmation')
17142                ? subscriptionPlanLS.replace('checkout', 'confirmation')
17143                : subscriptionPlanLS;
17144        }
17145        if (subscriptionPlanPrice) {
17146            pageFilter.freshPassPlanPrice = subscriptionPlanPrice;
17147            pageFilter.freshPassDiscountedMonths = subscriptionDiscountedMonths;
17148        }
17149        if (subscriptionInfoObj && this.isCartAndCheckoutPage('prebook')) {
17150            user.subscriptionStatus = subscriptionInfoObj?.planType?.includes('monthlyplan') ? 'freshpass-monthly' : subscriptionInfoObj?.planType?.includes('annualplan') ? 'freshpass-annual' : '';
17151        }
17152        if (this.isCartAndCheckoutPage('order/confirmation')) {
17153            this.removeLSItem('analyticsSubscriptionPlan');
17154            this.removeLSItem('analyticsFPPlanPrice');
17155            this.removeLSItem('analyticsFPDiscountedMonths');
17156        }
17157    }
17158
17159    this.initCartAndCheckoutPages = function ({ accordionData, pageSpecificData } = {}) {
17160        if (digitalData) {
17161            const openedAccordion = accordionData && (accordionData.filter((accordion) => accordion.isOpen == true))[0];
17162            const currentPage = digitalData?.pageDetails?.pageName;
17163            const { pageDetails, pageFilter, user, modal, link } = digitalData;
17164            if (!this.isDFTAPage()) {
17165                for (let i = 0; i <= 3; i++) {
17166                    pageDetails[`subSection${i + 1}`] = '';
17167                }
17168            }
17169
17170            pageDetails.channel = 'Checkout';
17171
17172            switch (true) {
17173                // Full Cart page
17174                case this.isCartAndCheckoutPage('erums/cart'):
17175                    pageDetails.subSection1 = 'Full Cart';
17176                    break;
17177                // Order confirmation page
17178                case this.isCartAndCheckoutPage('order/confirmation'):
17179                    pageDetails.subSection1 = 'Checkout';
17180                    pageDetails.subSection2 = 'Order Confirmation';
17181                    break;
17182                // Slots
17183                case this.isCartAndCheckoutPage('prebook'):
17184                    pageDetails.subSection1 = 'reserve time';
17185                    pageDetails.subSection2 = 'delivery date and time';
17186                    if (pageSpecificData?.availableSlots && pageSpecificData?.serviceType === 'DELIVERY') {
17187                        link.linkName = 'prebook-more-delivery-times';
17188                        pageDetails.subSection3 = 'more-delivery-times';
17189                    }
17190                    break;
17191                // Checkout
17192                case this.isCartAndCheckoutPage('erums/checkout'):
17193                    pageDetails.subSection1 = 'Checkout';
17194                    pageDetails.subSection2 = openedAccordion?.referenceId === 'COA' ? 'credit on account' : openedAccordion?.label;
17195                    if (pageSpecificData?.bagFeePreference) {
17196                        this.setImpression(pageSpecificData.bagFeePreference?.toggleEnabled === true ? 'bagprf-on' : 'bagprf-off');
17197                    }
17198                    if (pageSpecificData?.selectiveCart) {
17199                        // Need to reset cart info since it gets set on pageLoad from LS
17200                        digitalData.cart = {
17201                            cartInfo: {},
17202                            item: [],
17203                            transaction: {
17204                                subTotal: ''
17205                            },
17206                            savings: {}
17207                        };
17208                        AB.DATALAYER.updateCart(pageSpecificData);
17209                        pageDetails.isSelectiveCart = true;
17210                    }
17211                    break;
17212                // Edit Full Cart
17213                case this.isCartAndCheckoutPage('edit/cart'):
17214                    pageDetails.subSection1 = 'edit order';
17215                    pageDetails.subSection2 = 'edit cart';
17216                    break;
17217                //Edit Confirmation
17218                case this.isCartAndCheckoutPage('checkout/confirmation'):
17219                    pageDetails.subSection1 = 'edit order';
17220                    pageDetails.subSection2 = 'edit order confirmation';
17221                    break;
17222                // Edit Slot
17223                case this.isCartAndCheckoutPage('edit/slot'):
17224                    pageDetails.subSection1 = 'edit order';
17225                    pageDetails.subSection2 = 'edit delivery date and time';
17226                    break;
17227                // Edit Checkout
17228                case this.isCartAndCheckoutPage('edit/checkout'):
17229                    pageDetails.subSection1 = 'edit order';
17230                    pageDetails.subSection2 = 'edit order checkout';
17231                    break;
17232                // Don't forget to add
17233                case this.isDFTAPage():
17234                    pageDetails.pageUrl = window.location.href;
17235                    pageDetails.referringURL = this.getReferringUrl();
17236                    pageFilter.topNav = this.initTopNav();
17237                    pageDetails.subSection1 = 'erums';
17238                    pageDetails.subSection2 = 'cart';
17239                    pageDetails.subSection3 = 'dnf';
17240                    break;
17241            }
17242
17243            this.setPageName('', true, openedAccordion ? openedAccordion?.id : undefined);
17244
17245            this.initUser();
17246
17247            this.setFreshpassPageFilterValues();
17248
17249            this.updatesFromLSBeforePageLoad();
17250
17251            if ((/PromoNPay/gi).test(openedAccordion?.uniqueId) && pageSpecificData?.storeConfiguration?.isSNAPEligible) {
17252                this.setImpression('ebt-available');
17253            }
17254            openedAccordion?.id === 2 && this.trackEliteSlots(pageSpecificData);
17255
17256            if (pageSpecificData?.slots?.reservedSlot) {
17257                pageFilter.premiumSlots = localStorage.getItem('dtm-premiumslots');
17258            }
17259
17260            user && Object.keys(user).length !== 0 && (user.deliveryCombo = pageSpecificData?.deliveryType ? pageSpecificData?.deliveryType : pageSpecificData?.order?.deliveryType ? pageSpecificData?.order?.deliveryType : '');
17261            if (pageSpecificData) {
17262                AB.DATALAYER.setDefaultValues(pageSpecificData);
17263            }
17264
17265            const isPaypalPayment = pageSpecificData?.customerPreferences?.fundsAllocation?.tenderAllocationSummary?.some((x) => x?.paymentSubType === 'PAYPAL');
17266            this.setPaymentMethodPaypal('checkout', isPaypalPayment);
17267
17268            if (this.isCartAndCheckoutPage('order/confirmation')) {
17269                pageDetails.sellerId = pageSpecificData?.order?.seller?.sellerId ? pageSpecificData?.order?.seller?.sellerId : pageSpecificData?.order?.cartCategory === '1P_WINE' ? '22222222' : AB.DATALAYER.getBannerSellerId();
17270            }
17271
17272            if (this.isCartAndCheckoutPage('order/confirmation') || this.isCartAndCheckoutPage('checkout/confirmation')) {
17273                modal.modalMessage = this.getPaymentUpdatedStatus();
17274            }
17275
17276            if (openedAccordion && openedAccordion?.id && currentPage?.indexOf(openedAccordion.label) < 0) {
17277                const isFirstCallSent = appEventData.length === 0;
17278                let event = openedAccordion && openedAccordion?.id === 1 && isFirstCallSent ? 'checkout' : `checkout_step${openedAccordion?.id}`;
17279                AB.DATALAYER.setPreviousPageName();
17280                AB.DATALAYER.setRestrictedPageCnc();
17281                this.pushEvent(event, {
17282                    page: digitalData?.pageDetails,
17283                    pageFilter: digitalData?.pageFilter,
17284                    user: digitalData?.user,
17285                    productInfo: digitalData?.productInfo,
17286                    modal: digitalData?.modal,
17287                    cart: digitalData?.cart
17288                });
17289            } else if (this.isCartAndCheckoutPage('prebook') || this.isDFTAPage()) {
17290                AB.DATALAYER.setPreviousPageName();
17291                this.pushEvent(this.EVENTS.PAGE_LOADED, {
17292                    page: digitalData?.pageDetails,
17293                    pageFilter: digitalData?.pageFilter,
17294                    link: digitalData?.link,
17295                    user: digitalData?.user,
17296                    cart: digitalData?.cart
17297                });
17298            }
17299            pageFilter.topNav = '';
17300        }
17301    }
17302    this.setBentoHeroTracking = function (action, payload, _element) {
17303        try {
17304            if (!payload || !window.digitalData) return;
17305
17306            var isCartOrCoupon = action === 'cart_add' || action === 'coupon_clipped';
17307            var isNavToNextPage = action === 'pdp-card';
17308            var isCrossPage = action === 'banner' || isNavToNextPage || action === 'deal-line';
17309
17310            var applyBentoProducts = function (products) {
17311                if (!products) return;
17312                digitalData.productInfo = digitalData.productInfo || {};
17313                var productId = products.split(';')[1] || '';
17314                var eVar14Match = products.match(/(?:^|\|)eVar14=([^|]+)/);
17315                var eVar14 = eVar14Match ? eVar14Match[1] : '';
17316                digitalData.productInfo.products = products;
17317                digitalData.productInfo.productString = products;
17318                if (productId && !digitalData.productInfo.productID) {
17319                    digitalData.productInfo.productID = productId;
17320                }
17321                if (eVar14) {
17322                    digitalData.productInfo.pfmDetail = eVar14;
17323                }
17324            };
17325
17326            if (payload.v218) {
17327                if (isCrossPage) {
17328                    try { localStorage.setItem('aemZoneAnalytics', payload.v218); } catch (e) { }
17329                } else {
17330                    digitalData.pageFilter.bannerCardCarousel = payload.v218;
17331                }
17332            }
17333
17334            if (payload.l2) {
17335                digitalData.pageDetails.abTestDetails = payload.l2;
17336                if (isCrossPage) {
17337                    try { localStorage.setItem('analyticsProductMsg', payload.l2); } catch (e) { }
17338                }
17339            }
17340
17341            if (payload.products) {
17342                applyBentoProducts(payload.products);
17343                if (isNavToNextPage) {
17344                    try { localStorage.setItem('bentoHeroProducts', payload.products); } catch (e) { }
17345                }
17346            }
17347
17348            var v80Fields = null;
17349            if (payload.v80 && action !== 'coupon_clipped') {
17350                var parts = payload.v80.split('#');
17351                v80Fields = {
17352                    mediaType: parts[0],
17353                    recommendationType: parts[1] || undefined,
17354                    placement: parts.length > 2 ? parts.slice(2).join('#') : undefined,
17355                };
17356            }
17357
17358            if (payload.v171) {
17359                if (action === 'deal-line') {
17360                    try { localStorage.setItem('bentoHeroCTAValue', payload.v171); } catch (e) { }
17361                } else {
17362                    this.analyticsCTATracking(payload.v171);
17363                }
17364            }
17365
17366            if (payload.carouselTitle && action === 'coupon_clipped' && digitalData.pageFilter) {
17367                digitalData.pageFilter.bentoCarouselTitle = payload.carouselTitle;
17368            }
17369            if (action === 'coupon_clipped' && payload.v218 && digitalData.pageFilter) {
17370                digitalData.pageFilter.bentoCouponV218Set = true;
17371            }
17372
17373            if (action === 'cart_add') {
17374                digitalData.link = digitalData.link || {};
17375                digitalData.link.linkName = 'cart_add';
17376            }
17377
17378            if (isCartOrCoupon) {
17379                if (v80Fields) Object.assign(digitalData.pageFilter, v80Fields);
17380            } else if (isCrossPage) {
17381                if (payload.v80) {
17382                    try { localStorage.setItem('bentoHeroMediaPlacement', payload.v80); } catch (e) { }
17383                }
17384                if (action === 'banner' && payload.v218) {
17385                    var eventPageFilter = Object.assign({}, digitalData.pageFilter);
17386                    eventPageFilter.bannerCardCarousel = payload.v218;
17387                    if (v80Fields) Object.assign(eventPageFilter, v80Fields);
17388                    this.pushEvent(this.EVENTS.LINK_CLICK, {
17389                        link: {
17390                            linkName: payload.v218,
17391                            oneTagLinkName: 'banner-clicked'
17392                        },
17393                        pageFilter: eventPageFilter,
17394                        page: Object.assign({}, digitalData.pageDetails),
17395                    });
17396                }
17397            }
17398        } catch (error) {
17399            console.error('@AnalyticsTeam: graceful failure in setBentoHeroTracking:', error);
17400        }
17401    };
17402
17403    this.initAEMZoneTracking = function () {
17404        if (localStorage.getItem('aemZoneAnalytics') && digitalData?.pageFilter) {
17405            digitalData.pageFilter.bannerCardCarousel = localStorage.getItem('aemZoneAnalytics');
17406            localStorage.removeItem('aemZoneAnalytics');
17407        }
17408
17409        // ACIP-576827: V80 carry-over for Blog component CTA click that navigated to this page.
17410        if (localStorage.getItem('mediaPlacementClick') && digitalData?.pageFilter) {
17411            digitalData.pageFilter.mediaPlacementClick = localStorage.getItem('mediaPlacementClick');
17412            localStorage.removeItem('mediaPlacementClick');
17413        }
17414
17415        var bentoMediaPlacement = localStorage.getItem('bentoHeroMediaPlacement');
17416        if (bentoMediaPlacement && digitalData?.pageFilter) {
17417            var mpParts = bentoMediaPlacement.split('#');
17418            digitalData.pageFilter.mediaType = mpParts[0];
17419            if (mpParts[1] !== undefined) digitalData.pageFilter.recommendationType = mpParts[1];
17420            if (mpParts.length > 2) digitalData.pageFilter.placement = mpParts.slice(2).join('#');
17421            localStorage.removeItem('bentoHeroMediaPlacement');
17422        }
17423
17424        var bentoHeroProducts = localStorage.getItem('bentoHeroProducts');
17425        if (bentoHeroProducts && digitalData) {
17426            digitalData.productInfo = digitalData.productInfo || {};
17427            var productId = bentoHeroProducts.split(';')[1] || '';
17428            var eVar14Match = bentoHeroProducts.match(/(?:^|\|)eVar14=([^|]+)/);
17429            var eVar14 = eVar14Match ? eVar14Match[1] : '';
17430            digitalData.productInfo.products = bentoHeroProducts;
17431            digitalData.productInfo.productString = bentoHeroProducts;
17432            if (productId && !digitalData.productInfo.productID) {
17433                digitalData.productInfo.productID = productId;
17434            }
17435            if (eVar14) {
17436                digitalData.productInfo.pfmDetail = eVar14;
17437            }
17438            localStorage.removeItem('bentoHeroProducts');
17439        }
17440
17441        var bentoHeroCTAValue = localStorage.getItem('bentoHeroCTAValue');
17442        if (bentoHeroCTAValue && digitalData?.pageFilter) {
17443            digitalData.pageFilter.topNav = bentoHeroCTAValue;
17444            localStorage.removeItem('bentoHeroCTAValue');
17445        }
17446    }
17447
17448    this.initMealsPages = function ({ page, path, data, topNavTracking } = {}) {
17449        if (digitalData) {
17450            const { pageDetails, pageFilter } = digitalData;
17451            let legacyId, mealsRelatedData = {}, recipeType = digitalData.pageDetails.subSection1.includes('meal') ? 'meals' : 'recipes';
17452            if (data && typeof (data) === 'object' && Object.keys(data).length > 0) {
17453                ({ legacyId, ...mealsRelatedData } = data);
17454                mealsRelatedData.variantId = legacyId || '';
17455            }
17456            for (let i = 0; i <= 3; i++) {
17457                pageDetails[`subSection${i + 1}`] = '';
17458            }
17459            const parts = path.split(':');
17460            pageDetails.channel = page ? page : '';
17461            pageDetails.subSection1 = page ? page : '';
17462            pageDetails.subSection2 = parts[0] || '';
17463            pageDetails.subSection3 = parts[1] || '';
17464            pageDetails.subSection4 = parts[2] || '';
17465            pageDetails.pageUrl = window.location.pathname;
17466            pageDetails.pfmDetail = window.location.pathname.split('/').filter(x => x != '').join(':');
17467            pageFilter.topNav = pageFilter.topNav || topNavTracking;
17468            // update subSection3 on edit order flow
17469            if (pageDetails.subSection2 === 'srp' && !pageDetails.subSection3 && !pageDetails.subSection4 && AB.DATALAYER.getCookie('SlotInfo') && AB.DATALAYER.getCookie('OrderNumber')) {
17470                pageDetails.subSection3 = 'order-edit';
17471            }
17472            this.setPageName(undefined, true, undefined);
17473            this.updatesFromLSBeforePageLoad();
17474            AB.DATALAYER.setPreviousPageName();
17475            if (pageDetails.subSection2 === 'bundle' && pageDetails.subSection3.startsWith('bundle+')) {
17476                setTimeout(() => {
17477                    mealsRelatedData.bundleProducts = AB.DATALAYER.getBundleProducts();
17478                    mealsRelatedData.bundleTitle = AB.DATALAYER.handleGetLSValue('analyticsBundleTitle');
17479                    AB.DATALAYER.pushEvent(AB.DATALAYER.EVENTS.PAGE_LOADED, {
17480                        page: digitalData.pageDetails,
17481                        pageFilter: digitalData.pageFilter,
17482                        modal: digitalData.modal,
17483                        [recipeType]: mealsRelatedData || {},
17484                        user: digitalData?.user
17485                    })
17486                    pageFilter.topNav = '';
17487                }, 2000);
17488            } else {
17489                this.pushEvent(this.EVENTS.PAGE_LOADED, {
17490                    page: digitalData?.pageDetails,
17491                    pageFilter: digitalData?.pageFilter,
17492                    modal: digitalData?.modal,
17493                    [recipeType]: mealsRelatedData || {},
17494                    user: digitalData?.user
17495                })
17496                pageFilter.topNav = '';
17497            }
17498        }
17499    }
17500
17501    this.setMealsActions = function ({ event, action, path, modalMessage, mealsData } = {}) {
17502        let legacyId, mealsRelatedData = {}, recipeType = digitalData.pageDetails.subSection1.includes('meal') ? 'meals' : 're
17502cipes';
17503        if (mealsData && typeof (mealsData) === 'object' && Object.keys(mealsData).length > 0) {
17504            ({ legacyId, ...mealsRelatedData } = mealsData);
17505            mealsRelatedData.variantId = legacyId || '';
17506        }
17507        const { pageDetails, modal, link } = digitalData;
17508        if (path) {
17509            const parts = path.split(':');
17510            pageDetails.subSection2 = parts[0] || '';
17511            pageDetails.subSection3 = parts[1] || '';
17512            pageDetails.subSection4 = parts[2] || '';
17513        }
17514        link.linkName = event.includes('link') ? action : '';
17515        modal.modalAction = event.includes('modal') ? action : '';
17516        modal.modalMessage = modalMessage || '';
17517        digitalData[recipeType] = mealsRelatedData || {};
17518        let oncePerPageView = false;
17519        let actionType = recipeType === 'meals' ? 'sendMealsData' : recipeType === 'recipes' ? 'sendRecipesData' : '';
17520
17521        if (event === 'linkClick') {
17522            if (['favorite-recipe', 'unfavorite-recipe', 'scale-recipe', 'recipe|print-recipe', 'share-recipe', 'tab-instruction', 'tab-detail', 'tab-ingredient'].indexOf(action) !== -1) {
17523                oncePerPageView = true;
17524            }
17525            this.setLinkClickEvents(action, oncePerPageView, actionType);
17526        } else {
17527            if (event === 'modalView') {
17528                if (['select-replacement|view'].indexOf(action) !== -1) {
17529                    oncePerPageView = true;
17530                }
17531                this.setModalViewEvents(action, oncePerPageView, actionType);
17532            } else {
17533                this.setModalClickEvents(action, actionType, oncePerPageView);
17534            }
17535        }
17536
17537        digitalData.modal = {
17538            modalAction: '',
17539            modalMessage: ''
17540        }
17541        digitalData.link = {
17542            linkName: '',
17543        }
17544        digitalData.productInfo = {};
17545        digitalData?.meals && (digitalData.meals = {})
17546        digitalData?.recipes && (digitalData.recipes = {})
17547    }
17548
17549    this.getBundleProducts = function () {
17550        const productsIds = document.querySelectorAll('button[id^="select-button-"]');
17551        const productsPrices = document.querySelectorAll('span')?.length > 0 && Array.from(document.querySelectorAll('span')).filter(el => el.textContent?.trim()?.startsWith('Total $'));
17552        let bundleProducts = [];
17553        if (productsIds.length > 0 && productsPrices.length > 0) {
17554            bundleProducts = Array.from(productsIds).map((product, index) => {
17555                const productId = product.id?.split('-')?.pop();
17556                const productPrice = productsPrices[index]?.textContent?.split('$')[1];
17557                return {
17558                    bpn: productId,
17559                    price: productPrice,
17560                    selectedAmount: 1
17561                }
17562            });
17563        }
17564        return bundleProducts;
17565    }
17566
17567    this.trackRelatedProductAction = function (action, product, element) {
17568        this.productInfo(product);
17569        if (element) {
17570            const subSection1 = digitalData.pageDetails.subSection1 ? digitalData.pageDetails.subSection1 : '';
17571            const subSection2 = digitalData.pageDetails.subSection2 ? digitalData.pageDetails.subSection2 : '';
17572            const subSection3 = digitalData.pageDetails.subSection3 ? digitalData.pageDetails.subSection3 : '';
17573            const subSection4 = digitalData.pageDetails.subSection4 ? digitalData.pageDetails.subSection4 : '';
17574
17575            const currentSlide = element.closest('[aria-roledescription="slide"]');
17576            const currentCarousel = element.closest('#carousel-items-related-products');
17577            const allCarousels = document.querySelectorAll('#carousel-items-related-products')?.length > 0 ? Array.from(document.querySelectorAll('#carousel-items-related-products')) : [];
17578            const allSlides = currentCarousel?.querySelectorAll('[aria-roledescription="slide"]')?.length > 0 ? Array.from(currentCarousel?.querySelectorAll('[aria-roledescription="slide"]')) : [];
17579            const rowValue = allCarousels.indexOf(currentCarousel) < 10 ? `0${allCarousels.indexOf(currentCarousel) + 1}` : `${allCarousels.indexOf(currentCarousel) + 1}`;
17580            const slotValue = allSlides.indexOf(currentSlide) < 10 ? `0${allSlides.indexOf(currentSlide) + 1}` : `${allSlides.indexOf(currentSlide) + 1}`;
17581            const carouselTitle = element.closest('div:has(h3)')?.querySelector('h3')?.innerText;
17582            const sanitizedTitle = carouselTitle ? AB.DATALAYER.sanitizeAnalyticsText(carouselTitle) : 'no-value';
17583            const recommendationType = currentSlide?.innerText?.toLowerCase()?.indexOf('sponsored') !== -1 ? 'sponsored' : 'not-recommended';
17584            digitalData.productInfo.pfmDetail = `${[subSection1, subSection2, subSection3, subSection4]?.join(':')}#${sanitizedTitle}#non-search#${recommendationType}#R${rowValue}#S${slotValue}`;
17585            if (action === 'add-item' && digitalData.productInfo?.productID) {
17586                digitalData.crossPageData = digitalData.crossPageData || {};
17587                digitalData.crossPageData.recipeRelatedPfm = digitalData.crossPageData.recipeRelatedPfm || {};
17588                digitalData.crossPageData.recipeRelatedPfm[digitalData.productInfo?.productID] = digitalData.productInfo.pfmDetail;
17589            } else if (action === 'recipe|remove-item' && digitalData.productInfo.productID) {
17590                digitalData.crossPageData = digitalData.crossPageData || {};
17591                digitalData.crossPageData.recipeRelatedPfm = digitalData.crossPageData.recipeRelatedPfm || {};
17592                delete digitalData.crossPageData.recipeRelatedPfm[digitalData.productInfo.productID];
17593            }
17594        }
17595        let payload = {
17596            link: {
17597                linkName: action,
17598            },
17599            page: digitalData?.pageDetails,
17600            pageFilter: digitalData?.pageFilter,
17601            user: digitalData?.user,
17602            productInfo: digitalData?.productInfo,
17603        };
17604        this.pushEvent(this.EVENTS.LINK_CLICK, payload);
17605    }
17606
17607    this.saveProductPFMonAIAssistant = function (product, element, type) {
17608        if (element) {
17609            const carouselTitle = element.closest('div:has(h3)')?.querySelector('h3')?.innerText;
17610            const sanitizedTitle = carouselTitle ? AB.DATALAYER.sanitizeAnalyticsText(carouselTitle) : 'no-value';
17611            if (type === 'recipe') {
17612                const pfmDetail = `${AB.DATALAYER.pathSections?.join(':')}#${sanitizedTitle}:chat#non-search#not-recommended#R00#S00#no-badge`;
17613                digitalData.crossPageData = digitalData.crossPageData || {};
17614                digitalData.crossPageData.aiAssistantRecipePFM = digitalData.crossPageData.aiAssistantRecipePFM || {};
17615                digitalData.crossPageData.aiAssistantRecipePFM[product.recipeId] = pfmDetail;
17616            } else if (type === 'item') {
17617                const currentSlide = element.closest('[data-testid="product-card"]');
17618                const currentCarousel = element.closest('[data-testid="products-row"]');
17619                const allCarousels = document.querySelectorAll('[data-testid="products-row"]')?.length > 0 ? Array.from(document.querySelectorAll('[data-testid="products-row"]')) : [];
17620                const allSlides = currentCarousel?.querySelectorAll('[data-testid="product-card"]')?.length > 0 ? Array.from(currentCarousel?.querySelectorAll('[data-testid="product-card"]')) : [];
17621                const rowValue = allCarousels.indexOf(currentCarousel) < 10 ? `0${allCarousels.indexOf(currentCarousel) + 1}` : `${allCarousels.indexOf(currentCarousel) + 1}`;
17622                const slotValue = allSlides.indexOf(currentSlide) < 10 ? `0${allSlides.indexOf(currentSlide) + 1}` : `${allSlides.indexOf(currentSlide) + 1}`;
17623                const recommendationType = currentSlide?.innerText?.toLowerCase()?.indexOf('sponsored') !== -1 ? 'sponsored' : 'not-recommended';
17624                const pfmDetail = `${AB.DATALAYER.pathSections?.join(':')}#${sanitizedTitle}#non-search#${recommendationType}#R${rowValue}#S${slotValue}#no-badge`;
17625
17626                digitalData.crossPageData = digitalData.crossPageData || {};
17627                digitalData.crossPageData.aiAssistantProductPFM = digitalData.crossPageData.aiAssistantProductPFM || {};
17628                digitalData.crossPageData.aiAssistantProductPFM[product.id] = pfmDetail;
17629            }
17630        }
17631    }
17632
17633    // Order Ahead Data Layer Migration
17634    // Start
17635    this.orderAheadSetUserInfo = function (storeValue) {
17636        const storeNumber = storeValue?.storeNumber ? storeValue.storeNumber.toString() : '';
17637        if (digitalData) {
17638            digitalData.user = {
17639                shopStoreId: storeNumber,
17640                j4uStoreId: storeNumber
17641            };
17642            this.initAbsVisitorId();
17643        }
17644    }
17645
17646    this.orderAheadSetPageDetails = function () {
17647        const pageDetails = digitalData?.pageDetails || {};
17648        AB.DATALAYER.initPathSections();
17649        if (AB.DATALAYER.pathSections.length < 1) {
17650            pageDetails.subSection1 = 'home';
17651        } else {
17652            AB.DATALAYER.setSubsections();
17653        }
17654        pageDetails.banner = this.getBanner();
17655        pageDetails.channel = 'orderahead';
17656        AB.DATALAYER.setPageName(pageDetails.channel, true)
17657        pageDetails.pageUrl = window.location.href;
17658        pageDetails.referringUrl = this.getReferringUrl() || window.location.href || '';
17659    }
17660
17661    this.initOrderAhead = function (storeValue) {
17662        digitalData = digitalData || {};
17663        digitalData.pageDetails = {}
17664        digitalData.user = {}
17665        this.orderAheadSetUserInfo(storeValue);
17666        this.orderAheadSetPageDetails();
17667    }
17668
17669    this.orderAheadUpdateOrderInfo = function (order) {
17670        let cartInfo = [];
17671        let totalOrderValue = 0;
17672        cartInfo = order.items.map(function (item) {
17673            return {
17674                productId: item.id.toString(),
17675                productName: item.name,
17676                units: item.quantity.toString(),
17677                listPrice: (item.price / item.quantity).toString(),
17678                totalPrice: item.price.toString()
17679            };
17680        });
17681        cartInfo.forEach(function (item) {
17682            totalOrderValue += Number(item.totalPrice);
17683        });
17684
17685        digitalData.cart = {};
17686        digitalData.cart.item = cartInfo;
17687        digitalData.cart.transaction = {
17688            orderID: order.orderInformation.customerOrderId,
17689            revenue: totalOrderValue.toString(),
17690            deliveryTime: this.getFullDateWithTime(order.orderInformation.pickupDate)
17691        }
17692        digitalData.user = {
17693            shopZipCode: order.store.zipCode,
17694            j4UZipCode: order.store.zipCode
17695        };
17696    }
17697
17698
17699    this.setOrderAheadOrderEvent = function (orderEvent) {
17700        this.pushEvent(orderEvent, {
17701            user: digitalData.user,
17702            page: digitalData.pageDetails,
17703            cart: digitalData.cart
17704        })
17705    }
17706
17707
17708    this.trackP13nViewAll = function (element) {
17709        if (AB.DATALAYER.isLpPage()) {
17710            const wrapper = element?.closest('.coupon-carousel, .master-product-carousel')?.querySelector('lazy-wrapper');
17711            const carouselType = wrapper?.getAttribute('data-lazy-component') === 'coupon-carousel' && wrapper?.getAttribute('data-carousel-filter') === 'p13n' ? 'deals' : wrapper?.getAttribute('data-lazy-component') === 'product-carousel' && wrapper?.getAttribute('data-carousel-driven') === 'p13n-generic' ? 'products' : '';
17712            carouselType && AB.DATALAYER.analyticsCTATracking(`cta:${AB.DATALAYER.pathSections.join(':')}|link|${carouselType}-view-all`);
17713        }
17714    }
17715
17716    this.initSelfAccountsMergePages = function (screen, accInfo) {
17717        if (digitalData?.pageDetails) {
17718            digitalData.pageDetails.subSection1 = 'customer-account';
17719            digitalData.pageFilter.topNav = digitalData?.pageFilter?.topNav ? digitalData.pageFilter.topNav : AB.DATALAYER.initTopNav();
17720
17721            switch (screen) {
17722                case 'step1':
17723                    digitalData.pageDetails.subSection2 = 'merge-accounts-step-1';
17724                    digitalData.pageDetails.subSection3 = '';
17725                    digitalData.pageDetails.subSection4 = '';
17726                    AB.DATALAYER.setImpression(`ac:${accInfo}`);
17727                    break;
17728                case 'step2-email':
17729                    digitalData.pageDetails.subSection2 = 'merge-accounts-step-2';
17730                    digitalData.pageDetails.subSection3 = 'email-verification-needed';
17731                    digitalData.pageDetails.subSection4 = '';
17732                    break;
17733                case 'step2-phone':
17734                    digitalData.pageDetails.subSection2 = 'merge-accounts-step-2';
17735                    digitalData.pageDetails.subSection3 = 'phone-verification-needed';
17736                    digitalData.pageDetails.subSection4 = '';
17737                    break;
17738                case 'step2-email-verify-account':
17739                    digitalData.pageDetails.subSection2 = 'merge-accounts-step-2';
17740                    digitalData.pageDetails.subSection3 = 'email-verification-needed';
17741                    digitalData.pageDetails.subSection4 = 'verify-account';
17742                    break;
17743                case 'step2-phone-verify-account':
17744                    digitalData.pageDetails.subSection2 = 'merge-accounts-step-2';
17745                    digitalData.pageDetails.subSection3 = 'phone-verification-needed';
17746                    digitalData.pageDetails.subSection4 = 'verify-account';
17747                    break;
17748                case 'step2-email-failed':
17749                    digitalData.pageDetails.subSection2 = 'merge-accounts-step-2';
17750                    digitalData.pageDetails.subSection3 = 'email-verification-needed';
17751                    digitalData.pageDetails.subSection4 = 'verify-failed';
17752                    break;
17753                case 'step2-phone-failed':
17754                    digitalData.pageDetails.subSection2 = 'merge-accounts-step-2';
17755                    digitalData.pageDetails.subSection3 = 'email-verification-needed';
17756                    digitalData.pageDetails.subSection4 = 'verify-failed';
17757                    break;
17758                case 'step3':
17759                    digitalData.pageDetails.subSection2 = 'merge-accounts-step-3';
17760                    digitalData.pageDetails.subSection3 = 'choose-main-account';
17761                    digitalData.pageDetails.subSection4 = '';
17762                    break;
17763                case 'step4':
17764                    digitalData.pageDetails.subSection2 = 'merge-accounts-step-4';
17765                    digitalData.pageDetails.subSection3 = 'review-accounts';
17766                    digitalData.pageDetails.subSection4 = '';
17767                    const message = 'We\'re merging your accounts. Track progress here in the Account settings';
17768                    AB.DATALAYER.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsModalMessage', data: message, isAcrossPages: true });
17769                    break;
17770                default:
17771                    break;
17772            }
17773            this.setPageName('loyalty', true);
17774        }
17775        AB.DATALAYER.setPageLoad();
17776        digitalData.pageFilter.topNav = '';
17777    }
17778
17779    this.initBundlesComponent = function () {
17780        const bundleEl = document.querySelectorAll('.image.section');
17781        if (bundleEl.length > 0) {
17782            bundleEl?.forEach(element => {
17783                element.addEventListener('click', () => {
17784                    const title = element.closest('div.image')?.parentElement?.querySelector('h3')?.textContent?.trim();
17785                    localStorage.setItem('analyticsBundleTitle', title);
17786                    AB.DATALAYER.trackAEMZone('carousel', element, title);
17787                });
17788            });
17789        }
17790    }
17791
17792    this.trackBundleClicks = function (element) {
17793        const currentBundleParent = element?.closest('div:has(>webgen-bundles), div:has(>webgen-bundles-carousel)');
17794        const currentBundle = element.closest('.bundles-box');
17795        const title = currentBundle?.querySelector('.bundles-content-header')?.textContent?.trim();
17796        const bundleContent = currentBundleParent?.querySelector('webgen-bundles')?.getAttribute('data-bundles-content') || currentBundleParent?.querySelector('webgen-bundles-carousel')?.getAttribute('data-bundles-carousel-content');
17797        const bundleContentObj = AB.DATALAYER.safeJSONParse(bundleContent);
17798        let abTestDetails = '';
17799        let bundleId = '';
17800
17801        if (bundleContentObj.containerItems?.length > 0) {
17802            abTestDetails = bundleContentObj.p13nAdobeMetrics?.metricA;
17803            const currentBundleId = element?.closest('.bundles-box')?.getAttribute('data-analytics-id');
17804            const currentBundleInfo = bundleContentObj.containerItems.find(bundle => bundle.bundleSlugId == currentBundleId);
17805            if (currentBundleInfo?.p13nAdobeMetrics) {
17806                abTestDetails = currentBundleInfo.p13nAdobeMetrics?.metricA;
17807            }
17808            bundleId = currentBundleId;
17809        } else {
17810            if ((bundleContentObj?.p13nAdobeMetrics)) {
17811                abTestDetails = bundleContentObj.p13nAdobeMetrics?.metricA;
17812            }
17813            bundleId = bundleContentObj?.bundleSlugId;
17814        }
17815        localStorage.setItem('bundleAbTestDetails', abTestDetails);
17816        this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsFeatureTracking', data: 'bundlesACIP400316', isAcrossPages: true });
17817        this.analyticsCTATracking(`cta:${AB.DATALAYER.pathSections?.join(':')}|link|bundle`);
17818        AB.DATALAYER.trackAEMZone('carousel', element, `standard-bundle:${title}`, bundleId);
17819    }
17820
17821    this.trackRoktAdImpression = function (isRoktEnabled) {
17822        if (AB.DATALAYER.isCartAndCheckoutPage('confirmation') && isRoktEnabled) {
17823            function triggerAdImpression() {
17824                const roktAd = document.querySelector('#RoktAds');
17825                if (roktAd && AB.DATALAYER.isElementVisible(roktAd)) {
17826                    AB.DATALAYER.setLinkClickEvents('rokt-ad|impressions', true);
17827                    document.removeEventListener('scroll', throttledImpression);
17828                }
17829            }
17830            const throttledImpression = AB.DATALAYER.throttleEvent(triggerAdImpression, 200);
17831            document.addEventListener('scroll', throttledImpression);
17832        }
17833    }
17834
17835    this.trackDietaryPrefs = function (prefType, prefOptions, ctaValue) {
17836        let curatedOptions = prefType === 'diets-you-shop-for' ? prefOptions : prefOptions?.map((option) => {
17837            if (option?.name) {
17838                return AB.DATALAYER.sanitizeAnalyticsText(option.name);
17839            }
17840        })?.join(':');
17841        this.setAnalyticsCrossPageData({ action: 'set', name: 'analyticsFeatureTracking', data: 'dietaryPrefACIP455391' });
17842        this.setModalClickEvents(`${prefType}|${AB.DATALAYER.sanitizeAnalyticsText(ctaValue)}`, `${prefType}|${curatedOptions ? curatedOptions : 'no-selection'}`);
17843    }
17844
17845    // Tracks clicks on forward/back arrows on coupons and bia carousels on homepage
17846    this.trackSlickArrows = function ({ caller, action, component } = {}) {
17847        if (AB.DATALAYER.isHomePage() && (caller === 'deals' || component?.dataset?.carouselDriven === 'buy-it-again' || component?.dataset?.apiDriven === 'buy-it-again' || component?.closest('targeted-wrapper, lazy-wrapper')?.dataset?.carouselBehaviour === 'buy-it-again')) {
17848            const arrowSelector = action === 'left'
17849                ? '.slick-prev, .slick-redesign-prev, .carousel-control-prev'
17850                : '.slick-next, .slick-redesign-next, .carousel-control-next';
17851            const arrowElement = component?.matches?.(arrowSelector) ? component : component?.querySelector?.(arrowSelector);
17852            if (arrowElement) {
17853                AB.DATALAYER.setCRSHomeArrowClick(arrowElement);
17854            }
17855            return;
17856        }
17857    }
17858
17859    this.initSlickArrowTracking = function (component) {
17860        let leftArrow = component?.querySelector('.slick-prev');
17861        let rightArrow = component?.querySelector('.slick-next');
17862        if (leftArrow && rightArrow) {
17863            leftArrow?.addEventListener('click', () => {
17864                AB.DATALAYER.trackSlickArrows({ caller: 'deals', action: 'left', component: component });
17865            });
17866            rightArrow?.addEventListener('click', () => {
17867                AB.DATALAYER.trackSlickArrows({ caller: 'deals', action: 'right', component: component });
17868            });
17869        } else {
17870            setTimeout(() => {
17871                leftArrow = component?.querySelector('.slick-prev');
17872                rightArrow = component?.querySelector('.slick-next');
17873                if (leftArrow && rightArrow) {
17874                    leftArrow?.addEventListener('click', () => {
17875                        AB.DATALAYER.trackSlickArrows({ caller: 'deals', action: 'left', component: component });
17876                    });
17877                    rightArrow?.addEventListener('click', () => {
17878                        AB.DATALAYER.trackSlickArrows({ caller: 'deals', action: 'right', component: component });
17879                    });
17880                }
17881            }, 500);
17882        }
17883    }
17884
17885    this.trackProfileCompletion = function (profileObj) {
17886        if (profileObj.flowType === 'dismiss') {
17887            digitalData.pageDetails.subSection1 = AB.DATALAYER.pathSections[0];
17888            digitalData.pageDetails.subSection2 = AB.DATALAYER.pathSections[1] || '';
17889            digitalData.pageDetails.subSection3 = AB.DATALAYER.pathSections[2] || '';
17890            digitalData.pageDetails.subSection4 = AB.DATALAYER.pathSections[3] || '';
17891            digitalData.modal.modalMessage = '';
17892            this.setAnalyticsCrossPageData({ action: 'remove', name: 'profileCompletionCheckBox' });
17893            this.setAnalyticsCrossPageData({ action: 'remove', name: 'profileCompletionPoints' });
17894            this.analyticsCTATracking('');
17895            digitalData.pageFilter.topNav = '';
17896            AB.DATALAYER.setPageName('loyalty');
17897        } else {
17898            const rewardPoints = digitalData.crossPageData?.profileCompletionPoints?.data || 0;
17899            digitalData.pageDetails.subSection1 = 'complete-your-profile';
17900            digitalData.pageDetails.subSection2 = `${profileObj.flowType}`;
17901            digitalData.modal.modalMessage = `${rewardPoints}#${profileObj.percentage}#${profileObj.step}`;
17902            digitalData.pageDetails.pageName = `${this.getBanner()}:loyalty:${digitalData.pageDetails.subSection1}:${digitalData.pageDetails.subSection2}`;
17903            digitalData.pageFilter.topNav = AB.DATALAYER.initTopNav();
17904        }
17905        this.setPageLoad();
17906        digitalData.pageFilter.topNav = '';
17907    }
17908
17909    /**
17910     * Initializes the datalayer
17911     * (called by AB.COMMON.commonPreInit()) - will try to move this init within these files as well
17912     * Keep at the bottom of this file (datalayer-event-driven) to prevent any issues with functions not existing
17913     */
17914    this.init = function () {
17915        console.info('@AnalyticsTeam - Initializing datalayer');
17916        if (this.areCookiesEnabled() && !digitalData.initialisationCompleted) {
17917            this.isInitialized = true;
17918            this.initQueryParams();
17919            this.initEventsFromPreviousPage();
17920            this.initPage();
17921            this.initPaymentPage();
17922            this.initUser();
17923            this.initPfmDetail();
17924            this.initRecipeDetails();
17925            this.initEpisodicOptInPage();
17926            this.initCRSHomeClickLayer();
17927            this.initFlexBannerClickLayer();
17928            this.initCRSHomeUniversalTracking();
17929            this.initBlogTracking();
17930            this.initFlexModuleExposureOnLoad();
17931            this.updatePathsectionsForSPA();
17932            if (this.globalPageLoadRules()) {
17933                if (digitalData.crossPageData?.analyticsModalMessage?.data && digitalData.modal) {
17934                    digitalData.modal.modalMessage = digitalData.crossPageData.analyticsModalMessage.data;
17935                }
17936                this.setPageLoad();
17937                if (digitalData.crossPageData?.analyticsModalMessage) {
17938                    delete digitalData.crossPageData.analyticsModalMessage;
17939                    digitalData.modal.modalMessage = '';
17940                    this.setAnalyticsCrossPageData({ action: 'remove', name: 'analyticsModalMessage' });
17941                }
17942                !this.isAccountResetPage() && this.handleAccountEvents();
17943            } else if (this.isAislesL2Page()) {
17944                this.initAislesPage();
17945            } else if (this.isPdp()) {
17946                this.initPDP();
17947            } else if (this.isSubscriptionDeliveryPage()) {
17948                if (localStorage.getItem('analyticsLPpageLoad')) {
17949                    const freshpassObj = AB.DATALAYER.safeJSONParse(AB.DATALAYER.handleGetLSValue('analyticsLPpageLoad'));
17950                    this.updateAnalyticsSubscriptionInfo('landing', freshpassObj);
17951                }
17952            }
17952 else if (this.isPharmacyRxPage()) {
17953                if (localStorage.getItem('analyticsPharmacyPageLoad')) {
17954                    this.initPharmacyRx(localStorage.getItem('analyticsPharmacyPageLoad'));
17955                    localStorage.removeItem('analyticsPharmacyPageLoad');
17956                }
17957            } else if (this.isSearchResultsPage()) {
17958                console.info('analytics datalayer page load event type is set in setSearch method');
17959            }
17960            this.initBIAPage();
17961            this.handleEvents();
17962            this.initFireworkEvents();
17963            this.initInHouseVideoEvents();
17964            this.initStickyBannerImpressions();
17965            if (window.location.pathname === '/pet-program.html') {
17966                this.initPetProgramHandlers();
17967            }
17968            if (document.getElementById('delete-profile-modal')) {
17969                // Handles modal view for delete pet profile
17970                // Kept the Jquery since the event listener can't listen to the shown.bs.modal bootstrap custom event
17971                if (jQuery && typeof jQuery !== 'undefined') {
17972                    $('#delete-profile-modal').on('shown.bs.modal', () => {
17973                        AB.DATALAYER.setModalViewEvents('pet-profile-delete|view');
17974                    });
17975                }
17976            }
17977            this.setTopNavCategoriesPage();
17978            if (window.location.pathname === '/account/sign-in.html') {
17979                this.createAcountHandler();
17980            }
17981            this.initBundlesComponent();
17982            !this.isAccountResetPage() && (digitalData.initialisationCompleted = true);
17983        } else {
17984            console.warn('@AnalyticsTeam - datalayer is undefined or cookies are not enabled');
17985        }
17986    };
17987
17988    /**
17989     * Fires a product-impressions event for a Marketing Card embedded within a Product Carousel.
17990     * Triggered via IntersectionObserver once the carousel enters the viewport.
17991     *
17992     * Payload distinctions vs standard product-impressions:
17993     *   page.bnrName       = "<mktCardTitle>-<carouselTitle>|<promotionId>"
17994     *   pageFilter.mTyp    = "product-carousel-mktng-card"
17995     *   pageFilter.carousel = sanitized carousel title
17996     *
17997     * Note – displayType "imageOnly" → mktCardTitle = sanitized backgroundImgAltText value.
17998     *
17999     * @param {Object} marketingTileData  IMarketingTile object from CaaS / zone API response.
18000     * @param {string} carouselTitle      Raw carousel title (data-carousel-title attribute value).
18001     * @param {Element} carouselWrapper   DOM element used as IntersectionObserver target.
18002     */
18003    this.sendMarketingCardImpression = function (marketingTileData, carouselTitle, carouselWrapper) {
18004        if (!marketingTileData) return;
18005
18006        const formattedCarouselTitle = AB.DATALAYER.sanitizeAnalyticsText(carouselTitle) || 'no-value';
18007
18008        const mktCardTitle = marketingTileData.displayType === 'imageOnly'
18009            ? (AB.DATALAYER.sanitizeAnalyticsText(marketingTileData.backgroundImgAltText) || 'no-value')
18010            : (AB.DATALAYER.sanitizeAnalyticsText(marketingTileData.marketingTileTitle) || 'no-value');
18011
18012        const promotionId = marketingTileData.promotionId || 'no-value';
18013        const bnrName = `${mktCardTitle}-${formattedCarouselTitle}|${promotionId}`;
18014
18015        const observeTarget = (carouselWrapper && carouselWrapper.closest && (
18016            carouselWrapper.closest('.master-product-carousel') ||
18017            carouselWrapper.closest('.slick-product-carousel') ||
18018            (carouselWrapper.localName === 'product-carousel-al-v1' ? carouselWrapper.querySelector('.carousel-content-wrapper') : null) ||
18019            carouselWrapper
18020        )) || carouselWrapper;
18021
18022        var _pcData = AB.DATALAYER.safeJSONParse(carouselWrapper && carouselWrapper.getAttribute && carouselWrapper.getAttribute('data-products')) || {};
18023        var _pcZoneMatch = (_pcData.zone || '').match(/\d+/);
18024        var _pcZoneNum = _pcZoneMatch ? parseInt(_pcZoneMatch[0], 10) : 0;
18025        var _pcZone = _pcZoneNum > 0 ? (_pcZoneNum < 10 ? '0' + _pcZoneNum : '' + _pcZoneNum) : '00';
18026        var mktCardPlacement = 'r01#s01#z' + _pcZone;
18027
18028        const fireImpression = function () {
18029            const pageDetails = Object.assign({}, digitalData.pageDetails, { bnrName: bnrName });
18030            const payload = {
18031                link: { linkName: 'product-impressions' },
18032                page: pageDetails,
18033                pageFilter: Object.assign({}, digitalData.pageFilter, {
18034                    mediaType: 'product-carousel-mktng-card',
18035                    carousel: formattedCarouselTitle,
18036                    placement: mktCardPlacement
18037                }),
18038                user: digitalData.user
18039            };
18040            AB.DATALAYER.pushEvent('product-impressions', payload);
18041            digitalData.pageDetails.bnrName = '';
18042        };
18043
18044        if (observeTarget && typeof IntersectionObserver !== 'undefined') {
18045            var observer = new IntersectionObserver(function (entries, obs) {
18046                entries.forEach(function (entry) {
18047                    if (entry.isIntersecting) {
18048                        fireImpression();
18049                        obs.unobserve(observeTarget);
18050                    }
18051                });
18052            }, { root: null, rootMargin: '0px', threshold: 0.5 });
18053            observer.observe(observeTarget);
18054        } else {
18055            fireImpression();
18056        }
18057    };
18058
18059    /**
18060     * Fires an experiment-exposure-loaded event for a Marketing Card embedded within a Product Carousel.
18061     * Triggered via IntersectionObserver once the carousel enters the viewport.
18062     *
18063     * Payload distinctions:
18064     *   event.subEvent         = "experiment-exposure"
18065     *   link.name              = "experiment-exposure-loaded"
18066     *   page.bnrName           = "<mktCardTitle>-<carouselTitle>|<promotionId>"
18067     *   page.abTestDetails     = p13nAdobeMetrics.msgExperiment (pre-formatted experiment string)
18068     *   pageFilter.mTyp        = "product-carousel-mktng-card"
18069     *   pageFilter.carousel    = sanitized carousel title
18070     *
18071     * @param {Object} marketingTileData  IMarketingTile object from CaaS / zone API response.
18072     * @param {string} carouselTitle      Raw carousel title (data-carousel-title attribute value).
18073     * @param {Element} carouselWrapper   DOM element used as IntersectionObserver target.
18074     * @param {Object} p13nData           p13n data object; expects p13nData.msgExperiment for abTestDetails.
18075     */
18076    this.sendMarketingCardExposure = function (marketingTileData, carouselTitle, carouselWrapper, p13nData) {
18077        if (!marketingTileData) return;
18078
18079        const formattedCarouselTitle = AB.DATALAYER.sanitizeAnalyticsText(carouselTitle) || 'no-value';
18080
18081        const mktCardTitle = marketingTileData.displayType === 'imageOnly'
18082            ? (AB.DATALAYER.sanitizeAnalyticsText(marketingTileData.backgroundImgAltText) || 'no-value')
18083            : (AB.DATALAYER.sanitizeAnalyticsText(marketingTileData.marketingTileTitle) || 'no-value');
18084
18085        const promotionId = marketingTileData.promotionId || 'no-value';
18086        const bnrName = `${mktCardTitle}-${formattedCarouselTitle}|${promotionId}`;
18087        const abTestDetails = p13nData?.msgExperiment || 'no-value';
18088
18089        const observeTarget = (carouselWrapper && carouselWrapper.closest && carouselWrapper.closest('.master-product-carousel'))
18090            || carouselWrapper;
18091
18092        const fireExposure = function () {
18093            const pageDetails = Object.assign({}, digitalData.pageDetails, { bnrName: bnrName, abTestDetails: abTestDetails });
18094            const payload = {
18095                link: { linkName: 'experiment-exposure-loaded' },
18096                page: pageDetails,
18097                pageFilter: Object.assign({}, digitalData.pageFilter, {
18098                    mediaType: 'product-carousel-mktng-card',
18099                    carousel: formattedCarouselTitle
18100                }),
18101                user: digitalData.user
18102            };
18103            AB.DATALAYER.pushEvent(AB.DATALAYER.EVENTS.LINK_CLICK, payload);
18104            digitalData.pageDetails.bnrName = '';
18105            digitalData.pageDetails.abTestDetails = '';
18106        };
18107
18108        if (observeTarget && typeof IntersectionObserver !== 'undefined') {
18109            var observer = new IntersectionObserver(function (entries, obs) {
18110                entries.forEach(function (entry) {
18111                    if (entry.isIntersecting) {
18112                        fireExposure();
18113                        obs.unobserve(observeTarget);
18114                    }
18115                });
18116            }, { root: null, rootMargin: '0px', threshold: 0.5 });
18117            observer.observe(observeTarget);
18118        } else {
18119            fireExposure();
18120        }
18121    };
18122
18123    /**
18124     * Fires a deals-impressions event for a Marketing Card embedded in a Deals / Coupon Carousel.
18125     *
18126     * Payload highlights:
18127     *   link.linkName          = "deals-impressions"
18128     *   page.bnrName           = "<mktCardTitle>-<carouselTitle>|<promotionId>"
18129     *   page.abTestDetails     = "impdeals#<p13nAdobeMetrics.msgExperiment>" (when experiment data available)
18130     *   pageFilter.mTyp        = "deals-carousel-mktng-card"  (via mediaType → mTyp OneTag mapping)
18131     *   pageFilter.carousel    = sanitized carousel title
18132     *
18133     * @param {Object} marketingTileData  IMarketingTile object.
18134     * @param {string} carouselTitle      Raw carousel title.
18135     * @param {Element} carouselWrapper   DOM element for IntersectionObserver (pass null for zone-API path).
18136     * @param {Object} p13nData           Optional; expects p13nData.msgExperiment for abTestDetails prefix.
18137     */
18138    this.sendDealsCarouselMarketingCardImpression = function (marketingTileData, carouselTitle, carouselWrapper, p13nData) {
18139        if (!marketingTileData) return;
18140
18141        const formattedCarouselTitle = AB.DATALAYER.sanitizeAnalyticsText(carouselTitle) || 'no-value';
18142
18143        const mktCardTitle = marketingTileData.displayType === 'imageOnly'
18144            ? (AB.DATALAYER.sanitizeAnalyticsText(marketingTileData.backgroundImgAltText) || 'no-value')
18145            : (AB.DATALAYER.sanitizeAnalyticsText(marketingTileData.marketingTileTitle) || 'no-value');
18146
18147        const promotionId = marketingTileData.promotionId || 'no-value';
18148        const bnrName = `${mktCardTitle}-${formattedCarouselTitle}|${promotionId}`;
18149
18150        if (carouselWrapper && !carouselWrapper.hasAttribute('data-deals-carousel-content') && carouselWrapper.closest) {
18151            var _normalized = carouselWrapper.closest('[data-deals-carousel-content]');
18152            if (_normalized) carouselWrapper = _normalized;
18153        }
18154
18155        if (carouselWrapper && carouselWrapper._dealsCardImpSetup) return;
18156        if (carouselWrapper) carouselWrapper._dealsCardImpSetup = true;
18157
18158        const observeTarget = (carouselWrapper && (
18159            (carouselWrapper.querySelector && carouselWrapper.querySelector('.slick-coupon-carousel')) ||
18160            (carouselWrapper.querySelector && carouselWrapper.querySelector('.coupon-carousel')) ||
18161            carouselWrapper
18162        )) || carouselWrapper;
18163
18164        // Row from position among all [data-deals-carousel-content] wrappers
18165        var impAllDealsWrappers = Array.from(document.querySelectorAll('[data-deals-carousel-content]'));
18166        var impRowIdx = impAllDealsWrappers.indexOf(carouselWrapper) + 1;
18167        if (impRowIdx < 1) impRowIdx = 1;
18168        var impRow = impRowIdx < 10 ? '0' + impRowIdx : '' + impRowIdx;
18169        // Zone and slot from carousel JSON — zone API returns "zone":"zone1","zoneRenderedSlot":"7" in component data
18170        var _impCd = AB.DATALAYER.safeJSONParse(carouselWrapper?.getAttribute?.('data-deals-carousel-content')) || {};
18171        var _impZoneMatch = (_impCd.zone || '').match(/\d+/);
18172        var impZoneNum = _impZoneMatch ? parseInt(_impZoneMatch[0], 10) : 0;
18173        var impZone = impZoneNum > 0 ? (impZoneNum < 10 ? '0' + impZoneNum : '' + impZoneNum) : '00';
18174        var impSlotNum = 1;
18175        var impSlot = '01';
18176        var mktCardImpPlacement = 'r' + impRow + '#s' + impSlot + '#z' + impZone;
18177
18178        const fireImpression = function () {
18179            const pageDetails = Object.assign({}, digitalData.pageDetails, { bnrName: bnrName });
18180            if (p13nData?.msgExperiment) {
18181                pageDetails.abTestDetails = `impdeals#${p13nData.msgExperiment}`;
18182            }
18183            const payload = {
18184                link: { linkName: 'deals-impressions' },
18185                page: pageDetails,
18186                pageFilter: Object.assign({}, digitalData.pageFilter, {
18187                    mediaType: 'deals-carousel-mktng-card',
18188                    carousel: formattedCarouselTitle,
18189                    placement: mktCardImpPlacement
18190                }),
18191                user: digitalData.user
18192            };
18193            AB.DATALAYER.pushEvent(AB.DATALAYER.EVENTS.LINK_CLICK, payload);
18194            digitalData.pageDetails.bnrName = '';
18195        };
18196
18197        if (observeTarget && typeof IntersectionObserver !== 'undefined') {
18198            var observer = new IntersectionObserver(function (entries, obs) {
18199                entries.forEach(function (entry) {
18200                    if (entry.isIntersecting) {
18201                        fireImpression();
18202                        obs.unobserve(observeTarget);
18203                    }
18204                });
18205            }, { root: null, rootMargin: '0px', threshold: 0.5 });
18206            observer.observe(observeTarget);
18207        } else {
18208            fireImpression();
18209        }
18210    };
18211
18212    /**
18213     * Fires an experiment-exposure event for a Marketing Card embedded in a Deals / Coupon Carousel.
18214     * Only called when p13n experiment data is present in the zone API response.
18215     *
18216     * Payload highlights:
18217     *   link.linkName          = "experiment-exposure-loaded-deals"
18218     *   page.bnrName           = "<mktCardTitle>-<carouselTitle>|<promotionId>"
18219     *   page.abTestDetails     = p13nAdobeMetrics.msgExperiment
18220     *   pageFilter.mTyp        = "deals-carousel-mktng-card"
18221     *   pageFilter.carousel    = sanitized carousel title
18222     *
18223     * @param {Object} marketingTileData  IMarketingTile object.
18224     * @param {string} carouselTitle      Raw carousel title.
18225     * @param {Element} carouselWrapper   DOM element for IntersectionObserver (pass null for zone-API path).
18226     * @param {Object} p13nData           Expects p13nData.msgExperiment for abTestDetails.
18227     */
18228    this.sendDealsCarouselMarketingCardExposure = function (marketingTileData, carouselTitle, carouselWrapper, p13nData) {
18229        if (!marketingTileData) return;
18230
18231        const formattedCarouselTitle = AB.DATALAYER.sanitizeAnalyticsText(carouselTitle) || 'no-value';
18232
18233        const mktCardTitle = marketingTileData.displayType === 'imageOnly'
18234            ? (AB.DATALAYER.sanitizeAnalyticsText(marketingTileData.backgroundImgAltText) || 'no-value')
18235            : (AB.DATALAYER.sanitizeAnalyticsText(marketingTileData.marketingTileTitle) || 'no-value');
18236
18237        const promotionId = marketingTileData.promotionId || 'no-value';
18238        const bnrName = `${mktCardTitle}-${formattedCarouselTitle}|${promotionId}`;
18239        const abTestDetails = p13nData?.msgExperiment || 'no-value';
18240
18241        // Normalize to the [data-deals-carousel-content] element for consistent zone/slot/row reading
18242        if (carouselWrapper && !carouselWrapper.hasAttribute('data-deals-carousel-content') && carouselWrapper.closest) {
18243            var _expNormalized = carouselWrapper.closest('[data-deals-carousel-content]');
18244            if (_expNormalized) carouselWrapper = _expNormalized;
18245        }
18246
18247        const observeTarget = (carouselWrapper && (
18248            (carouselWrapper.querySelector && carouselWrapper.querySelector('.slick-coupon-carousel')) ||
18249            (carouselWrapper.querySelector && carouselWrapper.querySelector('.coupon-carousel')) ||
18250            carouselWrapper
18251        )) || carouselWrapper;
18252
18253        var expAllDealsWrappers = Array.from(document.querySelectorAll('[data-deals-carousel-content]'));
18254        var expRowIdx = expAllDealsWrappers.indexOf(carouselWrapper) + 1;
18255        if (expRowIdx < 1) expRowIdx = 1;
18256        var expRow = expRowIdx < 10 ? '0' + expRowIdx : '' + expRowIdx;
18257        var _expCd = AB.DATALAYER.safeJSONParse(carouselWrapper?.getAttribute?.('data-deals-carousel-content')) || {};
18258        var _expZoneMatch = (_expCd.zone || '').match(/\d+/);
18259        var expZoneNum = _expZoneMatch ? parseInt(_expZoneMatch[0], 10) : 0;
18260        var expZone = expZoneNum > 0 ? (expZoneNum < 10 ? '0' + expZoneNum : '' + expZoneNum) : '00';
18261        var expSlotNum = parseInt(_expCd.zoneRenderedSlot, 10) || 1;
18262        var expSlot = expSlotNum < 10 ? '0' + expSlotNum : '' + expSlotNum;
18263        var mktCardExpPlacement = 'r' + expRow + '#s' + expSlot + '#z' + expZone;
18264
18265        const fireExposure = function () {
18266            const pageDetails = Object.assign({}, digitalData.pageDetails, { bnrName: bnrName, abTestDetails: abTestDetails });
18267            const payload = {
18268                link: { linkName: 'experiment-exposure-loaded-deals' },
18269                page: pageDetails,
18270                pageFilter: Object.assign({}, digitalData.pageFilter, {
18271                    mediaType: 'deals-carousel-mktng-card',
18272                    carousel: formattedCarouselTitle,
18273                    placement: mktCardExpPlacement
18274                }),
18275                user: digitalData.user
18276            };
18277            AB.DATALAYER.pushEvent(AB.DATALAYER.EVENTS.LINK_CLICK, payload);
18278            digitalData.pageDetails.bnrName = '';
18279            digitalData.pageDetails.abTestDetails = '';
18280        };
18281
18282        if (observeTarget && typeof IntersectionObserver !== 'undefined') {
18283            var observer = new IntersectionObserver(function (entries, obs) {
18284                entries.forEach(function (entry) {
18285                    if (entry.isIntersecting) {
18286                        fireExposure();
18287                        obs.unobserve(observeTarget);
18288                    }
18289                });
18290            }, { root: null, rootMargin: '0px', threshold: 0.5 });
18291            observer.observe(observeTarget);
18292        } else {
18293            fireExposure();
18294        }
18295    };
18296
18297    /**
18298     * Fires V218 (bannerCardCarousel) and V80 (mediaPlacementClick) click-tracking when a
18299     * Marketing Card CTA is clicked in a product carousel (cardType='product') or a deals /
18300     * coupon carousel (cardType='deals'). Follows the same bento pattern: set values on
18301     * digitalData.pageFilter + localStorage before calling setBannerClickedEvent, then restore.
18302     *
18303     * @param {Element}  clickedElement    - The anchor/button element that was clicked
18304     * @param {Object}   marketingTileData - IMarketingTile object (marketingTileTitle, backgroundImgAltText, displayType, promotionId)
18305     * @param {string}   carouselTitle     - Unformatted carousel title string
18306     * @param {string}   cardType          - 'product' | 'deals'
18307     */
18308    this.sendMarketingCardClickEvent = function (clickedElement, marketingTileData, carouselTitle, cardType) {
18309        if (!marketingTileData || !carouselTitle || !digitalData?.pageFilter) return;
18310
18311        const pad = function (v) { return Number(v) < 10 ? '0' + Number(v) : String(v); };
18312        const formattedCarouselTitle = AB.DATALAYER.sanitizeAnalyticsText(carouselTitle) || 'no-value';
18313        const mktCardTitle = marketingTileData.displayType === 'imageOnly'
18314            ? (AB.DATALAYER.sanitizeAnalyticsText(marketingTileData.backgroundImgAltText) || 'no-value')
18315            : (AB.DATALAYER.sanitizeAnalyticsText(marketingTileData.marketingTileTitle) || 'no-value');
18316        const promotionId = marketingTileData.promotionId || 'no-value';
18317        const cardTypeStr = cardType === 'deals' ? 'deal-card' : 'mkt-card';
18318        const mediaType = cardType === 'deals' ? 'deals-carousel-mktng-card' : 'product-carousel-mktng-card';
18319        const content = mktCardTitle + ':' + formattedCarouselTitle;
18320
18321        // For zone-API deals carousels: zone/slot/row from [data-deals-carousel-content] JSON.
18322        // For zone-API product carousels: zone from targeted-wrapper data-products JSON; row/slot always 01.
18323        // For AEM-authored carousels: fall back to getZoneInfo which walks the AEM zone DOM hierarchy.
18324        var _clickDealsEl = clickedElement && clickedElement.closest ? clickedElement.closest('[data-deals-carousel-content]') : null;
18325        var _clickTwEl = !_clickDealsEl && clickedElement && clickedElement.closest ? clickedElement.closest('targeted-wrapper') : null;
18326        var zone, row, slot;
18327        if (_clickDealsEl) {
18328            var _clickCd = AB.DATALAYER.safeJSONParse(_clickDealsEl.getAttribute('data-deals-carousel-content')) || {};
18329            var _clickWrappers = Array.from(document.querySelectorAll('[data-deals-carousel-content]'));
18330            var _clickRowIdx = Math.max(_clickWrappers.indexOf(_clickDealsEl) + 1, 1);
18331            row  = pad(_clickRowIdx);
18332            var _clickZoneNum = parseInt(((_clickCd.zone || '').match(/\d+/) || [])[0], 10) || 0;
18333            zone = pad(_clickZoneNum);
18334            slot = '01';
18335        } else if (_clickTwEl) {
18336            var _clickTwData = AB.DATALAYER.safeJSONParse(_clickTwEl.getAttribute('data-products')) || {};
18337            var _clickTwZoneNum = parseInt(((_clickTwData.zone || '').match(/\d+/) || [])[0], 10) || 0;
18338            zone = pad(_clickTwZoneNum);
18339            row  = '01';
18340            slot = '01';
18341        } else {
18342            var _zi = {};
18343            try { _zi = AB.DATALAYER.getZoneInfo(clickedElement) || {}; } catch (e) { /* no-op */ }
18344            zone = pad(parseInt(_zi.zone, 10) || 0);
18345            row  = pad(Number(_zi.row) > 0 ? Number(_zi.row) : 1);
18346            slot = '01';
18347        }
18348
18349        // V218: z<zone>|<card-type>|<card title>:<carousel title>|sp<row>|<unique id>  (max 256 chars)
18350        const v218 = ('z' + zone + '|' + cardTypeStr + '|' + content + '|sp' + row + '|' + promotionId).slice(0, 256);
18351
18352        // Recommendation type and V80 placement
18353        const recommendationType = cardType === 'deals' ? 'not-recommended' : 'sponsored';
18354        const placement = 'r' + row + '#s' + slot;
18355        // V80: <card-type>:<card title>#<recommendation>#r<row>#s01  (max 256 chars)
18356        const v80 = (cardTypeStr + ':' + mktCardTitle + '#' + recommendationType + '#' + placement).slice(0, 256);
18357
18358        // Cross-page persistence (read by next-page datalayer init)
18359        try { localStorage.setItem('aemZoneAnalytics', v218); } catch (e) { /* no-op */ }
18360        try { localStorage.setItem('mediaPlacementClick', v80); } catch (e) { /* no-op */ }
18361
18362        // Same-page snapshot — setBannerClickedEvent takes structuredClone of pageFilter immediately
18363        const previousV218 = digitalData.pageFilter.bannerCardCarousel;
18364        digitalData.pageFilter.bannerCardCarousel = v218;
18365        digitalData.pageFilter.mediaPlacementClick = v80;
18366
18367        try {
18368            AB.DATALAYER.setBannerClickedEvent(
18369                placement,                     // placement → pageFilter.placement
18370                'bannerclicked|' + content,    // linkName
18371                recommendationType,            // → pageFilter.recommendationType
18372                mediaType,                     // → pageFilter.mediaType
18373                content                        // bannerTitle → page.bnrName = content + '|no-value'
18374            );
18375        } finally {
18376            digitalData.pageFilter.bannerCardCarousel = previousV218 || '';
18377            digitalData.pageFilter.mediaPlacementClick = '';
18378        }
18379    };
18380
18381    /**
18382     * Registers a single document-level click listener (idempotent — guarded by _mktCardClickInit)
18383     * that fires sendMarketingCardClickEvent when any Marketing Card CTA inside a
18384     * .pds-marketing-card element is clicked.
18385     *
18386     * Data resolution order:
18387     *   1. DOM-attribute path: [data-mt-includeMarketingTile="true"] ancestor carries tile JSON
18388     *   2. Zone-API deals path: [data-deals-carousel-content] ancestor carries carousel JSON
18389     *
18390     * Call this once when any marketing-card carousel loads (trackP13nCarousel / setP13nExperimentExposure).
18391     */
18392    /**
18393     * DOM-scan impression initialiser for Marketing Cards in AEM-authored Deals Carousels.
18394     * Mirrors the initStickyBannerImpressions pattern: runs at datalayer init time,
18395     * finds server-rendered [data-deals-carousel-content] wrappers, then uses a
18396     * MutationObserver to wait for Angular to render the .slick-coupon-carousel container
18397     * before handing off to sendDealsCarouselMarketingCardImpression + IntersectionObserver.
18398     */
18399    this.initDealsCarouselMktCardTracking = function () {
18400        if (AB.DATALAYER._dealsCarouselMktCardTrackingInit || typeof MutationObserver === 'undefined') return;
18401        AB.DATALAYER._dealsCarouselMktCardTrackingInit = true;
18402
18403        var wrappers = document.querySelectorAll('[data-deals-carousel-content]');
18404        wrappers.forEach(function (wrapper) {
18405            var carouselData = AB.DATALAYER.safeJSONParse(wrapper.getAttribute('data-deals-carousel-content'));
18406            if (!carouselData || carouselData.includeMarketingTile !== 'true' || !carouselData.marketingTile) return;
18407
18408            var carouselTitle = wrapper.getAttribute('data-carousel-title') || carouselData.title || '';
18409            var marketingTile = carouselData.marketingTile;
18410
18411            var trySetup = function () {
18412                if (!wrapper.querySelector('.slick-coupon-carousel')) return false;
18413                AB.DATALAYER.sendDealsCarouselMarketingCardImpression(marketingTile, carouselTitle, wrapper, null);
18414                return true;
18415            };
18416
18417            if (!trySetup()) {
18418                var mutObs = new MutationObserver(function (mutations, observer) {
18419                    if (trySetup()) { observer.disconnect(); }
18420                });
18421                mutObs.observe(wrapper, { childList: true, subtree: true });
18422            }
18423        });
18424    };
18425
18426    this.initMarketingCardClickTracking = function () {
18427        if (AB.DATALAYER._mktCardClickInit) return;
18428        AB.DATALAYER._mktCardClickInit = true;
18429
18430        document.addEventListener('click', function (e) {
18431            if (!e.target || !e.target.closest) return;
18432            var link = e.target.closest('a') || e.target.closest('button');
18433            if (!link) return;
18434            var card = link.closest('.pds-marketing-card');
18435            if (!card) return;
18436
18437            // DOM-attribute path: tile JSON on lazy-wrapper (AEM-authored carousels)
18438            var lazyWrapper = card.closest('[data-mt-includeMarketingTile="true"]');
18439            if (lazyWrapper) {
18440                var mktTileJson = lazyWrapper.getAttribute('data-mt-marketingTileJson');
18441                var mktTile = mktTileJson && AB.DATALAYER.safeJSONParse(mktTileJson);
18442                if (mktTile) {
18443                    var carouselTitle = lazyWrapper.getAttribute('data-carousel-title') || '';
18444                    var isCoupon = !!card.closest('.slick-coupon-carousel');
18445                    AB.DATALAYER.sendMarketingCardClickEvent(link, mktTile, carouselTitle, isCoupon ? 'deals' : 'product');
18446                    return;
18447                }
18448            }
18449
18450            // Zone-API deals path: carousel JSON on deals-carousel-wrapper ancestor
18451            var dealsWrapper = card.closest('[data-deals-carousel-content]');
18452            if (dealsWrapper) {
18453                var carouselData = AB.DATALAYER.safeJSONParse(dealsWrapper.getAttribute('data-deals-carousel-content'));
18454                if (carouselData && carouselData.includeMarketingTile === 'true' && carouselData.marketingTile) {
18455                    var dealsCarouselTitle = dealsWrapper.getAttribute('data-carousel-title') || carouselData.title || '';
18456                    AB.DATALAYER.sendMarketingCardClickEvent(link, carouselData.marketingTile, dealsCarouselTitle, 'deals');
18457                    return;
18458                }
18459            }
18460
18461            // Zone-API product carousel path: marketing tile data inside targeted-wrapper data-products JSON
18462            var twWrapper = card.closest('targeted-wrapper');
18463            if (twWrapper) {
18464                var twData = AB.DATALAYER.safeJSONParse(twWrapper.getAttribute('data-products'));
18465                if (twData && twData.includeMarketingTile === 'true' && twData.marketingTile) {
18466                    var twCarouselTitle = twWrapper.getAttribute('data-carousel-title') || twData.carouselTitle || twData.title || '';
18467                    AB.DATALAYER.sendMarketingCardClickEvent(link, twData.marketingTile, twCarouselTitle, 'product');
18468                }
18469            }
18470        });
18471    };
18472
18473}).call(AB.DATALAYER);
18474
18475if (AB?.DATALAYER && Object.keys(AB.DATALAYER).length > 0) {
18476    window.eddlLoadComplete = true;
18477    window.shouldCnCCallEddl = true;
18478    window.shouldOrderAheadCallEddl = true;
18479    AB.DATALAYER.initMarketingCardClickTracking();
18480    AB.DATALAYER.initDealsCarouselMktCardTracking();
18481    let eddlLoadComplete = new Event('eddlLoadComplete');
18482    document.dispatchEvent(eddlLoadComplete);
18483    let cartUpdateFromLs = function () {
18484        if (digitalData?.cart?.cartInfo && Object.keys(digitalData.cart.cartInfo).length === 0 && AB.DATALAYER.getLSItem('abCart') && !AB.DATALAYER.isSelectiveCartPage()) {
18485            AB.DATALAYER.updateCart(AB.DATALAYER.safeJSONParse(AB.DATALAYER.getLSItem('abCart')));
18486        }
18487    }
18488    if (AB.DATALAYER.getLSItem('abCart')) {
18489        cartUpdateFromLs();
18490    } else {
18491        document.addEventListener('cartSavedToLS', cartUpdateFromLs);
18492    }
18493
18494}
18495
18496if (window.AB?.DATALAYER?.isWeeklyAdPage()) {
18497    window.AB.DATALAYER.init();
18498}
18499

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.