ecommerce

The following code sample depicts sitemap code for an imaginary implementation of Marketing Cloud Personalization on the Northern Trail Outfitters website https://www.northerntrailoutfitters.com. This sitemap code is not exhaustive and maps only key areas valuable for demonstrating an example implementation of Personalization. The primary focus of this sitemap code is to depict how to approach designing a Catalog for ecommerce websites.

This example sitemap is for reference purposes only. Avoid copying this code into your Sitemap Editor as it does not produce the results you intended.

This example includes an SKU implementation, however most sitemaps don’t require them. For more information about Marketing Cloud Personalization SKU implementation, see Stock Keeping Units.

Important

Example Sitemap in the SalesforceInteractions Namespace 

1SalesforceInteractions.init({
2  cookieDomain: "northerntrailoutfitters.com",
3  consents: [
4    {
5      purpose: SalesforceInteractions.mcis.ConsentPurpose.Personalization,
6      provider: "Example Consent Manager",
7      status: SalesforceInteractions.ConsentStatus.OptIn,
8    },
9  ],
10}).then(() => {
11  const sitemapConfig = {
12    global: {
13      onActionEvent: (actionEvent) => {
14        const email = SalesforceInteractions.mcis.getValueFromNestedObject(
15          "window._etmc.user_info.email",
16        );
17        if (email) {
18          actionEvent.user = actionEvent.user || {};
19          actionEvent.user.identities = actionEvent.user.identities || {};
20          actionEvent.user.identities.emailAddress = email;
21        }
22        return actionEvent;
23      },
24      contentZones: [
25        { name: "global_infobar_top_of_page", selector: "header.site-header" },
26        { name: "global_infobar_bottom_of_page", selector: "footer.site-footer" },
27      ],
28      listeners: [
29        SalesforceInteractions.listener("submit", ".email-signup", () => {
30          const email = SalesforceInteractions.cashDom("#dwfrm_mcsubscribe_email").val();
31          if (email) {
32            SalesforceInteractions.sendEvent({
33              interaction: { name: "Email Sign Up - Footer" },
34              user: { identities: { emailAddress: email } },
35            });
36          }
37        }),
38      ],
39    },
40    pageTypeDefault: {
41      name: "default",
42      interaction: {
43        name: "Default Page",
44      },
45    },
46    pageTypes: [
47      {
48        name: "product_detail",
49        /*
50                The best practice for isMatch is to match as quickly as possible. If matching immediately is not an option, you can use a Promise.
51                The Promise should resolve true or false and not pend indefinitely. This Promise example uses a setTimeout to prevent the isMatch from pending indefinitely if the match condition is not met fast enough. In this scenario, we know that the match condition will be met within 50 milliseconds or not at all. Note that using a timeout like this might not be sufficient in all cases and if you are using a Promise it should be tailored to your specific use-case.
52                */
53        isMatch: () =>
54          new Promise((resolve, reject) => {
55            let isMatchPDP = setTimeout(() => {
56              resolve(false);
57            }, 50);
58            return SalesforceInteractions.DisplayUtils.pageElementLoaded(
59              "div.page[data-action='Product-Show']",
60              "html",
61            ).then(() => {
62              clearTimeout(isMatchPDP);
63              resolve(true);
64            });
65          }),
66        interaction: {
67          name: SalesforceInteractions.CatalogObjectInteractionName.ViewCatalogObject,
68          catalogObject: {
69            type: "Product",
70            id: () => {
71              return SalesforceInteractions.util.resolveWhenTrue.bind(() => {
72                const productId = SalesforceInteractions.cashDom(".product-id").first().text();
73                const products = getProductsFromDataLayer();
74                if (products && products.length > 0) {
75                  return products[0].id;
76                } else if (productId) {
77                  return productId;
78                } else {
79                  return false;
80                }
81              });
82            },
83            attributes: {
84              sku: {
85                id: SalesforceInteractions.cashDom(".product-detail[data-pid]").attr("data-pid"),
86              },
87              name: SalesforceInteractions.resolvers.fromJsonLd("name"),
88              description: SalesforceInteractions.resolvers.fromSelector(
89                ".short-description",
90                (desc) => desc.trim(),
91              ),
92              url: SalesforceInteractions.resolvers.fromHref(),
93              imageUrl: SalesforceInteractions.resolvers.fromSelectorAttribute(
94                ".product-carousel .carousel-item[data-slick-index='0'] img",
95                "src",
96                (url) => window.location.origin + url,
97              ),
98              inventoryCount: 1,
99              price: SalesforceInteractions.resolvers.fromSelector(
100                ".prices .price .value",
101                (price) => parseFloat(price.replace(/[^0-9\.]+/g, "")),
102              ),
103              rating: () => {
104                return SalesforceInteractions.mcis.extractFirstGroup(
105                  /([.\w]+) out of/,
106                  SalesforceInteractions.cashDom(".ratings .sr-only").text(),
107                );
108              },
109            },
110            relatedCatalogObjects: {
111              Category: SalesforceInteractions.DisplayUtils.pageElementLoaded(
112                ".container .product-breadcrumb .breadcrumb a",
113                "html",
114              ).then((ele) => {
115                return SalesforceInteractions.resolvers.buildCategoryId(
116                  ".container .product-breadcrumb .breadcrumb a",
117                  null,
118                  null,
119                  (categoryId) => [categoryId.toUpperCase()],
120                );
121              }),
122              Gender: SalesforceInteractions.DisplayUtils.pageElementLoaded(
123                ".product-breadcrumb .breadcrumb a, h1.product-name",
124                "html",
125              ).then((ele) => {
126                if (
127                  SalesforceInteractions.cashDom(".product-breadcrumb .breadcrumb a")
128                    .first()
129                    .text()
130                    .toLowerCase() === "women" ||
131                  SalesforceInteractions.cashDom("h1.product-name").text().indexOf("Women") >= 0
132                ) {
133                  return ["WOMEN"];
134                } else if (
135                  SalesforceInteractions.cashDom(".product-breadcrumb .breadcrumb a")
136                    .first()
137                    .text()
138                    .toLowerCase() === "men" ||
139                  SalesforceInteractions.cashDom("h1.product-name").text().indexOf("Men") >= 0
140                ) {
141                  return ["MEN"];
142                } else {
143                  return;
144                }
145              }),
146              Color: SalesforceInteractions.DisplayUtils.pageElementLoaded(
147                ".attributes",
148                "html",
149              ).then((ele) => {
150                return SalesforceInteractions.resolvers.fromSelectorAttributeMultiple(
151                  ".color-value",
152                  "data-attr-value",
153                );
154              }),
155              Feature: SalesforceInteractions.DisplayUtils.pageElementLoaded(
156                ".features",
157                "html",
158              ).then((ele) => {
159                return SalesforceInteractions.resolvers.fromSelectorMultiple(
160                  ".long-description li",
161                  (features) => {
162                    return features.map((feature) => {
163                      return feature.trim().toUpperCase();
164                    });
165                  },
166                );
167              }),
168            },
169          },
170        },
171        contentZones: [
172          {
173            name: "product_detail_recs_row_1",
174            selector: ".row.recommendations div[id*='cq']:nth-of-type(1)",
175          },
176          {
177            name: "product_detail_recs_row_2",
178            selector: ".row.recommendations div[id*='cq']:nth-of-type(2)",
179          },
180          { name: "testHeader", selector: ".site-header" },
181        ],
182        listeners: [
183          SalesforceInteractions.listener("click", ".add-to-cart", () => {
184            let lineItem = SalesforceInteractions.mcis.buildLineItemFromPageState(
185              "select.quantity-select option:checked",
186            );
187            SalesforceInteractions.sendEvent({
188              interaction: {
189                name: SalesforceInteractions.CartInteractionName.AddToCart,
190                lineItem: lineItem,
191              },
192            });
193          }),
194          SalesforceInteractions.listener("click", ".attribute", (event) => {
195            let classList = event.target.classList.value.split(" ");
196            if (classList.includes("color-value") || classList.includes("size-value")) {
197              SalesforceInteractions.sendEvent({
198                interaction: {
199                  name: SalesforceInteractions.CatalogObjectInteractionName.ViewCatalogObjectDetail,
200                  catalogObject: {
201                    type: "Product",
202                    id: SalesforceInteractions.getSitemapResult().currentPage.interaction
203                      .catalogObject.id,
204                    attributes: {
205                      sku: {
206                        id: SalesforceInteractions.cashDom(".product-detail[data-pid]").attr(
207                          "data-pid",
208                        ),
209                      },
210                    },
211                    relatedCatalogObjects: {
212                      Color: [
213                        SalesforceInteractions.cashDom(".color-value.selected").attr(
214                          "data-attr-value",
215                        ),
216                      ],
217                    },
218                  },
219                },
220              });
221            }
222          }),
223        ],
224      },
225      {
226        name: "Category",
227        isMatch: () =>
228          new Promise((resolve, reject) => {
229            let isMatchCat = setTimeout(() => {
230              resolve(false);
231            }, 50);
232            return SalesforceInteractions.DisplayUtils.pageElementLoaded(
233              "#product-search-results",
234              "html",
235            ).then(() => {
236              clearTimeout(isMatchCat);
237              resolve(SalesforceInteractions.cashDom(".breadcrumb").length > 0);
238            });
239          }),
240        interaction: {
241          name: SalesforceInteractions.CatalogObjectInteractionName.ViewCatalogObject,
242          catalogObject: {
243            type: "Category",
244            id: SalesforceInteractions.DisplayUtils.pageElementLoaded(
245              ".breadcrumb .breadcrumb-item a",
246              "html",
247            ).then((ele) => {
248              return SalesforceInteractions.resolvers.buildCategoryId(
249                ".breadcrumb .breadcrumb-item a",
250                1,
251                null,
252                (categoryId) => categoryId.toUpperCase(),
253              );
254            }),
255          },
256        },
257        listeners: [
258          SalesforceInteractions.listener("click", ".quickview", (e) => {
259            const pid = SalesforceInteractions.cashDom(e.target).attr("href").split("pid=")[1];
260            if (!pid) {
261              return;
262            }
263
264            SalesforceInteractions.sendEvent({
265              interaction: {
266                name: SalesforceInteractions.CatalogObjectInteractionName.QuickViewCatalogObject,
267                catalogObject: {
268                  type: "Product",
269                  id: pid,
270                },
271              },
272            });
273          }),
274          SalesforceInteractions.listener("click", "body", (e) => {
275            if (
276              SalesforceInteractions.cashDom(e.target).closest("button[data-dismiss='modal']")
277                .length > 0
278            ) {
279              SalesforceInteractions.sendEvent({
280                interaction: {
281                  name: SalesforceInteractions.mcis.CatalogObjectInteractionName
282                    .StopQuickViewCatalogObject,
283                },
284              });
285            } else if (
286              SalesforceInteractions.cashDom(e.target).closest("#quickViewModal").length > 0 &&
287              SalesforceInteractions.cashDom(e.target).find("#quickViewModal .modal-dialog")
288                .length > 0
289            ) {
290              SalesforceInteractions.sendEvent({
291                interaction: {
292                  name: SalesforceInteractions.mcis.CatalogObjectInteractionName
293                    .StopQuickViewCatalogObject,
294                },
295              });
296            }
297          }),
298        ],
299      },
300      {
301        name: "department",
302        isMatch: () =>
303          new Promise((resolve, reject) => {
304            let isMatchDept = setTimeout(() => {
305              resolve(false);
306            }, 50);
307            return SalesforceInteractions.DisplayUtils.pageElementLoaded(
308              "div.category-tile",
309              "html",
310            ).then(() => {
311              clearTimeout(isMatchDept);
312              resolve(!/\/homepage/.test(window.location.href));
313            });
314          }),
315      },
316      {
317        name: "search_results",
318        isMatch: () => /\/default\/search$/.test(window.location.pathname),
319      },
320      {
321        name: "cart",
322        isMatch: () => /\/cart/.test(window.location.href),
323        interaction: {
324          name: SalesforceInteractions.CartInteractionName.ReplaceCart,
325          lineItems: SalesforceInteractions.DisplayUtils.pageElementLoaded(
326            ".cart-empty, .checkout-btn",
327            "html",
328          ).then(() => {
329            let cartLineItems = [];
330            SalesforceInteractions.cashDom(".product-info .product-details").each((index, ele) => {
331              let itemQuantity = parseInt(
332                SalesforceInteractions.cashDom(ele).find(".qty-card-quantity-count").text().trim(),
333              );
334              if (itemQuantity && itemQuantity > 0) {
335                let lineItem = {
336                  catalogObjectType: "Product",
337                  catalogObjectId: SalesforceInteractions.cashDom(ele)
338                    .find(".line-item-quanity-info")
339                    .attr("data-pid"),
340                  price:
341                    SalesforceInteractions.cashDom(ele)
342                      .find(".pricing")
343                      .text()
344                      .replace(/[^0-9\.]+/g, "") / itemQuantity,
345                  quantity: itemQuantity,
346                };
347                cartLineItems.push(lineItem);
348              }
349            });
350            return cartLineItems;
351          }),
352        },
353      },
354      {
355        name: "order_confirmation",
356        isMatch: () => /\/confirmation/.test(window.location.href),
357        interaction: {
358          name: SalesforceInteractions.OrderInteractionName.Purchase,
359          order: {
360            id: SalesforceInteractions.DisplayUtils.pageElementLoaded(".order-number", "html").then(
361              (ele) => {
362                return SalesforceInteractions.resolvers.fromSelector(".order-number");
363              },
364            ),
365            lineItems: SalesforceInteractions.DisplayUtils.pageElementLoaded(
366              ".product-line-item",
367              "html",
368            ).then(() => {
369              let purchaseLineItems = [];
370              SalesforceInteractions.cashDom(".product-line-item").each((index, ele) => {
371                let itemQuantity = parseInt(
372                  SalesforceInteractions.cashDom(ele)
373                    .find(".qty-card-quantity-count")
374                    .text()
375                    .trim(),
376                );
377                if (itemQuantity && itemQuantity > 0) {
378                  let lineItem = {
379                    catalogObjectType: "Product",
380                    catalogObjectId: SalesforceInteractions.cashDom(ele)
381                      .find(".line-item-quanity-info")
382                      .attr("data-pid")
383                      .trim(),
384                    price:
385                      SalesforceInteractions.cashDom(ele)
386                        .find(".pricing")
387                        .text()
388                        .trim()
389                        .replace(/[^0-9\.]+/g, "") / itemQuantity,
390                    quantity: itemQuantity,
391                  };
392                  purchaseLineItems.push(lineItem);
393                }
394              });
395              return purchaseLineItems;
396            }),
397          },
398        },
399      },
400      {
401        name: "login",
402        isMatch: () =>
403          /\/login/.test(window.location.href) &&
404          window.location.hostname !== "community.northerntrailoutfitters.com",
405        interaction: {
406          name: "Login",
407        },
408        listeners: [
409          SalesforceInteractions.listener("click", "form[name='login-form'] button", () => {
410            const email = SalesforceInteractions.cashDom("#login-form-email").val();
411            if (email) {
412              SalesforceInteractions.sendEvent({
413                interaction: { name: "Logged In" },
414                user: { identities: { emailAddress: email } },
415              });
416            }
417          }),
418        ],
419      },
420      {
421        name: "home",
422        isMatch: () => /\/homepage/.test(window.location.href),
423        interaction: {
424          name: "Homepage",
425        },
426        contentZones: [
427          { name: "home_hero", selector: ".experience-carousel-bannerCarousel" },
428          {
429            name: "home_sub_hero",
430            selector: ".experience-carousel-bannerCarousel + .experience-component",
431          },
432          { name: "home_popup" },
433        ],
434      },
435      {
436        name: "community_login",
437        isMatch: () =>
438          window.location.hostname === "community.northerntrailoutfitters.com" &&
439          /\/s\/login/.test(window.location.href),
440        interaction: {
441          name: "Community Login",
442        },
443        listeners: [
444          SalesforceInteractions.listener("click", ".loginButton", (event) => {
445            const email = SalesforceInteractions.cashDom("input[placeholder='Email']").val();
446            if (email) {
447              SalesforceInteractions.sendEvent({
448                interaction: { name: "Community Log In" },
449                user: { identities: { emailAddress: email } },
450              });
451            }
452          }),
453        ],
454      },
455      {
456        name: "community_home",
457        isMatch: () => {
458          return (
459            window.location.hostname === "community.northerntrailoutfitters.com" &&
460            /^\/s\/?$/.test(window.location.pathname)
461          );
462        },
463        interaction: {
464          name: "Community Homepage",
465        },
466        listeners: [
467          SalesforceInteractions.listener("click", "li.topicItem", (event) => {
468            const topicLabel = SalesforceInteractions.cashDom(event.currentTarget)
469              .find(".topicLabel")
470              .text()
471              .trim();
472            if (topicLabel) {
473              SalesforceInteractions.sendEvent({
474                interaction: { name: "Community Homepage - " + topicLabel },
475              });
476            }
477          }),
478        ],
479      },
480    ],
481  };
482  const getProductsFromDataLayer = () => {
483    if (window.dataLayer) {
484      for (let i = 0; i < window.dataLayer.length; i++) {
485        if (
486          ((window.dataLayer[i].ecommerce && window.dataLayer[i].ecommerce.detail) || {}).products
487        ) {
488          return window.dataLayer[i].ecommerce.detail.products;
489        }
490      }
491    }
492  };
493  SalesforceInteractions.initSitemap(sitemapConfig);
494});

