Source: components/instant-search/instant-search-item/instant-search-result-item-product.js

import jQ from "jquery";

import Utils from "../../../helpers/utils";
import Class from "../../../helpers/class";
import Settings from "../../../helpers/settings";
import Globals from "../../../helpers/globals";
import InstantSearchResultItem from "./instant-search-result-item";

/**
 * Instant search result item - Product item
 * @extends InstantSearchResultItem
 */
class InstantSearchResultItemProduct extends InstantSearchResultItem {
	/**
	 * @constructs
	 */
	constructor() {
		super();
		this.id = '';
		this.title = '';
		this.imageUrl = '';
		this.url = '';
		this.sku = '';
		this.label = '';
		this.vendor = '';

		this.isShow = false;
	}

	/**
	 * Enum of Product item templates (SKU, VENDOR, IMAGE, PRICE_SALE)
	 * @enum {Object}
	 */
	static get tempType() {
		return {
			SKU: 'sku',
			VENDOR: 'vendor',
			IMAGE: 'thumb',
			PRICE: 'regular_price',
			PRICE_SALE: 'sale_price'
		};
	}
	
	/**
	 * Get the raw template of Instant search result item - Product item
	 * @returns {String} The raw HTML string
	 */
	getTemplate(tempType) {
		switch (tempType) {
			case InstantSearchResultItemProduct.tempType.IMAGE:
				return `
					<div class="{{class.searchSuggestion}}-left">
						<img src="{{imageUrl}}" alt="{{escapedTitle}}">
					</div>
				`;
			case InstantSearchResultItemProduct.tempType.SKU:
				return `
					<p class="{{class.searchSuggestion}}-product-sku">SKU: {{sku}}</p>
				`;
			case InstantSearchResultItemProduct.tempType.VENDOR:
				return `
					<p class="{{class.searchSuggestion}}-product-vendor">{{vendor}}</p>
				`;
			case InstantSearchResultItemProduct.tempType.PRICE:
				return `
					<p class="{{class.searchSuggestion}}-product-price">
						<span class="{{class.searchSuggestion}}-product-regular-price">{{regularPrice}}</span>
					</p>
				`;
			case InstantSearchResultItemProduct.tempType.PRICE_SALE:
				return `
					<p class="{{class.searchSuggestion}}-product-price">
						<s>{{compareAtPrice}}</s>&nbsp;
						<span class="{{class.searchSuggestion}}-product-sale-price">{{regularPrice}}</span>
					</p>
				`;
			default:
				return `
					<li class="{{class.searchSuggestionItem}} {{class.searchSuggestionItem}}-product {{class.searchUiAutocompleteItem}}" aria-label="{{escapedBlockType}}: {{escapedTitle}}" data-id="{{id}}">
						<a href="{{url}}" {{newTabAttribute}}>
							{{itemProductImage}}
							<div class="{{class.searchSuggestion}}-right">
								<p class="{{class.searchSuggestion}}-product-title">{{title}}</p>
								{{itemProductSku}}
								{{itemProductVendor}}
								{{itemProductPrice}}
							</div>
						</a>
					</li>
				`;
		}
	}

	/**
	 * Replace the brackets in raw html template with proper values
	 * @returns {String} HTML string
	 */
	compileTemplate() {
		if (this.isShow) {
			var searchTerm = Utils.escape(Globals.currentTerm);
			// Product image
			var imageHTML = '';
			if (Settings.getSettingValue('search.showSuggestionProductImage') && this.imageUrl.length) {
				imageHTML = this.getTemplate(InstantSearchResultItemProduct.tempType.IMAGE);
				imageHTML = imageHTML.replace(/{{imageUrl}}/g, this.imageUrl);
			}
			// Product title
			var productTitle = this.customizeProductTitle();
			productTitle = this._highlightSuggestionResult(productTitle, searchTerm);
			// SKU
			var skuHTML = '';
			if (Settings.getSettingValue('search.showSuggestionProductSku') && this.sku.length) {
				skuHTML = this.getTemplate(InstantSearchResultItemProduct.tempType.SKU);
				skuHTML = skuHTML.replace(/{{sku}}/g, this.sku);
			}
			// Vendor
			var vendorHTML = '';
			if (Settings.getSettingValue('search.showSuggestionProductVendor') && this.vendor.length) {
				vendorHTML = this.getTemplate(InstantSearchResultItemProduct.tempType.VENDOR);
				vendorHTML = vendorHTML.replace(/{{vendor}}/g, this.vendor);
			}
			// Price
			var priceHTML = this.compileSuggestionProductPrice();
			// Open the result item in new tab when selected
			var newTabAttr = Settings.getSettingValue('search.openProductNewTab') ? 'target="_blank"' : '';

			return this.getTemplate()
				.replace(/{{id}}/g, this.id)
				.replace(/{{escapedBlockType}}/g, Utils.escape(this.parent.type))
				.replace(/{{url}}/g, this.url)
				.replace(/{{newTabAttribute}}/g, newTabAttr)
				.replace(/{{itemProductImage}}/g, imageHTML)
				.replace(/{{title}}/g, productTitle)
				.replace(/{{escapedTitle}}/g, Utils.escape(productTitle))
				.replace(/{{itemProductSku}}/g, skuHTML)
				.replace(/{{itemProductVendor}}/g, vendorHTML)
				.replace(/{{itemProductPrice}}/, priceHTML)
				.replace(/{{class.searchSuggestion}}/g, Class.searchSuggestion)
				.replace(/{{class.searchSuggestionItem}}/g, Class.searchSuggestionItem)
				.replace(/{{class.searchUiAutocompleteItem}}/g, Class.searchUiAutocompleteItem);
		} else {
			return '';
		}
	}

