UNPKG

@salla.sa/twilight-components

Version:
165 lines (159 loc) 9.95 kB
/*! * Crafted with ❤ by Salla */ 'use strict'; var index = require('./index-Oy30xVAt.js'); var DiscountType; (function (DiscountType) { DiscountType["PERCENTAGE"] = "percentage"; DiscountType["FIXED"] = "fixed"; DiscountType["FREE_PRODUCT"] = "free_product"; })(DiscountType || (DiscountType = {})); var OfferType; (function (OfferType) { OfferType["PRODUCT_COUNT"] = "products_count"; OfferType["PRODUCT_PURCHASE"] = "order_amount"; })(OfferType || (OfferType = {})); const sallaConditionalOfferCss = ":host{display:block}"; const SallaConditionalOffer = class { constructor(hostRef) { index.registerInstance(this, hostRef); this.offer = null; this.products = {}; this.isLoading = false; this.canRender = true; } componentWillLoad() { salla.onReady().then(() => { if (!salla.config.get('store.features')?.includes('conditional-offer') || (salla.storage.get("cart") !== '' && !salla.storage.get("cart")?.summary?.count)) { throw new Error('feature or cart object does not existed'); } }) .then(() => salla.api.cart.offers()) .then(({ data }) => { this.offer = data.find(offer => offer.type === "conditional"); if (!this.offer) { this.canRender = false; return; } this.isLoading = true; this.offer.details.discounts.unshift(({ value: 0, min_spend: 0 })); return this.updateInitialOfferValue(); }).then(() => { if (!this.offer) return; return this.getProducts(); }).then(() => { if (!this.offer) return; salla.event.on("cart::updated", (updatedCart) => this.updateOfferValues(updatedCart)); }) .catch(error => { this.canRender = false; salla.logger.warn('salla-conditional-offer:: ', error); }).finally(() => { this.isLoading = false; }); } getProducts() { const freeProductIDs = this.offer.details.discounts.filter(({ type }) => type === DiscountType.FREE_PRODUCT).map(({ value }) => value).filter(Boolean); if (freeProductIDs.length > 0) { return salla.product.fetch({ source: 'selected', source_value: freeProductIDs }).then((response) => { const data = response?.data; if (data && Array.isArray(data)) { const updatedProducts = { ...this.products }; data.forEach(({ id, url, image, name, price }) => { if (id && name && image?.url && url && price !== undefined) { updatedProducts[id] = { url, image, name, price }; } }); this.products = updatedProducts; } }); } } updateInitialOfferValue() { return salla.api.cart.details().then(({ data: { cart } }) => this.updateOfferValues(cart)); } updateOfferValues({ items, sub_total }) { const current_value = this.offer.details.based_on === OfferType.PRODUCT_COUNT ? items?.reduce((count, { quantity }) => count + quantity, 0) ?? 0 : sub_total; //we need to assign the offer object a new reference to trigger re-rendering this.offer = { ...this.offer, details: { ...this.offer?.details, current_value, } }; return this.offer; } renderTooltip(discount) { const productId = discount.value; const productItem = this.products[productId]; const targetId = `avatar-product-${productId}`; if (!productItem) { salla.logger.error(`salla-conditional-offer:: there is no product with id (${discount.value})!`); return null; } return index.h("salla-tooltip", { class: 'absolute left-0 -top-2', targetId: targetId, theme: "dark" }, index.h("div", { class: "flex gap-3 text-start" }, productItem?.image?.url && index.h("img", { src: productItem.image.url, alt: productItem?.image?.alt || productItem.name || "", class: "w-12 h-12 object-cover rounded-lg flex-shrink-0", loading: "lazy", decoding: "async" }), index.h("div", { class: "flex-1" }, index.h("div", { class: "leading-tight mb-1" }, productItem.name), index.h("div", { class: "text-xs text-gray-300", innerHTML: salla.money(productItem.price) })))); } getCheckpointContent(discount) { if (discount.type === DiscountType.PERCENTAGE) return `${discount.value}%`; if (discount.type === DiscountType.FIXED) return index.h("span", { innerHTML: salla.money(discount.value) }); if (discount.type !== DiscountType.FREE_PRODUCT) { salla.logger.error(`salla-conditional-offer:: unexpected type (${discount.type})!`); return ""; } const productItem = this.products[discount.value]; if (!productItem) { salla.logger.error(`salla-conditional-offer:: there is no product with id (${discount.value})!`); return ""; } return index.h("a", { class: "s-conditional-offer-product-link", href: productItem.url }, index.h("img", { class: "s-conditional-offer-checkpoint-image-content", loading: "lazy", decoding: "async", alt: productItem?.image?.alt || "", src: productItem?.image?.url })); } getOfferType(discount) { const basedOn = this.offer.details?.based_on; if (basedOn === OfferType.PRODUCT_COUNT) return salla.lang.choice("blocks.header.products_count", discount.min_spend); if (basedOn === OfferType.PRODUCT_PURCHASE) return salla.money(discount.min_spend); salla.logger.warn(`salla-conditional-offer:: Unexpected offer detail's based_on value: ${basedOn}`); return `${discount.min_spend}`; } clamp(value, min, max) { return Math.max(min, Math.min(value, max)); } mapValueRanges(value, initialMinRange, initialMaxRange, newMinRange, newMaxRange) { const newRange = ((value - initialMinRange) * (newMaxRange - newMinRange)) / (initialMaxRange - initialMinRange) + newMinRange; if (newRange === Number.POSITIVE_INFINITY) return 100; if (newRange === Number.NEGATIVE_INFINITY) return 0; return this.clamp(newRange, 0, 100); } getCheckPointView(discount, index$1) { const checkpointIndex = this.offer.details.discounts.findIndex(({ min_spend }) => min_spend === discount.min_spend); const previousCheckpointValue = this.offer.details.discounts[checkpointIndex - 1]?.min_spend ?? 0; const progressPercentage = this.mapValueRanges(this.offer.details.current_value, previousCheckpointValue, discount.min_spend, 0, 100); const isActive = discount.min_spend <= this.offer.details.current_value; return (index.h("div", { class: "s-conditional-offer-checkpoint-container" }, index$1 > 0 ? [ index.h("div", { key: "progress-line", class: "s-conditional-offer-progress-line-container" }, index.h("div", { class: "s-conditional-offer-progress-line-inactive" }), index.h("div", { class: "s-conditional-offer-progress-line-active", style: { width: `${progressPercentage}%` } })), index.h("div", { key: "checkpoint", class: `s-conditional-offer-checkpoint ${isActive ? "s-conditional-offer-active-checkpoint" : ""}` }, index.h("div", { class: `s-conditional-offer-item-avatar-content ${isActive ? "active" : ""}`, id: discount.type === DiscountType.FREE_PRODUCT ? `avatar-product-${discount.value}` : `avatar-${discount.value ?? index$1}` }, this.products && this.getCheckpointContent(discount)), this.products && discount.type === DiscountType.FREE_PRODUCT && this.renderTooltip(discount), index.h("div", { class: `s-conditional-offer-checkpoint-label ${isActive ? "active" : ""}`, innerHTML: this.getOfferType(discount) })) ] : index.h("div", { key: "label", class: { "s-conditional-offer-checkpoint-label": true, "first-checkpoint": index$1 === 0, active: isActive }, innerHTML: this.getOfferType(discount) }))); } getLoadingSkeletonView() { return index.h(index.Host, { class: "s-conditional-offer-container" }, index.h("div", { class: "s-conditional-offer-skeleton-inner-container" }, index.h("div", { class: "s-conditional-offer-skeleton-subtitle" }, index.h("salla-skeleton", { height: "16px", width: "30%" })), index.h("div", { class: "s-conditional-offer-skeleton-subtitle" }, index.h("salla-skeleton", { height: "16px", width: "35%" })), index.h("div", { class: "s-conditional-offer-skeleton-checkpoints-wrapper" }, Array(3).fill(null).map(() => ([index.h("salla-skeleton", { key: "checkpoint-line", height: "8px" }), index.h("div", { key: "checkpoint" }, index.h("salla-skeleton", { height: "60px", width: "60px", type: "circle" }))]))))); } render() { if (!this.canRender) return null; if (this.isLoading) return this.getLoadingSkeletonView(); if (!this.offer) return null; return index.h(index.Host, { class: "s-conditional-offer-container" }, index.h("div", { class: "s-conditional-offer-title-wrapper" }, index.h("div", { class: "s-conditional-offer-title" }, this.offer.title), this.offer.description ? index.h("div", { class: "s-conditional-offer-subtitle" }, this.offer.description, " ", index.h("i", { class: "sicon-information" })) : null), index.h("div", { class: "s-conditional-offer-progress-container" }, this.offer.details.discounts.map((discount, index$1) => (index.h("div", { class: { "flex-1": index$1 > 0 }, key: discount.min_spend }, this.getCheckPointView(discount, index$1)))))); } }; SallaConditionalOffer.style = sallaConditionalOfferCss; exports.salla_conditional_offer = SallaConditionalOffer;