Add the script to fully customize the recommendation widget
var STOCK_STATUS_VARIANT_NAME = "Sellable"; // The name of the variant attribute that has holds the stock status
var TAG_VARIANT_NAME = "Tag";
var IN_STORE_TAG_NAME = "AVAILBLEINSTORE"; // if exist product is available in store
var ONLINE_TAG_NAME = "AVAILABLEONLINE"; // if exist product is available in online
/**
* isp_slickSetup - hold the setup for each recommendation slick element
*
* @type: JSON
*/
const isp_slickSetup_base = {
lazyLoad: 'ondemand',
dots: false,
infinite: true,
arrows: true,
prevArrow: '<button type="button" class="isp-widget-arrow prev"></button>',
nextArrow: '<button type="button" class="isp-widget-arrow next"</button>',
speed: 400,
slidesToShow: 4,
slidesToScroll: 3,
responsive: [{
breakpoint: 1024,
settings: {
slidesToShow: 3,
}
}, {
breakpoint: 800,
settings: {
slidesToShow: 2,
}
}, {
breakpoint: 500,
settings: "unslick" // destroys slick
}]
};
const isp_slickSetup = {
"Fun stuff you may also love": {
...isp_slickSetup_base,
slidesToShow: 3,
slidesToScroll: 3,
responsive: [{
breakpoint: 1024,
settings: {
slidesToShow: 3,
}
}, {
breakpoint: 800,
settings: {
slidesToShow: 2,
}
}, {
breakpoint: 500,
settings: "unslick" // destroys slick
}]
},
"Recently viewed items": {
...isp_slickSetup_base,
slidesToShow: 5,
slidesToScroll: 3,
responsive: [{
breakpoint: 1024,
settings: {
slidesToShow: 4,
}
}, {
breakpoint: 800,
settings: {
slidesToShow: 2,
}
}, {
breakpoint: 500,
settings: "unslick" // destroys slick
}]
},
"What’s new and now!":{
...isp_slickSetup_base,
slidesToShow: 3,
slidesToScroll: 3,
responsive: [{
breakpoint: 1024,
settings: {
slidesToShow: 3,
}
}, {
breakpoint: 800,
settings: {
slidesToShow: 2,
}
}, {
breakpoint: 500,
settings: "unslick" // destroys slick
}]
},
"default" : {
...isp_slickSetup_base,
}
};
// related options are in charge of the recommendation widget customization
var isp_related_options = {
with_product_attributes: true, // add attributes to the request to get access to product tags (default is false)
/**
* Handle the response of the recommendation request (REST API)
*
* @param response JSON Object
*/
custom_related_products_render: response => {
response.widget_responses.forEach((widgetData, index) => {
const {products, title} = widgetData;
const widgetID = `#isp-related-widget-${index+1}`;
$jquery_isp(widgetID).append(getWidgetHtml(products, title));
$jquery_isp(`${widgetID} .isp_custom_product_carousel`).slick(isp_slickSetup[title] || isp_slickSetup["default"]);
});
// Legacy (get rid of containers)
$jquery_isp(".recently-view-products .sixteen.columns").attr("class","");
$jquery_isp(".recently-view-products .container").attr("class","");
$jquery_isp('.recently-view-products').attr("class","");
$jquery_isp(".related-products .sixteen.columns").attr("class","");
$jquery_isp(".related-products .container").attr("class","");
$jquery_isp('.related-products').attr("class","");
}
};
/**
* Create Widget HTML
*
* @param products - the product from the recommendation response
* @param title - the name of the widget
* @returns {String} (HTML)
*/
const getWidgetHtml = (products, title) => {
let retHtml = `<div id="custom-recommendations-widget" class="isp-recommendations-widget">`;
retHtml += `<h3 class="isp-recommendations-title">${title}</h3>`;
retHtml += getProductCarousel(products);
retHtml += '<div>';
return retHtml;
};
/**
* Create HTML for the product carousel
*
* @param products - the product from the recommendation response
* @returns {String} (HTML)
*/
const getProductCarousel = (products) => {
let carouselHTML = '<div class="isp_custom_product_carousel" >';
products.forEach(product => {
// badge HTML
const badgeCount = product.b ? product.b.length : 0;
carouselHTML += `<div class="isp-custom-product-card" productID="${product.id}" badge-count="${badgeCount}">`;
carouselHTML += `<div class="isp-product-top-bar">`;
carouselHTML += `<div class="isp-badge-container">`;
if(product.b){
product.b.forEach(badge => {
carouselHTML += `<span class="isp_badge" type="${badgeList[badge].toLowerCase()}">${badgeList[badge]}</span>`;
});
}
carouselHTML += `</div>`; // close isp-badge-container
// Favorite Button HTML
const productFirstVariant = product.vra && product.vra.length > 0 ? product.vra[0][0] : product.id;
carouselHTML += `<button class="swym-button swym-add-to-wishlist-view-product product_${product.id}" data-swaction="addToWishlist" data-with-epi="true" data-product-id="${product.id}" data-variant-id="${productFirstVariant}"></button>`;
carouselHTML += `</div>`; // isp-product-top-bar
//Product image HTML
carouselHTML += `<a class="isp-product-card-image-container" href="${product.u}">`;
carouselHTML += `<img class="isp-product-card-image" src="${product.t}" alt="product image">`;
carouselHTML += `</a>`;
//Product info HTML
carouselHTML += '<div class="isp-product-card-info">';
carouselHTML += `<a class="isp-product-title-container" href="${product.u}">`;
carouselHTML += `<div class="isp-product-card-title">${product.l}</div>`;
carouselHTML += `</a>`;
carouselHTML += `<div class="isp-product-card-price">$${product.p}</div>`;
//Product Stock status HTML
carouselHTML += getStockInfoHTMLRecommendations(product);
carouselHTML += '</div></div>'; // Close info, close product tile
});
carouselHTML += '</div>'; // close carousel
return carouselHTML;
};
const getStockInfoHTMLRecommendations = (product) => {
let retHTML = `<div class="isp-product-stock-info-container">`;
const productStockStatus = isProductInStockRecommendations(product);
const inStockIcon = productStockStatus ? "store-icon" : "not-store-icon";
const inStockText = productStockStatus ? "Available online" : "Not available online";
retHTML += `<div class="label-container"><span class="${inStockIcon}"></span><div class="isp-label isStock">${inStockText}</div></div>`;
const productStoreStatus = isProductInStoreRecommendations(product);
const inStoreIcon = productStoreStatus ? "store-icon" : "not-store-icon";
const inStoreText = productStoreStatus ? "Available in-store" : "Not available in-store";
retHTML += `<div class="label-container"><span class="${inStoreIcon}"></span><div class="isp-label isStore">${inStoreText}</div></div>`;
return retHTML + '</div>'
};
/**
* Check stock status for a single product by looking for ONLINE_TAG_NAME
*
* @param product
* @returns {boolean}
*/
const isProductInStockRecommendations = (product) =>{
if(product.att){
const tags = product.att.find(attribute => attribute[0] === TAG_VARIANT_NAME);
return tags ? tags[1].find(tag => tag === ONLINE_TAG_NAME) : false;
}
return false;
};
/**
* Check in store stock status by checking the product tag by looking for IN_STORE_TAG_NAME
*
* @param product
* @returns {boolean}
*/
const isProductInStoreRecommendations = (product) => {
if(product.att){
const tags = product.att.find(attribute => attribute[0] === TAG_VARIANT_NAME);
return tags ? tags[1].find(tag => tag ===IN_STORE_TAG_NAME) : false;
}
return false;
};