	/**
	 * Render the Instant search result item - Product item
	 * @returns {Object} jQuery object
	 */
	render() {
		if (this.isShow) {
			this.$element = jQ(this.compileTemplate());
			// Set item data for ui-autocomplete-item
			var type = Utils.escape(this.parent.type);
			var title = Utils.escape(this.title);
			this.$element.data('ui-autocomplete-item', {
				label: type + ': ' + title,
				value: title
			});
		} else {
			this.$element = null;
		}
	}

	/**
	 * Set data for Instant search result item - Product item
	 * @param {Object} data Instant search result item data
	 */
	setData(data) {
		if (data) {
			this.data = data;
			this.id = data.id;
			this.title = data.title;
			this.imageUrl = data.images_info.length > 0 ? Utils.optimizeImage(data.images_info[0].src, '200x') : boostPFSConfig.general.no_image_url;
			this.url = Utils.buildProductItemUrl(data, false);
			this.sku = data.skus && data.skus.length > 0 ? data.skus[0] : '';
			this.label = data.label;
			this.vendor = data.vendor;
			this.isShow = true;
		} else {
			this.data = null;
			this.id = '';
			this.title = '';
			this.imageUrl = '';
			this.url = '';
			this.sku = '';
			this.label = '';
			this.vendor = '';
			
			this.isShow = false;
		}
	}

	/**
	 * Build the product price and replace with the brackets in raw html template
	 */
	compileSuggestionProductPrice() {
		// If the multi-currency feature is enabled, update the product price
		this.prepareSuggestionProductPriceData();
		// Check on sale
		var onSale = this.data.compare_at_price_min > this.data.price_min;
		// Format price
		var price = Utils.formatMoney(this.data.price_min);
		var compareAtPrice = '';
		if (this.data && this.data.compare_at_price_min) {
			compareAtPrice = Utils.formatMoney(this.data.compare_at_price_min);
			if (Settings.getSettingValue('search.removePriceDecimal')) {
				price = Utils.removeDecimal(price);
				compareAtPrice = Utils.removeDecimal(compareAtPrice);
			}
		}
		
		// Build Price
		var result = '';
		if (Settings.getSettingValue('search.showSuggestionProductPrice')) {
			if (onSale && Settings.getSettingValue('search.showSuggestionProductSalePrice')) {
				result = this.getTemplate(InstantSearchResultItemProduct.tempType.PRICE_SALE);
			} else {
				result = this.getTemplate(InstantSearchResultItemProduct.tempType.PRICE);
			}
		}
		return result
			.replace(/{{regularPrice}}/g, price)
			.replace(/{{compareAtPrice}}/g, compareAtPrice);
	}

	/**
	 * Customize the Isntant search result item - product title
	 */
	customizeProductTitle() {
		// Override this method for customization
		return this.title;
	}

	/**
	 * Prepare product price data for multi-currency feature
	 */
	prepareSuggestionProductPriceData() {
		var currenciesSeting = Settings.getSettingValue('general.currencies');
		if (typeof currenciesSeting != 'undefined' && currenciesSeting.length > 1) {
			var currentCurrency = Settings.getSettingValue('general.current_currency').toLowerCase().trim();
			var prices = ['price_min', 'price_max', 'compare_at_price_min', 'compare_at_price_max'];
			prices.forEach((priceKey) => {
				var currentPriceKey = priceKey + '_' + currentCurrency;
				if (typeof this.data[currentPriceKey] !== 'undefined') {
					this.data[priceKey] = this.data[currentPriceKey];
				}
			});
		}
	}
}

export default InstantSearchResultItemProduct;