PageSourceSearch

https://www.tcs.ch/global/wGlobal/layout/scripts/ocln/mcpEvents.js

js tcs.ch collected 2026-09-24 08:50:04 UTC 21,314 bytes, 493 lines download raw bytes

1async function fetchMcpProductsData() {
2    try {
3        const response = await fetch(location.origin + '/backend/api/mcp/getNisProductsDataForMcp');
4
5        if (!response.ok) {
6            throw new Error('API error from NIS products for MCP');
7        }
8
9        const data = await response.json();
10        return data;
11    } catch (error) {
12        console.error('Error: ', error);
13    }
14}
15
16/**
17 * Creation of an event listener to send events from the basket to MCP.
18 *
19 * When a push datalayer is sent, it is intercepted in order to retrieve these values and use them for MCP.
20 * These values are then sent to the new custom event if the event corresponds to add_to_cart or remove_from_cart.
21 */
22
23window.dataLayer = window.dataLayer || new Proxy([], {
24    set: (obj, prop, value) => {
25        if (prop !== 'length' && value.event && (value.event === 'add_to_cart' || value.event === 'remove_from_cart')) {
26            const pushEvent = new CustomEvent('datalayerPushMcp', {
27                detail: value
28            });
29
30            window.dispatchEvent(pushEvent);
31        }
32
33        return Reflect.set(obj, prop, value);
34    }
35});
36
37window.addEventListener('datalayerPushMcp', async event => {
38    if (typeof SalesforceInteractions === 'undefined') {
39        return;
40    }
41
42    let detail = event.detail;
43
44    let eventName = (detail.event === 'add_to_cart' ? SalesforceInteractions.CartInteractionName.AddToCart : SalesforceInteractions.CartInteractionName.RemoveFromCart);
45
46    let datalayerItems = detail.ecommerce.items;
47    let lineItems = [];
48
49    datalayerItems.forEach((item) => {
50        let lineItem = {
51            catalogObjectType: "Product",
52            catalogObjectId: item.cp_ecom_product_name,
53            quantity: item.quantity,
54            price: item.price,
55            currency: "CHF"
56        }
57        lineItems.push(lineItem);
58    });
59
60    // As Replace Cart can't be correctly handled in mcp we need to replace cart with an empty array and then make all add to cart calls like before.
61    // see : https://tcsgroup.atlassian.net/browse/WWW-7886
62    // See: https://developer.salesforce.com/docs/marketing/personalization/guide/event-options-salesforceinteractions.html#cartinteraction
63
64
65    if (eventName === SalesforceInteractions.CartInteractionName.AddToCart) {
66        // Tested that SalesforceInteractions.sendEvent returns a Promise
67        // So we await for remove from cart to answer before we do AddToCarts
68        await SalesforceInteractions.sendEvent({
69            interaction: {
70                name: SalesforceInteractions.CartInteractionName.ReplaceCart,
71                lineItems: []
72            },
73            user: {
74                attributes: {
75                    CheckoutConsent: false
76                }
77            }
78        });
79    }
80    lineItems.forEach((lineItem) => {
81        SalesforceInteractions.sendEvent({
82            interaction: {
83                name: eventName,
84                lineItem: lineItem
85            },
86            user: {
87                attributes: {
88                    CheckoutConsent: false
89                }
90            }
91        });
92    });
93
94
95});
96
97function checkUsercentricsMcpStatus() {
98    if (typeof SalesforceInteractions === 'undefined') {
99        return;
100    }
101    let serviceId = "IQMIegSQF";
102    if (!Usercentrics.isServiceIdAvailable(serviceId)) {
103        console.error(`Usercentrics Service ${serviceId} does not exist !`);
104        return;
105    }
106
107    var technologyName = Usercentrics.getServiceNameForId(serviceId);
108
109    if (Usercentrics.getConsentStatusForId(serviceId) === true) {
110        setMcpOptInConsent();
111    }
112    window.addEventListener("ucEvent", function (e) {
113        if (e.detail[technologyName.toString()]) {
114            setMcpOptInConsent();
115        } else {
116            setMcpOptOutConsent();
117        }
118    });
119}
120
121function setMcpOptInConsent() {
122    const consent = {
123        provider: "Consent Provider",
124        purpose: SalesforceInteractions.mcis.ConsentPurpose.Personalization,
125        status: SalesforceInteractions.ConsentStatus.OptIn
126    };
127    SalesforceInteractions.updateConsents(consent);
128    SalesforceInteractions.reinit();
129}
130
131function setMcpOptOutConsent() {
132    const consent = {
133        provider: "Consent Provider",
134        purpose: SalesforceInteractions.mcis.ConsentPurpose.Personalization,
135        status: SalesforceInteractions.ConsentStatus.OptOut
136    };
137    SalesforceInteractions.updateConsents(consent);
138}
139
140function pushDataLayerFromMcp(context) {
141    if (
142        context.gaProductName != ''
143        || context.gaProductName1 != ''
144        || context.gaProductName2 != ''
145        || context.items.length > 0
146    ) {
147        fetchMcpProductsData().then(data => {
148            let relatedArea = SalesforceInteractions.getSitemapConfig().global.contentZones.filter((zone) => zone.name === context.contentZone);
149            if (relatedArea.length > 0) {
150                let areaSelector;
151                if (relatedArea[0].selector) {
152                    areaSelector = SalesforceInteractions.getSitemapConfig().global.contentZones.filter((zone) => zone.name === context.contentZone)[0].selector;
153                } else {
154                    areaSelector = '#' + SalesforceInteractions.getSitemapConfig().global.contentZones.filter((zone) => zone.name === context.contentZone)[0].name;
155                    areaSelector = areaSelector.replaceAll('_', '-');
156                }
157
158                let productData = [];
159                if (context.imgSrc1 && context.imgSrc2 && context.secondItemRendering) {
160                    const linkSelectors = document.querySelector(areaSelector).querySelectorAll('.evg-btn');
161                    // Search page product offers with 2 products
162                    // Product 1 has productName defined
163                    if (context.gaProductName1 !== 'NOT_GA4_PRODUCT') {
164                        const gaProduct1 = data[context.gaProductName1];
165                        const variant1 = (gaProduct1.coverType || 'N/A')
166                            + '_' + (gaProduct1.familyVariant || 'N/A')
167                            + '_' + (gaProduct1.breakdownVariant || 'N/A')
168                            + '_N/A';
169                        const basicPrice1 =
170                            context.normalPrice1 && context.normalPrice1 !== '' ?
171                                Number(context.normalPrice1.replace(/[^0-9.-]+/g, "")) :
172                                +gaProduct1.price;
173                        let discount1 = 0;
174                        if (context.discountPrice1 && context.discountPrice1 !== '') {
175                            discount1 = (
176                                basicPrice1 -
177                                Number(context.discountPrice1.replace(/[^0-9.-]+/g, ""))
178                            ).toFixed(2);
179                        }
180                        let image1;
181                        if (context.imgSrc1 && context.imgSrc1 !== '') {
182                            image1 = context.imgSrc1.split('/').pop();
183                        } else if (context.videoId1 && context.videoId1 !== '') {
184                            image1 = context.videoId1;
185                        }
186
187                        productData.push({
188                            image: image1,
189                            campaignId: context.campaign,
190                            campaignName: context.header,
191                            productId: gaProduct1.id,
192                            productShortName: gaProduct1.shortName,
193                            category: gaProduct1.category,
194                            variant: variant1,
195                            price: basicPrice1.toFixed(2),
196                            discount: discount1,
197                            familyVariant: gaProduct1.familyVariant || "N/A",
198                            breakdownVariant: gaProduct1.breakdownVariant || "N/A",
199                            fullName: gaProduct1.fullName,
200                            coverageAmount: gaProduct1.coverageAmount || "N/A",
201                            link: linkSelectors[0]
202                        });
203                    }
204                    // Product 2 has productName defined
205                    if (context.gaProductName2 !== 'NOT_GA4_PRODUCT') {
206                        const gaProduct2 = data[context.gaProductName2];
207                        const variant2 = (gaProduct2.coverType || 'N/A')
208                            + '_' + (gaProduct2.familyVariant || 'N/A')
209                            + '_' + (gaProduct2.breakdownVariant || 'N/A')
210                            + '_N/A';
211                        const basicPrice2 =
212                            context.normalPrice2 && context.normalPrice2 !== '' ?
213                                Number(context.normalPrice2.replace(/[^0-9.
213-]+/g, "")) :
214                                +gaProduct2.price;
215                        let discount2 = 0;
216                        if (context.discountPrice2 && context.discountPrice2 !== '') {
217                            discount2 = (
218                                basicPrice2 -
219                                Number(context.discountPrice2.replace(/[^0-9.-]+/g, ""))
220                            ).toFixed(2);
221                        }
222                        let image2;
223                        if (context.imgSrc2 && context.imgSrc2 !== '') {
224                            image2 = context.imgSrc2.split('/').pop();
225                        } else if (context.videoId2 && context.videoId2 !== '') {
226                            image2 = context.videoId2;
227                        }
228
229                        productData.push({
230                            image: image2,
231                            campaignId: context.campaign,
232                            campaignName: context.header,
233                            productId: gaProduct2.id,
234                            productShortName: gaProduct2.shortName,
235                            category: gaProduct2.category,
236                            variant: variant2,
237                            price: basicPrice2.toFixed(2),
238                            discount: discount2,
239                            familyVariant: gaProduct2.familyVariant || "N/A",
240                            breakdownVariant: gaProduct2.breakdownVariant || "N/A",
241                            fullName: gaProduct2.fullName,
242                            coverageAmount: gaProduct2.coverageAmount || "N/A",
243                            link: linkSelectors[1]
244                        });
245                    }
246
247                } else if (
248                    context.items && context.items.length > 0
249                ) {
250                    // Carousel object is rendered on the page
251                    context.items.forEach((item, index) => {
252                        if (item.gaProductName && item.gaProductName !== 'NOT_GA4_PRODUCT') {
253                            const gaProductName = item.gaProductName;
254                            const gaProduct = data[gaProductName];
255                            const linkSelector = document.querySelector(areaSelector).querySelectorAll('.evg-btn')[index];
256
257                            const basicPrice =
258                                item.price && item.price !== '' ?
259                                    Number(item.price.replace(/[^0-9.-]+/g, "")) :
260                                    +gaProduct.price;
261
262                            let discount = 0;
263                            if (item.discountPrice && item.discountPrice !== '') {
264                                discount = (
265                                    basicPrice -
266                                    Number(item.discountPrice.replace(/[^0-9.-]+/g, ""))
267                                ).toFixed(2);
268                            }
269
270                            const variant = (gaProduct.coverType || 'N/A')
271                                + '_' + (gaProduct.familyVariant || 'N/A')
272                                + '_' + (gaProduct.breakdownVariant || 'N/A')
273                                + '_N/A';
274
275                            productData.push({
276                                image: item.imgSrc.split('/').pop(),
277                                campaignId: context.campaign,
278                                campaignName: item.title,
279                                productId: gaProduct.id,
280                                productShortName: gaProduct.shortName,
281                                category: gaProduct.category,
282                                variant: variant,
283                                price: basicPrice.toFixed(2),
284                                discount: discount,
285                                familyVariant: gaProduct.familyVariant || "N/A",
286                                breakdownVariant: gaProduct.breakdownVariant || "N/A",
287                                fullName: gaProduct.fullName,
288                                coverageAmount: gaProduct.coverageAmou
288nt || "N/A",
289                                link: linkSelector
290                            });
291                        }
292                    });
293                } else {
294                    // Page with only one product
295                    // Search page with one product too
296                    let gaProductName;
297                    let image;
298                    let gaProduct;
299                    let discount = 0;
300                    const linkSelector = document.querySelector(areaSelector).querySelector('.evg-btn');
301
302                    if (context.imgSrc1 && !context.secondItemRendering) {
303                        gaProductName = context.gaProductName1;
304                        if (context.gaProductName1 && context.gaProductName1 !== 'NOT_GA4_PRODUCT') {
305                            gaProduct = data[gaProductName];
306                            image = context.imgSrc1.split('/').pop();
307
308                            const basicPrice =
309                                context.normalPrice1 && context.normalPrice1 !== '' ?
310                                    Number(context.normalPrice1.replace(/[^0-9.-]+/g, "")) :
311                                    +gaProduct.price;
312
313                            if (context.discountPrice1 && context.discountPrice1 !== '') {
314                                discount = (
315                                    basicPrice -
316                                    Number(context.discountPrice1.replace(/[^0-9.-]+/g, ""))
317                                ).toFixed(2);
318                            }
319                        }
320                    } else {
321                        gaProductName = context.gaProductName;
322                        if (context.gaProductName && context.gaProductName !== 'NOT_GA4_PRODUCT') {
323                            gaProduct = data[gaProductName];
324                            if (context.imgSrc && context.imgSrc !== '') {
325                                image = context.imgSrc.split('/').pop();
326                            } else if (context.videoId && context.videoId !== '') {
327                                image = context.videoId;
328                            }
329
330                            const basicPrice =
331                                context.normalPrice && context.normalPrice !== '' ?
332                                    Number(context.normalPrice.replace(/[^0-9.-]+/g, "")) :
333                                    +gaProduct.price;
334
335                            if (context.discountPrice && context.discountPrice !== '') {
336                                discount = (
337                                    basicPrice -
338                                    Number(context.discountPrice.replace(/[^0-9.-]+/g, ""))
339                                ).toFixed(2);
340                            }
341                        }
342                    }
343
344                    if (gaProductName !== 'NOT_GA4_PRODUCT') {
345                        const variant = (gaProduct.coverType || 'N/A')
346                            + '_' + (gaProduct.familyVariant || 'N/A')
347                            + '_' + (gaProduct.breakdownVariant || 'N/A')
348                            + '_N/A';
349
350                        productData.push({
351                            image: image,
352                            campaignId: context.campaign,
353                            campaignName: context.header,
354                            productId: gaProduct.id,
355                            productShortName: gaProduct.shortName,
356                            category: gaProduct.category,
357                            variant: variant,
358                            price: gaProduct.price.toFixed(2),
359                            discount: discount,
360                            familyVariant: gaProduct.familyVariant || "N/A",
361                            breakdownVariant: gaProduct.breakdownVariant || "N/A",
362                            fullName: gaProduct.fullName,
363                            coverageAmount: gaProduct.coverageAmount || "N/A",
364                            link: linkSelector
365                        });
366                    }
367                }
368
369                const dataLayer = window.dataLayer || [];
370                if (productData.length > 0) {
371                    pushViewPromotion(
372                        dataLayer,
373                        productData
374                    );
375                    addEventListenerForSelectPromotion(
376                        dataLayer,
377                        productData
378                    );
379                }
380            }
381        });
382    }
383}
384
385function pushViewPromotion(
386    dataLayer,
387    productData
388) {
389    productData.forEach((product) => {
390        dataLayer.push(
391            createDatalayerContent("view_promotion", product)
392        )
393    });
394}
395
396function addEventListenerForSelectPromotion(
397    dataLayer,
398    productData
399) {
400    productData.forEach((product) => {
401        product.link.addEventListener('click', function () {
402            dataLayer.push(
403                createDatalayerContent("select_promotion", product)
404            )
405        });
406    });
407}
408
409function createDatalayerContent(
410    event,
411    product
412) {
413    return {
414        "event": event,
415        "ecommerce": {
416            "creative_name": product.image,
417            "creative_slot": "Interaction Banner",
418            "promotion_id": product.campaignId,
419            "promotion_name": product.campaignName,
420            "items": [
421                {
422                    "item_id": product.productId,
423                    "item_name": product.productShortName,
424                    "discount": product.discount,
425                    "currency": "CHF",
426                    "index": 1,
427                    "item_brand": "Club",
428                    "item_category": product.category,
429                    "item_variant": product.variant,
430                    "price": product.price,
431                    "quantity": 1,
432                    "cp_ecom_product_region": "N/A",
433                    "cp_ecom_product_club_scope": product.familyVariant,
434                    "cp_ecom_product_club_breakdown_service": product.breakdownVariant,
435                    "cp_ecom_product_name": product.fullName,
436                    "cp_ecom_insurance_coverage_amount": product.coverageAmou
436nt
437                }
438            ]
439        }
440    }
441}
442
443const TEASER_CONTENT_ZONE_ID = '#mcpSectionArea';
444const CAMPAIGN_CONTROL_EXPERIENCE_NAME = 'Control';
445// Set timeout to check if Flicker Defender ends it work.
446// If it's the case, it tests if we need to handle pending datalayers
447function addFlickerDefenderTimeout() {
448    if (typeof SalesforceInteractions !== 'undefined' && typeof SalesforceInteractions.getSitemapConfig().global !== 'undefined') {
449    setTimeout(function () {
450            const targetedZone = SalesforceInteractions.mcis.getCampaignResponses()[0]?.payload.contentZone;
451            const sitemapContentZones = SalesforceInteractions.getSitemapConfig().global?.contentZones||[];
452            const targetedZoneSelector = sitemapContentZones.filter(zone => {
453                return zone.name === targetedZone;
454            })[0]?.selector;
455
456            if (!document.querySelector('style.evergagePersonalizationSections')) {
457                if (!document.querySelector(TEASER_CONTENT_ZONE_ID) ||
458                    targetedZoneSelector !== TEASER_CONTENT_ZONE_ID ||
459                    SalesforceInteractions.mcis.getCampaignResponses().length === 0 ||
460                    SalesforceInteractions.mcis.getCampaignResponses()[0].userGroup === CAMPAIGN_CONTROL_EXPERIENCE_NAME
461                ) {
462
463                    // If no active Ajax requests
464                    if ($.active === 0) {
465                        handlePendingDataLayers();
466                    } else {
467                        $(document).ajaxStop(function() {
468                            handlePendingDataLayers();
469                        });
470                    }
471                }
472                return;
473            }
474            addFlickerDefenderTimeout();
475    }, 3000);
476    }
477}
478
479// Function to handle pending data layers
480function handlePendingDataLayers() {
481    while (pendingDataLayers.length > 0) {
482        var pendingDataLayer = pendingDataLayers.shift();
483        handleDataLayer(pendingDataLayer);
484    }
485}
486
487let pendingDataLayers = [];
488// Add pending datalayer from 4 columns main
489function addPendingDatalayerViewPromotion(dataLayer) {
490    pendingDataLayers.push(dataLayer);
491}
492
493window.addEventListener('load', addFlickerDefenderTimeout);

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.