Example Sitemap in the Evergage Namespace 

1Evergage.init({
2  cookieDomain: "northerntrailoutfitters.com",
3}).then(() => {
4  const config = {
5    global: {
6      onActionEvent: (actionEvent) => {
7        const email = Evergage.util.getValueFromNestedObject("window._etmc.user_info.email");
8        if (email) {
9          actionEvent.user = actionEvent.user || {};
10          actionEvent.user.attributes = actionEvent.user.attributes || {};
11          actionEvent.user.attributes.emailAddress = email;
12        }
13        return actionEvent;
14      },
15      contentZones: [
16        { name: "global_infobar_top_of_page", selector: "header.site-header" },
17        { name: "global_infobar_bottom_of_page", selector: "footer.site-footer" },
18      ],
19      listeners: [
20        Evergage.listener("submit", ".email-signup", () => {
21          const email = Evergage.cashDom("#dwfrm_mcsubscribe_email").val();
22          if (email) {
23            Evergage.sendEvent({
24              action: "Email Sign Up - Footer",
25              user: { attributes: { emailAddress: email } },
26            });
27          }
28        }),
29      ],
30    },
31    pageTypeDefault: {
32      name: "default",
33    },
34    pageTypes: [
35      {
36        name: "product_detail",
37        isMatch: () => {
38          return Evergage.DisplayUtils.pageElementLoaded("div.page", "html").then((ele) => {
39            const pageType = Evergage.cashDom(ele).attr("data-action");
40            return pageType === "Product-Show";
41          });
42        },
43        catalog: {
44          Product: {
45            _id: () => {
46              return Evergage.util.resolveWhenTrue.bind(() => {
47                const productId = Evergage.cashDom(".product-id").first().text();
48                const products = getProductsFromDataLayer();
49                if (products && products.length > 0) {
50                  return products[0].id;
51                } else if (productId) {
52                  return productId;
53                } else {
54                  return false;
55                }
56              });
57            },
58            sku: { _id: Evergage.cashDom(".product-detail[data-pid]").attr("data-pid") },
59            name: Evergage.resolvers.fromJsonLd("name"),
60            description: Evergage.resolvers.fromSelector(".short-description"),
61            url: Evergage.resolvers.fromHref(),
62            imageUrl: Evergage.resolvers.fromSelectorAttribute(
63              ".product-carousel .carousel-item[data-slick-index='0'] img",
64              "src",
65            ),
66            inventoryCount: 1,
67            price: Evergage.resolvers.fromSelector(".prices .price .value"),
68            rating: () => {
69              return Evergage.util.extractFirstGroup(
70                /([.\w]+) out of/,
71                Evergage.cashDom(".ratings .sr-only").text(),
72              );
73            },
74            categories: () => {
75              return Evergage.DisplayUtils.pageElementLoaded(
76                ".container .product-breadcrumb .breadcrumb a",
77                "html",
78              ).then((ele) => {
79                return Evergage.resolvers.buildCategoryId(
80                  ".container .product-breadcrumb .breadcrumb a",
81                  null,
82                  null,
83                  (categoryId) => [categoryId.toUpperCase()],
84                );
85              });
86            },
87            relatedCatalogObjects: {
88              // In case you're using 'dimensions' instead of 'relatedCatalogObjects', you can continue to do so as they both function the same way.
89              Gender: () => {
90                return Evergage.DisplayUtils.pageElementLoaded(
91                  ".product-breadcrumb .breadcrumb a, h1.product-name",
92                  "html",
93                ).then((ele) => {
94                  if (
95                    Evergage.cashDom(".product-breadcrumb .breadcrumb a")
96                      .first()
97                      .text()
98                      .toLowerCase() === "women" ||
99                    Evergage.cashDom("h1.product-name").text().indexOf("Women") >= 0
100                  ) {
101                    return ["WOMEN"];
102                  } else if (
103                    Evergage.cashDom(".product-breadcrumb .breadcrumb a")
104                      .first()
105                      .text()
106                      .toLowerCase() === "men" ||
107                    Evergage.cashDom("h1.product-name").text().indexOf("Men") >= 0
108                  ) {
109                    return ["MEN"];
110                  } else {
111                    return;
112                  }
113                });
114              },
115              Color: () => {
116                return Evergage.DisplayUtils.pageElementLoaded(".attributes", "html").then(
117                  (ele) => {
118                    return Evergage.resolvers.fromSelectorAttributeMultiple(
119                      ".color-value",
120                      "data-attr-value",
121                    );
122                  },
123                );
124              },
125              Feature: () => {
126                return Evergage.DisplayUtils.pageElementLoaded(".features", "html").then((ele) => {
127                  return Evergage.resolvers.fromSelectorMultiple(
128                    ".features .feature",
129                    (features) => {
130                      return features.map((feature) => {
131                        return feature.trim();
132                      });
133                    },
134                  );
135                });
136              },
137            },
138          },
139        },
140        contentZones: [
141          {
142            name: "product_detail_recs_row_1",
143            selector: ".row.recommendations div[id*='cq']:nth-of-type(1)",
144          },
145          {
146            name: "product_detail_recs_row_2",
147            selector: ".row.recommendations div[id*='cq']:nth-of-type(2)",
148          },
149          { name: "testHeader", selector: ".site-header" },
150        ],
151        listeners: [
152          Evergage.listener("click", ".add-to-cart", () => {
153            const lineItem = Evergage.util.buildLineItemFromPageState("select[id*=quantity]");
154            lineItem.sku = { _id: Evergage.cashDom(".product-detail[data-pid]").attr("data-pid") };
155            Evergage.sendEvent({
156              itemAction: Evergage.ItemAction.AddToCart,
157              cart: {
158                singleLine: {
159                  Product: lineItem,
160                },
161              },
162            });
163          }),
164          Evergage.listener("click", ".attribute", (event) => {
165            let classList = event.target.classList.value.split(" ");
166            if (classList.includes("color-value") || classList.includes("size-value")) {
167              Evergage.sendEvent({
168                itemAction: Evergage.ItemAction.ViewItemDetail,
169                catalog: {
170                  Product: {
171                    _id: Evergage.util.buildLineItemFromPageState("select[id*=quantity]")._id,
172                    sku: { _id: Evergage.cashDom(".product-detail[data-pid]").attr("data-pid") },
173                    relatedCatalogObjects: {
174                      Color: [Evergage.cashDom(".color-value.selected").attr("data-attr-value")],
175                    },
176                  },
177                },
178              });
179            }
180          }),
181        ],
182      },
183      {
184        name: "Category",
185        action: "Viewed Category",
186        isMatch: () => {
187          return Evergage.DisplayUtils.pageElementLoaded(".page", "html").then((ele) => {
188            const pageType = Evergage.cashDom(ele).attr("data-action");
189            return pageType === "Search-Show" && Evergage.cashDom(".breadcrumb").length > 0;
190          });
191        },
192        catalog: {
193          Category: {
194            _id: () => {
195              return Evergage.DisplayUtils.pageElementLoaded(
196                ".breadcrumb .breadcrumb-item a",
197                "html",
198              ).then((ele) => {
199                return Evergage.resolvers.buildCategoryId(
200                  ".breadcrumb .breadcrumb-item a",
201                  1,
202                  null,
203                  (categoryId) => categoryId.toUpperCase(),
204                );
205              });
206            },
207          },
208        },
209        listeners: [
210          Evergage.listener("click", ".quickview", (e) => {
211            const pid = Evergage.cashDom(e.target).attr("href").split("pid=")[1];
212            if (!pid) {
213              return;
214            }
215
216            Evergage.sendEvent({
217              action: "Category Page Quick View",
218              itemAction: Evergage.ItemAction.QuickViewItem,
219              catalog: {
220                Product: {
221                  _id: pid,
222                },
223              },
224            });
225          }),
226          Evergage.listener("click", "body", (e) => {
227            if (Evergage.cashDom(e.target).closest("button[data-dismiss='modal']").length > 0) {
228              Evergage.sendEvent({
229                action: "Close Quick View",
230                itemAction: Evergage.ItemAction.StopQuickViewItem,
231              });
232            } else if (
233              Evergage.cashDom(e.target).closest("#quickViewModal").length > 0 &&
234              Evergage.cashDom(e.target).find("#quickViewModal .modal-dialog").length > 0
235            ) {
236              Evergage.sendEvent({
237                action: "Close Quick View",
238                itemAction: Evergage.ItemAction.StopQuickViewItem,
239              });
240            }
241          }),
242        ],
243      },
244      {
245        name: "department",
246        isMatch: () => {
247          return Evergage.DisplayUtils.pageElementLoaded("div.category-tile", "html").then(
248            (ele) => {
249              return !/\/homepage/.test(window.location.href);
250            },
251          );
252        },
253      },
254      {
255        name: "search_results",
256        isMatch: () => /\/default\/search$/.test(window.location.pathname),
257      },
258      {
259        name: "cart",
260        isMatch: () => /\/cart/.test(window.location.href),
261        itemAction: Evergage.ItemAction.ViewCart,
262        catalog: {
263          Product: {
264            lineItems: {
265              _id: () => {
266                return Evergage.DisplayUtils.pageElementLoaded(
267                  ".cart-empty, .checkout-btn",
268                  "html",
269                ).then((ele) => {
270                  return Evergage.resolvers.fromSelectorAttributeMultiple(
271                    ".product-info .product-details .line-item-quantity-info",
272                    "data-pid",
273                  );
274                });
275              },
276              price: () => {
277                return Evergage.DisplayUtils.pageElementLoaded(
278                  ".cart-empty, .checkout-btn",
279                  "html",
280                ).then((ele) => {
281                  return Evergage.resolvers.fromSelectorMultiple(
282                    ".product-info .product-details .pricing",
283                  );
284                });
285              },
286              quantity: () => {
287                return Evergage.DisplayUtils.pageElementLoaded(
288                  ".cart-empty, .checkout-btn",
289                  "html",
290                ).then((ele) => {
291                  return Evergage.resolvers.fromSelectorMultiple(
292                    ".product-info .product-details .qty-card-quantity-count",
293                  );
294                });
295              },
296            },
297          },
298        },
299      },
300      {
301        name: "order_confirmation",
302        isMatch: () => /\/confirmation/.test(window.location.href),
303        itemAction: Evergage.ItemAction.Purchase,
304        catalog: {
305          Product: {
306            orderId: () => {
307              return Evergage.DisplayUtils.pageElementLoaded(".order-number", "html").then(
308                (ele) => {
309                  return Evergage.resolvers.fromSelector(".order-number");
310                },
311              );
312            },
313            lineItems: {
314              _id: () => {
315                return Evergage.DisplayUtils.pageElementLoaded(
316                  ".product-line-item line-item-quantity-info",
317                  "html",
318                ).then((ele) => {
319                  return Evergage.resolvers.fromSelectorAttributeMultiple(
320                    ".product-line-item .line-item-quantity-info",
321                    "data-pid",
322                  );
323                });
324              },
325              price: () => {
326                return Evergage.DisplayUtils.pageElementLoaded(
327                  ".product-line-item .pricing",
328                  "html",
329                ).then((ele) => {
330                  return Evergage.resolvers.fromSelectorAttributeMultiple(
331                    ".product-line-item .pricing",
332                    "data-pid",
333                  );
334                });
335              },
336              quantity: () => {
337                return Evergage.DisplayUtils.pageElementLoaded(
338                  ".product-line-item .qty-card-quantity-count",
339                  "html",
340                ).then((ele) => {
341                  return Evergage.resolvers.fromSelectorAttributeMultiple(
342                    ".product-line-item .qty-card-quantity-count",
343                    "data-pid",
344                  );
345                });
346              },
347            },
348          },
349        },
350      },
351      {
352        name: "login",
353        action: "Login",
354        isMatch: () =>
355          /\/login/.test(window.location.href) &&
356          window.location.hostname !== "community.northerntrailoutfitters.com",
357        listeners: [
358          Evergage.listener("click", "form[name='login-form'] button", () => {
359            const email = Evergage.cashDom("#login-form-email").val();
360            if (email) {
361              Evergage.sendEvent({
362                action: "Logged In",
363                user: { attributes: { emailAddress: email } },
364              });
365            }
366          }),
367        ],
368      },
369      {
370        name: "home",
371        action: "Homepage",
372        isMatch: () => /\/homepage/.test(window.location.href),
373        contentZones: [
374          { name: "home_hero", selector: ".experience-carousel-bannerCarousel" },
375          {
376            name: "home_sub_hero",
377            selector: ".experience-carousel-bannerCarousel + .experience-component",
378          },
379          { name: "home_popup" },
380        ],
381      },
382      {
383        name: "community_login",
384        action: "Community Login",
385        isMatch: () =>
386          window.location.hostname === "community.northerntrailoutfitters.com" &&
387          /\/s\/login/.test(window.location.href),
388        listeners: [
389          Evergage.listener("click", ".loginButton", (event) => {
390            const email = Evergage.cashDom("input[placeholder='Email']").val();
391            if (email) {
392              Evergage.sendEvent({
393                action: "Community Log In",
394                user: { attributes: { emailAddress: email } },
395              });
396            }
397          }),
398        ],
399      },
400      {
401        name: "community_home",
402        action: "Community Homepage",
403        isMatch: () => {
404          return (
405            window.location.hostname === "community.northerntrailoutfitters.com" &&
406            /^\/s\/?$/.test(window.location.pathname)
407          );
408        },
409        listeners: [
410          Evergage.listener("click", "li.topicItem", (event) => {
411            const topicLabel = Evergage.cashDom(event.currentTarget)
412              .find(".topicLabel")
413              .text()
414              .trim();
415            if (topicLabel) {
416              Evergage.sendEvent({ action: "Community Homepage - " + topicLabel });
417            }
418          }),
419        ],
420      },
421    ],
422  };
423  const getProductsFromDataLayer = () => {
424    if (window.dataLayer) {
425      for (let i = 0; i < window.dataLayer.length; i++) {
426        if (
427          ((window.dataLayer[i].ecommerce && window.dataLayer[i].ecommerce.detail) || {}).products
428        ) {
429          return window.dataLayer[i].ecommerce.detail.products;
430        }
431      }
432    }
433  };
434  Evergage.initSitemap(config);
435});