@salla.sa/twilight-components
Version:
Salla Web Component
364 lines (358 loc) • 18.8 kB
JavaScript
/*!
* Crafted with ❤ by Salla
*/
import { proxyCustomElement, HTMLElement, h } from '@stencil/core/internal/client';
import { d as defineCustomElement$c } from './salla-add-product-button2.js';
import { d as defineCustomElement$b } from './salla-button2.js';
import { d as defineCustomElement$a } from './salla-count-down2.js';
import { d as defineCustomElement$9 } from './salla-loading2.js';
import { d as defineCustomElement$8 } from './salla-modal2.js';
import { d as defineCustomElement$7 } from './salla-product-availability2.js';
import { d as defineCustomElement$6 } from './salla-product-card2.js';
import { d as defineCustomElement$5 } from './salla-progress-bar2.js';
import { d as defineCustomElement$4 } from './salla-quick-buy2.js';
import { d as defineCustomElement$3 } from './salla-slider2.js';
import { d as defineCustomElement$2 } from './salla-tel-input2.js';
var PageType;
(function (PageType) {
PageType["ProductDetail"] = "product.single";
PageType["Cart"] = "cart";
})(PageType || (PageType = {}));
var OfferType;
(function (OfferType) {
OfferType["Conditional"] = "conditional";
OfferType["PercentageOrFixed"] = "fixed";
OfferType["DiscountsTable"] = "discounts_table";
OfferType["Bank"] = "bank";
OfferType["BuyXGetY"] = "buy_x_get_y";
})(OfferType || (OfferType = {}));
const sallaOfferCss = ".s-offer-wrapper .s-slider-block__title h2{font-size:1.125rem;line-height:1.75rem;color:#f87171}.s-offer-wrapper .s-slider-block__title h2::before{font-family:\"sallaicons\";content:\"\\ee30\" !important;position:absolute;top:1rem;font-size:3rem;font-weight:400;line-height:1;color:#fef2f2}.s-offer-bank-wrapper-sinlge-item{display:-ms-flexbox;display:flex;-ms-flex-align:center !important;align-items:center !important;gap:14px}.s-offer-bank-wrapper{display:-ms-flexbox !important;display:flex !important;width:100% !important}";
const SallaOffer$1 = /*@__PURE__*/ proxyCustomElement(class SallaOffer extends HTMLElement {
constructor() {
super();
this.__registerHost();
var _a;
/**
* Custom Card Component for the Salla Products List.
*
* This component allows you to customize the appearance of individual product cards within a Salla Products List.
*
* @example
* <salla-products-list product-card-component="my-custom-card-style1" ...
* <salla-products-list product-card-component="my-custom-card-style2" ...
*/
this.productCardComponent = 'custom-salla-product-card';
// Declare component state variables
this.offersList = [];
this.isMultipleBank = false;
this.isBankOffer = false;
this.canRender = false;
this.showOffer = salla.config.get('store.settings.product.show_special_offers');
// Default translated texts
this.offer_with_price_text = salla.lang.get('pages.offer.with_price', { price: '' });
this.with_discount_text = salla.lang.get('pages.products.with_a_discount');
this.product_discount_text = salla.lang.get('pages.products.discount');
this.special_offer_text = salla.lang.get('pages.products.special_offer');
this.multipleBankOfferTitleText = salla.lang.get('pages.offer.multiple_bank_offers_title');
this.multipleBankOfferTitleDescription = salla.lang.get('pages.offer.multiple_bank_offers_message');
this.buy_quantity_text = (quantity) => salla.lang.get('pages.offer.buy_quantity', { quantity });
// Language
salla.lang.onLoaded(() => {
this.offer_with_price_text = salla.lang.get('pages.offer.with_price');
this.with_discount_text = salla.lang.get('pages.products.with_a_discount');
this.product_discount_text = salla.lang.get('pages.products.discount');
this.special_offer_text = salla.lang.get('pages.products.special_offer');
this.multipleBankOfferTitleText = salla.lang.get('pages.offer.multiple_bank_offers_title');
this.multipleBankOfferTitleDescription = salla.lang.get('pages.offer.multiple_bank_offers_message');
this.buy_quantity_text(0);
});
salla.onReady(() => {
this.currentPage = salla.config.get('page.slug');
this.userCurrency = salla.config.get('currencies')[salla.config.get('user.currency_code')].symbol;
});
this.categorySlot = ((_a = this.host.querySelector('[slot="category"]')) === null || _a === void 0 ? void 0 : _a.innerHTML) || '<a href={url} class="s-offer-slide-cat-entry"><i class={icon}></i><h4>{name}</h4></a>';
}
getEndpointByPageName() {
return {
[PageType.Cart]: `offers/cart/${salla.storage.get('cart.id')}`,
[PageType.ProductDetail]: `offers/product/${salla.config.get('page.id')}`,
}[this.currentPage] || "offers";
}
componentWillLoad() {
this.hasCustomComponent = !!customElements.get(this.productCardComponent);
// let offers = this.getOffersFromStorage();
// if (offers) {
// return offers.then(offersFromStorage => this.offersList = offersFromStorage);
// }
return (new Promise(resolve => salla.onReady(resolve)))
.then(() => {
this.showOffer = !salla.url.is_page('product.single') || salla.config.get('store.settings.product.show_special_offers');
if (this.showOffer) {
return;
}
throw new Error("Merchant disabled showing the offers on product page");
})
.then(() => salla.api.request(this.getEndpointByPageName()))
.then((res) => {
if (!(this.offersList = res.data).length) {
throw new Error('salla-offers:: There is no offers!');
}
//we support these offers only
const offer = this.offersList.find(offer => [OfferType.Bank, OfferType.BuyXGetY, OfferType.DiscountsTable].includes(offer.type));
if (!offer) {
throw new Error('salla-offers:: Offer type not supported yet!');
}
//because there is no need for special handling for discounts table, just skip the other cases
if (offer.type === OfferType.DiscountsTable) {
return this.offersList = [offer];
}
//if it's banks offer, we need to include the other banks overs
if ((this.isBankOffer = offer.type === OfferType.Bank)) {
this.offersList = this.offersList.filter(offer => offer.type === OfferType.Bank);
this.isMultipleBank = this.offersList.length > 1;
return this.offersList;
}
//BuyXGetY offers
const getY = offer.details.get;
return getY.source === 'products'
//todo:: avoid this request, and the handling for the products, just use `salla-products-slider` and don't forget to pass the customcard
? salla.product.api.fetch({ source: "selected", source_value: getY.source_value })
.then((response) => {
getY.products = response.data;
offer.details.get = getY;
return this.offersList = [offer];
}) //set the products
: salla.product.api.categories() //get all categories in one query, then extract only the selected one, instead of sending multi requests
.then((res) => {
getY.categories = this.findCategories(res.data, getY.source_value);
offer.details.get = getY;
return this.offersList = [offer];
});
})
.then((offers) => {
salla.storage.set(this.getStorageKey(), { offers, stored_at: new Date().getTime() });
this.canRender = true;
})
.catch((error) => {
salla.logger.warn(error);
});
}
componentDidLoad() {
let nav = this.host.querySelector('.s-slider-block__title-nav');
nav === null || nav === void 0 ? void 0 : nav.classList.add("s-offer-bank-payment-nav");
}
findCategories(categories, ids) {
var _a;
let found = [];
for (const category of categories) {
if (ids.includes(category.id_ || category.id)) { //here we are using || because we are planning to drop `id_`
found.push(category);
}
if (((_a = category.sub_categories) === null || _a === void 0 ? void 0 : _a.length) > 0) {
found = found.concat(this.findCategories(category.sub_categories, ids));
}
}
return found;
}
//todo::add to the key params, to make sure it will support multi offers in the same page if it's wanted
getStorageKey() {
try {
const pageSlug = salla.config.get('page.slug').replace('.', '_');
const locale = salla.lang.getLocale();
const currencyCode = salla.config.currency().code;
if (!pageSlug || !locale || !currencyCode) {
throw new Error('Unable to get the storage key.');
}
return `s-offers-${pageSlug}-${salla.config.get('page.id')}-${locale}-${currencyCode}`;
}
catch (error) {
return '';
}
}
//@ts-ignore
getOffersFromStorage() {
let storageOffers = salla.storage.get(this.getStorageKey());
//if the offers not existed, or it has been stored before 10 minutes from now, ignore it;
if (!storageOffers || storageOffers.stored_at < (new Date().getTime() - 10 * 60 * 1000)) {
salla.storage.remove(this.getStorageKey());
return null;
}
this.canRender = true;
//return it as resolve to support .then
return Promise.resolve(storageOffers.offers);
}
render() {
if (!this.offersList.length || !this.canRender || !this.showOffer)
return null;
const offer = this.offersList[0];
const blockTitle = this.isBankOffer ? (this.isMultipleBank ? this.multipleBankOfferTitleText : null) : offer.title;
const blockSubTitle = this.isBankOffer ? (this.isMultipleBank ? this.multipleBankOfferTitleDescription : null) : offer.description;
const titles = {
'block-title': blockTitle,
'block-subTitle': blockSubTitle,
'show-controls': this.isMultipleBank
};
return (h("div", { class: "s-offer-wrapper" }, h("p", { class: "s-offer-corner-badge" }, this.special_offer_text), h("salla-slider", Object.assign({ type: "carousel", id: "offer-slider" }, titles), h("div", { slot: 'items' }, this.renderSectionForOfferType(offer.type)))));
}
renderSectionForOfferType(offerType) {
if (this.isBankOffer) {
return this.renderBankSection();
}
if (offerType == OfferType.BuyXGetY) {
return this.renderBuyXGetYSection();
}
return this.renderDiscountTableSection();
}
/**
* Generates content for the categories section.
*
* @param offeredCategories - An array of Category objects.
* @returns An array of HTML elements representing categories.
*/
getCategoriesSection(category) {
return h("div", { class: "s-offer-slide-one-sixth swiper-slide", innerHTML: this.categorySlot
.replace(/\{url\}/g, category.url)
.replace(/\{icon\}/g, category.icon || "sicon-store")
.replace(/\{name\}/g, category.name) });
}
renderBuyXGetYSection() {
var _a, _b;
const details = this.offersList[0].details;
return [
(_a = details.get.products) === null || _a === void 0 ? void 0 : _a.map((product) => (h("div", { class: "s-offer-slide-one-fourth" }, this.hasCustomComponent
? h(this.productCardComponent, { product: product })
: h("salla-product-card", { "shadow-on-hover": true, product: product })))),
(_b = details.get.categories) === null || _b === void 0 ? void 0 : _b.map((category) => this.getCategoriesSection(category))
];
}
/**
* Generates content for the bank section.
*
* @param offeredBank - An array of Bank objects.
* @param name - The title of the current offer.
* @param description - The description of the current offer.
* @returns An array of HTML elements representing banks.
*
* TODO: loop over the list and filter bank types and pass it to this function
*/
renderBankSection() {
return this.offersList.map((bankOffer) => {
return h("div", { class: { "s-offer-slide-one-sixth": this.isMultipleBank, "s-offer-bank-wrapper-sinlge-item": !this.isMultipleBank } }, h("div", { class: { "s-offer-bank-wrapper": true, "s-offer-slide-one-sixth": !this.isMultipleBank, "s-offer-bank-wrapper-multi-spacer": this.isMultipleBank } }, h("div", { class: "s-offer-bank-logo" }, h("img", { src: bankOffer.details.logo || salla.url.cdn('images/s-empty.png'), "data-src": bankOffer.details.logo, alt: bankOffer.title + " offer" })), h("ul", { class: "s-offer-bank-payment-wrapper" }, bankOffer.details.payments.map((payment) => {
return h("li", { class: "s-offer-bank-payment-single" }, h("img", { src: salla.url.cdn('images/payment/' + payment + '.png') || salla.url.cdn('images/s-empty.png'), "data-src": salla.url.cdn('images/payment/' + payment + '.png'), alt: "payment" }));
})), this.isMultipleBank ?
h("p", { class: "s-offer-bank-payment-discount-percent" }, `${this.product_discount_text} ${bankOffer.details.discount_value}${bankOffer.details.discount_type === "percentage" && '%'}`)
: ""), !this.isMultipleBank ?
h("div", { class: "s-offer-bank-message s-offer-slide-one-fourth" }, h("h2", null, this.offersList[0].title), h("p", { innerHTML: this.generateBankDescription(this.offersList[0].description, bankOffer.details.discount_value) }))
: "");
});
}
generateBankDescription(desc, value) {
return desc.replace(new RegExp(`${value} %`), `<span class="s-offer-bank-message-amount">${value} %</span>`);
}
/**
* Generates content for the discount table section.
*
* @param discountTable - An array of Discount objects.
* @returns An array of HTML elements representing discounts_table.
*/
renderDiscountTableSection() {
var _a;
const offer = this.offersList[0];
let show_discounted_price = offer.details.show_price_after_discount;
return (_a = this.offersList[0].details.discounts) === null || _a === void 0 ? void 0 : _a.map((discount) => h("div", { class: "s-offer-slide-one-fourth" }, h("div", { class: "s-offer-slide-offer-entry" }, h("div", { class: "s-offer-slide-offer-entry-price-quantity-container" }, h("p", { class: "s-offer-slide-offer-entry-quantity" }, this.buy_quantity_text(discount.quantity)), show_discounted_price ?
h("div", { class: "s-offer-slide-offer-entry-price" }, h("span", null, this.offer_with_price_text), h("span", { class: "s-offer-slide-offer-entry-price-amount" }, discount.discounted_amount), " ", h("span", null, this.userCurrency)) : ""), h("p", { class: "s-offer-slide-offer-entry-price-amount-percent" }, this.with_discount_text, "(", h("span", null, discount.percentage, !!discount.percentage && '%'), ")"))));
}
get host() { return this; }
static get style() { return sallaOfferCss; }
}, [0, "salla-offer", {
"productCardComponent": [1, "product-card-component"],
"offersList": [32],
"userCurrency": [32],
"isMultipleBank": [32],
"title": [32],
"currentPage": [32],
"hasCustomComponent": [32],
"isBankOffer": [32],
"canRender": [32],
"showOffer": [32],
"offer_with_price_text": [32],
"with_discount_text": [32],
"product_discount_text": [32],
"special_offer_text": [32],
"multipleBankOfferTitleText": [32],
"multipleBankOfferTitleDescription": [32],
"buy_quantity_text": [32]
}]);
function defineCustomElement$1() {
if (typeof customElements === "undefined") {
return;
}
const components = ["salla-offer", "salla-add-product-button", "salla-button", "salla-count-down", "salla-loading", "salla-modal", "salla-product-availability", "salla-product-card", "salla-progress-bar", "salla-quick-buy", "salla-slider", "salla-tel-input"];
components.forEach(tagName => { switch (tagName) {
case "salla-offer":
if (!customElements.get(tagName)) {
customElements.define(tagName, SallaOffer$1);
}
break;
case "salla-add-product-button":
if (!customElements.get(tagName)) {
defineCustomElement$c();
}
break;
case "salla-button":
if (!customElements.get(tagName)) {
defineCustomElement$b();
}
break;
case "salla-count-down":
if (!customElements.get(tagName)) {
defineCustomElement$a();
}
break;
case "salla-loading":
if (!customElements.get(tagName)) {
defineCustomElement$9();
}
break;
case "salla-modal":
if (!customElements.get(tagName)) {
defineCustomElement$8();
}
break;
case "salla-product-availability":
if (!customElements.get(tagName)) {
defineCustomElement$7();
}
break;
case "salla-product-card":
if (!customElements.get(tagName)) {
defineCustomElement$6();
}
break;
case "salla-progress-bar":
if (!customElements.get(tagName)) {
defineCustomElement$5();
}
break;
case "salla-quick-buy":
if (!customElements.get(tagName)) {
defineCustomElement$4();
}
break;
case "salla-slider":
if (!customElements.get(tagName)) {
defineCustomElement$3();
}
break;
case "salla-tel-input":
if (!customElements.get(tagName)) {
defineCustomElement$2();
}
break;
} });
}
const SallaOffer = SallaOffer$1;
const defineCustomElement = defineCustomElement$1;
export { SallaOffer, defineCustomElement };
//# sourceMappingURL=salla-offer.js.map
//# sourceMappingURL=salla-offer.js.map