1; (() => { 2 const Tracker = { 3 init: (config) => { 4 Tracker.config = config 5 Tracker.log(`Initialised`, 'log') 6 Tracker.nonce = crypto.randomUUID() 7 8 window.addEventListener('load', () => Tracker.setup()) 9 }, 10 refresh: () => { 11 Tracker.setup() 12 }, 13 setup: () => { 14 Tracker.assignTracker() 15 Tracker.getPageData() 16 Tracker.eventBind() 17 Tracker.handlers.pageVisit() 18 }, 19 assignTracker: () => { 20 window.Tracker = Object.assign(Tracker, window.Tracker) 21 }, 22 handlerCaller: (el) => { }, 23 urlEvent: () => { 24 if (!Tracker.config.watchers) { 25 return 26 } 27 const keys = Object?.keys(Tracker.config.watchers.params) 28 const searchParams = new URLSearchParams(window.location.search) 29 keys.map((key) => { 30 if ( 31 searchParams.get(Tracker?.config?.watchers?.params[key].paramName) 32 ) { 33 Tracker.handlers[Tracker?.config?.watchers?.params[key].eventName]() 34 let url = new URL(window?.location?.href) 35 url.searchParams.delete( 36 Tracker?.config?.watchers?.params[key]?.paramName 37 ) 38 history.replaceState(history.state, '', url.href) 39 } 40 }) 41 }, 42 eventBind: (el) => { 43 Tracker.urlEvent() 44 let nodes = [] 45 46 if (el) { 47 nodes = [el] 48 } else { 49 nodes = [ 50 ...document.querySelectorAll(`[${Tracker.config.selectors.track}]`) 51 ] 52 } 53 nodes.map((node) => { 54 let el = node, 55 handler = el.getAttribute(Tracker.config.selectors.track), 56 eventType = el.getAttribute(Tracker.config.selectors.type) 57 ? el.getAttribute(Tracker.config.selectors.type).split('|') 58 : ['click'] 59 if (typeof Tracker.handlers[handler] !== 'undefined') { 60 if (eventType[0] === 'impression') { 61 const observer = new IntersectionObserver((entries) => { 62 entries.forEach((entry) => { 63 if (entry.isIntersecting) { 64 Tracker.handlers[handler](el) 65 } 66 }) 67 }) 68 observer.observe(el) 69 } else if (eventType[0] === 'onload') { 70 Tracker.handlers[handler](el) 71 } else { 72 el.addEventListener(eventType, Tracker.handlers[handler]) 73 } 74 } else { 75 Tracker.log(`Hanlder ${handler} not found on element: %o`, node) 76 } 77 }) 78 }, 79 getPageData: () => { 80 const currencyEl = document.querySelector( 81 `[${Tracker.config.selectors.currency}]` 82 ) 83 Tracker.page = {} 84 if (currencyEl) { 85 if ( 86 window.Tracker.store.currency !== 87 currencyEl.getAttribute(Tracker?.config?.selectors?.currency) 88 ) { 89 Tracker.store.set( 90 'currency', 91 currencyEl.getAttribute(Tracker?.config?.selectors?.currency) 92 ) 93 } 94 } else { 95 Tracker.log( 96 `Required attribute ${Tracker?.config?.selectors?.currency} not found. Include ${Tracker.config.selectors.currency}="GBP" (for e.g.) to an element in the DOM.` 97 ) 98 } 99 }, 100 getAttributes: (el) => { 101 const target = el.currentTarget 102 const store = target?.getAttribute(Tracker.config.selectors.store) 103 const type = target?.getAttribute(Tracker.config.selectors.type) 104 const track = target?.getAttribute(Tracker.config.selectors.track) 105 return { store, type, track } 106 }, 107 push: (obj, config) => { 108 Tracker.log(`Pushed event: ${JSON.stringify(obj)}`, 'log') 109 if (window.dataLayer) { 110 if (config?.commerce) { 111 window.dataLayer.push({ commerce: true }) 112 } 113 window.dataLayer.push(obj) 114 } 115 }, 116 marshalPubSub: ( 117 operationName, 118 url, 119 eventData, 120 legacyRayId, 121 experiments 122 ) => { 123 const rayId = 124 legacyRayId || Tracker.store.get('rayId')?.value || 'unknown' 125 126 const { origin: eventOrigin, ...restEventData } = eventData 127 128 const legacyData = { 129 ...restEventData, 130 ray_ids: [rayId], 131 nonce: Tracker.nonce, 132 server: { 133 elysium_version: Tracker.trackApiConfig.elysium_config.version 134 }, 135 request: { start_timestamp: Date.now(), url: url }, 136 origin: { referrer: document.referrer, ...(eventOrigin || {}) }, 137 property: { 138 site_id: Tracker.trackApiConfig.elysium_config.site_id, 139 channel: Tracker.trackApiConfig.elysium_config.channel, 140 subsite: Tracker.trackApiConfig.elysium_config.subsite, 141 locale: Tracker.store.get('locale')?.value 142 }, 143 experiments 144 } 145 const basket = Tracker.store.get('basket') 146 const basketItems = Tracker.getAllBasketItems(basket) 147 const cart = { 148 items: basketItems?.map((item) => { 149 const itemId = item?.id?.includes('~')
150 ? item?.id?.split('~')?.[1] 151 : item?.id 152 return { 153 product_group: { 154 id: parseInt(itemId), 155 selected_variant: { 156 price: { 157 currency: Tracker.store.get('currency'), 158 value: parseFloat(item.product.price?.price?.amount) 159 }, 160 sku: parseInt(item.product.product?.sku) 161 }, 162 total_variants: item.product.product?.variants?.length || null 163 }, 164 quantity: parseInt(item.quantity) 165 } 166 }), 167 total_size: basket?.totalQuantity || 0, 168 total_price: { 169 currency: Tracker.store.get('currency'), 170 value: parseFloat(basket?.chargePrice?.amount) 171 } 172 } 173 174 if (cart.items?.length) { 175 legacyData.cart = cart 176 } 177 178 const payload = { 179 operationName: operationName, 180 metadata: {}, 181 path: url, 182 version: 'altitude', 183 rayId: rayId, 184 currency: 185 Tracker.store.get('currency') || Tracker.store.get('curr')?.value, 186 shippingDestination: Tracker.store.get('ship')?.value, 187 locale: Tracker.store.get('locale')?.value 188 } 189 190 if (Object?.keys(legacyData).length) payload.legacy = legacyData 191 return payload 192 }, 193 pushToTrackAPI: async (payload) => { 194 const trackUrl = Tracker.trackApiConfig.trackAPIUrl 195 if (!Tracker.config.dev && !trackUrl) return 196 const dataBlob = new Blob([JSON.stringify(payload)], { 197 type: 'application/json' 198 }) 199 navigator.sendBeacon(trackUrl, dataBlob) 200 window.debugger && 201 window.debugger.push({ 202 message: payload?.legacy?.event?.type, 203 snippet: JSON.stringify(payload), 204 type: 'event' 205 }) 206 }, 207 sendPubSubEvent: async ( 208 operationName, 209 eventData, 210 legacyRayId = null, 211 recommendationContext = null, 212 recommendationSlotIndex = null, 213 giftBoxedSkus = null 214 ) => { 215 const experiments = [] 216 if (window.__EXPERIMENTS__) { 217 const chunks = window.__EXPERIMENTS__?.split(',') 218 chunks?.forEach((pair) => { 219 const [name, value] = pair?.split(':') 220 if (name && value) { 221 experiments.push({ name, value }) 222 } 223 }) 224 } 225 226 const requestUrl = new URL(window.location) 227 if (recommendationContext) { 228 requestUrl.searchParams.set('rctxt', recommendationContext) 229 } 230 231 if (recommendationSlotIndex) { 232 requestUrl.searchParams.set( 233 'sponsoredAdsPLPIndex', 234 recommendationSlotIndex 235 ) 236 } 237 238 if (giftBoxedSkus) { 239 requestUrl.searchParams.set('giftBoxedSkus', giftBoxedSkus) 240 } 241 242 const payload = Tracker.marshalPubSub( 243 operationName, 244 requestUrl.pathname + requestUrl.search, 245 eventData, 246 legacyRayId, 247 experiments 248 ) 249 250 return Tracker.pushToTrackAPI(payload) 251 }, 252 log: (message, type = 'warn') => { 253 type === 'warn' && console.warn('[Tracker]: %s', message) 254 type === 'log' && console.debug('[Tracker]: %s', message) 255 }, 256 translateTarget: (e) => { 257 if (e instanceof Event) { 258 return e.currentTarget.getAttribute(Tracker.config.selectors?.store) 259 } else if (e instanceof HTMLElement) { 260 return e.getAttribute(Tracker.config.selectors?.store) 261 } else if (e?.store) { 262 return e?.store 263 } else { 264 return e 265 } 266 }, 267 handlers: { 268 performanceData: (CWVObject, perfDataObject) => { 269 const experiments = [] 270 if (window.__EXPERIMENTS__) { 271 const chunks = window.__EXPERIMENTS__?.split(',') 272 chunks?.forEach((pair) => { 273 const [name, value] = pair?.split(':') 274 if (name && value) { 275 experiments.push({ name, value }) 276 } 277 }) 278 } 279 const perfData = { 280 request: { 281 server_timestamp: null, 282 client_timestamp: new Date(Date.now()).toISOString(), 283 url: window.location.href 284 }, 285 experiments: experiments, 286 errors: [{ type: null, label: null }], 287 timing: { 288 backend_load_time: 289 perfDataObject?.navigationTiming?.backendLoadTime, 290 cache_time: perfDataObject?.navigationTiming?.cacheTime, 291 connection_time: perfDataObject?.navigationTiming?.connectionTime, 292 dns_time: perfDataObject?.navigationTiming?.dnsTime, 293 dom_interactive_time: 294 perfDataObject?.navigationTiming?.domInteractiveTime, 295 dom_parsing_time: perfDataObject?.navigationTiming?.domParsingTime, 296 dom_ready_time: perfDataObject?.navigationTiming?.domReadyTime, 297 first_paint_time: perfDataObject?.navigationTiming?.firstPaintTime, 298 frontend_load_time: 299 perfDataObject?.navigationTiming?.frontendLoadTime, 300 load_event_time: perfDataObject?.navigationTiming?.loadEventTime, 301 navigation_time: perfDataObject?.navigationTiming?.navigationTime, 302 redirect_time: perfDataObject?.navigationTiming?.redirectTime, 303 first_contentful_paint_time: CWVObject?.fcp || null, 304 first_input_delay: CWVObject?.fid || null, 305 largest_contentful_paint_time: CWVObject?.lcp || null, 306 first_byte_time: CWVObject?.ttfb || null, 307 interaction_to_next_paint_time: CWVObject?.inp || null 308 }, 309 score: { cumulative_layout_shift: CWVObject?.cls || null }, 310 nonce: Tracker.nonce, 311 device: perfDataObject?.device, 312 page: perfDataObject?.page, 313 network: perfDataObject?.network, 314 abtasty: [ 315 { 316 name: null, 317 time_to_first_byte: null, 318 transfer: null, 319 total: null, 320 encoded_file_size: null 321 } 322 ] 323 } 324 Tracker.pushToTrackAPI({ 325 operationName: 'perfData', 326 metaData: { destination: 'performanceData' }, 327 eventData: perfData 328 }) 329 }, 330 // Page Load 331 pageLoad: (e) => { 332 Tracker.push(window?.Tracker?.store?.pageInfo) 333 }, 334 335 // Cookie Consent 336 cookieModalOpen: () => { 337 const elyEvent = { 338 event: 'elysiumEvent', 339 event_name: 'cookie_modal_shown', 340 action: 'shown', 341 eventData: {
342 eventCategory: 'Cookie Modal', 343 eventAction: 'Shown', 344 eventLabel: 'Accept Cookie Button', 345 eventPage: window?.location?.pathname 346 } 347 } 348 Tracker.push(elyEvent) 349 }, 350 351 cookieModalAccepted: () => { 352 const elyEvent = { 353 event: 'elysiumEvent', 354 event_name: 'cookie_modal_clicked', 355 action: 'accepted all', 356 eventData: { 357 eventCategory: 'Cookie Modal', 358 eventAction: 'Accept All', 359 eventLabel: 'Accept Cookie Button', 360 eventPage: window?.location?.pathname 361 } 362 } 363 Tracker.push(elyEvent) 364 }, 365 cookieModalRejected: () => { 366 const elyEvent = { 367 event: 'elysiumEvent', 368 event_name: 'cookie_modal_clicked', 369 action: 'reject all', 370 eventData: { 371 eventCategory: 'Cookie Modal', 372 eventAction: 'Reject All', 373 eventLabel: 'Reject Cookie Button', 374 eventPage: window?.location?.pathname 375 } 376 } 377 Tracker.push(elyEvent) 378 }, 379 cookieSet: (el) => { 380 const elyEvent = { 381 event: 'elysiumEvent', 382 event_name: 'cookie_modal_clicked', 383 action: `set preference to be ${el}`, 384 eventData: { 385 eventCategory: 'Cookie Modal', 386 eventAction: 'Set preference', 387 eventLabel: 'Set Preference Button', 388 eventValue: el, 389 eventPage: window?.location?.pathname 390 } 391 } 392 Tracker.push(elyEvent) 393 }, 394 395 // Site Settings modal 396 siteSettingsSet: (trackerParam) => { 397 const elyEvent = { 398 event: 'settings_changed', 399 shipping_destination: trackerParam.shipping_destination, 400 region_setting: trackerParam.region_setting, 401 currency_setting: trackerParam.currency_setting 402 } 403 Tracker.push(elyEvent) 404 }, 405 // ReEngagement Modal 406 reEngOpen: () => { 407 const elyEvent = { 408 event: 'elysiumEvent', 409 event_name: 'newsletter_signup_shown', 410 eventData: { 411 eventCategory: 'reEngagement Tooltip Modal', 412 eventAction: 'Shown', 413 eventLabel: 'reEngagement Modal Message', 414 eventPage: window?.location?.pathname 415 } 416 } 417 Tracker.push(elyEvent) 418 }, 419 420 reEngClicked: (el) => { 421 const elyEvent = { 422 event: 'elysiumEvent', 423 event_name: 'newsletter_signup_clicked', 424 eventData: { 425 eventCategory: 'reEngagement Tooltip Modal', 426 eventAction: 'Clicked', 427 eventLabel: 'Continue Modal Button', 428 eventPage: window?.location?.pathname 429 } 430 } 431 Tracker.push(elyEvent) 432 }, 433 434 // Email Signup 435 newsletterSignup: (params) => { 436 const status = params?.status 437 const location = params?.location || window?.location?.pathname 438 439 const elyEvent = { 440 event: 'customEvent', 441 event_name: 'newsletter_signup_complete', 442 eventData: { 443 eventCategory: 'newsletter', 444 eventAction: status, 445 eventPage: location 446 } 447 } 448 449 Tracker.push(elyEvent) 450 }, 451 452 // Widget Track 453 widgetTrack: (e) => { 454 const widgetDescription = e.parentElement.dataset.description 455 const widgetId = e.parentElement.dataset.id 456 457 const ecommerceEvent = { 458 event: 'ecom_event', 459 event_name: 'view_promotion', 460 ecommerce: { 461 creative_name: Tracker.store.get('widgets')[widgetId] ?? '', 462 creative_slot: e.parentElement.dataset.creativeSlot ?? '', 463 promotion_id: widgetId, 464 promotion_name: widgetDescription, 465 promotion_page: window?.location?.pathname 466 } 467 } 468 Tracker.push(ecommerceEvent, { commerce: true }) 469 }, 470 471 widgetClick: (el) => { 472 if (!el) return 473 474 const sponsoredElement = el.target.closest('[id^="sponsored-product-"]') 475 476 if (sponsoredElement) { 477 // can extend for more ads using /^sponsored-product-(list|pdp|banner)-(\d+)$/ 478 const SPONSORED_PRODUCT_REGEX = /^sponsored-product-(list)-(\d+)$/ 479 const sponsoredProductMatch = sponsoredElement.id.match( 480 SPONSORED_PRODUCT_REGEX 481 ) 482 483 if (sponsoredProductMatch) { 484 const [, type, slotNumber] = sponsoredProductMatch 485 486 if (!slotNumber || !type) { 487 return 488 } 489 490 const sponsoredAdsMap = { 491 list: 'sponsoredProductPLP' 492 } 493 494 const getSponsoredAdsExperimentByType = (type) => { 495 if (!window.__EXPERIMENTS__) return null 496 497 const typeToExperimentMap = { 498 list: 'sponsored_ads_slots_plp' 499 } 500 501 const experimentName = typeToExperimentMap[type] 502 if (!experimentName) return null 503 504 const chunks = window.__EXPERIMENTS__.split(',') 505 for (const pair of chunks) { 506 const [name, value] = pair.split(':') 507 if (name === experimentName && value) { 508 return { name, value } 509 } 510 } 511 return null 512 } 513 514 let promotionName = '' 515 let promotionId = '' 516 517 const experiment = getSponsoredAdsExperimentByType(type) 518 if (experiment) { 519 promotionName = experiment.name 520 promotionId = experiment.value 521 } 522 523 const ecommerceEvent = { 524 event: 'ecom_event', 525 event_name: 'select_promotion', 526 ecommerce: { 527 creative_name: sponsoredAdsMap[type], 528 creative_slot: slotNumber, 529 promotion_id: promotionId, 530 promotion_name: promotionName, 531 promotion_page: window?.location?.pathname 532 } 533 } 534 535 Tracker.push(ecommerceEvent, { commerce: true }) 536 return 537 } 538 } 539 540 let widget = Tracker.translateTarget(el) 541 const widgetContainer = el?.target?.closest('.widgets') 542 const widgetDescription = widgetContainer?.dataset?.description 543 const widgetId = widgetContainer?.dataset?.id 544 545 const elyEvent = { 546 event: 'elysiumEvent', 547 event_name: 'widget_clicked', 548 component: widget, 549 widget_id: widgetId, 550 eventData: { 551 eventCategory: 'Widget Track', 552 eventAction: 'clicked', 553 eventLabel: widget, 554 eventLabelValue: widgetId, 555 eventPage: window?.location?.pathname 556 } 557 } 558 559 const ecommerceEvent = { 560 event: 'ecom_event', 561 event_name: 'select_promotion', 562 ecommerce: { 563 creative_name: Tracker.store.get('widgets')[widgetId] ?? '', 564 creative_slot: widgetContainer?.dataset?.creativeSlot ?? '', 565 promotion_id: widgetId, 566 promotion_name: widgetDescription, 567 promotion_page: window?.location?.pathname 568 } 569 } 570 571 if (widget !== 'ProductListWidget') { 572 Tracker.push(elyEvent) 573 Tracker.push(ecommerceEvent, { commerce: true }) 574 } 575 }, 576 577 // Navigation 578 navigationHeader: (el) => { 579 const elyEvent = { 580 event: 'elysiumEvent', 581 event_name: 'navigation_header', 582 action: `Clicked ${window.tenantConfig?.application?.siteName}`, 583 eventData: { 584 eventCategory: 'Navigation Header', 585 eventAction: `Clicked ${window.tenantConfig?.application?.siteName}`, 586 eventLabel: window.tenantConfig?.application?.livedomain, 587 eventPage: window?.location?.pathname 588 } 589 } 590 Tracker.push(elyEvent) 591 }, 592 593 navigationMenu: (el) => { 594 const mainCategory = el.target.innerText 595 596 const elyEvent = { 597 event: 'elysiumEvent', 598 event_name: 'navigation_main_category', 599 action: `Clicked ${mainCategory}`, 600 eventData: { 601 eventCategory: 'Navigation Header', 602 eventAction: `Clicked ${mainCategory}` 603 } 604 } 605 Tracker.push(elyEvent) 606 }, 607 608 navigationSubnav: (el) => { 609 const subCategory = el.target.innerText 610 611 const elyEvent = { 612 event: 'elysiumEvent', 613 event_name: 'navigation_sub_category', 614 action: `Clicked ${subCategory}`, 615 eventData: { 616 eventCategory: 'Navigation Header', 617 eventAction: `Clicked ${subCategory}` 618 } 619 } 620 Tracker.push(elyEvent) 621 }, 622 623 navigationButton: (el) => { 624 const button = Tracker.translateTarget(el) 625 626 const elyEvent = { 627 event: 'elysiumEvent', 628 event_name: 'navigation_header', 629 action: `Clicked ${button}`, 630 eventData: { 631 eventCategory: 'Navigation Header', 632 eventAction: `Clicked ${button}` 633 } 634 } 635 Tracker.push(elyEvent) 636 }, 637 638 clickUSP: (el) => { 639 let usp = Tracker.translateTarget(el) 640 641 const elyEvent = { 642 event: 'elysiumEvent', 643 event_name: 'responsive_usp_bar', 644 action: `click ${usp}`, 645 click_url: '', 646 component: 'Responsive USP bar', 647 eventData: { 648 eventCategory: 'Widget Track', 649 eventAction: usp,
650 eventLabel: 'Responsive USP bar', 651 eventPage: window?.location?.pathname 652 } 653 } 654 Tracker.push(elyEvent) 655 }, 656 657 // Search 658 search: () => { 659 const searchInfo = window.Tracker.store.get('searchInfo') 660 const pageData = Tracker.store.get('productList') 661 const currency = Tracker.store.get('currency') 662 const rayId = searchInfo?.rayId 663 664 const elyEvent = { 665 event: 'elysiumEvent', 666 event_name: 'search', 667 search_term: searchInfo?.input, 668 search_results: searchInfo?.resultsNumber, 669 eventData: { 670 eventCategory: 'Navigation Header', 671 eventAction: `Clicked ${searchInfo?.input ?? ''}`, 672 eventLabel: window?.location?.pathname + window?.location?.search, 673 eventPage: window?.location?.pathname 674 } 675 } 676 Tracker.push(elyEvent) 677 678 Tracker.sendPubSubEvent( 679 'Search', 680 { 681 event: { type: 'search' }, 682 page: { 683 search: { 684 query: searchInfo?.input || '', 685 total_results: searchInfo?.resultsNumber 686 }, 687 items: Object.values(pageData?.items ?? {})?.map((product) => { 688 return { 689 product_group: { 690 selected_variant: { 691 price: { 692 currency: currency, 693 value: parseFloat(product?.price) 694 }, 695 sku: parseInt(product?.item_id) 696 }, 697 total_variants: product?.total_variants 698 } 699 } 700 }) 701 } 702 }, 703 rayId 704 ) 705 }, 706 suggestedSearchQueries: (el) => { 707 let query = Tracker.translateTarget(el) 708 709 const elyEvent = { 710 event: 'elysiumEvent', 711 event_name: 'search', 712 actions: 'search suggestions', 713 search_term: query, 714 eventData: { 715 eventCategory: 'Navigation Header', 716 eventAction: `Clicked ${query}`, 717 eventLabel: `/search/?q=${query}`, 718 eventPage: window?.location?.pathname 719 } 720 } 721 Tracker.push(elyEvent) 722 }, 723 724 suggestedSearchProduct: (el) => { 725 const sku = Tracker.translateTarget(el) 726 const product = Tracker.store.get('suggestedProducts')[sku] 727 728 const elyEvent = { 729 event: 'elysiumEvent', 730 event_name: 'search', 731 actions: 'product details', 732 input: product, 733 eventData: { 734 eventCategory: 'Navigation Header', 735 eventAction: `Clicked ${product?.product_id}:${product?.product_name}`, 736 eventLabel: product?.url, 737 eventPage: window?.location?.pathname 738 } 739 } 740 Tracker.push(elyEvent) 741 }, 742 743 // Basket 744 goToBasket: (el) => { 745 const key = Tracker.translateTarget(el) 746 747 const quantity = Tracker.store.get(key) 748 749 const elyEvent = { 750 event: 'Link', 751 752 eventData: { 753 eventCategory: 'Link', 754 eventAction: 'Go To Basket', 755 eventLabel: quantity, 756 eventPage: window?.location?.pathname 757 } 758 } 759 Tracker.push(elyEvent) 760 }, 761 762 viewBasket: () => { 763 const elyEvent = { 764 event: 'elysiumEvent', 765 event: 'view_cart', 766 eventData: { 767 eventCategory: 'Navigation Header', 768 eventAction: 'Clicked View Basket', 769 eventPage: window?.location?.pathname 770 } 771 } 772 Tracker.push(elyEvent) 773 }, 774 updateCart: (e) => { 775 const store = Tracker.translateTarget(e) 776 const item = Tracker.store.get(store) 777 Tracker.sendPubSubEvent('UpdateCart', { 778 event: { 779 type: 'cart_interaction_event', 780 subtype: 'quantity_change', 781 items: [ 782 { 783 product_group: { 784 id: item?.item_master, 785 selected_variant: { 786 price: { 787 currency: Tracker.store.get('currency'), 788 value: parseFloat(item.price) * parseInt(item.quantity) 789 }, 790 sku: parseInt(item.item_id) 791 } 792 }, 793 quantity: parseInt(item.quantity) 794 } 795 ] 796 } 797 }) 798 }, 799 800 chatbotFeedback: (trackerParam, messageId) => { 801 Tracker.sendPubSubEvent( 802 'ChatbotConversationFeedback', 803 { 804 event: { type: 'conversation', subtype: `${trackerParam}` }, 805 ...(messageId && { origin: { widget_id: `${messageId}` } }) 806 }, 807 window.__xAltitudeHorizonRay__ 808 ) 809 }, 810 811 //Beauty assistant 812 askQuestion: ({ prompt }) => { 813 const { value } = Tracker.store.get('rayId') 814 815 const elyEvent = { 816 event: 'elysiumEvent', 817 event_name: 'ask_beauty_assistant_question', 818 eventData: { 819 eventLabel: 'Ask Beauty Assistant Question', 820 eventCategory: 'Beauty Assistant', 821 eventAction: 'Ask Question', 822 eventLabelValue: prompt, 823 path: window?.location?.pathname 824 } 825 } 826 827 Tracker.push(elyEvent) 828 829 Tracker.sendPubSubEvent( 830 'AskBeautyAssistantQuestion', 831 { 832 event: { type: 'ask_beauty_assistant_question' }, 833 page: { search: { query: `${prompt}` } } 834 }, 835 value 836 ) 837 }, 838 getBeautyAssistantRecommendations: ({ recommendations }) => { 839 const { value } = Tracker.store.get('rayId') 840 841 const items = recommendations.reduce( 842 (itemsAccumulator, currentRecommendedProduct) => { 843 const variant = 844 currentRecommendedProduct?.defaultVariant || 845 currentRecommendedProduct?.cheapestVariant 846 847 if (!variant) { 848 return itemsAccumulator 849 } 850 851 return [ 852 ...itemsAccumulator, 853 { 854 product_group: { 855 id: parseInt(variant?.sku), 856 selected_variant: { 857 price: { 858 currency: Tracker.store.get('currency'), 859 value: parseFloat(variant?.price?.price?.amount) 860 }, 861 sku: parseInt(variant?.sku) 862 } 863 } 864 } 865 ] 866 }, 867 [] 868 ) 869 870 const elyEvent = { 871 event: 'elysiumEvent', 872 event_name: 'get_beauty_assistant_recommendations', 873 eventData: { 874 eventLabel: 'Get Beauty Assistant Recommendations', 875 eventCategory: 'Beauty Assistant', 876 eventAction: 'Get Recommendations', 877 eventLabelValue: '', 878 path: window?.location?.pathname 879 } 880 } 881 882 Tracker.push(elyEvent) 883 884 Tracker.sendPubSubEvent( 885 'GetBeautyAssistantRecommendations', 886 { 887 event: { type: 'get_beauty_assistant_recommendations' }, 888 page: { items } 889 }, 890 value 891 ) 892 }, 893 894 addToCart: ( 895 e, 896 recommendationContext = null, 897 recommendationSlotIndex = null, 898 giftBoxedSkus = null 899 ) => { 900 const from_suggestions = !!document.getElementById('style-suggestions') 901 let data = 902 Tracker.store.get('buylistProducts')?.[e] ?? 903 Tracker.store.get('products')?.[e] ?? 904 Tracker.store.get('basket')?.[e] 905 906 const eventType = !from_suggestions 907 ? 'cart_interaction_event' 908 : 'outfit_suggestions_cart_interaction_event' 909 910 const elyEvent = { 911 event: 'elysiumEvent', 912 eventData: { 913 eventCategory: 'Product | AddToBasket', 914 eventAction: 'success', 915 eventLabel: data?.item_id, 916 eventLabelValue: data?.item_name 917 }, 918 eventPage: window?.location?.pathname 919 } 920 const basketItems = Tracker.getAllBasketItems(Tracker.store.get('basket')) 921 const ecommerceEvent = { 922 event: 'ecom_event', 923 event_name: 'add_to_cart', 924 ecommerce: { 925 currencyCode: data?.currency ?? '', 926 value: data?.value, 927 basketItems: basketItems.map((item) => ({ 928 sku: item.product.sku, 929 quantity: item.quantity, 930 vipPrice: item.product.vipPrice, 931 price: item.product.price, 932 isFreeGift: item.freeGift 933 })), 934 items: [ 935 { 936 item_id: data?.item_id ?? '', 937 item_name: data?.item_name ?? '', 938 item_brand: data?.item_brand ?? '', 939 price: data?.value ?? 'unknown', 940 index: data?.index, 941 discount: data?.discount, 942 affiliation: data?.affiliation, 943 coupon: data?.coupon, 944 item_category: data?.item_category, 945 item_list_name: data?.item_list_name, 946 item_variant: data?.variant, 947 quantity: data?.quantity ?? 0 948 } 949 ] 950 } 951 } 952 Tracker.push(ecommerceEvent, { commerce: true }) 953 Tracker.push(elyEvent) 954 const items = [data] 955 Tracker.sendPubSubEvent( 956 'AddToCart', 957 { 958 event: { 959 type: eventType, 960 subtype: 'initial_add', 961 items: items.map((item) => ({ 962 product_group: { 963 id: item?.item_master, 964 selected_variant: { 965 price: { 966 currency: Tracker.store.get('currency'), 967 value: parseFloat(item?.price) * parseInt(item?.quantity) 968 }, 969 sku: parseInt(item?.item_id) 970 } 971 }, 972 quantity: parseInt(item?.quantity) 973 })) 974 } 975 }, 976 null, 977 recommendationContext, 978 recommendationSlotIndex, 979 giftBoxedSkus 980 ) 981 }, 982 983 addMultipleToCart: ( 984 skus, 985 recommendationContext = null, 986 recommendationSlotIndex = null 987 ) => { 988 if (!Array.isArray(skus) || skus.length === 0) { 989 console.warn('addMultipleToCart requires a non-empty array of SKUs') 990 return 991 } 992 993 const from_suggestions = !!document.getElementById('style-suggestions') 994 const eventType = !from_suggestions 995 ? 'cart_interaction_event' 996 : 'outfit_suggestions_cart_interaction_event' 997 998 const items = skus 999 .map( 1000 (sku) => 1001 Tracker.store.get('buylistProducts')?.[sku] ?? 1002 Tracker.store.get('products')?.[sku] ?? 1003 Tracker.store.get('basket')?.[sku] 1004 ) 1005 .filter(Boolean) 1006 1007 if (items.length === 0) { 1008 console.warn('No valid items found for SKUs:', skus) 1009 return 1010 } 1011 1012 const totalValue = items.reduce( 1013 (sum, item) => sum + (parseFloat(item.value) || 0), 1014 0 1015 ) 1016 1017 const firstItem = items[0] 1018 const elyEvent = { 1019 event: 'elysiumEvent', 1020 eventData: { 1021 eventCategory: 'Product | AddToBasket', 1022 eventAction: 'success', 1023 eventLabel: firstItem?.item_id, 1024 eventLabelValue: firstItem?.item_name 1025 }, 1026 eventPage: window?.location?.pathname 1027 } 1028 const basketItems = Tracker.getAllBasketItems(Tracker.store.get('basket')) 1029 const ecommerceEvent = { 1030 event: 'ecom_event', 1031 event_name: 'add_to_cart', 1032 ecommerce: { 1033 currencyCode: firstItem?.currency ?? '', 1034 value: totalValue, 1035 basketItems: basketItems?.map((item) => ({ 1036 sku: item.product.sku, 1037 quantity: item.quantity, 1038 vipPrice: item.product.vipPrice, 1039 price: item.product.price, 1040 isFreeGift: item.freeGift 1041 })), 1042 items: items.map((data) => ({ 1043 item_id: data?.item_id ?? '', 1044 item_name: data?.item_name ?? '', 1045 item_brand: data?.item_brand ?? '', 1046 price: data?.value ?? 'unknown', 1047 index: data?.index, 1048 discount: data?.discount, 1049 affiliation: data?.affiliation, 1050 coupon: data?.coupon, 1051 item_category: data?.item_category, 1052 item_list_name: data?.item_list_name, 1053 item_variant: data?.variant, 1054 quantity: data?.quantity ?? 0 1055 })) 1056 } 1057 } 1058 1059 Tracker.push(ecommerceEvent, { commerce: true }) 1060 Tracker.push(elyEvent) 1061 1062 Tracker.sendPubSubEvent( 1063 'AddToCart', 1064 { 1065 event: { 1066 type: eventType, 1067 subtype: 'initial_add', 1068 items: items.map((item) => ({ 1069 product_group: { 1070 id: item?.item_master, 1071 selected_variant: { 1072 price: { 1073 currency: Tracker.store.get('currency'), 1074 value: parseFloat(item?.price) * parseInt(item?.quantity) 1075 }, 1076 sku: parseInt(item?.item_id) 1077 } 1078 }, 1079 quantity: parseInt(item?.quantity) 1080 })) 1081 } 1082 }, 1083 null, 1084 recommendationContext, 1085 recommendationSlotIndex 1086 ) 1087 }, 1088 1089 removeFromCart: ( 1090 e, 1091 giftBoxedSkus = null 1092 ) => { 1093 let data = Tracker.store.get('basket')[e] 1094 const basketItems = Tracker.getAllBasketItems(Tracker.store.get('basket')) 1095 const elyEvent = { 1096 event: 'elysiumEvent', 1097 eventData: { 1098 eventCategory: 'Product | Remove From Basket', 1099 eventAction: 'success', 1100 eventLabel: data?.item_id, 1101 eventLabelValue: data?.item_name 1102 }, 1103 eventPage: window?.location?.pathname 1104 } 1105 const ecommerceEvent = { 1106 event: 'ecom_event', 1107 event_name: 'remove_from_cart', 1108 ecommerce: { 1109 currencyCode: data?.currency ?? '', 1110 value: data?.value, 1111 basketItems: basketItems?.map((item) => ({ 1112 sku: item.product.sku, 1113 quantity: item.quantity, 1114 vipPrice: item.product.vipPrice, 1115 price: item.product.price, 1116 isFreeGift: item.freeGift 1117 })), 1118 items: [ 1119 { 1120 item_id: data?.item_id ?? '', 1121 item_name: data?.item_name ?? '', 1122 item_brand: data?.item_brand ?? '', 1123 price: data?.value ?? 'unknown', 1124 index: data?.index, 1125 discount: data?.discount, 1126 affiliation: data?.affiliation, 1127 coupon: data?.coupon, 1128 item_category: data?.item_category, 1129 item_list_name: data?.item_list_name, 1130 item_variant: data?.variant, 1131 quantity: data?.quantity ?? 0 1132 } 1133 ] 1134 } 1135 } 1136 Tracker.push(ecommerceEvent, { commerce: true }) 1137 Tracker.push(elyEvent) 1138 const items = [data] 1139 Tracker.sendPubSubEvent('RemoveFromCart', { 1140 event: { 1141 type: 'cart_interaction_event', 1142 subtype: 'trash', 1143 items: items.map((item) => ({ 1144 product_group: { 1145 selected_variant: { 1146 price: { 1147 currency: Tracker.store.get('currency'), 1148 value: parseFloat(item?.price) * parseInt(item?.quantity) 1149 }, 1150 sku: parseInt(item?.item_id) 1151 } 1152 }, 1153 quantity: parseInt(item?.quantity) 1154 })) 1155 } 1156 }, 1157 null, 1158 null, 1159 null, 1160 giftBoxedSkus 1161 ) 1162 }, 1163 updateCart: (e) => { 1164 const store = Tracker.translateTarget(e) 1165
1165 const item = Tracker.store.get(store) 1166 Tracker.sendPubSubEvent('UpdateCart', { 1167 event: { 1168 type: 'cart_interaction_event', 1169 subtype: 'quantity_change', 1170 items: [ 1171 { 1172 product_group: { 1173 selected_variant: { 1174 price: { 1175 currency: Tracker.store.get('currency'), 1176 value: parseFloat(item.price) * parseInt(item.quantity) 1177 }, 1178 sku: parseInt(item.item_id) 1179 } 1180 }, 1181 quantity: parseInt(item.quantity) 1182 } 1183 ] 1184 } 1185 }) 1186 }, 1187 goToCheckout: () => { 1188 const event = { 1189 event: 'elysiumEvent', 1190 event_name: 'go_to_checkout', 1191 eventData: { eventAction: 'Go To Checkout' } 1192 } 1193 1194 Tracker.push(event) 1195 }, 1196 goToBasket: () => { 1197 const event = { 1198 event: 'elysiumEvent', 1199 event_name: 'go_to_basket', 1200 quantity: Tracker.store.get('basketQuantity'), 1201 eventData: { eventAction: 'Go To Basket' } 1202 } 1203 Tracker.push(event) 1204 }, 1205 1206 basketProductClick: (e) => { 1207 let clickedItem = Tracker.translateTarget(e) 1208 const item = Tracker.store.get('basket')[clickedItem] 1209 1210 const elyEvent = { 1211 event: 'elysiumEvent', 1212 eventData: { 1213 eventCategory: 'Product | AddToBasket', 1214 eventAction: 'success', 1215 eventLabel: clickedItem, 1216 eventLabelValue: item?.item_name 1217 }, 1218 eventPage: window?.location?.pathname 1219 } 1220 1221 Tracker.push(elyEvent) 1222 }, 1223 1224 viewFreeGift: (e) => { 1225 const id = Tracker.translateTarget(e) 1226 const elyEvent = { 1227 event: 'elysiumEvent', 1228 eventData: { 1229 eventCategory: 'freeProductSelection', 1230 eventAction: 'ViewedFreeGift', 1231 eventLabel: id 1232 }, 1233 eventPage: window?.location?.pathname 1234 } 1235 1236 Tracker.push(elyEvent) 1237 }, 1238 1239 selectFreeGift: (e) => { 1240 const elyEvent = { 1241 event: 'elysiumEvent', 1242 event_name: 'add_to_cart', 1243 currencyCode: window.siteObj.currency ?? '', 1244 ecommerce: { product_name: e }, 1245 eventData: { 1246 eventCategory: 'freeProductSelection', 1247 eventAction: 'Add Item', 1248 eventLabel: e 1249 }, 1250 eventPage: window?.location?.pathname 1251 } 1252 1253 Tracker.push(elyEvent) 1254 }, 1255 1256 removeFreeGift: (e) => { 1257 const elyEvent = { 1258 event: 'elysiumEvent', 1259 event_name: 'remove_from_cart', 1260 currencyCode: window.siteObj.currency ?? '', 1261 ecommerce: { product_name: e }, 1262 eventData: { 1263 eventCategory: 'freeProductSelection', 1264 eventAction: 'Removing Item', 1265 eventLabel: e 1266 }, 1267 eventPage: window?.location?.pathname 1268 } 1269 Tracker.push(elyEvent) 1270 }, 1271 1272 applyCouponSuccess: (e) => { 1273 let coupon = Tracker.translateTarget(e) 1274 1275 const elyEvent = { 1276 event: 'elysiumEvent', 1277 event_name: 'apply_coupon_success', 1278 coupon_code: coupon, 1279 eventData: { 1280 eventCategory: 'Discount codes', 1281 eventAction: 'Valid', 1282 eventLabel: coupon, 1283 eventPage: window?.location?.pathname 1284 } 1285 } 1286 1287 Tracker.push(elyEvent) 1288 Tracker.handlers.applyDiscountCode({ message: e.message }) 1289 }, 1290 1291 applyCouponFailure: (e) => { 1292 const elyEvent = { 1293 event: 'elysiumEvent', 1294 event_name: 'apply_coupon_fail', 1295 coupon_code: e.promoCode, 1296 validation_errors: e.errorMessage, 1297 eventData: { 1298 eventCategory: 'Discount codes', 1299 eventAction: 'Inactive', 1300 eventLabel: e.promoCode, 1301 eventPage: window?.location?.pathname 1302 } 1303 } 1304 Tracker.push(elyEvent) 1305 Tracker.handlers.applyDiscountCode({ message: e.errorMessage }) 1306 }, 1307 applyDiscountCode: (e) => { 1308 Tracker.sendPubSubEvent('ApplyDiscountCodeToBasket', { 1309 event: { type: 'discount_code_event' } 1310 }) 1311 },
1312 // Wish list 1313 wishlistLoggedout: (el) => { 1314 const item = 1315 Tracker?.store?.get('productList')?.items?.[el] || 1316 Tracker?.store?.get('products')?.[el] || 1317 Tracker?.store?.get('basket')?.[el] 1318 const elyEvent = { 1319 event: 'elysiumEvent', 1320 event_name: 'wishlist_logged_out', 1321 product_id: el, 1322 product_name: item?.item_name, 1323 eventData: { 1324 eventCategory: 'Wishlist Engagement', 1325 eventAction: 'Clicked add to wishlist | Logged out', 1326 eventLabel: el, 1327 eventPage: window?.location?.pathname 1328 } 1329 } 1330 1331 Tracker.push(elyEvent) 1332 }, 1333 1334 // wishlistLogin: (el) => { 1335 // const sku = el?.target.dataset.trackPush 1336 // console.log(sku) 1337 // let item 1338 // if(Tracker.store.get('productList')){ 1339 // item = Tracker.store.productList.items[sku] 1340 // } else if (Tracker.store.get('products')){ 1341 // item = Tracker.store.products[sku] 1342 // } 1343 // const elyEvent = { 1344 // event: 'elysiumEvent', 1345 // event_name: 'wishlist_login', 1346 // product_id: sku, 1347 // product_name: item.item_name, 1348 // eventData: { 1349 // eventCategory: 'Wishlist Engagement', 1350 // eventAction: 'clicked login link', 1351 // eventLabel: sku, 1352 // eventPage: window?.location?.pathname 1353 // } 1354 // } 1355 // Tracker.push(elyEvent) 1356 // }, 1357 1358 // wishlistRegister: (el) => { 1359 // let item 1360 // if(Tracker.store.get('productList')){ 1361 // item = Tracker.store.productList.items[el] 1362 // } else if (Tracker.store.get('products')){ 1363 // item = Tracker.store.products[el] 1364 // } 1365 1366 // const elyEvent = { 1367 // event: 'elysiumEvent', 1368 // event_name: 'wishlist_login', 1369 // product_id: id, 1370 // product_name: item.item_name, 1371 // eventData: { 1372 // eventCategory: 'Wishlist Engagement', 1373 // eventAction: 'clicked register link', 1374 // eventLabel: id, 1375 // eventLabeValue: item?.item_name, 1376 // eventPage: window?.location?.pathname 1377 // } 1378 // } 1379 // Tracker.push(elyEvent) 1380 // }, 1381 1382 wishlistAdded: (el) => { 1383 const item = 1384 Tracker?.store?.get('productList')?.items?.[el] || 1385 Tracker?.store?.get('products')?.[el] || 1386 Tracker?.store?.get('basket')?.[el] 1387 1388 const elyEvent = { 1389 event: 'elysiumEvent', 1390 event_name: 'add_to_wishlist', 1391 product_id: item?.item_id, 1392 product_name: item?.item_name, 1393 eventData: { 1394 eventCategory: 'Wishlist Engagement', 1395 eventAction: 'added to wishlist', 1396 eventLabel: item?.item_id, 1397 eventPage: window?.location?.pathname 1398 } 1399 } 1400 1401 Tracker.push(elyEvent) 1402 1403 const gaEvent = { 1404 event: 'ecom_event', 1405 event_name: 'add_to_wishlist', 1406 ecommerce: { 1407 currency: Tracker.store.get('currency') ?? '', 1408 page_type: window?.location?.pathname, 1409 item_list_name: item?.item_list_name, 1410 items: [ 1411 { 1412 item_id: item?.item_id, 1413 item_name: item?.item_name, 1414 item_brand: item?.brand || item?.item_brand, 1415 price: item?.price, 1416 discount: item?.discount, 1417 affiliation: item?.affiliation, 1418 coupon: item?.coupon, 1419 item_category: item?.item_category, 1420 item_list_name: item?.item_list_name, 1421 item_variant: item?.variant, 1422 quantity: 1 1423 } 1424 ] 1425 } 1426 } 1427 Tracker.push(gaEvent) 1428 1429 Tracker.sendPubSubEvent('AddToWishlist', { 1430 event: { 1431 type: 'wishlist_interaction_event', 1432 subtype: 'initial_add', 1433 items: [{ product_group: { id: parseInt(el) }, quantity: 1 }] 1434 } 1435 }) 1436 }, 1437 1438 wishlistRemove: (el) => { 1439 const item = 1440 Tracker?.store?.get('productList')?.items?.[el] || 1441 Tracker?.store?.get('products')?.[el] || 1442 Tracker?.store?.get('basket')?.[el] 1443 1444 const elyEvent = { 1445 event: 'elysiumEvent', 1446 event_name: 'wishlist_removed', 1447 product_id: item?.item_id, 1448 product_name: item?.item_name, 1449 eventData: { 1450 eventCategory: 'Wishlist Engagement', 1451 eventAction: 'removed from wishlist', 1452 eventLabel: item?.item_id, 1453 eventPage: window?.location?.pathname 1454 } 1455 } 1456 1457 Tracker.push(elyEvent) 1458 1459 const gaEvent = { 1460 event: 'ecom_event', 1461 event_name: 'remove_from_wishlist', 1462 ecommerce: { 1463 currency: Tracker.store.get('currency') ?? '', 1464 page_type: window?.location?.pathname, 1465 item_list_name: item?.item_list_name, 1466 items: [ 1467 { 1468 item_id: item?.item_id, 1469 item_name: item?.item_name,
1470 item_brand: item?.brand || item?.item_brand, 1471 price: item?.price, 1472 discount: item?.discount, 1473 affiliation: item?.affiliation, 1474 coupon: item?.coupon, 1475 item_category: item?.item_category, 1476 item_list_name: item?.item_list_name, 1477 item_variant: item?.variant, 1478 quantity: 1 1479 } 1480 ] 1481 } 1482 } 1483 Tracker.push(gaEvent) 1484 1485 Tracker.sendPubSubEvent('RemoveFromWishlist', { 1486 event: { 1487 type: 'wishlist_interaction_event', 1488 subtype: 'trash', 1489 items: [{ product_group: { id: parseInt(el) }, quantity: 1 }] 1490 } 1491 }) 1492 }, 1493 1494 // PLP 1495 plp: () => { 1496 const pageData = Tracker.store.get('productList') 1497 1498 Tracker.sendPubSubEvent( 1499 'ProductList', 1500 { 1501 event: { type: 'product_list_visit' }, 1502 page: { 1503 items: Object.values(pageData?.items ?? {})?.map((product) => { 1504 return { 1505 product_group: { 1506 selected_variant: { 1507 price: { 1508 currency: 1509 pageData.currency || Tracker.store.get('currency'), 1510 value: parseFloat(product?.price) 1511 }, 1512 sku: parseInt(product?.item_id) 1513 }, 1514 total_variants: product?.total_variants 1515 } 1516 } 1517 }) 1518 } 1519 }, 1520 window.__xAltitudeHorizonRay__ 1521 ) 1522 }, 1523 1524 home: (e) => { 1525 const store = Tracker.translateTarget(e) 1526 const pageData = Tracker.store.get(store) 1527 Tracker.sendPubSubEvent( 1528 'Homepage', 1529 { event: { type: 'homepage' } }, 1530 pageData.rayId 1531 ) 1532 }, 1533 1534 viewItemList: () => { 1535 const list = window.Tracker.store.get('productList') 1536 1537 const gaEvent = { 1538 event: 'view_item_list', 1539 currencyCode: list?.currency, 1540 ecommerce: { 1541 item_list_id: list?.id ?? '', 1542 item_list_name: list?.title ?? '', 1543 items: list.items && Object.values(list.items) 1544 }, 1545 platformType: 'Altitude' 1546 } 1547 Tracker.push(gaEvent) 1548 }, 1549 1550 ReadMoreClicked: () => { 1551 const elyEvent = { 1552 event: 'elysiumEvent', 1553 event_name: 'read_more_click', 1554 eventData: { 1555 eventCategory: 'Read More Button', 1556 eventAction: `Clicked`, 1557 eventPage: window?.location?.pathname 1558 } 1559 } 1560 Tracker.push(elyEvent) 1561 }, 1562 1563 selectItem: (el) => { 1564 const item = Tracker.translateTarget(el) 1565 const product = Tracker.store.get('productList').items 1566 const elyEvent = { 1567 event: 'elysiumEvent', 1568 event_name: 'navigation_list', 1569 action: 'Click product image', 1570 product_id: product[item]?.item_id, 1571 product_name: product[item]?.item_name, 1572 eventData: { 1573 eventCategory: 'List Page Navigation', 1574 eventAction: ` ${product[item]?.url}| Click product image`, 1575 eventLabel: product[item]?.item_id, 1576 eventPage: window?.location?.pathname 1577 } 1578 } 1579 1580 const gaEvent = { 1581 event: 'select_item', 1582 ecommerce: { 1583 item_list_id: product[item]?.item_list ?? '', 1584 item_list_name: product[item]?.title ?? '', 1585 items: [ 1586 { 1587 item_id: product[item]?.item_id, 1588 item_list: product[item]?.item_list, 1589 item_brand: product[item]?.brand, 1590 price: product[item]?.price, 1591 value: product[item]?.value, 1592 discount: product[item]?.discount, 1593 coupon: product[item]?.coupon, 1594 affiliation: product[item]?.affiliation, 1595 index: product[item]?.index, 1596 item_list_id: product[item]?.item_id, 1597 item_list_name: product[item]?.item_list, 1598 item_variant: product[item]?.variant, 1599 quantity: 1 1600 } 1601 ] 1602 } 1603 } 1604 Tracker.push(elyEvent) 1605 Tracker.push(gaEvent) 1606 }, 1607 1608 showFilter: () => { 1609 const elyEvent = { 1610 event: 'elysiumEvent', 1611 event_name: 'filter', 1612 category: 'product category', 1613 action: 'opens', 1614 type: 'amino acids', 1615 eventData: { 1616 eventCategory: 'responsiveFacets', 1617 eventAction: 'Opens', 1618 eventPage: window?.location?.pathname 1619 } 1620 } 1621 Tracker.push(elyEvent) 1622 }, 1623 1624 closeFilter: () => { 1625 const elyEvent = { 1626 event: 'elysiumEvent', 1627 event_name: 'filter', 1628 category: 'product category', 1629 action: 'closes', 1630 type: 'amino acids', 1631 eventData: { 1632 eventCategory: 'responsiveFacets', 1633 eventAction: 'Closes', 1634 eventPage: window?.location?.pathname 1635 } 1636 } 1637 Tracker.push(elyEvent) 1638 }, 1639 1640 filterOpen: () => { 1641 const event = { 1642 event: 'elysiumEvent', 1643 event_name: 'filter_open', 1644 category: '', 1645 eventData: { 1646 eventCategory: 'responsiveFacets', 1647 eventAction: 'Opens', 1648 type: 'amino acids', 1649 eventPage: window?.location?.pathname 1650 } 1651 } 1652 1653 Tracker.push(event) 1654 }, 1655 1656 filter: (e) => { 1657 const elyEvent = { 1658 event: 'elysiumEvent', 1659 event_name: 'filter_applied', 1660 filter: e, 1661 eventData: { 1662 eventCategory: 'responsiveFacets', 1663 eventAction: 'add', 1664 eventLabel: e, 1665 eventPage: window?.location?.pathname 1666 } 1667 } 1668 Tracker.push(elyEvent) 1669 }, 1670 1671 filterRemoved: (el) => { 1672 const elyEvent = { 1673 event: 'elysiumEvent', 1674 event_name: 'filter_removed', 1675 category: el.eventCategory, 1676 eventData: { 1677 eventCategory: 'responsiveFacets', 1678 eventAction: 'Removes', 1679 eventLabel: el.eventCategory, 1680 eventPage: window?.location?.pathname 1681 } 1682 } 1683 Tracker.push(elyEvent) 1684 }, 1685 1686 filterClear: (e) => { 1687 const elyEvent = { 1688 event: 'elysiumEvent', 1689 event_name: 'filter_cleared', 1690 eventData: { 1691 eventCategory: 'responsiveFacets', 1692 eventAction: 'remove', 1693 eventLabel: 'all facets', 1694 eventPage: window?.location?.pathname 1695 } 1696 } 1697 Tracker.push(elyEvent) 1698 }, 1699 1700 sortByOpen: () => { 1701 const elyEvent = { 1702 event: 'elysiumEvent', 1703 event_name: 'sort_by_open', 1704 eventData: { 1705 eventCategory: 'Facet Engagement', 1706 eventAction: 'Opens Sort By', 1707 eventPage: window?.location?.pathname 1708 } 1709 } 1710 Tracker.push(elyEvent) 1711 }, 1712 1713 sortByClose: (el) => { 1714 const elyEvent = { 1715 event: 'elysiumEvent', 1716 event_name: 'sort_by_closed', 1717 eventData: { 1718 eventCategory: 'Facet Engagement', 1719 eventAction: 'Closes Sort By', 1720 eventPage: window?.location?.pathname 1721 } 1722 } 1723 Tracker.push(elyEvent) 1724 }, 1725 1726 sortByClick: (el) => { 1727 const sortType = Tracker.translateTarget(el) 1728 1729 const elyEvent = { 1730 event: 'elysiumEvent', 1731 event_name: 'sort_by_clicked', 1732 type: sortType, 1733 eventData: { 1734 eventCategory: 'Facet Engagement', 1735 eventAction: 'Selects Sort By', 1736 eventLabel: sortType, 1737 eventPage: window?.location?.pathname 1738 } 1739 } 1740 Tracker.push(elyEvent) 1741 }, 1742 1743 viewPromotion: (e) => { 1744 let promo = Tracker.translateTarget(e) 1745 1746 const elyEvent = { 1747 event: 'elysiumEvent', 1748 event_name: 'pap_banner_viewed', 1749 component: 'promo', 1750 ecommerce: { 1751 items: [ 1752 { 1753 promotion_id: '', 1754 promotion_name: promo, 1755 creative_name: '', 1756 creative_slot: '', 1757 location_id: '' 1758 } 1759 ] 1760 }, 1761 eventData: { 1762 eventCategory: 'Pap | papBanner', 1763 eventAction: 'Viewed',
1764 eventLabel: 'papBanner component', 1765 eventPage: window?.location?.pathname 1766 } 1767 } 1768 Tracker.push(elyEvent) 1769 }, 1770 1771 promoClick: (el) => { 1772 const promo = Tracker.translateTarget(el) 1773 const elyEvent = { 1774 event: 'elysiumEvent', 1775 event_name: 'pap_banner_description_clicked', 1776 component: 'promo', 1777 promotion_id: '', 1778 promotion_name: promo, 1779 creative_name: '', 1780 creative_slot: '', 1781 location_id: '', 1782 eventData: { 1783 eventCategory: 'Pap | papBanner', 1784 eventAction: 'Clicked', 1785 eventLabel: 'papBanner component', 1786 eventPage: window?.location?.pathname 1787 } 1788 } 1789 Tracker.push(elyEvent) 1790 }, 1791 1792 promoButtonClick: (e) => { 1793 const promo = Tracker.translateTarget(e) 1794 1795 const elyEvent = { 1796 event: 'elysiumEvent', 1797 eventData: { 1798 eventCategory: 'Pap | papDescriptionCTA', 1799 eventAction: 'Clicked', 1800 eventLabel: 'papDescription component', 1801 eventPage: window?.location?.pathname 1802 } 1803 } 1804 1805 Tracker.push(elyEvent) 1806 }, 1807 1808 // PDP/Quickbuy modal 1809 viewItem: (e) => { 1810 let itemSku = Tracker.translateTarget(e) 1811 let data = Tracker.store.get('products')?.[itemSku] 1812 1813 //checks if the product is not a variant (master sku product) 1814 //checks if the products deafult product is not pre selected (eg. size, colour) 1815 if (!data?.variant && data?.defaultVariantSku !== data?.item_id) { 1816 data = Tracker.store.get('products')[data?.defaultVariantSku] 1817 itemSku = data?.defaultVariantSku 1818 } 1819 1820 const elyEvent = { 1821 event: 'elysiumEvent', 1822 eventData: { 1823 eventCategory: 'Product | Viewed', 1824 eventAction: 'Viewed', 1825 eventLabel: itemSku, 1826 eventLabelValue: [Tracker.store.get(itemSku)], 1827 eventPage: window?.location?.pathname 1828 } 1829 } 1830 const gaEvent = { 1831 event: 'ecom_event', 1832 event_name: 'view_item', 1833 ecommerce: { 1834 currencyCode: Tracker.store.get('currency') ?? '', 1835 value: data?.value, 1836 items: [ 1837 { 1838 item_id: data?.item_id ?? '', 1839 item_name: data?.item_name ?? '', 1840 item_brand: data?.item_brand ?? '', 1841 price: data?.value ?? 'unknown', 1842 index: data?.index, 1843 discount: data?.discount, 1844 affiliation: data?.affiliation, 1845 coupon: data?.coupon, 1846 item_category: data?.category, 1847 item_list_name: data?.item_list_name, 1848 item_variant: data?.variant, 1849 quantity: data?.quantity ?? 0 1850 } 1851 ] 1852 } 1853 } 1854 Tracker.push(gaEvent) 1855 Tracker.push(elyEvent) 1856 }, 1857 1858 productDesView: () => { 1859 const elyEvent = { 1860 event: 'elysiumEvent', 1861 event_name: 'product_description_viewed', 1862 component: 'productDescriptionComponent', 1863 eventData: { 1864 eventCategory: 'Product | Description', 1865 eventAction: 'Viewed', 1866 eventLabel: 'productDescription component', 1867 eventPage: window?.location?.pathname 1868 } 1869 } 1870 Tracker.push(elyEvent) 1871 }, 1872 1873 productImageScrolled: (el) => { 1874 const imgInx = Tracker.translateTarget(el) 1875 const indexInfo = window.Tracker.store.get('imageIndex') 1876 1877 const elyEvent = { 1878 event: 'elysiumEvent', 1879 event_name: 'product_image_scroll', 1880 index: indexInfo?.index, 1881 eventData: { 1882 eventCategory: 'ProductImageCarousel', 1883 eventAction: 'scroll', 1884 eventLabel: `Scrolled to image ${indexInfo?.index} `, 1885 eventPage: window?.location?.pathname 1886 } 1887 } 1888 Tracker.push(elyEvent) 1889 }, 1890 1891 productThumbnailClicked: (el) => { 1892 const elyEvent = { 1893 event: 'elysiumEvent', 1894 event_name: 'product_image_click', 1895 carousel_nav: 'thumbnail', 1896 product_id: el?.id, 1897 product_name: el?.title, 1898 image_number: el?.index, 1899 eventData: { 1900 eventCategory: 'athenaProductImageCarousel', 1901 eventAction: 'click', 1902 eventLabel: `thumbnail`, 1903 eventLabelValue: el?.index, 1904 eventPage: window?.location?.pathname 1905 } 1906 } 1907 Tracker.push(elyEvent) 1908 }, 1909 1910 productDesClick: (el) => { 1911 const eventCategory = el.target.dataset.trackingPush 1912 1913 const elyEvent = { 1914 event: 'elysiumEvent', 1915 event: 'product_desciption_clicked', 1916 component: 'productDescriptionComponent', 1917 type: eventCategory, 1918 eventData: { 1919 eventCategory: 'Product | Description', 1920 eventAction: 'Clicked', 1921 eventLabel: `productDescription component clicked tab ${eventCategory}`, 1922 eventPage: window?.location?.pathname 1923 } 1924 } 1925 Tracker.push(elyEvent) 1926 }, 1927 1928 reviewViewed: () => { 1929 const elyEvent = { 1930 event: 'elysiumEvent', 1931 event_name: 'review_viewed', 1932 component: 'ProductReviews component', 1933 eventData: { 1934 eventCategory: 'Product | Review', 1935 eventAction: 'Viewed', 1936 eventLabel: 'athenaProductReviews component', 1937 eventPage: window?.location?.pathname 1938 } 1939 } 1940 Tracker.push(elyEvent) 1941 }, 1942 1943 reviewVoted: (el) => { 1944 const elyEvent = { 1945 event: 'elysiumEvent', 1946 event_name: 'review_voted', 1947 component: 'ProductReviews component', 1948 voted: el.voted, 1949 id: el.id, 1950 eventData: { 1951 eventCategory: 'Product | Voted', 1952 eventAction: 'Voted', 1953 eventLabel: `athenaProductReviews component voted ${el.voted} ${el.id}`, 1954 eventPage: window?.location?.pathname 1955 } 1956 } 1957 Tracker.push(elyEvent) 1958 }, 1959 1960 reviewReported: (el) => { 1961 const elyEvent = { 1962 event: 'elysiumEvent', 1963 event_name: 'product_reported', 1964 eventData: { 1965 eventCategory: 'Product | Reported', 1966 eventAction: 'Reported', 1967 eventLabel: `athenaProductReviews component reported ${el.id}`, 1968 eventPage: window?.location?.pathname 1969 } 1970 } 1971 Tracker.push(elyEvent) 1972 }, 1973 1974 reviewCreated: (el) => { 1975 const elyEvent = { 1976 event: 'elysiumEvent', 1977 event_name: 'review_create', 1978 product_id: el.product_id, 1979 product_name: el.product_name, 1980 rating: el?.rating, 1981 eventData: { 1982 eventCategory: 'Product | Reported', 1983 eventAction: 'Reported', 1984 eventLabel: `athenaProductReviews component reported ${el?.product_id}`, 1985 eventPage: window?.location?.pathname 1986 } 1987 } 1988 Tracker.push(elyEvent) 1989 }, 1990 1991 reviewPage: (el) => { 1992 const elyEvent = { 1993 event: 'elysiumEvent', 1994 event_name: 'review_pagination', 1995 eventData: { 1996 eventCategory: 'Product | Review', 1997 eventAction: 1998 el === 'next' ? 'Next Review Page' : 'Previous Review Page', 1999 eventLabel: `athenaProductReviews component go ${el} page`, 2000 eventPage: window?.location?.pathname 2001 } 2002 } 2003 Tracker.push(elyEvent) 2004 }, 2005 2006 // PDP 2007 productImageNav: (el) => { 2008 const elyEvent = { 2009 event: 'elysiumEvent', 2010 event_name: 'product_image_nav', 2011 action: `${el?.eventAction} image`, 2012 producnt_id: el?.id, 2013 product_name: el?.title, 2014 eventData: { 2015 eventCategory: 'ProductImageCarousel', 2016 eventAction: 'click', 2017 eventLabel: `${el?.eventAction} image`, 2018 eventPage: window?.location?.pathname 2019 } 2020 } 2021 Tracker.push(elyEvent) 2022 }, 2023 2024 sizeGuideClick: () => { 2025 const elyEvent = { 2026 event: 'elysiumEvent', 2027 event_name: 'product_size_guide', 2028 action: 'Clicked', 2029 component: 'productSizeGuide component clicked button', 2030 eventData: { 2031 eventCategory: 'Product | Size Guide', 2032 eventAction: 'Clicked', 2033 eventLabel: 'productSizeGuide', 2034 eventPage: window?.location?.pathname 2035 } 2036 } 2037 Tracker.push(elyEvent) 2038 }, 2039 2040 sizeGuideModalOpen: () => { 2041 const elyEvent = { 2042 event: 'elysiumEvent', 2043 event_name: 'product_size_guide', 2044 action: 'Clicked', 2045 component: 'productSizeGuide component clicked button', 2046 path: window?.location?.pathname, 2047 eventData: { 2048 eventCategory: 'Product | Size Guide modal', 2049 eventAction: 'Shown', 2050 eventLabel: 'productSizeGuide', 2051 eventPage: window?.location?.pathname 2052 } 2053 } 2054 Tracker.push(elyEvent) 2055 }, 2056 2057 sizeGuideModalClose: () => { 2058 const elyEvent = { 2059 event: 'elysiumEvent', 2060 event_name: 'product_size_guide_closed', 2061 component: 'product size guide modal', 2062 path: window?.location?.pathname, 2063 eventData: { 2064 eventCategory: 'Product | Size Guide modal', 2065 eventAction: 'Closed', 2066 eventLabel: 'product Size Guide', 2067 eventPage: window?.location?.pathname 2068 } 2069 } 2070 Tracker.push(elyEvent) 2071 }, 2072 updateMarketingPreferences: () => { 2073 Tracker.sendPubSubEvent('MarketingPreferenceUpdated', { 2074 event: { 2075 type: 'account_update', 2076 subtype: 'communication_preferences' 2077 } 2078 }) 2079 }, 2080 pageVisit: () => { 2081 Tracker.sendPubSubEvent( 2082 'PageVisit', 2083 { event: { type: 'page_visit' } }, 2084 window.__xAltitudeHorizonRay__ 2085 ) 2086 }, 2087 productVisit: (e) => { 2088 const store = Tracker.translateTarget(e) 2089 const pageData = Tracker.store.get(store) 2090 const productData = Tracker.store.get('products')[pageData.sku] 2091 Tracker.sendPubSubEvent( 2092 'ProductVisit', 2093 { 2094 event: { type: 'product_visit' }, 2095 page: { 2096 items: [ 2097 { 2098 product_group: { 2099 id: parseInt(productData?.item_id), 2100 selected_variant: { 2101 price: { 2102 currency: Tracker.store.get('currency'), 2103 value: parseFloat(productData?.price) 2104 }, 2105 sku: parseInt(productData?.item_id) 2106 } 2107 } 2108 } 2109 ] 2110 } 2111 }, 2112 pageData.rayId 2113 ) 2114 }, 2115 provenanceTrustBadgeClick: (e) => { 2116 const sku = e?.target?.dataset.sku 2117 const label = Tracker?.store['products'][sku]?.item_name 2118 2119 const elyEvent = { 2120 event: 'elysiumEvent', 2121 eventData: { 2122 eventAction: 'Verified Product', 2123 eventCategory: 'Provenance', 2124 eventLabel: label 2125 }, 2126 eventPage: window?.location?.pathname 2127 } 2128 2129 Tracker.push(elyEvent) 2130 }, 2131 // ---> MTA handlers <--- 2132 loginSuccess: () => { 2133 const elyEvent = { 2134 event: 'CustomEvent Account Creation', 2135 eventData: { 2136 eventCategory: 'login', 2137 eventAction: 'login success', 2138 eventLabel: 'Form' 2139 } 2140 } 2141 2142 Tracker.push(elyEvent) 2143 }, 2144 2145 loginFailed: () => { 2146 const elyEvent = { 2147 event: 'custom_event', 2148 event_name: 'login_failed', 2149 method: Tracker.store.get('login_method')?.value, 2150 error_value: Tracker.store.get('login_error_value')?.value 2151 } 2152 Tracker.push(elyEvent) 2153 }, 2154 2155 logout: () => { 2156 const elyEvent = { event: 'custom_event', event_name: 'logout' } 2157 Tracker.push(elyEvent) 2158 }, 2159 2160 accountRegistrationSuccess: () => { 2161 const elyEvent = { 2162 event: 'custom_event', 2163 event_name: 'sign_up', 2164 method: Tracker.store.get('account_registration_method')?.value, 2165 user_id: Tracker.store.get('user_id')?.value 2166 } 2167 Tracker.push(elyEvent) 2168 Tracker.sendPubSubEvent('Login', { 2169 event: { type: 'login', subtype: 'account_creation' } 2170 }) 2171 }, 2172 2173 accountRegistrationFail: () => { 2174 const elyEvent = { 2175 event: 'CustomEvent Account Creation', 2176 eventData: { 2177 eventCategory: 'login', 2178 eventAction: 'account created Failed', 2179 eventLabel: 'Form' 2180 } 2181 } 2182 2183 Tracker.push(elyEvent) 2184 }, 2185 checkoutStart: async (e) => { 2186 const items = Tracker.store.get('products') || [] 2187 const currency = Tracker.store.get('currency') 2188 2189 const gaEvent = { 2190 event_name: 'begin_checkout', 2191 currencyCode: currency, 2192 Items: Object.values(items) 2193 } 2194 2195 Tracker.push(gaEvent) 2196 // const store = Tracker.translateTarget(e); 2197 // const data = Tracker.store.get(store); 2198 // return Tracker.sendPubSubEvent( 2199 // "StartCheckout", 2200 // { 2201 // event: { 2202 // type: "checkout_start", 2203 // subtype: "standard_checkout", 2204 // }, 2205 // }, 2206 // data.rayId 2207 // ); 2208 }, 2209 guestCheckoutStart: async (e) => { 2210 const elyEvent = { 2211 event: 'elysiumEvent', 2212 event_name: 'continue_as_guest', 2213 category: 'Continue as guest', 2214 action: 'Clicked' 2215 } 2216 Tracker.push(elyEvent) 2217 2218 const store = Tracker.translateTarget(e) 2219 const data = Tracker.store.get(store) 2220 return Tracker.sendPubSubEvent( 2221 'StartGuestCheckout', 2222 { event: { type: 'checkout_start', subtype: 'guest_checkout' } }, 2223 data.rayId 2224 ) 2225 }, 2226 // ---> MTA handlers <--- 2227 pageNotFound: () => { 2228 const elyEvent = { 2229 event: 'elysiumEvent', 2230 event_name: 'page_not_found', 2231 eventData: { 2232 eventCategory: 'Errors', 2233 eventAction: 'Page Not Found', 2234 path: window?.location?.pathname 2235 } 2236 } 2237 2238 Tracker.push(elyEvent) 2239 }, 2240 emptyList: (el) => { 2241 const elyEvent = { 2242 event: 'elysiumEvent', 2243 event_name: 'empty_page', 2244 eventData: { 2245 eventLabel: 'Empty List', 2246 eventLabelValue: el, 2247 path: window?.location?.pathname 2248 } 2249 } 2250 2251 Tracker.push(elyEvent) 2252 }, 2253 noSearchResult: (el) => { 2254 const elyEvent = { 2255 event: 'elysiumEvent', 2256 event_name: 'no_search_results', 2257 eventData: { 2258 eventLabel: 'No Search Results', 2259 eventLabelValue: el, 2260 path: window?.location?.pathname + window?.location?.search 2261 } 2262 } 2263 2264 Tracker.push(elyEvent) 2265 }, 2266 startPageSize: (el) => {
2267 const key = Tracker.translateTarget(el) 2268 const size = Tracker.store.get(key) 2269 2270 const elyEvent = { 2271 event: 'elysiumEvent', 2272 event_name: 'start_page_size', 2273 height: size.height, 2274 width: size.width, 2275 eventData: { 2276 eventLabel: 'Start Page Size', 2277 eventLabelValue: { height: size.height, width: size.width }, 2278 path: window?.location?.pathname + window?.location?.search 2279 } 2280 } 2281 2282 Tracker.push(elyEvent) 2283 }, 2284 outOfStock: (el) => { 2285 const item = window.Tracker.store.get(el) 2286 2287 const elyEvent = { 2288 event: 'elysiumEvent', 2289 event_name: 'sold_out_product', 2290 eventData: { 2291 eventLabel: 'Sold Out Product', 2292 eventLabelValue: item, 2293 path: window?.location?.pathname + window?.location?.search 2294 } 2295 } 2296 Tracker.push(elyEvent) 2297 }, 2298 showOutfitSuggestions: ({ success = false, sku }) => { 2299 const product = Tracker.store.get('products')[sku] 2300 const { rayId } = Tracker.store.get('productVisit') 2301 2302 const items = success 2303 ? [ 2304 { 2305 product_group: { 2306 id: parseInt(product?.item_id), 2307 selected_variant: { 2308 price: { 2309 currency: Tracker.store.get('currency'), 2310 value: parseFloat(product?.price) 2311 }, 2312 sku: parseInt(product?.item_id) 2313 } 2314 } 2315 } 2316 ] 2317 : [] 2318 2319 const elyEvent = { 2320 event: 'elysiumEvent', 2321 event_name: 'show_outfit_suggestions', 2322 eventData: { 2323 eventLabel: 'Show Outfit Suggestions', 2324 eventSuccess: success, 2325 eventCategory: 'Outfit Suggestions', 2326 eventAction: 'Show', 2327 eventLabelValue: sku, 2328 path: window?.location?.pathname 2329 } 2330 } 2331 Tracker.push(elyEvent) 2332 2333 Tracker.sendPubSubEvent( 2334 'ShowOutfitSuggestions', 2335 { event: { type: 'show_outfit_suggestions' }, page: { items } }, 2336 rayId 2337 ) 2338 }, 2339 outfitSuggestionsVisit: ({ sku }) => { 2340 const product = Tracker.store.get('products')[sku] 2341 const { value } = Tracker.store.get('rayId') 2342 2343 const elyEvent = { 2344 event: 'elysiumEvent', 2345 event_name: 'visit_outfit_suggestions_item', 2346 eventData: { 2347 eventLabel: 'Visit Outfit Suggestions Item', 2348 eventCategory: 'Outfit Suggestions', 2349 eventAction: 'Visit Product', 2350 eventLabelValue: sku, 2351 path: window?.location?.pathname 2352 } 2353 } 2354 Tracker.push(elyEvent) 2355 2356 Tracker.sendPubSubEvent( 2357 'VisitOutfitSuggestionsItem', 2358 { 2359 event: { type: 'visit_outfit_suggestions_item' }, 2360 page: { 2361 items: [ 2362 { 2363 product_group: { 2364 id: parseInt(product?.item_id), 2365 selected_variant: { 2366 price: { 2367 currency: Tracker.store.get('currency'), 2368 value: parseFloat(product?.price) 2369 }, 2370 sku: parseInt(product?.item_id) 2371 } 2372 } 2373 } 2374 ] 2375 } 2376 }, 2377 value 2378 ) 2379 }, 2380 suggestedProductReview: ({ sku, approved = false }) => { 2381 const { value } = Tracker.store.get('rayId') 2382 const eventType = approved 2383 ? 'approved_suggested_item' 2384 : 'rejected_suggested_item' 2385 2386 const elyEvent = { 2387 event: 'elysiumEvent', 2388 event_name: eventType, 2389 eventData: { 2390 eventLabel: 'Review Suggestions Item', 2391 eventCategory: 'Outfit Suggestions', 2392 eventAction: 'Review Product', 2393 eventLabelValue: sku, 2394 path: window?.location?.pathname 2395 } 2396 } 2397 Tracker.push(elyEvent) 2398 2399 Tracker.sendPubSubEvent( 2400 'ReviewSuggestionsItem', 2401 { 2402 event: { type: eventType }, 2403 items: [{ product_group: { id: parseInt(sku) } }] 2404 }, 2405 value 2406 ) 2407 }, 2408 showSuggestedItemJustification: ({ sku }) => { 2409 const { value } = Tracker.store.get('rayId') 2410 2411 const elyEvent = { 2412 event: 'elysiumEvent', 2413 event_name: 'show_suggested_item_justification', 2414 eventData: { 2415 eventLabel: 'Show Suggested Item Justification', 2416 eventCategory: 'Outfit Suggestions', 2417 eventAction: 'Review Product', 2418 eventLabelValue: sku, 2419 path: window?.location?.pathname 2420 } 2421 } 2422 Tracker.push(elyEvent) 2423 2424 Tracker.sendPubSubEvent( 2425 'ShowSuggestedItemJustification', 2426 { 2427 event: { type: 'show_suggested_item_justification' }, 2428 items: [{ product_group: { id: parseInt(sku) } }] 2429 }, 2430 value 2431 ) 2432 }, 2433 2434 foundationFinderShadeMatch: (sku, source_id) => { 2435 Tracker.sendPubSubEvent('FFFindMyShadeMatch', { 2436 event: { 2437 type: 'ff_find_my_shade_match', 2438 items: [ 2439 { 2440 product_group: { 2441 id: parseInt(sku), 2442 promotion: { name: source_id } 2443 } 2444 } 2445 ] 2446 } 2447 }) 2448 }, 2449 foundationFinderToolOpen: (sku) => { 2450 Tracker.sendPubSubEvent('FFFindMyShadeOpen', { 2451 event: { 2452 type: 'ff_find_my_shade_open', 2453 items: [{ product_group: { id: parseInt(sku) } }] 2454 } 2455 }) 2456 }, 2457 showQuickBuyModal: (recommendationContext, recommendationSlotIndex) => { 2458 Tracker.sendPubSubEvent( 2459 'ShowQuickBuyModal', 2460 { 2461 event: { 2462 type: 'page_visit', 2463 subtype: 'quickbuy_modal_shown' 2464 } 2465 }, 2466 null, 2467 recommendationContext, 2468 recommendationSlotIndex 2469 ) 2470 }, 2471 showSideSheet: (subtype = '', recommendationContext, recommendationSlotIndex) => { 2472 Tracker.sendPubSubEvent( 2473 'ShowSideSheet', 2474 { 2475 event: { 2476 subtype, 2477 type: 'page_visit' 2478 } 2479 }, 2480 null, 2481 recommendationContext, 2482 recommendationSlotIndex 2483 ) 2484 }, 2485 clickShade: () => { 2486 Tracker.sendPubSubEvent('color_swatch_click', { 2487 event: { 2488 type: 'click',
2489 subtype: 'shade_selector' 2490 } 2491 }) 2492 }, 2493 foundationFinderShadeAddToBasket: (sku, source_id, type) => { 2494 Tracker.sendPubSubEvent('FFFindMyShadeAdd', { 2495 event: { 2496 type: 'ff_find_my_shade_add', 2497 items: [ 2498 { 2499 product_group: { 2500 id: parseInt(sku), 2501 promotion: { name: source_id, type: type } 2502 } 2503 } 2504 ] 2505 } 2506 }) 2507 }, 2508 // TODO - should refactor once tracking strategy is confirmed. New basket flow 2509 // is no longer built around passing a single gift box sku to the modal. 2510 // The sidesheet opens with all skus 2511 showGiftBoxSideSheet: (giftBoxSku) => { 2512 const giftBox = __AVAILABLE_GIFT_BOXES__?.[giftBoxSku] 2513 const eligibleProducts = giftBox?.eligibleProducts || [] 2514 2515 let ecommItems = [] 2516 let pubSubItems = [] 2517 2518 eligibleProducts.forEach(item => { 2519 ecommItems.push({ 2520 discount: item.discount, 2521 item_brand: item.brand, 2522 item_id: parseInt(item.sku, 10), 2523 item_name: item.title, 2524 item_variant: item.variant, 2525 price: item.price, 2526 }) 2527 pubSubItems.push({ 2528 product_group: { 2529 id: parseInt(item.sku, 10), 2530 selected_variant: { 2531 price: { 2532 currency: Tracker.store.get('currency'), 2533 value: parseFloat(item.price) 2534 }, 2535 sku: parseInt(item.sku, 10) 2536 } 2537 } 2538 }) 2539 }) 2540 2541 const elyEvent = { 2542 event: 'elysiumEvent', 2543 eventData: { 2544 eventCategory: 'Gift Box | Viewed', 2545 eventAction: 'Viewed', 2546 eventLabel: giftBoxSku, 2547 eventLabelValue: [Tracker.store.get(giftBoxSku)], 2548 eventPage: window?.location?.pathname 2549 } 2550 } 2551 const gaEvent = { 2552 event: 'ecom_event', 2553 event_name: 'view_gift_box', 2554 ecommerce: { 2555 currencyCode: Tracker.store.get('currency') ?? '', 2556 items: ecommItems, 2557 value: giftBox?.amount 2558 } 2559 } 2560 const pubSubEvent = { 2561 event: { 2562 items: pubSubItems, 2563 subtype: 'giftbox_modal_shown', 2564 type: 'page_visit' 2565 } 2566 } 2567 2568 Tracker.push(elyEvent) 2569 Tracker.push(gaEvent) 2570 Tracker.sendPubSubEvent( 2571 'ShowGiftBoxModal', 2572 pubSubEvent 2573 ) 2574 } 2575 }, 2576 trackApiConfig: null, 2577 config: null, 2578 store: { 2579 get(k) { 2580 return Tracker.store[k] 2581 }, 2582 set(k, v) { 2583 return (Tracker.store[k] = Tracker.store[k] 2584 ? Object.assign(Tracker.store[k], v) 2585 : v) 2586 } 2587 }, 2588 getAllBasketItems: (basketData) => { 2589 return [ 2590 ...(basketData?.items || []), 2591 ...(basketData?.giftWrapItems || []) 2592 ] 2593 } 2594 } 2595 Tracker.assignTracker() 2596 if (typeof window.Tracker.load !== 'function') { 2597 Tracker.init({ 2598 debug: true, 2599 selectors: { 2600 track: 'data-track', 2601 type: 'data-track-type', 2602 store: 'data-track-push', 2603 currency: 'data-track-currency' 2604 } 2605 }) 2606 } else { 2607 window.Tracker.load() 2608 } 2609})()
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.