1var eventDataFPI; 2 3const dyScripts = () => { 4 sendContext(); 5 window.DY_EXT = { 6 _dyInitialFetchPromiseResolutionMap: {}, 7 _dyCampaignsMap: {}, 8 _initialFetchProgressTrackerMap: {}, 9 _variationPromiseMap: {}, 10 11 getVariations: function getVariations({ tags, campaigns } = {}) { 12 13 function sendErrorMessage(msg) { 14 return { 15 "message": { 16 "message": msg 17 } 18 } 19 } 20 21 function fetchVariations({ tags, campaigns }) { 22 let page = 'other'; 23 if (window.location.pathname === "/" || window.__pageType === "homepage") 24 page = 'homepage'; 25 26 let url = "/ext/dynamic-yield/application/api/v1.0/variations"; 27 28 const params = { 29 tags: tags, 30 campaigns: campaigns, 31 page: page 32 }; 33 34 const cleanParams = {}; 35 36 for (const key in params) { 37 if (params[key]) 38 cleanParams[key] = params[key]; 39 } 40 41 if (cleanParams && Object.keys(cleanParams).length > 0) 42 url += '?' + new URLSearchParams(cleanParams); 43 44 return fetch(url, { 45 method: "GET", 46 headers: { "Content-Type": "application/json" } 47 }); 48 } 49 50 return new Promise(async (resolve, reject) => { 51 52 if (!tags || !tags.length) 53 return reject(sendErrorMessage(`'tags' not found`)); 54 55 if (!campaigns || !campaigns.length) 56 return reject(sendErrorMessage(`'campaigns' not found)`)); 57 58 if (!this._variationPromiseMap[tags]) 59 this._variationPromiseMap[tags] = new Promise(resolve => this._dyInitialFetchPromiseResolutionMap[tags] = resolve); 60 61 if (this._initialFetchProgressTrackerMap[tags]) 62 await this._variationPromiseMap[tags]; 63 64 if (!(tags in this._initialFetchProgressTrackerMap)) 65 this._initialFetchProgressTrackerMap[tags] = true; 66 67 const globalCampaignList = this._dyCampaignsMap[tags] || []; 68 69 if (globalCampaignList && globalCampaignList.length) { 70 const extractedCampaign = globalCampaignList.find(globalCampaign => campaigns === globalCampaign.meta.campaignName); 71 72 if (extractedCampaign) { 73 return resolve({ data: extractedCampaign }); 74 } 75 } 76 77 if (!this._initialFetchProgressTrackerMap[tags]) 78 return reject(sendErrorMessage(`Campaign '${campaigns}' does not exist in cached tag '${tags}' data`)); 79 80 fetchVariations({ tags }) 81 .then((response) => response.json()) 82 .then((campaignResp) => { 83 this._dyCampaignsMap[tags] = []; 84 if (campaignResp && campaignResp.message) 85 return reject(campaignResp.message); 86 87 if (campaignResp && campaignResp.data && campaignResp.data.length) { 88 89 this._dyCampaignsMap[tags] = campaignResp.data; 90 const extractedCampaign = campaignResp.data.find(globalCampaign => campaigns === globalCampaign.meta.campaignName); 91 92 if (extractedCampaign) 93 return resolve({ data: extractedCampaign }); 94 95 return reject(sendErrorMessage(`Campaign '${campaigns}' does not exist in tag '${tags}'`)); 96 } 97 98 return reject(sendErrorMessage(`Tag '${tags}' does not contain any campaigns`)); 99 }) 100 .catch((err) => { 101 this._dyCampaignsMap[tags] = []; 102 console.error("Request failed", err); 103 reject(err); 104 }) 105 .finally(() => { 106 this._dyInitialFetchPromiseResolutionMap[tags](); 107 this._initialFetchProgressTrackerMap[tags] = false; 108 }); 109 }) 110 111 } 112 113 } 114 function reportEngagement(eventData) { 115 fetch("/ext/dynamic-yield/application/api/v1.0/report-engagement", { 116 method: "POST", 117 headers: { "Content-Type": "application/json" }, 118 body: JSON.stringify({ 119 engagements: eventData.engagements, 120 channel: "web", 121 }), 122 }) 123 .then((res) => { }) 124 .catch((err) => { 125 console.error("Request failed", err); 126 }); 127 } 128 129 function sendContext() { 130 131 if (!document.cookie.includes("_dyid_server")) { 132 fetch("/ext/dynamic-yield/application/api/v1.0/report-pageview") 133 .then((response) => { 134 if (response.ok) { 135 return; 136 } 137 throw new Error("Something went wrong in pageview API"); 138 }) 139 .catch((error) => { 140 console.error("Something went wrong in pageview API", error); 141 }); 142 } 143 144 if (window.location.pathname === "/") { 145 DY.recommendationContext = { type: "HOMEPAGE" }; 146 return; 147 } 148 149 if ( 150 /cart\/bag/.test(window.location.href) || 151 /product\//.test(window.location.href) || 152 /collection\//.test(window.location.href) || 153 /products/.test(window.location.href) 154 ) { 155 return; 156 } 157 158 if (window.__pageType === "homepage") { 159 DY.recommendationContext = { type: "HOMEPAGE" }; 160 } else { 161 DY.recommendationContext = { type: "OTHER" }; 162 } 163 return; 164 } 165 166 (function () { 167 var pushState = history.pushState; 168 var replaceState = history.replaceState; 169 170 history.pushState = function () { 171 pushState.apply(history, arguments); 172 window.dispatchEvent(new Event("pushstate")); 173 window.dispatchEvent(new Event("locationchange")); 174 }; 175 176 history.replaceState = function () { 177 replaceState.apply(history, arguments); 178 window.dispatchEvent(new Event("replacestate")); 179 window.dispatchEvent(new Event("locationchange")); 180 }; 181 182 window.addEventListener("popstate", function () { 183 window.dispatchEvent(new Event("locationchange")); 184 }); 185 })(); 186 187 function shouldSkipProductPage(productId) { 188 const oldProductId = DY?.recommendationContext?.data?.[0]; 189 return ( 190 oldProductId && 191 oldProductId === productId && 192 DY.recommendationContext?.type === 'PRODUCT' 193 ); 194 } 195 196 function handleProductPage() { 197 const urlPath = window.location.pathname; 198 const productUrlMatch = urlPath.match(/\/product\/([^\/]+)/); 199 200 if (!productUrlMatch) return; 201 202 const productVariable = productUrlMatch[1]; 203 console.log("Product page detected", productVariable); 204 205 const reportProductView = function (data) { 206 const productId = 207 data?.product?.uid?.toString() || data?.uid?.toString(); 208 209 if (!productId) return; 210 211 if (shouldSkipProductPage(productId)) { 212 console.log("Skipping product view - already set", productId); 213 return; 214 } 215 216 console.log("reportProductView", productId); 217 218 DY.recommendationContext = { 219 type: "PRODUCT", 220 data: [productId], 221 }; 222 }; 223 224 const productViewIntervalId = setInterval(() => { 225 if (!window.fpi || !fpi.observeStore) return; 226 227 clearInterval(productViewIntervalId); 228 let unsubscribe; 229 unsubscribe = fpi.observeStore( 230 fpi.getters.PRODUCT_DETAILS, 231 (newProductState) => { 232 reportProductView(newProductState) 233 unsubscribe && unsubscribe(); 234 } 235 ); 236 }, 50); 237 } 238 239 window.addEventListener("locationchange", function () { 240 sendContext(); 241 window.DY_EXT._dyCampaignsMap = {}; 242 window.DY_EXT._dyInitialFetchPromiseResolutionMap = {}; 243 window.DY_EXT._initialFetchProgressTrackerMap = {}; 244 window.DY_EXT._variationPromiseMap = {}; 245 handleProductPage(); 246 }); 247 248 // Check on initial load 249 handleProductPage(); 250 251 FPI.event.on("cart.view", function (eventData) {
252 let cartItems = []; 253 eventData.products.forEach((item) => { 254 cartItems.push(item.uid.toString()); 255 }); 256 DY.recommendationContext = { type: "CART", data: cartItems }; 257 return; 258 }); 259 260 FPI.event.on("custom.category_viewed", function (eventData) { 261 DY.recommendationContext = { 262 type: "CATEGORY", 263 data: eventData.categories || [], 264 }; 265 return; 266 }); 267 268 var getCartState = function (data) { 269 let items = data?.all_cart_data?.items || data?.items; 270 let cartItems = []; 271 items.forEach((item) => { 272 cartItems.push({ 273 productId: item?.product?.uid?.toString(), 274 quantity: item.quantity, 275 itemPrice: item?.price?.base?.effective / item?.quantity, 276 }); 277 }); 278 if (!window.fpi) 279 FPI.state.cart.unsubscribe(data); 280 281 if (window.eventDataFPI?.event_action === "cart.remove") { 282 window.eventDataFPI.products.forEach((item) => { 283 let productIndex = cartItems.findIndex( 284 (x) => x.productId === item.uid.toString() 285 ); 286 if (productIndex > -1) { 287 cartItems.splice(productIndex, 1); 288 } 289 DY.API("event", { 290 name: "Remove from Cart", 291 properties: { 292 dyType: "remove-from-cart-v1", 293 value: item.price.effective, 294 productId: item.uid.toString(), 295 quantity: item.quantity.current, 296 currency: item.price.currency_code, 297 cart: cartItems, 298 }, 299 }); 300 }); 301 } else if (window.eventDataFPI?.event_action === "cart.newProduct") { 302 window.eventDataFPI.products.forEach((item) => { 303 DY.API("event", { 304 name: "Add to Cart", 305 properties: { 306 dyType: "add-to-cart-v1", 307 value: item.price.effective / item.quantity.current, 308 productId: item.uid.toString(), 309 quantity: 1, 310 currency: item.price.currency_code, 311 cart: cartItems, 312 }, 313 }); 314 }); 315 } else if (window.eventDataFPI?.event_action === "cart.update") { 316 if (window.eventDataFPI?.operation === "increment_quantity") { 317 window.eventDataFPI.products.forEach((item) => { 318 let productIndex = cartItems.findIndex( 319 (x) => x.productId === item.uid.toString() 320 ); 321 if (productIndex > -1) { 322 cartItems[productIndex] = { 323 productId: cartItems[productIndex].productId, 324 quantity: cartItems[productIndex].quantity, 325 itemPrice: cartItems[productIndex].itemPrice, 326 }; 327 } 328 DY.API("event", { 329 name: "Add to Cart", 330 properties: { 331 dyType: "add-to-cart-v1", 332 value: item.price_per_unit.base.effective, 333 productId: item.uid.toString(), 334 quantity: 1, 335 currency: item.price_per_unit.base.currency_code, 336 cart: cartItems, 337 }, 338 }); 339 }); 340 } else if (window.eventDataFPI?.operation === "decrement_quantity") { 341 window.eventDataFPI.products.forEach((item) => { 342 let productIndex = cartItems.findIndex( 343 (x) => x.productId === item.uid.toString() 344 ); 345 if (productIndex > -1) { 346 if (cartItems[productIndex].quantity < 1) { 347 cartItems.splice(productIndex, 1); 348 } else { 349 cartItems[productIndex] = { 350 productId: cartItems[productIndex].productId, 351 quantity: cartItems[productIndex].quantity, 352 itemPrice: cartItems[productIndex].itemPrice, 353 }; 354 } 355 } 356 DY.API("event", { 357 name: "Remove from Cart", 358 properties: { 359 dyType: "remove-from-cart-v1", 360 value: item.price_per_unit.base.effective, 361 productId: item.uid.toString(), 362 quantity: 1, 363 currency: item.price_per_unit.base.currency_code, 364 cart: cartItems, 365 }, 366 }); 367 }); 368 } 369 } 370 }; 371 372 FPI.event.on("cart.newProduct", function (eventData) { 373 eventDataFPI = eventData; 374 if (window.fpi) { 375 eventDataFPI.event_action = "cart.newProduct"; 376 const unsubscribe = fpi.observeStore( 377 fpi.getters.CART_ITEMS,
378 (newCartState) => { 379 getCartState(newCartState); 380 } 381 ); 382 unsubscribe(); 383 return; 384 } 385 FPI.state.cart.subscribe(getCartState); 386 FPI.state.cart.unsubscribe(getCartState); 387 }); 388 389 FPI.event.on("cart.remove", function (eventData) { 390 eventDataFPI = eventData; 391 if (window.fpi) { 392 eventDataFPI.event_action = "cart.remove"; 393 const unsubscribe = fpi.observeStore( 394 fpi.getters.CART_ITEMS, 395 (newCartState) => { 396 getCartState(newCartState); 397 } 398 ); 399 unsubscribe(); 400 return; 401 } 402 FPI.state.cart.subscribe(getCartState); 403 FPI.state.cart.unsubscribe(getCartState); 404 }); 405 406 FPI.event.on("cart.update", function (eventData) { 407 eventDataFPI = eventData; 408 if (window.fpi) { 409 eventDataFPI.event_action = "cart.update"; 410 const unsubscribe = fpi.observeStore( 411 fpi.getters.CART_ITEMS, 412 (newCartState) => { 413 getCartState(newCartState); 414 } 415 ); 416 unsubscribe(); 417 return; 418 } 419 FPI.state.cart.subscribe(getCartState); 420 FPI.state.cart.unsubscribe(getCartState); 421 }); 422 423 FPI.event.on("cart.view", function (eventData) {
424 let cartItems = []; 425 eventData.products.forEach((item) => { 426 cartItems.push({ 427 productId: item.uid.toString(), 428 quantity: item.quantity.current, 429 itemPrice: item.price.effective / item.quantity.current, 430 }); 431 }); 432 DY.API("event", { 433 name: "Sync cart", 434 properties: { 435 dyType: "sync-cart-v1", 436 currency: "INR", 437 cart: cartItems, 438 }, 439 }); 440 }); 441 442 FPI.event.on("wishlist.add", function (eventData) { 443 DY.API("event", { 444 name: "Add to Wishlist", 445 properties: { 446 dyType: "add-to-wishlist-v1", 447 productId: eventData?.item?.uid?.toString(), 448 }, 449 }); 450 }); 451 452 FPI.event.on("custom.product_searched", function (eventData) { 453 DY.API("event", { 454 name: "Keyword Search", 455 properties: { 456 dyType: "keyword-search-v1", 457 keywords: eventData.query || "", 458 }, 459 }); 460 }); 461 462 FPI.event.on("order.processed", function (eventData) { 463 let purchasedItems = []; 464 eventData.items.forEach((item) => { 465 //skip items with price < 5 466 if (item?.price?.price_effective < 5) { 467 return; 468 } 469 470 const productId = item.id.toString(); 471 const price = Number(item?.price?.price_effective); 472 473 const isFound = purchasedItems.findIndex((element) => { 474 if (element.productId === productId) { 475 return true; 476 } else { 477 return false; 478 } 479 }); 480 if (isFound >= 0) { 481 purchasedItems[isFound] = { 482 ...purchasedItems[isFound], 483 quantity: purchasedItems[isFound].quantity + item?.quantity, 484 }; 485 } else { 486 purchasedItems.push({ 487 productId, 488 quantity: item?.quantity, 489 itemPrice: Number.isFinite(price) ? price : 0, 490 size: item?.size, 491 }); 492 } 493 }); 494 console.log("purchasedItems", purchasedItems); 495 console.log("eventData", eventData); 496 497 DY.API("event", { 498 name: "Purchase", 499 properties: { 500 uniqueTransactionId: eventData?.order_id, 501 dyType: "purchase-v1", 502 value: eventData?.breakup_values_raw?.total, 503 currency: "INR", 504 cart: purchasedItems, 505 }, 506 }); 507 }); 508 509 FPI.event.on("user.login", function (eventData) { 510 DY.API("event", { 511 name: "Login", 512 properties: { 513 dyType: "login-v1", 514 cuid: eventData.user_id, 515 cuidType: "external", 516 }, 517 }); 518 }); 519 520 FPI.event.on("custom.user_register", function (eventData) { 521 DY.API("event", { 522 name: "Signup", 523 properties: { 524 dyType: "signup-v1", 525 cuid: eventData.user_id, 526 cuidType: "external", 527 gender: eventData.gender, 528 }, 529 }); 530 }); 531 532 533 FPI.event.on("custom.recommended_product_clicked", function (eventData) { 534 reportEngagement(eventData); 535 }); 536 537 FPI.event.on("custom.recommended_banner_clicked", function (eventData) { 538 reportEngagement(eventData); 539 }); 540} 541const intervalId = setInterval(() => { 542 if (typeof DY !== 'undefined' && window.fpi) { 543 clearInterval(intervalId); 544 dyScripts(); 545 } 546}, 30);
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.