1import CheckoutAccessHelper from "./checkout-access.helper.js?six_jsfix=20260923"; 2import ItemListAccessHelper from "./item-list-access.helper.js"; 3import ProductAccessHelper from "./product-access.helper.js"; 4import StorageAccessHelper from "./storage-access.helper.js"; 5import PayloadFormatHelper from './payload-format.helper.js'; 6 7export default class DatalayerHelper { 8 9 static login() { 10 const { 11 acceptedMads, 12 } = window; 13 let pushArray = { 14 event: 'login', 15 method: 'mail' 16 }; 17 if (acceptedMads) { 18 dataLayer.push({microsoft_ads_object: null}); 19 pushArray['microsoft_ads_object'] = { 20 event: 'login', 21 method: 'mail' 22 }; 23 } 24 dataLayer.cleanPush(pushArray); 25 } 26 27 static addToCartFromHeader(productId, quantity, remove, allowSave, keepOriginFromStorage) { 28 let pushArray = {event: 'add_to_cart'}; 29 30 if (remove) { 31 pushArray['event'] = 'remove_from_cart'; 32 allowSave = false; 33 } 34 35 let totalUAValue = parseFloat(ProductAccessHelper.getUAValueFromHeader(productId, quantity)); 36 let totalValue = parseFloat(ProductAccessHelper.getValueFromHeader(productId, quantity,false)); 37 let uaItem = ProductAccessHelper.getFormUAItemFromHeader(productId); 38 39 const { 40 ga4AdvancedConsentMode, 41 acceptedGa, 42 googleAnalyticsEnabled, 43 ga4Currency, 44 ga4Product, 45 acceptedGads, 46 googleAdsEnabled, 47 ecomm_pagetype, 48 acceptedMeta, 49 acceptedMads, 50 acceptedPinterest, 51 acceptedTiktok 52 } = window; 53 54 let productArray; 55 56 if (ga4Product && ga4Product[productId]) { 57 let {index, item_list_id, item_list_name} = ga4Product[productId]; 58 59 productArray = ProductAccessHelper.getProductFromHeader(productId, quantity, index, item_list_id, item_list_name, allowSave, keepOriginFromStorage); 60 StorageAccessHelper.setJsonEntry("ga4item_", productId, productArray); 61 StorageAccessHelper.setEntriesIfMissing([ 62 { 63 entryString: 'item_startPrice_', 64 productId: productId, 65 value: ga4Product[productId]["extra"]["item_startPrice"] 66 }, 67 { 68 entryString: 'taxRate_', 69 productId: productId, 70 value: ga4Product[productId]["extra"]["taxes"]}, 71 { 72 entryString: 'productId_', 73 productId: ga4Product[productId]["extra"]['item_shop_id'], 74 value: productId 75 }, 76 { 77 entryString: 'SKU_', 78 productId: productId, 79 value: ga4Product[productId]["extra"]['item_shop_id'] 80 }, 81 ]); 82 } 83 if ((productArray = StorageAccessHelper.getJsonEntry('ga4item_', productId)) !== null) { 84 productArray['quantity'] = quantity; 85 productArray['discount'] = Math.round((productArray['discount']) * 100) / 100; 86 } 87 88 if ((ga4AdvancedConsentMode || acceptedGa) && googleAnalyticsEnabled) { 89 dataLayer.push({ecommerce: null}); 90 91 92 pushArray['ecommerce'] = { 93 currency: ga4Currency, 94 value: parseFloat(totalValue.toFixed(2)), 95 items: [productArray] 96 }; 97 } 98 99 100 if ((ga4AdvancedConsentMode || acceptedGads) && googleAdsEnabled) { 101 dataLayer.push({items: null}); 102 103 pushArray['value'] = parseFloat(totalUAValue.toFixed(2)); 104 pushArray['items'] = [uaItem]; 105 } 106 107 if (acceptedMeta) { 108 dataLayer.push({meta_object: null}); 109 110 let metaItem = ProductAccessHelper.getMetaItemFromItem(productArray); 111 112 pushArray['meta_object'] = { 113 meta_event: remove ? 'RemoveFromCart' : 'AddToCart', 114 meta_object_data: { 115 contents: [metaItem.contents], 116 content_type: 'product', 117 content_name: metaItem.name, 118 content_category: metaItem.category 119 }, 120 }; 121 } 122 123 if (acceptedMads) { 124 dataLayer.push({microsoft_ads_object: null}); 125 let madsItem = ProductAccessHelper.getMadsItemFromItem(productArray); 126 if (madsItem) { 127 pushArray['microsoft_ads_object'] = { 128 'event': remove ? 'remove_from_cart' : 'add_to_cart', 129 'ecomm_prodid': madsItem.prodId, 130 'ecomm_pagetype': ecomm_pagetype, 131 'ecomm_totalvalue': parseFloat(madsItem.totalvalue.toFixed(2)), 132 'revenue_value': parseFloat(totalUAValue.toFixed(2)), 133 'currency': ga4Currency, 134 'items': madsItem.lineItem 135 }; 136 } else { 137 pushArray['microsoft_ads_object'] = { 138 'event': remove ? 'remove_from_cart' : 'add_to_cart', 139 'ecomm_prodid': productId, 140 'ecomm_pagetype': ecomm_pagetype, 141 'ecomm_totalvalue': parseFloat(totalValue.toFixed(2)), 142 'revenue_value': parseFloat(totalUAValue.toFixed(2)), 143 'currency': ga4Currency, 144 'items': undefined 145 }; 146 } 147 } 148 149 if (acceptedPinterest) { 150 dataLayer.push({pinterest_object: null}); 151 let pinterestItem = ProductAccessHelper.getPinterestItemFromItem(productArray); 152 if (pinterestItem) { 153 pushArray['pinterest_object'] = { 154 pinterest_event: remove ? 'removefromcart' : 'addtocart', 155 currency: ga4Currency, 156 line_items: [pinterestItem] 157 }; 158 } else { 159 pushArray['pinterest_object'] = { 160 pinterest_event: 'addtocart', 161 currency: ga4Currency, 162 line_items: undefined 163 }; 164 } 165 } 166 167 if (acceptedTiktok) { 168 dataLayer.push({tiktok_object: null}); 169 let tiktokItem = ProductAccessHelper.getTikTokItemFromItem(productArray); 170 if (tiktokItem) { 171 pushArray['tiktok_object'] = { 172 tiktok_event: 'AddToCart', 173 currency: ga4Currency, 174 value: parseFloat(tiktokItem.totalvalue.toFixed(2)),
175 quantity: tiktokItem.quantity, 176 content_type: 'product', 177 contents: [tiktokItem.lineItem] 178 }; 179 } else { 180 pushArray['tiktok_object'] = { 181 tiktok_event: 'AddToCart', 182 currency: ga4Currency, 183 value: undefined, 184 quantity: undefined, 185 content_type: 'product', 186 line_items: undefined 187 }; 188 } 189 } 190 191 dataLayer.cleanPush(pushArray); 192 } 193 194 static viewItemList(source, cms) { 195 const { 196 ga4activeNavigationId, 197 searchTerm, 198 ga4AdvancedConsentMode, 199 acceptedGa, 200 googleAnalyticsEnabled, 201 acceptedGads, 202 googleAdsEnabled, 203 acceptedMeta, 204 acceptedMads, 205 searchResult, 206 ga4Currency, 207 ecomm_pagetype, 208 acceptedPinterest 209 } = window; 210 211 let itemsListContainer; 212 let itemListId; 213 let itemListName; 214 215 if (source === 'category') { 216 itemsListContainer = document.querySelector('.listing--container'); 217 itemListId = ga4activeNavigationId ? ga4activeNavigationId : ''; 218 itemListName = document.title; 219 } else if (source === 'search') { 220 itemsListContainer = document.querySelector('.listing--container'); 221 itemListId = 'search=' + searchTerm; 222 itemListName = 'search'; 223 } else if (source === 'productCrossSelling') { 224 itemsListContainer = cms; 225 itemListId = cms.getAttribute('data-tab-id'); 226 itemListName = cms.querySelector('.tab--title').innerText; 227 } else if (source === "lastSeenProducts") { 228 itemsListContainer = cms; 229 itemListId = "lastSeenProducts"; 230 itemListName = "lastSeenProducts"; 231 } else { 232 itemsListContainer = cms; 233 itemListId = source; 234 itemListName = cms.querySelector(".panel--title").innerText; 235 } 236 237 if (!itemsListContainer) { 238 return; 239 } 240 241 let pushArray = {event: 'view_item_list'}; 242 243 let items = ItemListAccessHelper.getItems(itemsListContainer, itemListId, itemListName, false); 244 245 if ((ga4AdvancedConsentMode || acceptedGa) && googleAnalyticsEnabled) { 246 dataLayer.push({ecommerce: null}); 247 pushArray['ecommerce'] = { 248 item_list_id: itemListId, 249 item_list_name: itemListName, 250 items: items 251 }; 252 } 253 254 let adsItemsList; 255 let totalValue = 0; 256 257 adsItemsList = ItemListAccessHelper.getItems(itemsListContainer, itemListId, itemListName, true); 258 if (adsItemsList) { 259 totalValue = adsItemsList.pop(); 260 if ((ga4AdvancedConsentMode || acceptedGads) && googleAdsEnabled) { 261 dataLayer.push({items: null}); 262 pushArray['value'] = totalValue; 263 pushArray['items'] = adsItemsList; 264 } 265 } 266 267 if (source === 'search') { 268 this.viewSearchResults(adsItemsList, totalValue); 269 } 270 271 if (source === 'search' && acceptedMeta) { 272 dataLayer.push({meta_object: null}); 273 274 let metaItems = searchResult ? ProductAccessHelper.getMetaItemsFromWindow('view_search_results') : undefined; 275 276 pushArray['meta_object'] = { 277 meta_event: 'Search', 278 meta_object_data: { 279 contents: metaItems ? [metaItems.contents] : undefined, 280 content_type: 'product', 281 search_string: searchTerm 282 } 283 }; 284 } 285 286 if (acceptedMads) { 287 dataLayer.push({microsoft_ads_object: null}); 288 let madsItemsFromItems = ProductAccessHelper.getMadsItemsFromItems(items); 289 if (madsItemsFromItems) { 290 pushArray['microsoft_ads_object'] = { 291 'event': 'view_item_list', 292 'ecomm_category': document.title, 293 'ecomm_prodid': madsItemsFromItems.prodIds, 294 'ecomm_pagetype': window.ecomm_pagetype, 295 'ecomm_totalvalue': parseFloat(madsItemsFromItems.totalvalue.toFixed(2)), 296 'revenue_value': parseFloat(madsItemsFromItems.totalvalue.toFixed(2)), 297 'currency': ga4Currency, 298 'items': madsItemsFromItems.lineItems 299 }; 300 } else { 301 pushArray['microsoft_ads_object'] = { 302 'event': 'view_item_list', 303 'ecomm_category': document.title, 304 'ecomm_prodid': [], 305 'ecomm_pagetype': window.ecomm_pagetype, 306 'ecomm_totalvalue': undefined, 307 'revenue_value': undefined, 308 'currency': ga4Currency, 309 'items': [] 310 }; 311 } 312 } 313 314 315 dataLayer.cleanPush(pushArray); 316 317 if (acceptedPinterest && source === 'category') { 318 let pushArray = {event: 'view_category'}; 319 dataLayer.push({pinterest_object: null, microsoft_ads_object: null, meta_object: null, ecommerce: null}); 320 let pinterestItems = ProductAccessHelper.getPinterestItemsFromItems(items); 321 if (pinterestItems) { 322 pushArray['pinterest_object'] = { 323 pinterest_event: 'viewcategory', 324 currency: ga4Currency, 325 line_items: pinterestItems.lineItems 326 }; 327 } else { 328 pushArray['pinterest_object'] = { 329 pinterest_event: 'viewcategory', 330 currency: ga4Currency, 331 line_items: undefined 332 }; 333 } 334 dataLayer.cleanPush(pushArray); 335 } 336 337 } 338 339 static viewItemFromHeader(productId, quantity) { 340 if (!productId || !(productId in window.ga4Product)) { 341 return; 342 } 343 344 const { 345 ga4Product, 346 ga4Currency, 347 ga4AdvancedConsentMode, 348 acceptedGa, 349 googleAnalyticsEnabled, 350 googleAdsEnabled, 351 acceptedGads, 352 acceptedMeta, 353 acceptedMads, 354 ecomm_pagetype, 355 acceptedPinterest, 356 acceptedTiktok 357 } = window; 358 359 if (!(productId in ga4Product)) { 360 return; 361 } 362 363 let uaValue = ProductAccessHelper.getUAValueFromHeader(productId, quantity); 364 let value = ProductAccessHelper.getValueFromHeader(productId, quantity); 365 366 ga4Product[productId]['index'] = 0; 367 ga4Product[productId]['item_list_id'] = 'product'; 368 ga4Product[productId]['item_list_name'] = 'product'; 369 370 let pushArray = {event: 'view_item'}; 371 372 let productArray = ProductAccessHelper.getProductFromHeader(productId, quantity, 0, "", "", false); 373 374 375 if ((ga4AdvancedConsentMode || acceptedGa) && googleAnalyticsEnabled) { 376 dataLayer.push({ecommerce: null}); 377 pushArray['ecommerce'] = { 378 value: value, 379 currency: ga4Currency, 380 items: [productArray] 381 }; 382 } 383 if ((ga4AdvancedConsentMode || acceptedGads) && googleAdsEnabled) { 384 dataLayer.push({items: null}); 385 386 pushArray['value'] = uaValue; 387 388 pushArray['items'] = [ProductAccessHelper.getFormUAItemFromHeader(productId)]; 389 } 390 391 if (acceptedMeta) { 392 dataLayer.push({meta_object: null}); 393 let metaItem = ProductAccessHelper.getMetaItemFromItem(productArray); 394 395 pushArray['meta_object'] = { 396 meta_event: 'ViewContent', 397 meta_object_data: { 398 contents: [metaItem.contents], 399 content_type: 'product', 400 content_name: metaItem.name, 401 content_category: metaItem.category 402 }, 403 }; 404 405 } 406 407 if (acceptedMads) { 408 dataLayer.push({microsoft_ads_object: null}); 409 let madsItem = ProductAccessHelper.getMadsItemFromItem(productArray); 410 if (madsItem) { 411 pushArray['microsoft_ads_object'] = { 412 event: 'view_item', 413 ecomm_prodid: madsItem.prodId, 414 ecomm_pagetype: ecomm_pagetype, 415 ecomm_totalvalue: parseFloat(madsItem.totalvalue.toFixed(2)), 416 revenue_value: parseFloat(madsItem.totalvalue.toFixed(2)), 417 currency: ga4Currency, 418 items: madsItem.lineItem 419 }; 420 } else { 421 pushArray['microsoft_ads_object'] = { 422 event: 'view_item', 423 ecomm_prodid: productId, 424 ecomm_pagetype: ecomm_pagetype, 425 ecomm_totalvalue: parseFloat(value.toFixed(2)), 426 revenue_value: parseFloat(value.toFixed(2)), 427 currency: ga4Currency, 428 items: undefined 429 }; 430 } 431 } 432 433 if (acceptedPinterest) { 434 dataLayer.push({pinterest_object: null}); 435 let pinterestItem = ProductAccessHelper.getPinterestItemFromItem(productArray); 436 if (pinterestItem) { 437 pushArray['pinterest_object'] = { 438 pinterest_event: 'pagevisit', 439 currency: ga4Currency, 440 line_items: [pinterestItem] 441 }; 442 } else { 443 pushArray['pinterest_object'] = { 444 pinterest_event: 'pagevisit', 445 currency: ga4Currency, 446 line_items: undefined 447 }; 448 } 449 450 } 451 452 if (acceptedTiktok) { 453 dataLayer.push({tiktok_object: null}); 454 let tiktokItem = ProductAccessHelper.getTikTokItemFromItem(productArray); 455 if (tiktokItem) { 456 pushArray['tiktok_object'] = { 457 tiktok_event: 'ViewContent', 458 currency: ga4Currency, 459 value: parseFloat(tiktokItem.totalvalue.toFixed(2)), 460 content_type: 'product', 461 contents: [tiktokItem.lineItem] 462 }; 463 } else { 464 pushArray['tiktok_object'] = { 465 tiktok_event: 'ViewContent', 466 currency: ga4Currency, 467 value: undefined, 468 content_type: 'product', 469 line_items: undefined 470 }; 471 } 472 } 473 474 StorageAccessHelper.setJsonEntry('ga4item_', productId, productArray); 475 476 dataLayer.cleanPush(pushArray); 477 478 } 479 480 static selectItem(item, itemListId, itemListName) { 481 if (!item) { 482 return; 483 } 484 485 const { 486 ga4Currency, 487 acceptedMads, 488 ecomm_pagetype 489 } = window; 490 491 dataLayer.push({ecommerce: null, value: null, items: null, meta_object: null, microsoft_ads_object: null}); 492 493 let pushArray = {event: 'select_item'}; 494 495 pushArray['ecommerce'] = { 496 item_list_id: itemListId, 497 item_list_name: itemListName, 498 items: item 499 }; 500 501 if (acceptedMads) { 502 let madsItem = ProductAccessHelper.getMadsItemFromItem(item); 503 if (madsItem) { 504 pushArray['microsoft_ads_object'] = { 505 'event': 'select_content', 506 'ecomm_prodid': madsItem.prodId, 507 'ecomm_pagetype': ecomm_pagetype, 508 'ecomm_totalvalue': parseFloat(madsItem.totalvalue.toFixed(2)), 509 'revenue_value': parseFloat(madsItem.totalvalue.toFixed(2)), 510 'currency': ga4Currency, 511 'items': madsItem.lineItem 512 }; 513 } else { 514 pushArray['microsoft_ads_object'] = { 515 'event': 'select_content', 516 'ecomm_prodid': undefined, 517 'ecomm_pagetype': ecomm_pagetype, 518 'ecomm_totalvalue': undefined, 519 'revenue_value': undefined, 520 'currency': ga4Currency, 521 'items': undefined 522 }; 523 } 524 } 525 526 dataLayer.cleanPush(pushArray); 527 } 528 529 static addToCartFromForm(item) { 530 531 let pushArray = {event: 'add_to_cart'}; 532 533 if (!item) { 534 return; 535 } 536 537 const { 538 ga4Currency, 539 acceptedMeta 540 } = window; 541 542 dataLayer.push({ecommerce: null, value: null, items: null}); 543 544 pushArray['ecommerce'] = { 545 currency: ga4Currency, 546 items: [item] 547 }; 548 549 if (acceptedMeta) { 550 dataLayer.push({meta_object: null}); 551 552 pushArray['meta_object'] = { 553 meta_event: 'AddToCart', 554 meta_object_data: { 555 contents: [{ 556 id: item.item_id, 557 item_price: undefined 558 }], 559 content_type: 'product', 560 content_name: undefined, 561 content_category: undefined 562 }, 563 }; 564 565 } 566 567 dataLayer.cleanPush(pushArray); 568 } 569 570 static addToWishlist(item, valueString) { 571 572 if (!item) { 573 return; 574 } 575 576 let pushArray = {event: 'add_to_wishlist'}; 577 578 const { 579 ga4Currency, 580 acceptedMeta, 581 acceptedMads, 582 ecomm_pagetype, 583 acceptedTiktok 584 } = window; 585 586 dataLayer.push({ecommerce: null, value: null, items: null}); 587 588 const value = parseFloat(valueString.toFixed(2)) 589 590 pushArray['ecommerce'] = { 591 currency: ga4Currency, 592 value: value, 593 items: [item] 594 }; 595 596 if (acceptedMeta) { 597 dataLayer.push({meta_object: null}); 598 let metaItem = ProductAccessHelper.getMetaItemFromItem(item); 599 600 pushArray['meta_object'] = { 601 meta_event: 'AddToWishlist', 602 meta_object_data: { 603 contents: [metaItem.contents], 604 content_type: 'product', 605 content_name: metaItem.name, 606 content_category: metaItem.category 607 }, 608 }; 609 } 610 611 if (acceptedMads) { 612 dataLayer.push({microsoft_ads_object: null}); 613 let madsItem = ProductAccessHelper.getMadsItemFromItem(item); 614 pushArray['microsoft_ads_object'] = { 615 'event': 'add_to_wishlist', 616 'ecomm_prodid': madsItem.prodId, 617 'ecomm_pagetype': ecomm_pagetype, 618 'ecomm_totalvalue': value, 619 'revenue_value': value, 620 'currency': ga4Currency, 621 'items': madsItem.lineItem 622 }; 623 } 624 625 if (acceptedTiktok) { 626 dataLayer.push({tiktok_object: null}); 627 let tiktokItem = ProductAccessHelper.getTikTokItemFromItem(item); 628 if (tiktokItem) { 629 pushArray['tiktok_object'] = { 630 tiktok_event: 'AddToWishlist', 631 currency: ga4Currency, 632 value: parseFloat(tiktokItem.totalvalue.toFixed(2)), 633 content_type: 'product', 634 contents: [tiktokItem.lineItem] 635 }; 636 } else { 637 pushArray['tiktok_object'] = { 638 tiktok_event: 'AddToWishlist', 639 currency: ga4Currency, 640 value: undefined, 641 content_type: 'product', 642 line_items: undefined 643 }; 644 } 645 } 646 dataLayer.cleanPush(pushArray); 647 } 648 649 static shippingInfo(checkoutContainer, shipping) { 650 if (!checkoutContainer || !shipping) { 651 return; 652 } 653 654 const { 655 ga4Currency 656 } = window; 657 658 dataLayer.push({ecommerce
658: null, value: null, items: null}); 659 660 dataLayer.push({ 661 event: 'add_shipping_info', 662 ecommerce: { 663 currency: ga4Currency, 664 value: parseFloat(checkoutContainer.dataset.value.replace(",", ".")), 665 coupon: CheckoutAccessHelper.getCoupon(checkoutContainer).coupon, 666 shipping_tier: shipping.toString(), 667 items: CheckoutAccessHelper.getItemsFromStorage(checkoutContainer) 668 } 669 }); 670 } 671 672 static paymentInfo(checkoutContainer, payment) { 673 if (!checkoutContainer || !payment) { 674 return; 675 } 676 677 const { 678 ga4Currency, 679 acceptedMeta, 680 acceptedMads, 681 ecomm_pagetype, 682 acceptedTiktok 683 } = window; 684 685 dataLayer.push({ecommerce: null, value: null, items: null}); 686 687 let pushArray = {event: 'add_payment_info'}; 688 let items = CheckoutAccessHelper.getItemsFromStorage(checkoutContainer) 689 let value = parseFloat(checkoutContainer.dataset.value.replace(",", ".")); 690 691 pushArray['ecommerce'] = { 692 currency: ga4Currency, 693 value: value, 694 coupon: CheckoutAccessHelper.getCoupon(checkoutContainer).coupon, 695 payment_type: payment.toString(), 696 items: items 697 }; 698 699 if (acceptedMeta) { 700 dataLayer.push({meta_object: null}); 701 702 pushArray['meta_object'] = { 703 meta_event: 'AddPaymentInfo' 704 }; 705 } 706 707 if (acceptedMads) { 708 dataLayer.push({microsoft_ads_object: null}); 709 let madsItems = ProductAccessHelper.getMadsItemsFromItems(items) 710 if (madsItems && madsItems.prodIds.length > 0) { 711 pushArray['microsoft_ads_object'] = { 712 'event': 'add_payment_info', 713 'ecomm_prodid': madsItems.prodIds, 714 'ecomm_pagetype': ecomm_pagetype 715 }; 716 } else { 717 pushArray['microsoft_ads_object'] = { 718 'event': 'add_payment_info', 719 'ecomm_prodid': undefined, 720 'ecomm_pagetype': ecomm_pagetype 721 } 722 } 723 } 724 725 if (acceptedTiktok) { 726 dataLayer.push({tiktok_object: null}); 727 let tiktokItems = ProductAccessHelper.getTikTokItemsFromItems(items); 728 if (tiktokItems) { 729 pushArray['tiktok_object'] = { 730 tiktok_event: 'AddPaymentInfo', 731 currency: ga4Currency, 732 value: parseFloat(tiktokItems.totalvalue.toFixed(2)), 733 content_type: 'product', 734 contents: tiktokItems.lineItems 735 }; 736 } else { 737 pushArray['tiktok_object'] = { 738 tiktok_event: 'AddPaymentInfo', 739 currency: ga4Currency, 740 value: value, 741 content_type: 'product', 742 contents: undefined 743 } 744 } 745 } 746 747 dataLayer.cleanPush(pushArray); 748 749 } 750 751 static async purchase(checkoutContainer, adsContainer, transactionId) { 752 let pushArray = {event: 'purchase'}; 753 754 const { 755 ga4Currency, 756 ga4AdvancedConsentMode, 757 acceptedGa, 758 googleAnalyticsEnabled, 759 acceptedGads, 760 googleAdsEnabled, 761 ga4orderNumber, 762 ecomm_pagetype, 763 acceptedMeta, 764 acceptedMads, 765 acceptedPinterest, 766 acceptedTiktok 767 } = window; 768 769 const email = adsContainer.dataset.useremail; 770 const salutation = adsContainer.dataset.salutation; 771 let gender = 'not_specified'; 772 if (salutation === 'mr') { 773 gender = 'male'; 774 } else if (salutation === 'mrs') { 775 gender = 'female'; 776 } 777 const sha256_email = await this.sha256(email); 778 const first_name = adsContainer.dataset.firstname; 779 const sha256_first_name = await this.sha256(first_name) 780 const last_name = adsContainer.dataset.lastname; 781 const sha256_last_name = await this.sha256(last_name); 782 const street = adsContainer.dataset.street; 783 const city = adsContainer.dataset.city;
784 const postal_code = adsContainer.dataset.zip; 785 const region = adsContainer.dataset.region; 786 const country = adsContainer.dataset.land; 787 const phone_number = adsContainer.dataset.phone ? adsContainer.dataset.phone : null; 788 const sha256_phone_number = phone_number ? await this.sha256(phone_number): null; 789 const e164_phone_number = phone_number ? PayloadFormatHelper.gete164Phone(phone_number, country) : null; 790 const sha256_e164_phone_number = e164_phone_number ? await this.sha256(e164_phone_number): null; 791 const phone_number_international = phone_number ? PayloadFormatHelper.geteItnlPhone(phone_number, country) : null; 792 const sha256_phone_number_international = e164_phone_number ? await this.sha256(e164_phone_number) : null; 793 const transaction_id = ga4orderNumber.toString(); 794 const sha256_transaction_id = await DatalayerHelper.sha256(transaction_id); 795 796 const adsValue = this.getTotalAdsValue( 797 checkoutContainer.dataset.value, checkoutContainer.dataset.tax, checkoutContainer.dataset.shipping 798 ) 799 800 const discount = CheckoutAccessHelper.getCoupon(checkoutContainer).discount; 801 802 const coupon_code = CheckoutAccessHelper.getCoupon(checkoutContainer).code; 803 804 let ecommerce = this.checkoutContent(checkoutContainer, transactionId); 805 806 807 if ((ga4AdvancedConsentMode || acceptedGa) && googleAnalyticsEnabled && checkoutContainer) { 808 dataLayer.push({ecommerce: null}); 809 pushArray['ecommerce'] = ecommerce; 810 pushArray['coupon_code'] = coupon_code; 811 } 812 813 if ((ga4AdvancedConsentMode || acceptedGads) && googleAdsEnabled && adsContainer) { 814 pushArray['value'] = parseFloat(adsValue.toFixed(2)); 815 pushArray['transaction_id'] = transaction_id; 816 pushArray['currency'] = ga4Currency; 817 pushArray['discount'] = discount; 818 819 820 dataLayer.push({items: null}); 821 pushArray['items'] = CheckoutAccessHelper.getAdsItemsFromStorage(); 822 823 824 pushArray['email'] = sha256_email; 825 826 if(sha256_e164_phone_number) pushArray['phone_number'] = sha256_e164_phone_number; 827 828 let address = {}; 829 address['first_name'] = sha256_first_name; 830 address['last_name'] = sha256_last_name; 831 address['street'] = street; 832 address['city'] = city; 833 address['region'] = region; 834 address['postal_code'] = postal_code; 835 address['country'] = country; 836 pushArray['address'] = address; 837 838 } 839 840 if (acceptedMeta) { 841 dataLayer.push({meta_object: null}); 842 let metaItems = ProductAccessHelper.getMetaItemsFromItems(ecommerce.items); 843 844 pushArray['meta_object'] = { 845 meta_event: 'Purchase', 846 meta_object_data: { 847 value: adsValue ? parseFloat(adsValue.toFixed(2)) : ecommerce.value, 848 currency: ga4Currency, 849 contents: metaItems.contents, 850 content_type: 'product', 851 num_items: metaItems.numberOfItems, 852 order_id: transaction_id 853 }, 854 }; 855 } 856 857 if (acceptedMads) { 858 dataLayer.push({microsoft_ads_object: null}); 859 let madsItems = ProductAccessHelper.getMadsItemsFromItems(ecommerce.items); 860 pushArray['microsoft_ads_object'] = { 861 event: 'purchase', 862 transaction_id: transaction_id, 863 ecomm_prodid: madsItems ? madsItems.prodIds : undefined, 864 ecomm_pagetype: window.ecomm_pagetype, 865 ecomm_totalvalue: madsItems ? parseFloat(madsItems.totalvalue.toFixed(2)) : ecommerce.value, 866 revenue_value: adsValue ? parseFloat(adsValue.toFixed(2)) : ecommerce.value, 867 currency: ga4Currency, 868 tax: ecommerce.tax, 869 items: madsItems ? madsItems.lineItems : undefined 870 }; 871 } 872 873 if (acceptedPinterest) { 874 dataLayer.push({pinterest_object: null}); 875 let pinterestItems = ProductAccessHelper.getPinterestItemsFromItems(ecommerce.items); 876 pushArray['pinterest_object'] = { 877 pinterest_event: 'checkout', 878 value: adsValue ? adsValue : ecommerce.value, 879 order_quantity: pinterestItems ? pinterestItems.numberOfItems : undefined, 880 currency: ga4Currency, 881 order_id: transaction_id, 882 promo_code: coupon_code, 883 line_items: pinterestItems ? pinterestItems.lineItems : undefined 884 }; 885 } 886 887 if (acceptedTiktok) { 888 dataLayer.push({tiktok_object: null}); 889 let tiktokItems = ProductAccessHelper.getTikTokItemsFromItems(ecommerce.items); 890 if (tiktokItems) { 891 pushArray['tiktok_object'] = { 892 tiktok_event: 'CompletePayment', 893 currency: ga4Currency,
894 quantity: tiktokItems.numberOfItems, 895 value: adsValue ? parseFloat(adsValue.toFixed(2)) : ecommerce.value, 896 content_type: 'product', 897 contents: tiktokItems.lineItems 898 }; 899 } else { 900 pushArray['tiktok_object'] = { 901 tiktok_event: 'CompletePayment', 902 currency: ga4Currency, 903 quantity: undefined, 904 value: adsValue ? parseFloat(adsValue.toFixed(2)) : ecommerce.value, 905 content_type: 'product', 906 contents: undefined 907 } 908 } 909 } 910 911 if(sha256_e164_phone_number) { 912 pushArray['additional'] = { 913 email, 914 sha256_email, 915 first_name, 916 sha256_first_name, 917 last_name, 918 sha256_last_name, 919 e164_phone_number, 920 sha256_e164_phone_number, 921 phone_number, 922 sha256_phone_number, 923 phone_number_international, 924 sha256_phone_number_international, 925 gender, 926 street, 927 city, 928 postal_code, 929 region, 930 country, 931 transaction_id, 932 sha256_transaction_id 933 }; 934 }else { 935 pushArray['additional'] = { 936 email, 937 sha256_email, 938 first_name, 939 sha256_first_name, 940 last_name, 941 sha256_last_name, 942 gender, 943 street, 944 city, 945 postal_code, 946 region, 947 country, 948 transaction_id, 949 sha256_transaction_id 950 }; 951 } 952 953 954 dataLayer.cleanPush(pushArray); 955 } 956 957 static viewCart(checkoutContainer) { 958 dataLayer.push({ecommerce: null, value: null, items: null}); 959 dataLayer.cleanPush({ 960 event: 'view_cart', 961 ecommerce: this.cartContent(checkoutContainer), 962 coupon_code: CheckoutAccessHelper.getCoupon(checkoutContainer).code 963 }); 964 } 965 966 static beginCheckout(checkoutContainer) { 967 let pushArray = {event: 'begin_checkout'}; 968 969 const { 970 ga4Currency, 971 ecomm_pagetype, 972 acceptedMeta, 973 acceptedMads, 974 acceptedTiktok 975 } = window; 976 977 dataLayer.push({ecommerce: null, value: null, items: null}); 978 979 const currency = ga4Currency; 980 const value = parseFloat(checkoutContainer.dataset.value.replace(",", ".")); 981 982 const items = CheckoutAccessHelper.getItemsFromStorage(checkoutContainer); 983 const adsValue = this.getTotalAdsValue( 984 checkoutContainer.dataset.value, checkoutContainer.dataset.tax, checkoutContainer.dataset.shipping 985 ) 986 987 pushArray['ecommerce'] = { 988 currency, 989 value, 990 coupon: CheckoutAccessHelper.getCoupon(checkoutContainer).coupon, 991 items 992 }; 993 994 if (acceptedMeta) { 995 dataLayer.push({meta_object: null}); 996 997 let metaItems = ProductAccessHelper.getMetaItemsFromItems(items); 998 999 1000 pushArray['meta_object'] = { 1001 meta_event: 'InitiateCheckout', 1002 meta_object_data: { 1003 contents: [metaItems.contents], 1004 content_type: 'product', 1005 num_items: metaItems.numberOfItems, 1006 }, 1007 }; 1008 } 1009 1010 if (acceptedMads) { 1011 dataLayer.push({microsoft_ads_object: null}); 1012 let madsItems = ProductAccessHelper.getMadsItemsFromItems(items); 1013 pushArray['microsoft_ads_object'] = { 1014 event: 'begin_checkout', 1015 ecomm_prodid: madsItems ? madsItems.prodIds : undefined, 1016 ecomm_pagetype: ecomm_pagetype, 1017 ecomm_totalvalue: madsItems ? parseFloat(madsItems.totalvalue.toFixed(2)) : value, 1018 revenue_value: adsValue ? parseFloat(adsValue.toFixed(2)) : value, 1019 currency, 1020 items: madsItems ? madsItems.lineItems : undefined 1021 }; 1022 } 1023 1024 if (acceptedTiktok) { 1025 dataLayer.push({tiktok_object: null}); 1026 let tiktokItems = ProductAccessHelper.getTikTokItemsFromItems(items); 1027 if (tiktokItems) { 1028 pushArray['tiktok_object'] = { 1029 tiktok_event: 'InitiateCheckout', 1030 currency: ga4Currency, 1031 value: parseFloat(tiktokItems.totalvalue.toFixed(2)), 1032 content_type: 'product', 1033 contents: tiktokItems.lineItems 1034 }; 1035 } else { 1036 pushArray['tiktok_object'] = { 1037 tiktok_event: 'InitiateCheckout', 1038 currency: ga4Currency, 1039 value: value, 1040 content_type: 'product', 1041 contents: undefined 1042 } 1043 } 1044 } 1045 1046 dataLayer.cleanPush(pushArray); 1047 } 1048 1049 static signUp() { 1050 1051 let pushArray = { 1052 event: 'sign_up', 1053 method: 'mail' 1054 }; 1055 1056 const { 1057 acceptedMeta, 1058 acceptedMads, 1059 acceptedPinterest, 1060 acceptedTiktok 1061 } = window; 1062 1063 if (acceptedMeta) { 1064 dataLayer.push({meta_object: null}); 1065 1066 pushArray['meta_object'] = { 1067 meta_event: 'CompleteRegistration' 1068 }; 1069 } 1070 1071 if (acceptedMads) { 1072 dataLayer.push({microsoft_ads_object: null}); 1073 pushArray['microsoft_ads_object'] = { 1074 event: 'sign_up', 1075 method: 'mail' 1076 }; 1077 } 1078 1079 if (acceptedPinterest) { 1080 dataLayer.push({pinterest_object: null}); 1081 pushArray['pinterest_object'] = { 1082 pinterest_event: 'signup', 1083 }; 1084 } 1085 1086 if (acceptedTiktok) { 1087 dataLayer.push({tiktok_object: null}); 1088 pushArray['tiktok_object'] = { 1089 tiktok_event: 'CompleteRegistration', 1090 }; 1091 } 1092 1093 1094 dataLayer.cleanPush(pushArray); 1095 1096 } 1097 1098 /* 1099 static account(eventName, method) { 1100 const commonAccountData = {event: eventName, method}; 1101 1102 if (window.ga4UserId) { 1103 dataLayer.push({...commonAccountData, user_id: window.ga4UserId}); 1104 1105 return; 1106 } 1107 1108 dataLayer.push(commonAccountData); 1109 } 1110 */ 1111 static viewSearchResults(adsItemsList, totalValue) { 1112 1113 let pushArray = {event: 'view_search_results'}; 1114 dataLayer.push({ecommerce: null}); 1115 1116 const { 1117 searchTerm, 1118 searchResult, 1119 ga4AdvancedConsentMode, 1120 acceptedGads, 1121 googleAdsEnabled, 1122 acceptedMeta, 1123 acceptedMads, 1124 ecomm_pagetype 1125 } = window; 1126 1127 pushArray['search_term'] = searchTerm; 1128 1129 pushArray['search_result'] = 0; 1130 if (searchResult) { 1131 pushArray['search_result'] = parseInt(searchResult, 10); 1132 } 1133 1134 1135 if ((ga4AdvancedConsentMode || acceptedGads) && googleAdsEnabled && totalValue && adsItemsList) { 1136 dataLayer.push({items: null}); 1137 pushArray['value'] = totalValue; 1138 pushArray['items'] = adsItemsList; 1139 } 1140 1141 if (acceptedMeta) { 1142 dataLayer.push({meta_object: null}); 1143 1144 let metaItems = searchResult ? ProductAccessHelper.getMetaItemsFromWindow('view_search_results') : undefined; 1145 1146 pushArray['meta_object'] = { 1147 meta_event: 'Search', 1148 meta_object_data: { 1149 contents: metaItems ? [metaItems.contents] : undefined, 1150 content_type: 'product', 1151 search_string: searchTerm 1152 } 1153 }; 1154 } 1155 1156 if (acceptedMads) { 1157 dataLayer.push({microsoft_ads_object: null}); 1158 1159 const { 1160 ga4Product 1161 } = window; 1162 1163 let products = JSON.parse(JSON.stringify(ga4Product)); 1164 1165 let madsItemsFromItems = products ? ProductAccessHelper.getMadsItemsFromItems(products) : undefined; 1166 1167 if (madsItemsFromItems) { 1168 pushArray['microsoft_ads_object'] = { 1169 event: 'view_search_results', 1170 ecomm_query: searchTerm, 1171 ecomm_prodid: madsItemsFromItems.prodIds, 1172 ecomm_pagetype: ecomm_pagetype, 1173 search_term: searchTerm 1174 }; 1175 } else { 1176 pushArray['microsoft_ads_object'] = { 1177 event: 'view_search_results', 1178 ecomm_query: searchTerm, 1179 ecomm_prodid: undefined, 1180 ecomm_pagetype: ecomm_pagetype, 1181 search_term: searchTerm, 1182 }; 1183 } 1184 } 1185 1186 dataLayer.cleanPush(pushArray); 1187 1188 } 1189 1190 static changeQty(action) { 1191 const select = action.target; 1192 1193 1194 let difference = select.querySelector('[selected="selected"]').value - select.value; 1195 1196 let remove = false;
1197 1198 if (difference > 0) { 1199 remove = true; 1200 } 1201 1202 let shopId = select.closest('.row--product').querySelector('[name="sArticle"]').value; 1203 1204 let productId; 1205 1206 if (shopId) { 1207 let lineItemsContainer = document.getElementById('discoga4-checkout'); 1208 if (lineItemsContainer) { 1209 // let itemContainer = lineItemsContainer.querySelector("[data-id=" + lastSegment + "]"); 1210 let itemContainer = lineItemsContainer.querySelector('[data-id="' + shopId + '"]'); 1211 if (itemContainer) { 1212 productId = itemContainer.getAttribute("data-sku"); 1213 } 1214 } 1215 } 1216 1217 let quantity = Math.abs(difference); 1218 1219 this.addToCartFromHeader(productId, quantity, remove, false, true); 1220 } 1221 1222 static search() { 1223 1224 dataLayer.push({ecommerce: null}); 1225 1226 const { 1227 searchResult, 1228 searchTerm, 1229 acceptedMads, 1230 acceptedPinterest 1231 } = window; 1232 1233 let pushArray = { 1234 event: 'search', 1235 search_term: searchTerm ? searchTerm : undefined, 1236 search_result: searchResult ? parseInt(searchResult, 10) : undefined 1237 }; 1238 1239 if (acceptedMads) { 1240 dataLayer.push({microsoft_ads_object: null}); 1241 pushArray['microsoft_ads_object'] = { 1242 event: 'search', 1243 search_term: searchTerm 1244 }; 1245 } 1246 1247 if (acceptedPinterest) { 1248 dataLayer.push({pinterest_object: null}); 1249 pushArray['pinterest_object'] = { 1250 pinterest_event: 'search', 1251 search_query: searchTerm 1252 }; 1253 } 1254 1255 dataLayer.cleanPush(pushArray); 1256 1257 } 1258 1259 static lead() { 1260 dataLayer.push({ecommerce: null, value: null, items: null}); 1261 1262 const { 1263 generateLeadValue, 1264 acceptedMeta, 1265 acceptedMads, 1266 ecomm_pagetype, 1267 ga4Currency, 1268 acceptedPinterest, 1269 acceptedTiktok 1270 } = window; 1271 1272 let value = parseFloat(generateLeadValue); 1273 1274 let pushArray = { 1275 event: 'generate_lead', 1276 currency: ga4Currency, 1277 value: value 1278 }; 1279 1280 if (acceptedMeta) { 1281 dataLayer.push({meta_object: null}); 1282 pushArray['meta_object'] = { 1283 meta_event: 'Lead', 1284 meta_object_data: { 1285 value: value, 1286 currency: ga4Currency 1287 }, 1288 }; 1289 } 1290 1291 if (acceptedMads) { 1292 dataLayer.push({microsoft_ads_object: null}); 1293 pushArray['microsoft_ads_object'] = { 1294 event: 'generate_lead', 1295 ecomm_pagetype: ecomm_pagetype, 1296 ecomm_totalvalue: value, 1297 revenue_value: value, 1298 currency: ga4Currency, 1299 }; 1300 } 1301 if (acceptedPinterest) { 1302 dataLayer.push({pinterest_object: null}); 1303 pushArray['pinterest_object'] = { 1304 pinterest_event: 'lead', 1305 lead_type: 'Contactform', 1306 }; 1307 } 1308 1309 if (acceptedTiktok) { 1310 dataLayer.push({tiktok_object: null}); 1311 pushArray['tiktok_object'] = { 1312 tiktok_event: 'SubmitForm', 1313 }; 1314 } 1315 1316 dataLayer.cleanPush(pushArray); 1317 } 1318 1319 static forms(eventName) { 1320 dataLayer.push({ecommerce: null, value: null, items: null}); 1321 const { 1322 generateLeadValue, 1323 ga4Currency 1324 } = window; 1325 dataLayer.push({ 1326 event: eventName, 1327 currency: ga4Currency, 1328 value: generateLeadValue 1329 }); 1330 } 1331 1332 1333 static cartContent(checkoutContainer) { 1334 if (checkoutContainer.dataset) { 1335 const { 1336 ga4Currency 1337 } = window; 1338 return { 1339 currency: ga4Currency, 1340 value: parseFloat(checkoutContainer.dataset.value.replace(",", ".")), 1341 items: CheckoutAccessHelper.getItemsFromStorage(c
1341heckoutContainer) 1342 }; 1343 } 1344 return null; 1345 1346 }; 1347 1348 static checkoutContent(checkoutContainer, transactionId) { 1349 1350 let coupon = CheckoutAccessHelper.getCoupon(checkoutContainer).coupon; 1351 let discount = Math.abs(CheckoutAccessHelper.getCoupon(checkoutContainer).discount); 1352 1353 const { 1354 ga4Currency 1355 } = window; 1356 1357 if (transactionId) { 1358 return { 1359 transaction_id: transactionId, 1360 currency: ga4Currency, 1361 value: parseFloat(checkoutContainer.dataset.value.replace(",", ".")), 1362 shipping: parseFloat(checkoutContainer.dataset.shipping), 1363 tax: parseFloat(checkoutContainer.dataset.tax), 1364 coupon: coupon, 1365 discount: parseFloat(discount.toFixed(2)), 1366 items: CheckoutAccessHelper.getItemsFromStorage(checkoutContainer) 1367 }; 1368 } 1369 return { 1370 currency: ga4Currency, 1371 value: parseFloat(checkoutContainer.dataset.value.replace(",", ".")), 1372 shipping: parseFloat(checkoutContainer.dataset.shipping), 1373 tax: parseFloat(checkoutContainer.dataset.tax), 1374 coupon: coupon, 1375 discount: parseFloat(discount.toFixed(2)), 1376 items: CheckoutAccessHelper.getItemsFromStorage(checkoutContainer) 1377 }; 1378 }; 1379 1380 static async sha256(str) { 1381 const buffer = new TextEncoder("utf-8").encode(str); 1382 const hash = await crypto.subtle.digest("SHA-256", buffer); 1383 1384 return this.hex(hash); 1385 } 1386 1387 static hex(buffer) { 1388 let digest = ''; 1389 let view = new DataView(buffer); 1390 for (let i = 0; i < view.byteLength; i += 4) { 1391 let value = view.getUint32(i); 1392 let stringValue = value.toString(16); 1393 let padding = '00000000';
1394 let paddedValue = (padding + stringValue).slice(-padding.length); 1395 digest += paddedValue; 1396 } 1397 return digest; 1398 } 1399 1400 static replaceEmptyStringsWithUndefined(obj) { 1401 if (typeof obj !== 'object' || null === obj) { 1402 return obj; 1403 } 1404 1405 if (Array.isArray(obj)) { 1406 for (let i = 0; i < obj.length; i++) { 1407 if (typeof obj[i] === 'object' && obj[i] !== null) { 1408 this.replaceEmptyStringsWithUndefined(obj[i]); 1409 } else if (obj[i] === '') { 1410 obj[i] = undefined; 1411 } 1412 } 1413 1414 return obj; 1415 } 1416 1417 for (const key in obj) { 1418 if (obj.hasOwnProperty(key)) { 1419 const value = obj[key]; 1420 if (typeof value === 'object' && value !== null) { 1421 this.replaceEmptyStringsWithUndefined(value); 1422 } else if (value === '') { 1423 obj[key] = undefined; 1424 } 1425 } 1426 } 1427 1428 return obj; 1429 } 1430 1431 static getTotalAdsValue(rawValue, tax, shipping) { 1432 let totalAdsValue = parseFloat(rawValue) - parseFloat(shipping); 1433 // BruttoWithoutShipping 1434 1435 1436 const calculatedShipping = this.calculateShipping(shipping, this.getGlobalPurchaseTaxState()); 1437 const { 1438 conversionConfiguration 1439 } = window; 1440 1441 switch (conversionConfiguration) { 1442 case ("bruttoWithShipping"): // BruttoWithShipping 1443 totalAdsValue += parseFloat(calculatedShipping); 1444 break; 1445 case ("nettoWithShipping"): // NettoWithShipping 1446 totalAdsValue = totalAdsValue - parseFloat(tax) + parseFloat(calculatedShipping); 1447 break; 1448 case ("netto"): // NettoWithoutShipping 1449 totalAdsValue -= parseFloat(tax); 1450 break; 1451 } 1452 1453 return Math.round(totalAdsValue * 100) / 100; 1454 } 1455 1456 static calculateShipping(shipping, type = 'net') { 1457 let storageShipping = sessionStorage.getItem('ga4_shipping_price'); 1458 if (!storageShipping) { 1459 return 0; 1460 } 1461 1462 if (!type) { 1463 return shipping; 1464 } 1465 1466 storageShipping = JSON.parse(storageShipping); 1467 1468 return storageShipping[type]; 1469 } 1470 1471 static getGlobalPurchaseTaxState() { 1472 let storageShipping = sessionStorage.getItem('ga4_shipping_price'); 1473 if (!storageShipping) { 1474 return 'gross'; 1475 } 1476 1477 const {globalTaxState} = JSON.parse(storageShipping); 1478 1479 return globalTaxState; 1480 } 1481}
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.