Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses
Starry Sky Roses

Starry Sky Roses

Price

$12.99 $7.99
Save 38%
const TAG = "spz-custom-product-automatic"; class SpzCustomProductAutomatic extends SPZ.BaseElement { constructor(element) { super(element); this.variant_id = '853b7ba2-247b-410a-8682-fd290ba8fc87'; this.isRTL = SPZ.win.document.dir === 'rtl'; this.isAddingToCart_ = false; // ๅŠ ่ดญไธญ็Šถๆ€ } static deferredMount() { return false; } buildCallback() { this.action_ = SPZServices.actionServiceForDoc(this.element); this.templates_ = SPZServices.templatesForDoc(this.element); this.xhr_ = SPZServices.xhrFor(this.win); this.setupAction_(); this.viewport_ = this.getViewport(); } mountCallback() { this.init(); // ็›‘ๅฌไบ‹ไปถ this.bindEvent_(); } async init() { this.handleFitTheme(); const data = await this.getDiscountList(); this.renderApiData_(data); } async getDiscountList() { const productId = 'eb589160-7334-4f41-8b7b-649d3296f160'; const variantId = this.variant_id; const productType = 'default'; const reqBody = { product_id: productId, variant_id: variantId, discount_method: "DM_AUTOMATIC", customer: { customer_id: window.C_SETTINGS.customer.customer_id, email: window.C_SETTINGS.customer.customer_email }, product_type: productType } const url = `/api/storefront/promotion/display_setting/text/list`; const data = await this.xhr_.fetchJson(url, { method: "post", body: reqBody }).then(res => { return res; }).catch(err => { this.setContainerDisabled(false); }) return data; } async renderDiscountList() { this.setContainerDisabled(true); const data = await this.getDiscountList(); this.setContainerDisabled(false); // ้‡ๆ–ฐๆธฒๆŸ“ ๆŠ–ๅŠจ้—ฎ้ข˜ๅค„็† this.renderApiData_(data); } clearDom() { const children = this.element.querySelector('*:not(template)'); children && SPZCore.Dom.removeElement(children); } async renderApiData_(data) { const parentDiv = document.querySelector('.automatic_discount_container'); const newTplDom = await this.getRenderTemplate(data); if (parentDiv) { parentDiv.innerHTML = ''; parentDiv.appendChild(newTplDom); } else { console.log('automatic_discount_container is null'); } } doRender_(data) { const renderData = data || {}; return this.templates_ .findAndRenderTemplate(this.element, renderData) .then((el) => { this.clearDom(); this.element.appendChild(el); }); } async getRenderTemplate(data) { const renderData = data || {}; return this.templates_ .findAndRenderTemplate(this.element, { ...renderData, isRTL: this.isRTL }) .then((el) => { this.clearDom(); return el; }); } setContainerDisabled(isDisable) { const automaticDiscountEl = document.querySelector('.automatic_discount_container_outer'); if(isDisable) { automaticDiscountEl.setAttribute('disabled', ''); } else { automaticDiscountEl.removeAttribute('disabled'); } } // ็ป‘ๅฎšไบ‹ไปถ bindEvent_() { window.addEventListener('click', (e) => { let containerNodes = document.querySelectorAll(".automatic-container .panel"); let bool; Array.from(containerNodes).forEach((node) => { if(node.contains(e.target)){ bool = true; } }) // ๆ˜ฏๅฆpopover้ขๆฟ็‚นๅ‡ป่Œƒๅ›ด if (bool) { return; } if(e.target.classList.contains('drowdown-icon') || e.target.parentNode.classList.contains('drowdown-icon')){ return; } const nodes = document.querySelectorAll('.automatic-container'); Array.from(nodes).forEach((node) => { node.classList.remove('open-dropdown'); }) // ๅ…ผๅฎนไธป้ข˜ this.toggleProductSticky(true); }) // ็›‘ๅฌๅ˜ไฝ“ๅ˜ๅŒ– document.addEventListener('dj.variantChange', async(event) => { // ้‡ๆ–ฐๆธฒๆŸ“ const variant = event.detail.selected; if (variant.product_id == 'eb589160-7334-4f41-8b7b-649d3296f160' && variant.id != this.variant_id) { this.variant_id = variant.id; this.renderDiscountList(); } }); } // ๅ…ผๅฎนไธป้ข˜ handleFitTheme() { // top ๅฑžๆ€งๅฝฑๅ“ๆŠ–ๅŠจ let productInfoEl = null; if (window.SHOPLAZZA.theme.merchant_theme_name === 'Wind' || window.SHOPLAZZA.theme.merchant_theme_name === 'Flash') { productInfoEl = document.querySelector('.product-info-body .product-sticky-container'); } else if (window.SHOPLAZZA.theme.merchant_theme_name === 'Hero') { productInfoEl = document.querySelector('.product__info-wrapper .properties-content'); } if(productInfoEl){ productInfoEl.classList.add('force-top-auto'); } } // ๅ…ผๅฎน wind/flash /hero ไธป้ข˜ (stickyๅฑžๆ€งๅฝฑๅ“ popover ๅฑ‚็บงๅฑ•็คบ, ไผš่ขซๅ…ถไป–ๅ…ƒ็ด ่ฆ†็›–) toggleProductSticky(isSticky) { let productInfoEl = null; if (window.SHOPLAZZA.theme.merchant_theme_name === 'Wind' || window.SHOPLAZZA.theme.merchant_theme_name === 'Flash') { productInfoEl = document.querySelector('.product-info-body .product-sticky-container'); } else if (window.SHOPLAZZA.theme.merchant_theme_name === 'Hero') { productInfoEl = document.querySelector('.product__info-wrapper .properties-content'); } if(productInfoEl){ if(isSticky) { // ่ฟ˜ๅŽŸ่ฏฅไธป้ข˜ๅŽŸๆœ‰็š„stickyๅฑžๆ€งๅ€ผ productInfoEl.classList.remove('force-position-static'); return; } productInfoEl.classList.toggle('force-position-static'); } } setupAction_() { this.registerAction('handleDropdown', (invocation) => { const discount_id = invocation.args.discount_id; const nodes = document.querySelectorAll('.automatic-container'); Array.from(nodes).forEach((node) => { if(node.getAttribute('id') != `automatic-${discount_id}`) { node.classList.remove('open-dropdown'); } }) const $discount_item = document.querySelector(`#automatic-${discount_id}`); $discount_item && $discount_item.classList.toggle('open-dropdown'); // ๅ…ผๅฎนไธป้ข˜ this.toggleProductSticky(); }); // ๅŠ ่ดญไบ‹ไปถ this.registerAction('handleAddToCart', (invocation) => { // ้˜ปๆญขไบ‹ไปถๅ†’ๆณก const event = invocation.event; if (event) { event.stopPropagation(); event.preventDefault(); } // ๅฆ‚ๆžœๆญฃๅœจๅŠ ่ดญไธญ๏ผŒ็›ดๆŽฅ่ฟ”ๅ›ž if (this.isAddingToCart_) { return; } const quantity = invocation.args.quantity || 1; this.addToCart(quantity); }); } // ๅŠ ่ดญๆ–นๆณ• async addToCart(quantity) { // ่ฎพ็ฝฎๅŠ ่ดญไธญ็Šถๆ€ this.isAddingToCart_ = true; const productId = 'eb589160-7334-4f41-8b7b-649d3296f160'; const variantId = this.variant_id; const url = '/api/cart'; const reqBody = { product_id: productId, variant_id: variantId, quantity: quantity }; try { const data = await this.xhr_.fetchJson(url, { method: 'POST', body: reqBody }); // ่งฆๅ‘ๅŠ ่ดญๆˆๅŠŸๆ็คบ this.triggerAddToCartToast_(); return data; } catch (error) { error.then(err=>{ this.showToast_(err?.message || err?.errors?.[0] || 'Unknown error'); }) } finally { // ๆ— ่ฎบๆˆๅŠŸๅคฑ่ดฅ๏ผŒ้ƒฝ้‡็ฝฎๅŠ ่ดญ็Šถๆ€ this.isAddingToCart_ = false; } } showToast_(message) { const toastEl = document.querySelector("#apps-match-drawer-add_to_cart_toast"); if (toastEl) { SPZ.whenApiDefined(toastEl).then((apis) => { apis.showToast(message); }); } } // ่งฆๅ‘ๅŠ ่ดญๆˆๅŠŸๆ็คบ triggerAddToCartToast_() { // ๅฆ‚ๆžœไธป้ข˜ๆœ‰่‡ชๅทฑ็š„ๅŠ ่ดญๆ็คบ๏ผŒๅˆ™ไธๆ˜พ็คบ const themeAddToCartToastEl = document.querySelector('#add-cart-event-proxy'); if (themeAddToCartToastEl) return; // ๆ˜พ็คบๅบ”็”จ็š„ๅŠ ่ดญๆˆๅŠŸๆ็คบ this.showToast_("Added successfully"); } triggerEvent_(name, data) { const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {}); this.action_.trigger(this.element, name, event); } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } } SPZ.defineElement(TAG, SpzCustomProductAutomatic);
class SpzCustomDiscountBundle extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } mountCallback() { // ๅŒไธ€้กตๅฏ่ƒฝๆœ‰ๅคšไธช block ๅ„่‡ชๆธฒๆŸ“ๆœฌ snippet๏ผŒๅฏผ่‡ด้€ป่พ‘ๅ…ƒ็ด  spz-custom-discount-toast(#appsAddCartToastFunc) ้‡ๅคใ€‚ // ไป…ไฟ็•™ DOM ไธญ็ฌฌไธ€ไธชๅฎžไพ‹๏ผŒๅ…ถไฝ™้‡ๅคๅฎžไพ‹็งป้™ค่‡ช่บซ๏ผŒไฟ่ฏ้€ป่พ‘ๅ…ƒ็ด ๅŠๅ…ถ action ๅผ•็”จ(appsAddCartToastFunc)ๅ”ฏไธ€ใ€‚ const funcs = document.querySelectorAll('#appsAddCartToastFunc'); if (funcs.length > 1 && this.element !== funcs[0]) { this.element.remove(); return; } // ๅ…จๅฑ€ๆŠ˜ๆ‰ฃ toast ็š„ๅผนๅ‡บ็‚นๅˆ†ๆ•ฃๅœจๅคšไธชๆจกๆฟ/็ป„ไปถ้‡Œ๏ผˆๅซๅฃฐๆ˜Žๅผ @atcError๏ผ‰๏ผŒๆ— ๆณ•้€ไธ€ๅœจๅผนๅ‡บๅ‰ๅ‰็ฝฎ๏ผŒ // ๆ•…ๆŒ‚่ฝฝๆ—ถๅน‚็ญ‰ๅœฐๅŽป้‡ๅนถๆŒ‚ๅˆฐ body๏ผ›ๅŠ ่ดญ toast ๆ”นไธบๅผนๅ‡บๅ‰ๆŒ‰้œ€ๅŽป้‡๏ผˆ่ง showAddToCartToast๏ผ‰ this.ensureSingleToastInBody_('cart_match_discount_toast_wrap'); } unmountCallback() {} // ๅŒไธ€้กต้ขๅฏ่ƒฝๆœ‰ๅคšไธช block ๅ„่‡ชๆธฒๆŸ“ๆœฌ toast snippet๏ผˆๅฆ‚ๅ•†่ฏฆ็š„ discount_automatic + ่ดญ็‰ฉ่ฝฆๆŠฝๅฑ‰้‡Œ็š„ๆŠ˜ๆ‰ฃๆจชๅน…๏ผ‰๏ผŒ // ๅฏผ่‡ด toast ๅค–ๅฑ‚ๅ‡บ็Žฐ้‡ๅค idใ€‚้‡ๅค id ไธ‹ getElementById/querySelector ๅŠ SPZ ๅŠจไฝœๅผ•็”จ้ƒฝๅชๅ‘ฝไธญ็ฌฌไธ€ไธช๏ผŒ // ไธ”่ขซๅ…ณ่ฟ›ๆŠฝๅฑ‰็š„้‚ฃไปฝไผš่ขซๆŠฝๅฑ‰็š„ transform/overflow ่ฃๅ‰ช/้”™ไฝใ€‚่ฟ™้‡ŒๅœจๆŒ‚่ฝฝๆ—ถๅน‚็ญ‰ๅŽป้‡๏ผš // ๅชไฟ็•™ไธ€ไปฝใ€็งป้™คๅคšไฝ™็š„๏ผŒๅนถๆŠŠไฟ็•™็š„ๆŒ‚ๅˆฐ body๏ผˆbody ๆ˜ฏ position:fixed ๆœ€ๅฎ‰ๅ…จ็š„่ฝ็‚น๏ผŒ้ฟๅ…่ขซไปปไฝ•็ฅ–ๅ…ˆ่ฃๅ‰ช๏ผ‰ใ€‚ๅฏๅๅค่ฐƒ็”จใ€‚ ensureSingleToastInBody_(id) { const els = Array.from(document.querySelectorAll('#' + id)); if (!els.length) return; els.slice(1).forEach((el) => el.remove()); const keep = els[0]; if (keep.parentNode !== document.body) { document.body.appendChild(keep); } } // ไธป้ข˜่ดญ็‰ฉ่ฝฆๆŠฝๅฑ‰ๆ˜ฏๅฆๆ‰“ๅผ€ isInCartDrawer_() { return !!document.querySelector('[data-section-type="cart_drawer"] spz-sidebar[open]'); } setupAction_() { this.registerAction('showAddToCartToast', () => { // ๆŠฝๅฑ‰ๅ†…ๅŠ ่ดญ๏ผšไธป้ข˜ๆœฌๅฐฑไธไผšๆœ‰ๅŠ ่ดญๆ•ˆๆžœ๏ผŒ็ปŸไธ€ๅผนๆ’ไปถ่‡ชๅทฑ็š„ toast // ้žๆŠฝๅฑ‰๏ผšไธป้ข˜ๆœ‰ๅŠ ่ดญไปฃ็†ๅˆ™ๆฒฟ็”จไธป้ข˜ๅŠ ่ดญๆ•ˆๆžœ๏ผŒๅฆๅˆ™ๆ’ไปถๅ…œๅบ• const proxyEl = document.getElementById('add-cart-event-proxy'); const inDrawer = this.isInCartDrawer_(); if (!inDrawer && proxyEl) { return; } // ๅผนๅ‡บๅ‰ๆŒ‰้œ€ๅŽป้‡ๅนถๆŒ‚ๅˆฐ body๏ผˆๅน‚็ญ‰๏ผ‰๏ผŒ้ฟๅ…้‡ๅค id ๅ‘ฝไธญ้”™ๅฏน่ฑกๆˆ–่ขซๆŠฝๅฑ‰่ฃๅ‰ช/้”™ไฝ this.ensureSingleToastInBody_('apps_add_cart_toast_wrap'); const toastEl = document.querySelector('#apps-match-drawer-add_to_cart_toast') SPZ.whenApiDefined(toastEl).then((apis) => { apis.showToast("Added successfully"); }); }); } buildCallback() { this.setupAction_(); }; } SPZ.defineElement('spz-custom-discount-toast', SpzCustomDiscountBundle);
class SpzCustomDiscountFlashsale extends SPZ.BaseElement { constructor(element) { super(element); this.xhr_ = SPZServices.xhrFor(this.win); this.getFlashSaleApi = "\/api\/storefront\/promotion\/flashsale\/display_setting\/product_setting"; this.timer = null; this.variantId = "853b7ba2-247b-410a-8682-fd290ba8fc87"; // ไฟƒ้”€ๆดปๅŠจๆ•ฐๆฎ this.flashsaleData = {} } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } buildCallback() { this.templates_ = SPZServices.templatesForDoc(); this.viewport_ = this.getViewport(); // ๆŒ‚่ฝฝbindๅ‡ฝๆ•ฐ ่งฃๅ†ณthisๆŒ‡ๅ‘้—ฎ้ข˜ this.render = this.render.bind(this); this.resize = this.resize.bind(this); this.switchVariant = this.switchVariant.bind(this); } mountCallback() { // ่Žทๅ–ๆ•ฐๆฎ this.getData(); this.element.onclick = (e) => { const cur = this.win.document.querySelector(".app_discount_flashsale_desc"); const setting = this.flashsaleData.product_setting; const landingUrl = `/promotions/discount-default/${this.flashsaleData.discount_info.id}`; const finalUrl = appDiscountUtils.resolveDiscountHref(setting, landingUrl); if (finalUrl && appDiscountUtils.inProductBody(this.element) && e.target !== cur) { this.win.open(finalUrl, '_blank', 'noopener'); } } // ็ป‘ๅฎš this.viewport_.onResize(this.resize); // ็›‘ๅฌๅญๆฌพๅผๅˆ‡ๆข๏ผŒ้‡ๆ–ฐๆธฒๆŸ“ this.win.document.addEventListener('dj.variantChange', this.switchVariant); } unmountCallback() { // ่งฃ็ป‘ this.viewport_.removeResize(this.resize); this.win.document.removeEventListener('dj.variantChange', this.switchVariant); // ๆธ…้™คๅฎšๆ—ถๅ™จ if (this.timer) { clearTimeout(this.timer); this.timer = null; } } resize() { if (this.timer) { clearTimeout(this.timer) this.timer = null; } this.timer = setTimeout(() => { this.render(); }, 200) } switchVariant(event) { const variant = event.detail.selected; if (variant.product_id == 'eb589160-7334-4f41-8b7b-649d3296f160' && variant.id != this.variantId) { this.variantId = variant.id; this.getData(); } } getData() { const reqBody = { product_id: "eb589160-7334-4f41-8b7b-649d3296f160", product_type: "default", variant_id: this.variantId } this.flashsaleData = {}; this.win.fetch(this.getFlashSaleApi, { method: "POST", body: JSON.stringify(reqBody), headers: { "Content-Type": "application/json" } }).then(async (response) => { if (response.ok) { this.flashsaleData = await response.json(); this.render(); } else { this.clearDom(); } }).catch(err => { this.clearDom(); }); } clearDom() { const children = this.element.querySelector('*:not(template)'); children && SPZCore.Dom.removeElement(children); } render() { this.templates_ .findAndRenderTemplate(this.element, { isMobile: appDiscountUtils.judgeMobile(), isRTL: appDiscountUtils.judgeRTL(), inProductDetail: appDiscountUtils.inProductBody(this.element), flashsaleData: this.flashsaleData, image_domain: this.win.SHOPLAZZA.image_domain, }) .then((el) => { this.clearDom(); this.element.appendChild(el); }) } } SPZ.defineElement('spz-custom-discount-flashsale', SpzCustomDiscountFlashsale);

quantity

Please select a quantity

Quantity

/** @private {string} */ class SpzCustomAnchorScroll extends SPZ.BaseElement { static deferredMount() { return false; } constructor(element) { super(element); /** @private {Element} */ this.scrollableContainer_ = null; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } buildCallback() { this.viewport_ = this.getViewport(); this.initActions_(); } setTarget(containerId, targetId) { this.containerId = '#' + containerId; this.targetId = '#' + targetId; } scrollToTarget() { const container = document.querySelector(this.containerId); const target = container.querySelector(this.targetId); const {scrollTop} = container; const eleOffsetTop = this.getOffsetTop_(target, container); this.viewport_ .interpolateScrollIntoView_( container, scrollTop, scrollTop + eleOffsetTop ); } initActions_() { this.registerAction( 'scrollToTarget', (invocation) => this.scrollToTarget(invocation?.caller) ); this.registerAction( 'setTarget', (invocation) => this.setTarget(invocation?.args?.containerId, invocation?.args?.targetId) ); } /** * @param {Element} element * @param {Element} container * @return {number} * @private */ getOffsetTop_(element, container) { if (!element./*OK*/ getClientRects().length) { return 0; } const rect = element./*OK*/ getBoundingClientRect(); if (rect.width || rect.height) { return rect.top - container./*OK*/ getBoundingClientRect().top; } return rect.top; } } SPZ.defineElement('spz-custom-anchor-scroll', SpzCustomAnchorScroll); const STRENGTHEN_TRUST_URL = "/api/strengthen_trust/settings"; class SpzCustomStrengthenTrust extends SPZ.BaseElement { constructor(element) { super(element); this.renderElement_ = null; } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } buildCallback() { this.xhr_ = SPZServices.xhrFor(this.win); const renderId = this.element.getAttribute('render-id'); SPZCore.Dom.waitForChild( document.body, () => !!document.getElementById(renderId), () => { this.renderElement_ = SPZCore.Dom.scopedQuerySelector( document.body, `#${renderId}` ); if (this.renderElement_) { this.render_(); } this.registerAction('track', (invocation) => { this.track_(invocation.args); }); } ); } render_() { this.fetchData_().then((data) => { if (!data) { return; } SPZ.whenApiDefined(this.renderElement_).then((apis) => { apis?.render(data); document.querySelector('#strengthen-trust-render-1539149753700').addEventListener('click',(event)=>{ if(event.target.nodeName == 'A'){ this.track_({type: 'trust_content_click'}); } }) }); }); } track_(data = {}) { const track = window.sa && window.sa.track; if (!track) { return; } track('trust_enhancement_event', data); } parseJSON_(string) { let result = {}; try { result = JSON.parse(string); } catch (e) {} return result; } fetchData_() { return this.xhr_ .fetchJson(STRENGTHEN_TRUST_URL) .then((responseData) => { if (!responseData || !responseData.data) { return null; } const data = responseData.data; const moduleSettings = (data.module_settings || []).reduce((result, moduleSetting) => { return result.concat(Object.assign(moduleSetting, { logos: (moduleSetting.logos || []).map((item) => { return moduleSetting.logos_type == 'custom' ? this.parseJSON_(item) : item; }) })); }, []); return Object.assign(data, { module_settings: moduleSettings, isEditor: window.self !== window.top, }); }); } } SPZ.defineElement('spz-custom-strengthen-trust', SpzCustomStrengthenTrust); const getPluginI18nMessages = (message, replaceObj = {}) => { const lang = document.documentElement.lang || "en-US"; const [form, key] = message.split('.') let text = window.payment_plugin_message['en-US'][form][key]; if (window.payment_plugin_message[lang][form].hasOwnProperty(key)) { text = window.payment_plugin_message[lang][form][key]; } Object.keys(replaceObj).forEach(key => { text = text.replace(new RegExp(`\{${key}\}`, 'gi'), replaceObj[key]); }) return text; } const zhCN = { ec: { not_active_channel: "่ฏทๅˆฐๆ”ถๆฌพ่ฎพ็ฝฎไธญ{channelName}ๆˆ–ๅœจใ€Œๅฟซๆทๆ”ฏไป˜ๆŒ‰้’ฎใ€่ฎพ็ฝฎไธญ้€‰ๆ‹ฉๅ…ถไป–็š„ๆœๅŠกๆไพ›ๆ–น๏ผŒๅฆๅˆ™ๆŒ‰้’ฎๅฐ†ๆ— ๆณ•ๅฑ•็คบ", not_support_theme: "ๅฝ“ๅ‰ไธป้ข˜ไธๆ”ฏๆŒๆทปๅŠ ใ€Œๅฟซๆทๆ”ฏไป˜ๆŒ‰้’ฎใ€", more_button: "ๆ›ดๅคšๆ”ฏไป˜ๆ–นๅผ", skeleton_layer_tips_title: "ๅฟซๆทๆ”ฏไป˜ๆŒ‰้’ฎ", skeleton_layer_tips_content: "่ฏท็‚นๅ‡ปๅทฆไพงๅˆ—่กจไธญ็š„ใ€Œๅฟซๆทๆ”ฏไป˜ๆŒ‰้’ฎใ€๏ผŒๅœจ่ฎพ็ฝฎ้กต้ขๅผ€ๅฏๆƒณ่ฆ็š„ๅฑ•็คบ็š„ๆ”ฏไป˜ๆŒ‰้’ฎ", mock_tips: "ๅฟซๆทๆ”ฏไป˜ๆŒ‰้’ฎๆ˜ฏๅฆๅฑ•็คบ่ฟ˜ๅ–ๅ†ณไบŽไนฐๅฎถไฝฟ็”จ็š„ๆต่งˆๅ™จไปฅๅŠๅ•†ๅ“็š„่ดงๅธใ€้‡‘้ข", not_find_form_tips: "ๅฟซๆทๆ”ฏไป˜ๆŒ‰้’ฎ็ป„ไปถไป…ๆ”ฏๆŒ้…็ฝฎๅˆฐๅ•†ๅ“่ฏฆๆƒ…ๅก็‰‡ๅ†…", } }; const zhTW = { ec: { not_active_channel: "่ฏทๅˆฐๆ”ถๆฌพ่ฎพ็ฝฎไธญ{channelName}ๆˆ–ๅœจใ€Œๅฟซๆทๆ”ฏไป˜ๆŒ‰้’ฎใ€่ฎพ็ฝฎไธญ้€‰ๆ‹ฉๅ…ถไป–็š„ๆœๅŠกๆไพ›ๆ–น๏ผŒๅฆๅˆ™ๆŒ‰้’ฎๅฐ†ๆ— ๆณ•ๅฑ•็คบ", not_support_theme: "ๅฝ“ๅ‰ไธป้ข˜ไธๆ”ฏๆŒๆทปๅŠ ใ€Œๅฟซๆทๆ”ฏไป˜ๆŒ‰้’ฎใ€", more_button: "ๆ›ดๅคšไป˜ๆฌพๆ–นๅผ", } }; const arSA = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "ุงู„ู…ุฒูŠุฏ ู…ู† ุฎูŠุงุฑุงุช ุงู„ุฏูุน", } }; const deDE = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "Weitere Bezahlmรถglichkeiten", } }; const esES = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "Mรกs opciones de pago", } }; const frFR = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "Plus d'options de paiement", } }; const idID = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "Opsi pembayaran lainnya", } }; const itIT = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "Altre opzioni di pagamento", } }; const jaJP = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "ใใฎไป–ใฎๆ”ฏๆ‰•ใ„ใ‚ชใƒ—ใ‚ทใƒงใƒณ", } }; const koKR = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "๋” ๋งŽ์€ ๊ฒฐ์ œ ์˜ต์…˜", } }; const enUS = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "More payment options", skeleton_layer_tips_title: "Express Checkout Button", skeleton_layer_tips_content: "Please click theใ€ŒExpress checkout buttonใ€on the block list๏ผŒthen you could enable the payment option you want to display in settings.", mock_tips: "Whether the Express checkout button is displayed also depends on the browser used by the buyer and the currency and amount of the product.", not_find_form_tips: "Express Checkout Button could only be added to Product details block.", } }; const nlNL = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "Meer betalingsmogelijkheden", } }; const plPL = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "Wiฤ™cej Opcji Pล‚atnoล›ci", } }; const ptPT = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "Mais opรงรตes de pagamento", } }; const ruRU = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "ะ”ั€ัƒะณะธะต ะฒะฐั€ะธะฐะฝั‚ั‹ ะพะฟะปะฐั‚ั‹", } }; const thTH = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in theใ€ŒExpress checkout buttonใ€ settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support addingใ€ŒExpress checkout buttonใ€", more_button: "เธ•เธฑเธงเน€เธฅเธทเธญเธเธเธฒเธฃเธŠเธณเธฃเธฐเน€เธ‡เธดเธ™เน€เธžเธดเนˆเธกเน€เธ•เธดเธก", } }; window.payment_plugin_message = { getPluginI18nMessages, "zh-CN": zhCN, "zh-TW": zhTW, "ar-SA": arSA, "de-DE": deDE, "es-ES": esES, "fr-FR": frFR, "id-ID": idID, "it-IT": itIT, "ja-JP": jaJP, "ko-KR": koKR, "en-US": enUS, "nl-NL": nlNL, "pl-PL": plPL, "pt-PT": ptPT, "ru-RU": ruRU, "th-TH": thTH, } document.dispatchEvent(new CustomEvent('payment_plugin_message_reader'));
try { const dom = document.getElementById('pm-payment-express-button-1539149753700-10'); dom.i18n = window?.payment_plugin_message?.getPluginI18nMessages; if (dom.i18n) { document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { i18n: true } })) } else { document.addEventListener('payment_plugin_message_reader', () => { dom.i18n = window?.payment_plugin_message?.getPluginI18nMessages; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { i18n: true } })) }, {once: true}); } } catch (e) { } // ้€š็”จๅทฅๅ…ทๆ–นๆณ• try { const dom = document.getElementById('pm-payment-express-button-1539149753700-10') const ROOT_URL = (C_SETTINGS && C_SETTINGS.routes && C_SETTINGS.routes.root) || ''; const eventListeners = {}; const commonUtils = function () { return { getProduct() { const productJson = document.querySelector('#product-json'); if (productJson?.textContent) { return JSON.parse(productJson.textContent); } if (window.jQuery) { const $product = window.jQuery?.(document)?.data('djproduct'); const productData = JSON.parse(JSON.stringify($product || {})); return productData || {}; } return {}; }, isChrome() { return navigator?.userAgent?.indexOf('Chrome') > -1 || navigator?.userAgent?.indexOf('CriOS') > -1; }, isSafari() { let userAgentString = navigator.userAgent; let chromeAgent = userAgentString.indexOf('Chrome') > -1 || navigator?.userAgent?.indexOf('CriOS') > -1; let safariAgent = userAgentString.indexOf('Safari') > -1; if (chromeAgent && safariAgent) { safariAgent = false; } return safariAgent; }, isPreview() { return !!window?.C_EDITING_SETTINGS?.oseid; }, multiply(a, b) { const precision = 2; // ไฟ็•™ไธคไฝๅฐๆ•ฐ return Number((a * b).toFixed(precision)); }, loadScript(fnReady, id, src, datasets, onError, attributeConfig = {}) { const sdkDomId = id + '-sdk'; const loadedEventName = `${id}-loaded`; if (fnReady()) { return Promise.resolve({id: true}); } const existingScript = document.getElementById(sdkDomId); if (existingScript) { return new Promise((resolve) => { const handleLoaded = () => { if (fnReady()) { resolve({id: true}); } else { resolve({id: false}); onError && onError(); } }; if (existingScript.dataset.loaded === 'true') { handleLoaded(); } else { window.addEventListener(loadedEventName, handleLoaded, {once: true}); } }); } return new Promise((resolve) => { const s = document.createElement('script'); s.id = sdkDomId; s.src = src; s.defer = true; if (datasets) { Object.keys(datasets).map((item) => { s.dataset[item] = datasets[item]; }); } s.onload = function () { s.dataset.loaded = 'true'; window.dispatchEvent(new CustomEvent(loadedEventName)); resolve({id: true}); }; s.onerror = function () { resolve({id: false}); onError && onError(); }; Object.keys(attributeConfig).forEach((key) => { s.setAttribute(key, attributeConfig[key]); }); document.head.appendChild(s); }); }, track(eventName, data) { window.sa && window?.sa?.track('pm_' + eventName, JSON.parse(JSON.stringify(data))); }, getExtUrl(name) { const url = document.cookie.match(new RegExp('\\b' + name.replace(/_/g, '-') + '-(v[s0-9]+)')); if (url && url[1]) { return `${name}.${url[1]}.js`; } else { return window?.exts?.[name]; } }, req: { post: async (url, data = {}) => { try { const response = await fetch(req.ROOT_URL + url, { method: 'POST', headers: { 'Content-Type': 'application/json', }, ...data, body: JSON.stringify(data.body), }); return await response.json() } catch (error) { throw new Error('post request error' + error); } }, get: async (url, data = {}) => { try { const response = await fetch(ROOT_URL + url); return await response.json() } catch (error) { throw new Error('get request error' + error); } } }, debounce(fn, wait) { let timeout = null; return function () { if (timeout !== null) { clearTimeout(timeout); } timeout = setTimeout(function () { fn.apply(this, arguments); }, wait); } }, delayCallback(cb) { window.requestIdleCallback ? requestIdleCallback(cb, {timeout: 50}) : setTimeout(cb, 50); }, loadFilly(tag, cb, trackEcPerfFn) { if (!tag) { return } const script = document.createElement('script'); script.type = 'text/javaScript'; script.src = `//static.staticdj.com/${tag}`; script.onload = function() { if (trackEcPerfFn && !performance.getEntriesByName('ec_filly_load_end').length) { performance.mark('ec_filly_load_end'); const fillyStart = performance.getEntriesByName('ec_filly_load_start')[0]; const channels = window?.C_SETTINGS?.payment_settings?.dynamic_config?.express_checkout_config?.express_channels || []; trackEcPerfFn({ eventName: 'ec_perf_filly_load_end', extraData: { filly_load_time: fillyStart ? performance.now() - fillyStart.startTime : null, payment_channel: channels.join(',') }, eventType: 'card_expose' }); } cb && cb(); }; document.getElementsByTagName('head')[0].appendChild(script); }, ecEvent: { on: (eventName, listener, useCapture) => { eventListeners[eventName] = listener; window.addEventListener(eventName, listener, useCapture); }, emit: (eventName, data) => window.dispatchEvent(new CustomEvent(eventName, {detail: data})), }, trackEcPerf({ eventName, extraData, eventType }) { const skeletonStart = performance.getEntriesByName('ec_skeleton_start')[0]; const sinceSkeletonStart = skeletonStart ? performance.now() - skeletonStart.startTime : null; window.sa && window.sa.track('function_expose', { function_name: 'payment_platform', plugin_name: 'payment_platform', business_type: 'product_payment', module: 'payment', module_type: 'payment_platform', event_type: eventType || 'expose', event_developer: 'cartoon', event_info: JSON.stringify( Object.assign( { process_name: eventName, process_type: 'perf', since_skeleton: sinceSkeletonStart }, extraData || {} ) ) }); } } } dom.commonUtilsFn = commonUtils; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { commonUtils: true } })) } catch (e) { } // ๆ ธๅฟƒๆ•ฐๆฎ try { const dom = document.getElementById('pm-payment-express-button-1539149753700-10'); const coreData = function () { const {getProduct} = dom.commonUtils; let productDetail = getProduct(); let productPrice = productDetail?.selected?.price || 7.99; const shopCurrencyCode = "USD"; const expressCheckoutList = { sdkErrorList: [], paymentChannelList: [], disabledChannelList: [], showChannelList: [], blockChannelList: [], extraChannelList: [], }; const channelType = { googlepay: ['shoplazzagoogle'], applepay: ['shoplazzaapple'], credit: ['paypal'] }; const ecGlobalVarEnums = { paypal: 'pluginPaypalEC' }; const providerEnums = { SHOPLAZZA: 'shoplazza', STRIPE: 'stripe', PAYPAL: 'paypal' }; const channelEnums = { SHOPLAZZA_GOOGLE: 'shoplazzagoogle', SHOPLAZZA_APPLE: 'shoplazzaapple', STRIPE_GOOGLE: 'stripegoogle', STRIPE_APPLE: 'stripeapple', PAYPAL: 'paypal' }; const channelThemeConfig = { [channelEnums.PAYPAL]: { default: { url: 'oss/operation/f557c83808e1cd456411170286a1ea95.svg', classList: ['paypal-card'], }, }, [channelEnums.SHOPLAZZA_GOOGLE]: { light: { url: 'oss/operation/778afb93da43adf75bdc80b078e5d4fd.svg', classList: ['googlepay-light'], }, dark: { url: 'oss/operation/e53180c224f0b0af44b44663775aa930.svg', classList: ['googlepay-dark'], }, }, [channelEnums.SHOPLAZZA_APPLE]: { light: { url: 'oss/operation/dadceb884044e0a9bbfe26c15192f542.svg', classList: ['applepay-light'], }, dark: { url: 'oss/operation/6597f66eac8b0681ebfb75941e8f6f52.svg', classList: ['applepay-dark'], }, }, }; function getContainerDomId() { const domIDSuffix = '-express-button-container'; const prefix = 'pm-'; const formatId = (channel) => `${prefix}${channel}${domIDSuffix}-1539149753700-10`; return { [providerEnums.PAYPAL]: formatId(providerEnums.PAYPAL), [channelEnums.SHOPLAZZA_GOOGLE]: formatId(channelEnums.SHOPLAZZA_GOOGLE), [channelEnums.SHOPLAZZA_APPLE]: formatId(channelEnums.SHOPLAZZA_APPLE), }; } return { ecGlobalVarEnums, providerEnums, channelEnums, productPrice, shopCurrencyCode, getChannelThemeConfig(ecName) { const themeType = window.PaymentEC?.settings?.express_theme_configs?.[ecName]?.theme_type?.toLowerCase() || 'default'; return channelThemeConfig[ecName][themeType] || channelThemeConfig[ecName]['dark']; }, getProductPrice() { return productDetail?.selected?.price; }, getProductDetail() { return productDetail; }, setProductDetail(data) { productDetail = data; }, isRequiresShipping() { return productDetail?.product?.requires_shipping }, getOpenChannelType() { const {paymentChannelList, blockChannelList} = expressCheckoutList const openList = paymentChannelList.filter(item => blockChannelList.includes(item)) || []; return { hasApplepay: openList.filter(item => channelType.applepay.includes(item))?.length > 0, hasGooglepay: openList.filter(item => channelType.googlepay.includes(item))?.length > 0, hasCredit: openList.filter(item => channelType.credit.includes(item))?.length > 0 } }, containerDomId: getContainerDomId(), channel2ProviderEnums: { [channelEnums.PAYPAL]: channelEnums.PAYPAL, [channelEnums.SHOPLAZZA_GOOGLE]: channelEnums.SHOPLAZZA_GOOGLE, [channelEnums.SHOPLAZZA_APPLE]: channelEnums.SHOPLAZZA_APPLE, [channelEnums.STRIPE_GOOGLE]: providerEnums.STRIPE, [channelEnums.STRIPE_APPLE]: providerEnums.STRIPE, }, getExpressCheckoutList() { return expressCheckoutList; }, setShowChannel(showChannelList = []) { expressCheckoutList.showChannelList = showChannelList; return expressCheckoutList; }, setBlockChannel(blockChannelList = []) { expressCheckoutList.blockChannelList = blockChannelList; return expressCheckoutList; }, setPaymentChannelList(paymentChannelList = []) { expressCheckoutList.paymentChannelList = paymentChannelList; return expressCheckoutList; }, setSdkErrorList(paymentChannelList = []) { expressCheckoutList.sdkErrorList = paymentChannelList; return expressCheckoutList; }, setExtraChannelList(extraChannelList = []) { expressCheckoutList.extraChannelList = extraChannelList; return expressCheckoutList; }, setDisabledChannelList(disabledChannelList = []) { expressCheckoutList.disabledChannelList = disabledChannelList; return expressCheckoutList; } } } dom.coreDataFn = coreData; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { coreData: true } })) } catch (e) { console.log(e); } // ้€š็”จไธšๅŠกๆ•ฐๆฎๅค„็†ๆ–นๆณ• try { const dom = document.getElementById('pm-payment-express-button-1539149753700-10') const businessUtils = function () { const {track, isChrome, isSafari, req, isPreview, multiply, loadScript, trackEcPerf} = dom.commonUtils; const {getProductPrice, containerDomId, ecGlobalVarEnums, channelType, getOpenChannelType} = dom.coreData; const { channelEnums, shopCurrencyCode, isRequiresShipping, getProductDetail, setShowChannel, setBlockChannel, setSdkErrorList, setExtraChannelList, setDisabledChannelList, setPaymentChannelList, getExpressCheckoutList } = dom.coreData; const _businessUtils = { getECConfig: async () => { if (window.PaymentEC?.settings) { return window.PaymentEC?.settings; } // ไผ˜ๅ…ˆไปŽ C_SETTINGS ่Žทๅ– express_checkout_config let ecConfig = window?.C_SETTINGS?.payment_settings?.dynamic_config?.express_checkout_config; // ๅฆ‚ๆžœ C_SETTINGS ไธญๆฒกๆœ‰๏ผŒไฝฟ็”จๆŽฅๅฃ่ฏทๆฑ‚ไฝœไธบๅ…œๅบ• if (!ecConfig) { const result = await req.get('/api/payment/settings'); ecConfig = result?.settings?.express_checkout_config || {}; } const {blockChannelList} = getExpressCheckoutList(); const filteredExpressChannels = blockChannelList.filter(ecName => ecConfig?.express_channels?.includes(ecName)) || []; setPaymentChannelList(filteredExpressChannels); window.PaymentEC.settings = { ...ecConfig, express_channels: filteredExpressChannels, currencyCode: shopCurrencyCode }; return window.PaymentEC.settings; }, getAttributeConfig(channelInfo) { const {ecGlobalVar, ecName} = channelInfo; const config = { paypal: { 'data-namespace': ecGlobalVar } }; return config[ecName] || {}; }, getThemeFormData() { let themeFormData = {}; const formDOM = dom.closest("form"); if (formDOM) { themeFormData = { note: '', product_id: '', variant_id: '', quantity: 1, properties: {}, }; const formData = new FormData(formDOM); const formDataKey = formData.keys(); for (const key of formDataKey) { const value = formData.get(key); const propertiesKey = key.match(/^properties(?:\.(\w+)$|\[(\w+)\]$)/); if (!propertiesKey) { themeFormData[key] = value; continue; } const objKey = propertiesKey[1] || propertiesKey[2]; themeFormData['properties'] = {...themeFormData['properties'], [objKey]: value}; } } return themeFormData; }, getProductFormData() { const themeFormData = _businessUtils.getThemeFormData() return [{ ...themeFormData, note: themeFormData?.note || "", product_id: themeFormData?.product_id || "", variant_id: themeFormData?.variant_id || "", quantity: themeFormData?.quantity || 1, // ไธŽไธป้ข˜็กฎ่ฎค๏ผŒๅชไปฅไธ€ไธชไธบๅ‡†๏ผŒ้˜ฒๆญขformไธๅญ˜ๅœจ็š„ๆ•ฐๆฎไป่ขซไผ ้€’ properties: themeFormData?.properties || {}, }] }, getOrderFetchParams(data) { if (!data) { return {}; } return { line_items: data.map((item) => ({ ...item, note: item?.note || "", quantity: item?.quantity || 1, product_id: item?.product_id, variant_id: item?.variant_id, properties: item?.properties, })), refer_info: { source: 'buy_now', }, customer_note: '', }; }, isAllowTheme() { const allowThemeList = ['Nova 2023', 'Dropshiping', 'Geek', 'Hero', 'Eva']; const currentTheme = window?.C_SETTINGS?.theme?.merchant_theme_name; return allowThemeList.includes(currentTheme); }, getSubscriptionIdInit() { let defaultID; const selectSubscriptionEnum = { CLOSE: 1, ACTIVE: 2, } const productDetail = getProductDetail(); const sellingPlan = ""; if (!sellingPlan || typeof sellingPlan !== "object") { return null; } let sellingItems; if (sellingPlan?.spu?.[productDetail?.product?.id]) { sellingItems = sellingPlan.spu[productDetail?.product?.id] } if (sellingPlan?.sku?.[productDetail?.selected?.id]) { sellingItems = sellingPlan.sku[productDetail?.product?.id] } if (sellingItems?.cycles === selectSubscriptionEnum.ACTIVE && sellingItems?.selected_selling_plan_option_id) { defaultID = sellingItems?.selected_selling_plan_option_id } return defaultID ?? null }, getSubscriptionId() { const formData = _businessUtils.getThemeFormData(); const defaultID = _businessUtils.getSubscriptionIdInit(); console.log(`[paymentEC]่ฎข้˜…ไฟกๆฏ:form-${formData?.properties?._selling_plan_option_id},้ป˜่ฎค-${defaultID}`); if (formData?.properties) { return formData?.properties?._selling_plan_option_id } return defaultID ?? null; }, isSubscription() { return !!_businessUtils.getSubscriptionId(); }, isAllowSubscriptionPay(channel) { if (!_businessUtils.isSubscription()) { return true; } return [channelEnums.PAYPAL].includes(channel); }, checkApplePayAvailability(channel) { let available = false; let reason = 'no_session'; const isApplePay = channelType?.applepay?.includes?.(channel); if(!isApplePay){ return true; } if (window.ApplePaySession) { if (window.ApplePaySession.canMakePayments()) { available = true; reason = 'available'; } else { reason = 'cannot_make_payments'; } } trackEcPerf({ eventName: 'ec_applepay_availability_check', extraData: { available: available, reason: reason, layer: 'pike_init', payment_channel: channel }, eventType: 'expose' }); return available; }, blockChannelHandler() { const block_googlePay = false && "shoplazzagoogle"; const block_applePay = false && "shoplazzaapple"; const block_credit = true && "paypal"; const blockChannel = { googlepay: block_googlePay, applepay: block_applePay, credit: block_credit }; if (!isPreview()) { const expressChannels = window?.C_SETTINGS?.payment_settings?.dynamic_config?.express_checkout_config?.express_channels || []; const hasStripe = expressChannels.includes('shoplazzagoogle') || expressChannels.includes('shoplazzaapple'); const {hasApplepay} = getOpenChannelType(); if (hasStripe) { loadScript(() => window.Stripe, 'Stripe', 'https://js.stripe.com/v3/'); } if (hasApplepay) { loadScript(() => { const hasAppURL = document.getElementById('applepay-sdk'); return !!hasAppURL; }, 'applepay', 'https://applepay.cdn-apple.com/jsapi/v1/apple-pay-sdk.js'); } } const sortList = ['credit', 'googlepay', 'applepay']; const methodSort = Object.keys(blockChannel).filter(key => blockChannel[key] && key).sort((a, b) => { const indexA = sortList.indexOf(a); const indexB = sortList.indexOf(b); return indexA - indexB; }).map(key => blockChannel[key]); const result = setBlockChannel(methodSort); track('setBlockChannel', result); return result; }, showECButtonHandler() { const { paymentChannelList, sdkErrorList, disabledChannelList, extraChannelList, } = getExpressCheckoutList(); const showChannelList = paymentChannelList.filter((ecName) => !sdkErrorList.includes(ecName) && !disabledChannelList.includes(ecName) && !extraChannelList.includes(ecName)) || []; const result = setShowChannel(showChannelList); track('showECButton', result); return result; }, filterECButtonHandler({type}, cb) { const { paymentChannelList, sdkErrorList, disabledChannelList, extraChannelList, } = getExpressCheckoutList(); const showChannelList = paymentChannelList.filter((ecName) => !sdkErrorList.includes(ecName) && !disabledChannelList.includes(ecName) && !extraChannelList.includes(ecName)) || []; const result = setShowChannel(showChannelList.filter((ecName) => ecName !== type) || []); cb && cb(); track('filterECButton', result); return result; }, loadSDKErrorHandler(type) { const {sdkErrorList} = getExpressCheckoutList(); const result = setSdkErrorList([...sdkErrorList, type]); track('loadSDKError', result); return result; }, extraFilterShowHandler(channel) { const {extraChannelList} = getExpressCheckoutList(); const result = setExtraChannelList(extraChannelList.filter(ecName => ecName !== channel)); track('extraFilterEvent_show', result); return result; }, extraFilterHideHandler(channel) { const {extraChannelList} = getExpressCheckoutList(); const result = setExtraChannelList([...extraChannelList, channel]); track('extraFilterEvent_hide', result); return result; }, disabledChannelListHandler(checkoutData = {}, cb) { const {paymentChannelList} = getExpressCheckoutList(); const productDetail = getProductDetail(); const disabledChannelList = paymentChannelList.filter(ecName => { let mustDisable = false; if(!_businessUtils.checkApplePayAvailability(ecName)){ mustDisable = true; } if (!isRequiresShipping() && ecName !== channelEnums.PAYPAL) { mustDisable = true; } if (!_businessUtils.isAllowSubscriptionPay(ecName)) { mustDisable = true; } if (!productDetail?.selected?.available) { mustDisable = true; } const {payment_due} = checkoutData?.prices; const paymentDueNum = Number(payment_due || 0) * 100; const showFlag = paymentDueNum > 0; return mustDisable || !showFlag; }) const result = setDisabledChannelList(disabledChannelList) result?.disabledChannelList?.forEach(ecName => { cb && cb(ecName); }) track('disabledChannelListEvent', result); }, async getCheckoutData() { const formData = _businessUtils.getProductFormData(); const totalPrice = multiply(getProductPrice(), formData?.[0]?.quantity || 0); return { prices: {payment_due: totalPrice, subtotal_price: totalPrice}, orderParams: _businessUtils.getOrderFetchParams(_businessUtils.getProductFormData()), containerDOMIdEnums: containerDomId, ecGlobalVarEnums } }, } return _businessUtils } dom.businessUtilsFn = businessUtils; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { businessUtils: true } })) } catch (e) { } // ้€š็”จๆธฒๆŸ“ๆ–นๆณ• try { const dom = document.getElementById('pm-payment-express-button-1539149753700-10'); const containerDOM = 'pm-payment-express-button-container-1539149753700-10'; const commonRenderUtils = function () { return { addChildrenDOM(id, allowShow, options = {}) { if (!id) { return; } const paymentEl = document.getElementById(containerDOM); const childrenEL = document.getElementById(id); if (paymentEl && childrenEL) { childrenEL.style.display = allowShow ? 'block' : 'none'; return; } if (paymentEl && !childrenEL) { const dom = document.createElement('div'); dom.id = id; dom.style.display = allowShow ? 'block' : 'none'; if (options?.style) { Object.keys(options?.style).forEach(key => { dom.style[key] = options.style[key]; }) } if (Array.isArray(options?.classList)) { dom.classList.add(...options.classList) } paymentEl.appendChild(dom); } }, removeChildrenDOM(id) { if (!id) { return; } const paymentEl = document.getElementById(containerDOM); const childrenEL = document.getElementById(id); if (paymentEl && childrenEL) { // childrenEL.remove(); childrenEL.style.display = 'none'; } }, mockAddChildrenDOM(id, allowShow, options = {}) { if (!id) { return; } const paymentEl = document.getElementById(containerDOM); const childrenEL = document.getElementById(id); if (paymentEl && childrenEL) { childrenEL.style.display = allowShow ? 'flex' : 'none'; return; } if (paymentEl && !childrenEL) { const dom = document.createElement('div'); dom.id = id; dom.style.display = allowShow ? 'flex' : 'none'; if (options?.style) { Object.keys(options?.style).forEach(key => { dom.style[key] = options.style[key]; }) } if (Array.isArray(options?.classList)) { dom.classList.add(...options.classList) } dom.classList.add('mock-img'); const img = document.createElement('img'); img.src = `//static.staticdj.com/${options?.url}`; dom.appendChild(img); paymentEl.appendChild(dom); } }, resetRenderDOM() { const resetStyleList = [ "pm-payment-express-error-tips-1539149753700-10", "pm-payment-express-more-button-1539149753700-10", "pm-payment-express-mock-tips-1539149753700-10", "pm-payment-express-skeletonLayer-1539149753700-10", ] const resetHtmlList = [ "pm-payment-express-skeletonLayer-title-content-1539149753700-10", "pm-payment-express-skeletonLayer-content-1539149753700-10", "pm-payment-express-mock-tips-1539149753700-10", "pm-payment-express-error-tips-1539149753700-10", "pm-payment-express-button-container-1539149753700-10", "pm-payment-express-more-button-1539149753700-10", ] resetStyleList.forEach(domID => { const content = document.getElementById(domID); if (content) { content.style.display = 'none'; } }) resetHtmlList.forEach(domID => { const content = document.getElementById(domID); if (content) { content.innerHTML = ''; } }) } } } dom.commonRenderUtilsFn = commonRenderUtils; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { commonRenderUtils: true } })) } catch (e) { } // ้”™่ฏฏๆ็คบๆธฒๆŸ“ try { const dom = document.getElementById('pm-payment-express-button-1539149753700-10'); const renderTipsUtils = function () { const {i18n} = dom; const {isPreview} = dom.commonUtils; const {channelEnums} = dom.coreData; return { showChannelNotOpenTips(channelList) { const tipsDom = document.getElementById('pm-payment-express-error-tips-1539149753700-10'); if (!isPreview()) { return; } if (!tipsDom) { return; } tipsDom.style.display = channelList.length > 0 ? 'block' : 'none'; const channelName = { [channelEnums.SHOPLAZZA_GOOGLE]: "ShoplazzaPayments - GooglePay", [channelEnums.SHOPLAZZA_APPLE]: "ShoplazzaPayments - ApplePay", [channelEnums.PAYPAL]: "PayPal", } channelList.forEach(ecName => { const id = `pm-payment-express-error-tips-1539149753700-10-${ecName}`; const hasDom = document.getElementById(id) if (!hasDom) { const dom = document.createElement('div'); dom.id = id; dom.innerHTML = i18n('ec.not_active_channel', {channelName: channelName[ecName]}); tipsDom.appendChild(dom); } }) }, disabledThemTips() { const tipsDom = document.getElementById('pm-payment-express-error-tips-1539149753700-10'); if (!isPreview()) { return; } if (!tipsDom) { return; } tipsDom.style.display = 'block'; const id = 'pm-payment-express-error-tips-1539149753700-10-theme'; const hasDom = document.getElementById(id); if (!hasDom) { const dom = document.createElement('div'); dom.id = id; dom.innerHTML = i18n('ec.not_support_theme'); tipsDom.appendChild(dom); } }, notFindFormTips() { const tipsDom = document.getElementById('pm-payment-express-error-tips-1539149753700-10'); if (!isPreview()) { return; } if (!tipsDom) { return; } tipsDom.style.display = 'block'; const id = 'pm-payment-express-error-tips-1539149753700-10-theme'; const hasDom = document.getElementById(id); if (!hasDom) { const dom = document.createElement('div'); dom.id = id; dom.innerHTML = i18n('ec.not_find_form_tips'); tipsDom.appendChild(dom); } }, showSkeletonLayerTips() { const skeletonLayerDOMId = 'pm-payment-express-skeletonLayer-1539149753700-10'; const skeletonLayerDOM = document.getElementById(skeletonLayerDOMId); const titleDOM = document.getElementById('pm-payment-express-skeletonLayer-title-content-1539149753700-10'); const contentDOM = document.getElementById('pm-payment-express-skeletonLayer-content-1539149753700-10'); if (!skeletonLayerDOM || !titleDOM || !contentDOM) { return; } skeletonLayerDOM.style.display = 'block'; titleDOM.innerHTML = i18n('ec.skeleton_layer_tips_title'); contentDOM.innerHTML = i18n('ec.skeleton_layer_tips_content'); }, showMockTips() { const tipsDOM = document.getElementById('pm-payment-express-mock-tips-1539149753700-10'); if (!tipsDOM) { return; } tipsDOM.style.display = 'block'; tipsDOM.innerHTML = i18n('ec.mock_tips'); } } } dom.renderTipsUtilsFn = renderTipsUtils; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { renderTipsUtils: true } })) } catch (e) { } // ๆ›ดๅคšไฟกๆฏๆธฒๆŸ“ try { const dom = document.getElementById('pm-payment-express-button-1539149753700-10'); const moreDOM = document.getElementById('pm-payment-express-more-button-1539149753700-10'); const moreButtonConfig = { firstClick: true, maxSize: isNaN(2) ? 1 : 2 }; const renderMoreUtils = function () { const {i18n} = dom; const {getExpressCheckoutList, channelEnums} = dom.coreData; function moreButtonEvent(cb) { if (!moreDOM) { return; } moreDOM.style.display = 'none'; moreButtonConfig.firstClick = false; cb && cb(); } return { getMoreButtonConfig() { return moreButtonConfig }, showMoreButton(cb) { if (!moreDOM) { return; } let {showChannelList} = getExpressCheckoutList(); const showLength = showChannelList.length; const {firstClick, maxSize} = moreButtonConfig; moreDOM.style.display = (firstClick && showLength > 0 && showLength > maxSize) ? 'block' : 'none'; moreDOM.innerHTML = i18n('ec.more_button'); moreDOM.onclick = () => moreButtonEvent(cb); }, } } dom.renderMoreUtilsFn = renderMoreUtils; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { renderMoreUtils: true } })) } catch (e) { } try { const dom = document.getElementById('pm-payment-express-button-1539149753700-10'); function start() { const { getExtUrl, loadFilly, delayCallback, ecEvent, track, loadScript, debounce, trackEcPerf } = dom.commonUtils; const { blockChannelHandler, getAttributeConfig, showECButtonHandler, filterECButtonHandler, loadSDKErrorHandler, extraFilterShowHandler, extraFilterHideHandler, disabledChannelListHandler, getECConfig, isAllowTheme, getCheckoutData, getThemeFormData } = dom.businessUtils; const {addChildrenDOM, removeChildrenDOM} = dom.commonRenderUtils; const {getMoreButtonConfig, showMoreButton} = dom.renderMoreUtils; const { ecGlobalVarEnums, providerEnums, channelEnums, getExpressCheckoutList, getProductPrice, getProductDetail, setProductDetail, containerDomId, channel2ProviderEnums, getChannelThemeConfig } = dom.coreData; const expressChannels = window?.C_SETTINGS?.payment_settings?.dynamic_config?.express_checkout_config?.express_channels || []; if (!performance.getEntriesByName('ec_skeleton_start').length) { performance.mark('ec_skeleton_start'); trackEcPerf({ eventName: 'ec_perf_skeleton_start', extraData: { page_start: performance.now(), payment_channel: expressChannels.join(',') }, eventType: 'card_expose' }); } function getFilly() { if (!performance.getEntriesByName('ec_filly_load_start').length) { performance.mark('ec_filly_load_start'); trackEcPerf({ eventName: 'ec_perf_filly_load_start', extraData: { payment_channel: expressChannels.join(',') }, eventType: 'card_expose' }); } const fillyTag = getExtUrl('filly'); if (fillyTag) { loadFilly(fillyTag, init, trackEcPerf); } } function extraFilterEvent(e) { const {channel, domId, allowShow} = e?.detail || {}; if (channel && domId) { if (allowShow) { extraFilterShowHandler(channel); const container = document.getElementById(domId); if (container) { container.style.border = 'none'; container.style.backgroundColor = 'transparent'; } } else { extraFilterHideHandler(channel); filterECButtonHandler({type: channel}, () => removeChildrenDOM(domId) ); } renderEC(); } } const renderEC = () => { showECButtonHandler(); const expressCheckoutList = getExpressCheckoutList(); var {showChannelList} = expressCheckoutList; const {firstClick, maxSize} = getMoreButtonConfig(); if (showChannelList.length === 0) { showMoreButton(renderEC); } showChannelList.forEach((ecName, index) => { const disableShow = firstClick && index >= maxSize; const containerId = containerDomId[channel2ProviderEnums[ecName]]; addChildrenDOM(containerId, !disableShow, getChannelThemeConfig(ecName)); showMoreButton(renderEC); }); } const loadErrorEvent = (type) => { const domID = containerDomId[type]; if (!domID) { return; } loadSDKErrorHandler(type); filterECButtonHandler({type}, () => removeChildrenDOM(domID) ); showMoreButton(renderEC); }; async function loadEC() { const themeFormData = getThemeFormData?.() || {}; if (!themeFormData?.product_id || !themeFormData?.variant_id) { return; } const ecConfig = await getECConfig(); const expressCheckoutList = getExpressCheckoutList(); track('loadEC', expressCheckoutList); if (ecConfig) { const checkoutData = await getCheckoutData(); disabledChannelListHandler(checkoutData, (ecName) => { filterECButtonHandler({type: ecName}, () => removeChildrenDOM(containerDomId[channel2ProviderEnums[ecName]]) ); }); renderEC(); window.PaymentEC.handleEcPluginsLoad = ({ channelInfos = [], loadedCbFn = () => { } }) => { const expressCheckoutLoadList = []; const { showChannelList } = getExpressCheckoutList(); const hasStripeChannels = channelInfos.some(info => info.ecGlobalVar === 'Stripe'); const stripeExpressChannels = (window?.C_SETTINGS?.payment_settings?.dynamic_config?.express_checkout_config?.express_channels || []) .filter(ch => ['shoplazzagoogle'].includes(ch)); if (hasStripeChannels && !performance.getEntriesByName('ec_stripe_load_start').length) { performance.mark('ec_stripe_load_start'); trackEcPerf({ eventName: 'ec_perf_stripe_load_start', extraData: { payment_channel: stripeExpressChannels.join(',') }, eventType: 'card_expose' }); } channelInfos.map((channelInfo) => { const {ecGlobalVar, ecName = '', sdkPath = '', datasets, fnReady, sdkReadyCb, sdkName} = channelInfo; let hasContainer = document.getElementById(containerDomId[ecName]); if (!hasContainer) { return; } const scriptName = sdkName || ecName === 'paypal' ? ecGlobalVar : ecName; performance.mark('ec_third_party_sdk_load_start'); trackEcPerf({ eventName: 'ec_third_party_sdk_load_start', extraData: { payment_channel: ecName, sdk_path: sdkPath }, eventType: 'expose' }); const attributeConfig = getAttributeConfig(channelInfo) || {}; const loadPromise = loadScript(fnReady ? fnReady : () => window[ecGlobalVar], scriptName, sdkPath, datasets, () => { loadErrorEvent(ecName); }, attributeConfig).then(() => { if (ecGlobalVar === 'Stripe' && !performance.getEntriesByName('ec_stripe_load_end').length) { performance.mark('ec_stripe_load_end'); const stripeStart = performance.getEntriesByName('ec_stripe_load_start')[0]; trackEcPerf({ eventName: 'ec_perf_stripe_load_end', extraData: { stripe_load_time: stripeStart ? performance.now() - stripeStart.startTime : null, payment_channel: stripeExpressChannels.join(',') }, eventType: 'card_expose' }); } performance.mark('ec_third_party_sdk_load_end'); const sdkStartLoadTime = performance.getEntriesByName('ec_third_party_sdk_load_start')[0]; trackEcPerf({ eventName: 'ec_third_party_sdk_load_end', extraData: { sdk_load_time: sdkStartLoadTime ? performance.now() - sdkStartLoadTime.startTime : null, payment_channel: ecName, sdk_path: sdkPath }, eventType: 'expose' }); sdkReadyCb?.({ ...checkoutData, loadSpent: 0, paymentExpressChannels: showChannelList }); }); expressCheckoutLoadList.push(loadPromise); }); const startLoadSDKTime = Date.now(); Promise.all(expressCheckoutLoadList).then(() => { const finishLoadSDKTime = Date.now(); const loadSpent = finishLoadSDKTime - startLoadSDKTime; loadedCbFn({...checkoutData, loadSpent, paymentExpressChannels: showChannelList}); }); }; // ้€š็Ÿฅๅค–้ƒจๆ•ฐๆฎๅ˜ๆ›ด ecEvent.emit('tc_payment_ec_data_change', { ecGlobalVarEnums, containerDOMIdEnums: containerDomId }); } } const loadECDebounce = debounce(loadEC, 300) async function refreshEC(data = {}, sources) { if (!sources) { console.warn('[paymentEC]hide: sources is null'); return; } if (data?.detail?.selected?.price) { setProductDetail(data?.detail) } loadECDebounce(); } function init() { ecEvent.on('shoplazza_express_channels_change', extraFilterEvent, false); ecEvent.on('shoplazza_express_channels_change_ready', extraFilterEvent, false); if (typeof window.PaymentEC === 'object') { window.PaymentEC.getCheckoutData = getCheckoutData; } document.addEventListener('dj.variantChange', (data) => refreshEC(data, 'variantChange')); document.addEventListener('payment_ec_refresh', (data) => refreshEC(data, data?.detail?.sources)); refreshEC({}, 'init'); } if (isAllowTheme()) { blockChannelHandler(); // ๆๅ‰ๅŠ ่ฝฝ filly๏ผšๅฆ‚ๆžœ DOM ๅทฒ็ปๅ‡†ๅค‡ๅฅฝ๏ผŒ็ซ‹ๅณๅŠ ่ฝฝ๏ผ›ๅฆๅˆ™ๅœจ DOMContentLoaded ๆ—ถๅŠ ่ฝฝ // ไฝฟ็”จ DOMContentLoaded ๆ›ฟไปฃ load ไบ‹ไปถ๏ผŒๆๅ‰ๅŠ ่ฝฝๆ—ถๆœบ๏ผˆๆฏ” window.load ๆ›ดๆ—ฉ๏ผ‰ if (document.readyState === 'complete' || document.readyState === 'interactive') { getFilly(); } else if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', getFilly, {once: true}); } else { // ๅ…œๅบ•๏ผšๅฆ‚ๆžœ readyState ๆœช็Ÿฅ๏ผŒ็ซ‹ๅณๅŠ ่ฝฝ getFilly(); } } } dom.startFn = start; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { start: true } })) } catch (e) { console.log(e); } // ้ข„่งˆๆจกๅผ try { const dom = document.getElementById('pm-payment-express-button-1539149753700-10'); function start() { const {track} = dom.commonUtils; const {showMoreButton, getMoreButtonConfig} = dom.renderMoreUtils; const { showECButtonHandler, getECConfig, blockChannelHandler, isAllowTheme, getThemeFormData } = dom.businessUtils; const { disabledThemTips, showChannelNotOpenTips, showSkeletonLayerTips, showMockTips, notFindFormTips } = dom.renderTipsUtils; const {mockAddChildrenDOM, resetRenderDOM} = dom.commonRenderUtils; const { channelEnums, getChannelThemeConfig, getExpressCheckoutList, getOpenChannelType } = dom.coreData; const mockDomId = { [channelEnums.PAYPAL]: channelEnums.PAYPAL, [channelEnums.SHOPLAZZA_GOOGLE]: channelEnums.SHOPLAZZA_GOOGLE, [channelEnums.SHOPLAZZA_APPLE]: channelEnums.SHOPLAZZA_APPLE, [channelEnums.STRIPE_GOOGLE]: channelEnums.STRIPE_GOOGLE, [channelEnums.STRIPE_APPLE]: channelEnums.STRIPE_APPLE, } const renderNotOpenTips = () => { const {blockChannelList, paymentChannelList} = getExpressCheckoutList(); const notOpenChannel = blockChannelList.filter(ecName => !paymentChannelList.includes(ecName)); showChannelNotOpenTips(notOpenChannel); } const renderMockTips = () => { const {hasApplepay, hasGooglepay} = getOpenChannelType(); if (hasApplepay || hasGooglepay) { showMockTips(); } } const renderEC = () => { showECButtonHandler(); const {showChannelList} = getExpressCheckoutList(); const {firstClick, maxSize} = getMoreButtonConfig(); if (showChannelList.length === 0) { showMoreButton(renderEC); } showChannelList.forEach((ecName, index) => { const disableShow = firstClick && index >= maxSize; mockAddChildrenDOM(mockDomId[ecName], !disableShow, getChannelThemeConfig(ecName)); showMoreButton(renderEC); }); } async function loadEC() { const date = new Date().getTime(); dom.loadEC_timestamp = date const ecConfig = await getECConfig(); if (date !== dom.loadEC_timestamp) { return; } const expressCheckoutList = getExpressCheckoutList(); track('preview-loadEC', expressCheckoutList); resetRenderDOM(); // ๅˆๅง‹ๅŒ–ๆ—ถๆฒกๆœ‰ไบ‹ไปถๆŽจ้€ if (ecConfig) { renderNotOpenTips(); renderEC(); renderMockTips(); } } const init = () => { blockChannelHandler(); const {blockChannelList} = getExpressCheckoutList(); if (!isAllowTheme()) { disabledThemTips() return; } const themeFormData = getThemeFormData?.() || {}; if (!themeFormData?.product_id || !themeFormData?.variant_id) { notFindFormTips(); return; } if (blockChannelList.length > 0) { loadEC(); } else { showSkeletonLayerTips() } } init(); } dom.mockStartFn = start; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { start: true } })) } catch (e) { } try { const dom = document.getElementById('pm-payment-express-button-1539149753700-10'); window.PaymentEC = {} const delayCallback = (cb) => { window.requestIdleCallback ? requestIdleCallback(cb, {timeout: 50}) : setTimeout(cb, 50); } const checkReady = function (data) { const { i18n, commonUtilsFn, coreDataFn, businessUtilsFn, commonRenderUtilsFn, renderTipsUtilsFn, renderMoreUtilsFn, startFn, mockStartFn } = dom let readyData = { commonUtils: !!(commonUtilsFn) || false, coreData: !!(coreDataFn) || false, businessUtils: !!(businessUtilsFn) || false, commonRenderUtils: !!(commonRenderUtilsFn) || false, renderTipsUtils: !!(renderTipsUtilsFn) || false, renderMoreUtils: !!(renderMoreUtilsFn) || false, start: !!(startFn) || false, mockStart: !!(mockStartFn) || false, i18n: !!(i18n) || false } if (data?.detail) { Object.keys(data.detail).forEach(key => { readyData[key] = data.detail[key] }) } let isReady = true; Object.keys(readyData).forEach(key => { if (!readyData[key]) { isReady = false } }) return isReady } const readyFn = () => { if (!checkReady()) { return; } document.removeEventListener('payment_ec_core_ready', readyFn); dom.commonUtils = dom.commonUtilsFn(); dom.coreData = dom.coreDataFn(); dom.businessUtils = dom.businessUtilsFn(); dom.commonRenderUtils = dom.commonRenderUtilsFn(); dom.renderTipsUtils = dom.renderTipsUtilsFn(); dom.renderMoreUtils = dom.renderMoreUtilsFn(); const productData = dom?.commonUtils?.getProduct?.() || {}; if (JSON.stringify(productData) === '{}') { return; } if (dom?.commonUtils?.isPreview()) { dom.mockStartFn() } else { dom.startFn(); } } const init = () => { if (checkReady()) { readyFn(); } else { document.addEventListener('payment_ec_core_ready', readyFn) } } // ไฝฟ็”จ DOMContentLoaded ๆ›ฟไปฃ window.load๏ผŒๆๅ‰ๅˆๅง‹ๅŒ–ๆ—ถๆœบ๏ผˆไธŽ filly ๅŠ ่ฝฝ้€ป่พ‘ไธ€่‡ด๏ผ‰ if (document.readyState === 'complete' || document.readyState === 'interactive') { delayCallback(init); } else if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => delayCallback(init), {once: true}); } else { // ๅ…œๅบ•๏ผšๅฆ‚ๆžœ readyState ๆœช็Ÿฅ๏ผŒ็ซ‹ๅณๆ‰ง่กŒ delayCallback(init); } } catch (e) { } // ๅ‡‘ๅ•ๅผน็ช—ไธŽ้ฆ–้กต้™ๆ—ถไฟƒ้”€ๅก็‰‡ๅ…ฑ็”จๆ ทๅผ id "discount-match-drawer"๏ผŒไผšไบง็”Ÿ้‡ๅค idใ€‚ // ็”จๅผน็ช—ๆ น่Š‚็‚นไธŠไธ“็”จ็š„ js- ๅ‰็ผ€้’ฉๅญ็ฑปๅ”ฏไธ€ๅฎšไฝไฝœ็”จๅŸŸๆ น๏ผŒ้ฟๅ…ๅ‘ฝไธญ้ฆ–้กตๅก็‰‡ๅฏผ่‡ดๅผน็ช—ๅ†…ๅ…ƒ็ด ๆŸฅ่ฏขๅคฑ่ดฅใ€‚ const getDiscountMatchPopupEl = () => document.querySelector('.js-discount-match-popup'); class SpzCustomDiscountBundleProducts extends SPZ.BaseElement { constructor(element) { super(element); this.xhr_ = SPZServices.xhrFor(this.win); this.getDiscountPriceApi = "\/api\/storefront\/promotion\/calculate\/discounted_price"; this.buyNowApi = "\/api\/checkout\/order"; this.batchAtcApi = "\/api\/cart\/batch"; // ๆฌพๅผไฟกๆฏ้›†ๅˆ this.productStyleInfo = []; // ๅผน็ช—ๅ†…้€‰ๆ‹ฉๆฌพๅผ้›†ๅˆ this.modalVariantInfo = []; this.show_classic_bundle_spu_style = false; this.bundleProducts = []; //ๆ†็ป‘ๅ•†ๅ“ this.bundleConfig = {}; //ไธ‹ๆ–นๆŒ‰้’ฎ้…็ฝฎ this.discountId = ""; this.discountType = ""; this.discountInfo = ""; this.lineItems = []; this.tempCss = {}; this.renderQuickShop_ = this.win.SPZCore.Types.debounce(this.win, this.renderQuickShopModal.bind(this), 500); } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } buildCallback() { this.setupAction_(); }; init(data = []) { this.productStyleInfo = data; } handleRequestError_(data) { this.showToast(data?.message || data?.errors?.[0] || 'Unknown error'); }; showToast(message) { SPZ.whenApiDefined(document.getElementById("cart_match_discount_toast")).then((apis) => { apis.showToast(message); }); } //ๅค–้ƒจ็ป„ไปถ่ฐƒ็”จไผ ๅ€ผ setBundleData(products, config = "", id = "", type = "", info = {}) { this.bundleProducts = products; if(config) { this.bundleConfig = config; this.discountId = id; this.discountType = type; this.discountInfo = info; this.show_classic_bundle_spu_style = type === 'DT_CLASSIC_BUNDLE' && info.enable_min_purchase_qty && info.min_purchase_qty_type == 'spu'; // ็ปๅ…ธๆ†็ป‘ๅˆๅง‹ๅŒ–ๅ•†ๅ“ๆ•ฐๆฎ if(type == 'DT_CLASSIC_BUNDLE') { this.productStyleInfo = products.map((item) => { return this.getFilteredVariants_(item, 'single'); }); } } } handleChangeSort() { const result = this.productStyleInfo.reduce((map, item) => { if (!map[item.product_id]) { map[item.product_id] = []; } map[item.product_id].push(item); return map; }, {}); Object.values(result).forEach((item) => { this.handleSpzVariantRender_(item, item[0].product_id); this.handleProductOption_(item[0].product_id, true); }); } // ่ฐƒ็”จspz-tag็ป„ไปถ็š„doRenderๆ–นๆณ• handleSpzVariantRender_(data, id) { const spzVariantTag = SPZCore.Dom.scopedQuerySelector(document.body, `#promotionSpzVariantTags-${id}`); spzVariantTag && SPZ.whenApiDefined(spzVariantTag).then((api) => { api.render(data, true); }); } // ๆ‰ง่กŒ็ปๅ…ธๆ†็ป‘ๆœ€ไฝŽ่ดญไนฐๆ•ฐ้‡ๆ›ดๆ–ฐ handleMinPurchaseQtyUpdate_(data, id) { const minPruchaseQty = SPZCore.Dom.scopedQuerySelector(document.body, `#promotionMinPurchaseQty-${id}`); minPruchaseQty && SPZ.whenApiDefined(minPruchaseQty).then((api) => { api.render(data, true); }); } // ๆ›ดๆ–ฐไปทๆ ผ updateProductPrice_(data) { const bottomBtnContainer = SPZCore.Dom.scopedQuerySelector(getDiscountMatchPopupEl() || document.body, `#promotionBottomContainer`); if (data.length == 0) { bottomBtnContainer && SPZ.whenApiDefined(bottomBtnContainer).then((api) => { const renderInfo = { setting: this.bundleConfig, ...{ original_price: 0, received_discounts: 0, picked_qty: 0 } } api.render({original_price: 0, received_discounts: 0}, true); }); return; } const reqBody = { discount_id: this.discountId, customer: { customer_id: '', email: '', }, sales_channel: { sale_channel_type: "online", sale_channel_id: '2423756' }, line_items: data } // ๅฆ‚ๆžœๅทฒ็ปๆœ‰ไธ€ไธช่ฏทๆฑ‚ๅœจ็ญ‰ๅพ…๏ผŒ้‚ฃไนˆๅ–ๆถˆ่ฟ™ไธช่ฏทๆฑ‚ if (this.debounceTimer) { clearTimeout(this.debounceTimer); } this.debounceTimer = setTimeout(() => { this.xhr_.fetchJson(this.getDiscountPriceApi, { method: "post", body: reqBody }).then((res)=>{ // ๆ›ดๆ–ฐๅ•†ๅ“ๅˆ—่กจไปทๆ ผ Object.keys(res.line_items).forEach((key) => { const currentProductPrice = SPZCore.Dom.scopedQuerySelector(document.body, `#appDiscountProductPrice-${key}`); currentProductPrice && SPZ.whenApiDefined(currentProductPrice).then((api) => { api.render(res.line_items[key], true); }); }); // ๆ›ดๆ–ฐๅบ•้ƒจๆŒ‰้’ฎๆ€ปไปท/ๆ€ปๆŠ˜ๆ‰ฃไปท const picked_qty = data.reduce((acc, item) => { return acc + item.quantity; }, 0); bottomBtnContainer && SPZ.whenApiDefined(bottomBtnContainer).then((api) => { const data = { setting: this.bundleConfig, ...{ ...res.total_price, picked_qty } } api.render(data, true); }); }).catch((err)=>{ this.handleRequestError_(err); }).finally(()=>{ }) }, 100); } // ่ฟ˜ๅŽŸๅ•†ๅ“ไปทๆ ผ resetProductPrice_(data) { const {price, compare_at_price, id} = data; const currentProductPrice = SPZCore.Dom.scopedQuerySelector(document.body, `#appDiscountProductPrice-${id}`); currentProductPrice && SPZ.whenApiDefined(currentProductPrice).then((api) => { api.render({total_received_discounts: price, total_price: compare_at_price}, true); }); } //ๅค„็†ไธŽselector็ป„ไปถ็š„ไบคไบ’ handleProductOption_(productId, show) { const currentProductOption = SPZCore.Dom.scopedQuerySelector(document.body, `#promotionSelectOption-${productId}`); if (!currentProductOption) { return; }; currentProductOption.toggleAttribute('show', show); const isSelected = currentProductOption.hasAttribute('selected'); // !show ๅ–ๆถˆ้€‰ไธญ // !isSelected ้€‰ไธญๅ•†ๅ“ if (!show || !isSelected) { const productSelector = SPZCore.Dom.scopedQuerySelector(getDiscountMatchPopupEl() || document.body, `#promotionProductSelector`); productSelector && SPZ.whenApiDefined(productSelector).then((api) => { api.toggle_({ option: productId, value: show }); }); } } // ๆททๆญๅผน็ช—ๅ†…็š„ๅ‰็ซฏๅบ“ๅญ˜ๆ ก้ชŒ handleModalInventoryCheck_(data) { if(this.discountType == 'DT_MIX_MATCH_BUNDLE' || this.discountType == 'DT_CLASSIC_BUNDLE') { const currentVariantAddNum = this.modalVariantInfo.find((item) => item.variant_id == data.variant_id)?.quantity || 0; const quickShopBody = SPZCore.Dom.scopedQuerySelector(document.body, '#apps-discount-quick-shop-body'); if(!!data.variant && currentVariantAddNum == Number(data.variant.available_quantity)) { quickShopBody && quickShopBody.setAttribute('status', 'soldout'); } else { quickShopBody && quickShopBody.setAttribute('status', 'available'); } } else { return; } } // ๆทปๅŠ ๅ•†ๅ“ๅญๆฌพๅผ renderVariantTag() { let variantInfo; const quickShopBody = SPZCore.Dom.scopedQuerySelector(document.body, '#apps-discount-quick-shop-body'); quickShopBody && SPZ.whenApiDefined(quickShopBody).then((api) => { variantInfo = api.getVariantsData(); const productId = variantInfo.product_id; const variantId = variantInfo.variant_id; const minPruchaseQtyRender = variantInfo.product.discount_min_purchase_qty || variantInfo.variant.discount_info.discount_min_purchase_qty; if(this.discountType === 'DT_MIX_MATCH_BUNDLE') { const index = this.productStyleInfo.findIndex((item) => item.variant_id == variantInfo.variant_id); if (index != -1) { this.productStyleInfo[index].quantity = Number(this.productStyleInfo[index].quantity) + Number(variantInfo.quantity); this.updateProductPrice_(this.productStyleInfo); } else { this.productStyleInfo.push(this.getFilteredVariants_(variantInfo)); // ่‹ฅๅฝ“ๅ‰ๅ•†ๅ“ๅทฒ้€‰ไธญ๏ผŒๆ›ดๆ–ฐๅ•†ๅ“ไปทๆ ผ const currentProductOption = SPZCore.Dom.scopedQuerySelector(document.body, `#promotionSelectOption-${productId}`); const isSelected = currentProductOption && currentProductOption.hasAttribute('selected'); isSelected && this.updateProductPrice_(this.productStyleInfo); } const selectedVariantsFilter = this.productStyleInfo.filter((item) => item.product_id == productId); this.handleSpzVariantRender_(selectedVariantsFilter, productId); this.handleProductOption_(productId, true); } else { if(this.discountInfo.enable_min_purchase_qty == true && this.discountInfo.min_purchase_qty_type == 'spu' && minPruchaseQtyRender > 1) { const index = this.modalVariantInfo.findIndex((item) => item.variant_id == variantId); if (index != -1) { this.modalVariantInfo[index].quantity = Number(this.modalVariantInfo[index].quantity) + 1; } else { this.modalVariantInfo.push(this.getFilteredVariants_(variantInfo, 'classic_spu')); } const modalVariantTag = SPZCore.Dom.scopedQuerySelector(getDiscountMatchPopupEl() || document.body, '#promotionModalVariantTagRender'); modalVariantTag && SPZ.whenApiDefined(modalVariantTag).then((api) => { api.render(this.modalVariantInfo, true); }); this.handleModalInventoryCheck_(variantInfo); const selectedVariantsNum = this.modalVariantInfo.reduce((acc, item) => { return acc + item.quantity; }, 0); if(selectedVariantsNum == minPruchaseQtyRender) { this.handleSpzVariantRender_([this.getFilteredVariants_(variantInfo)], productId); this.productStyleInfo = this.productStyleInfo.filter((item) => item.product_id != productId).concat(this.modalVariantInfo); const renderData = this.productStyleInfo.filter((item) => item.product_id == productId).map((item) => { return { ...item, is_classic_bundle_product_list_variant_tag: true } }); const classicSpuTag = SPZCore.Dom.scopedQuerySelector(document.body, `#promotionClassicSpuTags-${productId}`); classicSpuTag && SPZ.whenApiDefined(classicSpuTag).then((api) => { api.render(renderData, true); }); this.updateProductPrice_(this.productStyleInfo); const quickView = SPZCore.Dom.scopedQuerySelector(document.body, '#apps-discount-quick-view'); quickView && SPZ.whenApiDefined(quickView).then((api)=>{ api.close(); }); this.modalVariantInfo = []; } else { return; } } // this.productStyleInfo ไธญๅทฒๅญ˜ๅœจไธŽproductId, variantId้ƒฝ็›ธๅŒ็š„ๅ•†ๅ“ ๅˆ™็›ดๆŽฅreturn ๅ…ณ้—ญๅผน็ช— const isExist = this.productStyleInfo.some((item) => item.product_id == productId && item.variant_id == variantId); if (isExist) { const quickView = SPZCore.Dom.scopedQuerySelector(document.body, '#apps-discount-quick-view'); quickView && SPZ.whenApiDefined(quickView).then((api)=>{ api.close(); }); return; } // ่‹ฅ this.productStyleInfo ไธญๅทฒๅญ˜ๅœจไธŽproductId็›ธๅŒ็š„ๅ•†ๅ“๏ผŒๅˆ™ไธๅ†ๆทปๅŠ  ๅฆๅˆ™ๆ›ฟๆข const index = this.productStyleInfo.findIndex((item) => item.product_id == productId); if (index != -1) { this.productStyleInfo[index] = this.getFilteredVariants_(variantInfo); } else { this.productStyleInfo.push(this.getFilteredVariants_(variantInfo)); } const selectedVariantsFilter = this.productStyleInfo.filter((item) => item.product_id == productId); this.handleSpzVariantRender_(selectedVariantsFilter, productId); this.handleMinPurchaseQtyUpdate_({discount_min_purchase_qty: minPruchaseQtyRender}, productId); this.updateProductPrice_(this.productStyleInfo); } const quickView = SPZCore.Dom.scopedQuerySelector(document.body, '#apps-discount-quick-view'); quickView && SPZ.whenApiDefined(quickView).then((api)=>{ api.close(); }); }); } // ๅ•ๅ˜ไฝ“็‚นๅ‡ปๆทปๅŠ ๆŒ‰้’ฎ renderSingleVariant(data) { const { product_id } = data; const currentProduct = this.bundleProducts.find((product) => product.id == product_id); // ่‹ฅๅฝ“ๅ‰ๅ•†ๅ“ๅทฒๅญ˜ๅœจ๏ผŒๅˆ™ไธๅ†ๆทปๅŠ  ่€Œๆ˜ฏๆ›ดๆ–ฐๆ•ฐ้‡ const index = this.productStyleInfo.findIndex((item) => item.product_id == product_id); if (index != -1) { this.productStyleInfo[index].quantity = Number(this.productStyleInfo[index].quantity) + 1; this.updateProductPrice_(this.productStyleInfo); } else { this.productStyleInfo.push(this.getFilteredVariants_(currentProduct, 'single')); } const renderProductArr = this.productStyleInfo.filter((item) => item.product_id == product_id); this.handleSpzVariantRender_(renderProductArr, product_id); this.handleProductOption_(product_id, true); } // ่ฟ‡ๆปค้€‰ไธญๅ•†ๅ“็š„ๅญๆฌพๅผ ่Žทๅ–ๆœ‰็”จ็š„ไฟกๆฏ product_id,variant_id,price,compare_at_price,quantity,title,variant_title getFilteredVariants_(data, type = '') { const { id, title, variants, inventory_tracking, inventory_policy, inventory_quantity, product_type } = data; const { product_id, variant_id, variant, quantity, product, discount_min_purchase_qty } = data; const isSingle = type == 'single'; const variantData = isSingle ? (variants[0] || data) : variant; const productData = isSingle ? data : product; let item_quantity = 0; if (this.discountType === 'DT_MIX_MATCH_BUNDLE') { item_quantity = isSingle ? 1 : Number(quantity); } else if (type === 'classic_spu') { item_quantity = 1; } else { item_quantity = discount_min_purchase_qty || productData.discount_min_purchase_qty || variantData.discount_info.discount_min_purchase_qty || 1; } return { product_id: isSingle ? id : product_id, variant_id: variantData?.id || '', price: variantData?.price || '0.00', compare_at_price: variantData?.compare_at_price || '0.00', quantity: item_quantity, inventory_tracking: productData.inventory_tracking, inventory_policy: productData.inventory_policy, inventory_quantity: productData.inventory_quantity, product_type: productData.product_type || this.bundleProducts.find((item) => item.id == product_id)?.product_type || this.bundleProducts.find((item) => item.id == id)?.product_type || '', title: productData.title, variant_title: variantData?.options.map((option) => option.value).join('/') || '', is_multi_style: productData.variants.length > 1, } } handleLoading_ (event) { const { type, action } = event; const loadingElementId = type === 'product' ? '#discount-match-drawer-products_loading' : '#apps-discount-whole-loading'; const loadingElement = document.querySelector(loadingElementId); if (loadingElement) { SPZ.whenApiDefined(loadingElement).then((api) => { if (action === 'show') { api.show_(); } else { api.close_(); } }); } } handleSelectProduct(productArr) { // ไปŽthis.productStyleInfo ่ฟ‡ๆปคๅ‡บ้€‰ไธญ็š„ๅ•†ๅ“ const selectedProducts = this.productStyleInfo.filter((item) => productArr.includes(item.product_id)); this.updateProductPrice_(selectedProducts); } // ๆธฒๆŸ“ๅŠ ่ดญๅผน็ช—ๅ†…ๅฎน async renderQuickShopModal(data){ this.handleLoading_({type: 'whole', action: 'show'}); this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product?product_id=${data.product_id}&discount_id=${this.discountId}&apply_scenario=1`, { method: "get", }).then(async(res)=>{ //flashไธป้ข˜ๆ”พblockๆœ‰ๅฑ‚็บง้—ฎ้ข˜ if(/Flash/.test(window.C_SETTINGS.theme.merchant_theme_name) && document.querySelector(".productInfoSection")) { this.tempCss.zIndex = document.querySelector(".product-info-body").style.zIndex; document.querySelector('.product-info-body').style.zIndex="1048"; } this.handleLoading_({type: 'whole', action: 'close'}); const $quickShop = await SPZ.whenApiDefined(document.querySelector('#apps-discount-quick-view-render')); // ๅฎšไน‰้ป˜่ฎคๆธฒๆŸ“็š„ๅญๆฌพๅผ const selectedVariant = res.product.variants.find((v)=> (v.available && v.is_hit_discount)) || res.product.variants[0]; let selectedValues = {}; selectedVariant.options.length && selectedVariant.options.forEach(item => { selectedValues[item.name] = item.value; }) // ้ป˜่ฎค้€‰ไธญ็š„ ๅญๆฌพๅผใ€ options res.product.defaultSelectValues = selectedValues; let data = {...res.product, product:res.product, selectedVariant, show_classic_bundle_spu_style: this.show_classic_bundle_spu_style, discountType: this.discountType}; $quickShop.render(data); // ๆ‰“ๅผ€ๅŠ ่ดญๅผน็ช— SPZ.whenApiDefined(document.querySelector(`#apps-discount-quick-view`)).then((api)=>{ api.open(); }); }).catch((err)=>{ this.handleLoading_({type: 'whole', action: 'close'}); }) } // ่Žทๅ–้€‰ไธญ็š„ๅ•†ๅ“ids getDefaultSelectorOptions_() { try { const selectedOptions = SPZCore.Dom.scopedQuerySelectorAll(document.body, '[id^="promotionSelectOption-"][selected]'); return SPZCore.Types.toArray(selectedOptions).map((item) => item.getAttribute('option')); } catch (error) { return []; } } // ๅˆ ้™คๅ•†ๅ“ๅญๆฌพๅผ deleteVariantTag(data) { const { product_id, variant_id } = data; if(this.discountInfo.enable_min_purchase_qty == true && this.discountInfo.min_purchase_qty_type == 'spu') { const modalProductVariants = this.modalVariantInfo.filter((item) => item.product_id == product_id && item.variant_id != variant_id); const modalVariantTag = SPZCore.Dom.scopedQuerySelector(getDiscountMatchPopupEl() || document.body, '#promotionModalVariantTagRender'); modalVariantTag && SPZ.whenApiDefined(modalVariantTag).then((api) => { api.render(modalProductVariants, true); }); this.handleModalInventoryCheck_(data); this.modalVariantInfo = modalProductVariants; return; } const currentProductVariants = this.productStyleInfo.filter((item) => item.product_id == product_id && item.variant_id != variant_id); this.handleSpzVariantRender_(currentProductVariants, product_id); // ๆ›ดๆ–ฐselectedVariants this.productStyleInfo = this.productStyleInfo.filter((item) => item.variant_id != variant_id); if(currentProductVariants.length > 0) { // currentProductVariants ไธญๅช่ฆๆœ‰ไธ€้กนๆ˜ฏๅคšๆฌพๅผๅ•†ๅ“๏ผŒๅฐฑๆ›ดๆ–ฐไปทๆ ผ const isMultiStyle = currentProductVariants.some((item) => item.is_multi_style); if (!isMultiStyle) return; this.handleProductOption_(product_id, true); const selected = this.getDefaultSelectorOptions_(); this.updateProductPrice_(this.productStyleInfo.filter((item) => selected.includes(item.product_id))); } else { this.handleProductOption_(product_id, false); this.resetProductPrice_(this.bundleProducts.find((item) => item.id == product_id)); } } // ๅŠ ่ดญๅผน็ช—ๆœชๅ‚ไธŽๆดปๅŠจ ๅŠ ่ดญๆŒ‰้’ฎไธๅฏ็‚นๅ‡ป TODO ๆ‹†ๅ‡บๆฅ handleNotHitDiscount_(data) { const $quickShopBody = document.querySelector('#apps-discount-quick-shop-body'); //ๅฝ“ๅ‰ๅญๆก†ๅผๆœชๅ‘ฝไธญๆดปๅŠจ if(data.variant.is_hit_discount == false) { $quickShopBody.setAttribute('variantstatus', 'notHitDiscount') } else { $quickShopBody.setAttribute('variantstatus', '') } } setupAction_() { // ๅญๆฌพๅผ ๆœชๅ‚ไธŽๆดปๅŠจ this.registerAction('handleNotHitDiscount', (invocation) => { const data = invocation.args.data; this.handleNotHitDiscount_(data); }); // ๆธฒๆŸ“ๅŠ ่ดญๅผน็ช— this.registerAction('renderQuickShop', (invocation) => { const data = invocation.args; this.renderQuickShop_(data); }); this.registerAction('renderSingleVariant', (invocation) => { const data = invocation.args; this.renderSingleVariant(data); }); this.registerAction('getVariantInfo', (invocation) => { this.renderVariantTag(); }); this.registerAction('deleteVariantTag', (invocation) => { const data = invocation.args; this.deleteVariantTag(data); }); this.registerAction('getSelectedProduct', (invocation) => { const data = invocation.args.data; this.handleSelectProduct(data); }); //TODO ๅŠ ่ดญไธ‹ๅ•้€ป่พ‘ๅ•็‹ฌๆ‹†็ป„ไปถ this.registerAction('handleClick', (data) => { if(this.discountType == 'DT_CLASSIC_BUNDLE') { this.lineItems = this.productStyleInfo; } else { const selectedOptions = SPZCore.Dom.scopedQuerySelectorAll(document.body, '[id^="promotionSelectOption-"]'); const idArr = [...selectedOptions].reduce((acc, item) => { if (item.hasAttribute('selected')) { const optionValue = item.getAttribute('option'); if (optionValue) { acc.push(optionValue); } } return acc; }, []); this.lineItems = this.productStyleInfo.filter((item) => idArr.includes(item.product_id)); } const action = data.args.action === "cart"; if(action) { //add to cart this.xhr_ .fetchJson(this.batchAtcApi, { method: 'POST', body: { line_items: this.lineItems.map((item) => { return { product_id: item.product_id, variant_id: item.variant_id, quantity: Number(item.quantity) } }) } }) .then((data) => { setTimeout(() => { window.location.href = '/cart'; }); }) .catch(async (error) => { await error.then((data) => { this.handleRequestError_(data); }); }); } else { //checkout this.xhr_ .fetchJson(this.buyNowApi, { method: 'POST', body: { line_items: (this.lineItems || []).map((product) => { return { quantity: Number(product.quantity), variant_id: product.variant_id, note: product.note || '', properties: product.properties || {} } }), refer_info: { source: 'buy_now' } } }) .then(async (data) => { if (data.state === 'success') { window.location.href = data.data?.checkout_url; } this.handleRequestError_(data); }) .catch(async (error) => { await error.then((data) => { this.handleRequestError_(data); }); }); } }); this.registerAction('resetModalVariantInfo', () => { //flashไธป้ข˜ๆ”พblockๆœ‰ๅฑ‚็บง้—ฎ้ข˜ if(/Flash/.test(window.C_SETTINGS.theme.merchant_theme_name) && document.querySelector(".productInfoSection")) { document.querySelector('.product-info-body').style.zIndex = this.tempCss.zIndex; } this.modalVariantInfo = []; }); this.registerAction('handleModalInventoryCheck', (invocation) => { const data = invocation.args.data; this.handleModalInventoryCheck_(data); }); }; }; SPZ.defineElement('spz-custom-discount-bundle-products', SpzCustomDiscountBundleProducts);
class SpzCustomDiscountBundle extends SPZ.BaseElement { constructor(element) { super(element); this.xhr_ = SPZServices.xhrFor(this.win); this.variant_id = '853b7ba2-247b-410a-8682-fd290ba8fc87'; this.discountCardApi = "\/api\/storefront\/promotion\/product_details_page\/card"; this.productsApi = "\/api\/storefront\/promotion\/product_page\/product\/list"; this.bundleRenderElement = "appDiscountProductBundle"; this.model = { loading: false, page: 2, limit: 20, params: { count: 0, has_more: false, sort: { by: "price", direction: "asc" } } } this.discountId = ""; this.discountType = ""; this.bundleProducts = []; //ๆ†็ป‘ๆดปๅŠจๅ•†ๅ“ this.buttomConfig = {};//ๆ€ปไปทๅŠไธ‹ๆ–นๆŒ‰้’ฎ้…็ฝฎ this.renderDiscount = this.win.SPZCore.Types.debounce(this.win, this.discountHandel.bind(this) , 500); } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } async getDiscountCardList() { const productId = 'eb589160-7334-4f41-8b7b-649d3296f160'; const productType = 'default'; const variantId = this.variant_id; if(!productId || !variantId || !productType) { return; } const reqBody = { product_id: productId, variant_id: variantId, discount_types: ["DT_CLASSIC_BUNDLE","DT_MIX_MATCH_BUNDLE"], discount_methods: ["DM_AUTOMATIC"], customer: { customer_id: '', email: '', }, product_type: productType } const data = await this.xhr_.fetchJson(this.discountCardApi, { method: "post", body: reqBody }).then(res => { return res; }).catch(err => { console.error(err); }) return data; }; async discountHandel() { const $bundle = document.querySelector(".app-discount-bundle-inner"); $bundle && SPZCore.Dom.removeElement($bundle); const data = await this.getDiscountCardList(); if(!data || !data.discount_info || data.discount_info.discount_id === "0") { return; } //ๅ˜้‡่ต‹ๅ€ผ this.bundleProducts = data.product_info.product; this.buttomConfig = data.product_setting; this.discountId = data.discount_info.discount_id; this.discountType = data.discount_info.discount_type; this.model.params ={ count: data.product_info.count, has_more: data.product_info.has_more, sort: data.product_info.sort } //็ป™ๆ†็ป‘็ป„ไปถไผ ๅ€ผ SPZ.whenApiDefined(document.getElementById("appDiscountBundleProductsFunc")).then((api) => { api.setBundleData(this.bundleProducts, this.buttomConfig, this.discountId, this.discountType, data.discount_info); }) document.querySelector(".app_discount_bundle").dataset.discountType = data.discount_info.discount_type; SPZ.whenApiDefined(document.getElementById(this.bundleRenderElement)) .then(apis => { apis.render(data,true).then(() => { SPZ.whenApiDefined(document.getElementById("bundleProductsRender")).then((api) => { api.render(data,true).then(() => { this.bindEvent_(); if(this.bundleProducts.length < 5) { document.querySelector(".app-discount-bundle-arrow-left").style.display="none"; document.querySelector(".app-discount-bundle-arrow-right").style.display="none"; } //็ปๅ…ธๆ†็ป‘ๆธฒๆŸ“ๆŒ‰้’ฎ if(this.discountType === "DT_CLASSIC_BUNDLE") { SPZ.whenApiDefined(document.getElementById("promotionBottomContainer")).then((api) => { const buttonData = { setting: this.buttomConfig, ...data.product_info.total_price } api.render(buttonData, true); }) } }) }) }) .then(() => { document.querySelector(".app-discount-bundle-inner").classList.add("discount_bundle_" + data.product_setting.template_type || "vertical"); }); }); //ๆœฌๅœฐ่ฐƒ่ฏ• ๆ”พๅ•†่ฏฆblock้‡Œ const isSection = document.querySelector( 'div[data-section-type^="shoplazza://apps/publicapp/blocks/discount_bundle/"] .app_discount_bundle' ); if(!isSection) { document.querySelector(".app_discount_bundle").classList.add("productInfoSection"); } }; // ่Žทๅ–ๅŠ ่ฝฝ็š„ๅ•†ๅ“ๆ•ฐๆฎ๏ผŒๆ‹ผๆŽฅhtmlๆจกๆฟ async loadData(cb) { // ่ฏทๆฑ‚ๆ•ฐๆฎ this.model.loading = true; //ๆŸฅ่ฏขๆดปๅŠจๅ•†ๅ“ๆŽฅๅฃ const reqBody = { discount_id: this.discountId, page: this.model.page, limit: this.model.limit, "apply_scenario": "AS_ENTITLED_PRODUCT", sort: this.model.params.sort, sales_channel: { sale_channel_type: "online", sale_channel_id: '2423756' }, product_id: 'eb589160-7334-4f41-8b7b-649d3296f160' } this.xhr_.fetchJson(this.productsApi, { method: "post", body: reqBody }).then(async(res)=>{ const count = res.count; this.model.params.has_more = res.has_more; if (count > 0) { this.model.page++; if (res.products && res.products.length > 0) { let products = res.products.map((product) => { return { ...product, url: appDiscountUtils.globalizePath(product.url), image_padding_bottom: appDiscountUtils.image_padding_bottom(product.image.width, product.image.height,'no-limit'), discount_type: this.discountType } }); // ่Žทๅ–ๅ•†ๅ“ๅˆ—่กจๆธฒๆŸ“ๆจกๆฟ, domๆŒ‚่ฝฝ const $content = document.querySelector(".app-discount-bundle-products"); this.templates_ = SPZServices.templatesForDoc(); this.templates_.renderTemplate(document.querySelector('#appDiscountBundleProductsTemplate'), products).then((el) => { const childNodes = el.querySelectorAll('.as-render-product-item'); if (childNodes && childNodes.length > 0) { $content.append(...childNodes); } }).then(() => { //้‡ๆ–ฐๆธฒๆŸ“ljs-selector const productSelector = SPZCore.Dom.scopedQuerySelector(document.body, `#promotionProductSelector`); productSelector && SPZ.whenApiDefined(productSelector).then((api) => { api.init(); }); }); this.bundleProducts = [...this.bundleProducts, ...res.products]; SPZ.whenApiDefined(document.getElementById("appDiscountBundleProductsFunc")).then((api) => { api.setBundleData(this.bundleProducts); }) // ็›‘ๅฌloadๅŽปๆމ็ฐ่‰ฒ่ƒŒๆ™ฏ document.dispatchEvent(new CustomEvent('fire.load.img')); // ่งฆๅ‘ๆ‡’ๅŠ ่ฝฝ cb && cb(products); window.lazyLoadInstance && window.lazyLoadInstance.update(); } } this.model.loading = false; }).catch((err)=>{ console.error(err); this.model.loading = false; }) }; setupAction_() { this.registerAction('shiftMove', (data) => { const $el = document.querySelector(".app-discount-bundle-products"); const action = data.args.direct === "right"; const scrollwidth = action ? $el.offsetWidth : -$el.offsetWidth; $el.scrollBy({ left: scrollwidth, behavior: 'smooth' }); }); }; bindEvent_() { // ็›‘ๅฌๅญๆฌพๅผๅˆ‡ๆข๏ผŒ้‡ๆ–ฐๆธฒๆŸ“ document.addEventListener('dj.variantChange', async(event) => { const variant = event.detail.selected; if (variant.product_id == 'eb589160-7334-4f41-8b7b-649d3296f160') { this.variant_id = variant.id; } this.renderDiscount(); }); // ็›‘ๅฌๆปšๅŠจ๏ผŒ่ฏทๆฑ‚ๆ•ฐๆฎ const $el = document.querySelector(".app-discount-bundle-products"); if($el) { $el.addEventListener("scroll", this.win.SPZCore.Types.debounce( this.win, () => { const isLeft = $el.scrollLeft === 0; const isRightEnd = $el.scrollLeft + $el.offsetWidth + 10 >= $el.scrollWidth; const isBottomEnd = $el.scrollTop + $el.clientHeight + 10 >= $el.scrollHeight; const isEnd = isBottomEnd && isRightEnd; if(isEnd && this.model.params.has_more && !this.model.loading) { this.loadData(); } }, 50 )) }; }; buildCallback() { this.setupAction_(); }; mountCallback() { this.renderDiscount(); this.bindEvent_(); }; } SPZ.defineElement('spz-custom-discount-bundle', SpzCustomDiscountBundle);

๐ŸชดWe are committed to providing our customers with quality, affordable seeds. ๐ŸŒฑ

๐Ÿ’ต Payments Via PayPal®&Credit Card.
๐Ÿ˜ 99.6% of customers buy  200 seeds or more to share
โœจPriority is given to delivery after payment
โœˆ Worldwide Express Shipping Available

๐ŸŒนWelcome to the Enchanting World of Starry Sky Roses!

Mysterious like the colors of the cosmos, rare and mesmerizing. Seize the opportunity to become one of the lucky few to own these precious blooms!

The Enigmatic Beauty of Starry Sky Roses

๐ŸŒŸ Magical Cosmic Colors: The flowers of Starry Sky Roses resemble the stars in the night sky, mysterious and captivating. Each bloom is unique, evoking boundless imagination.

๐ŸŒŸ A Rare Gem: Starry Sky Roses are a rare treasure, seldom seen. Don't miss out on this extraordinary and rare spectacle, make them the shining star of your garden!

Planting and Care Guide

๐ŸŒฟ Simple Cultivation: Planting Starry Sky Roses is not complicated. We provide detailed planting guides to make it easy for you to get started.

๐ŸŒฟ Ideal Growing Environment: Starry Sky Roses love ample sunlight and well-draining soil. Perfect for gardens, balconies, or pots.

๐ŸŒฟ Care Tips: Water regularly, keeping the soil moist but avoiding overwatering. Regular fertilization will keep your Starry Sky Roses flourishing and beautiful.

Mature Plant Information

๐ŸŒฑ Fast Growth: Starry Sky Roses grow rapidly, and within a few months, you'll witness breathtaking blooms.

๐ŸŒฑ High-Quality Seeds: We offer top-quality Starry Sky Rose seeds, ensuring you get the most exquisite flowers.

๐ŸŒฑ Limited Stock: Due to the rarity of Starry Sky Roses, our stock is limited. Act fast and seize the chance to own these precious blooms!

Ignite Your Desire to Purchase

๐Ÿ›’ Click to Buy: Click the buy button now to bring home the fantastical Starry Sky Roses and fill your garden with mystical beauty!

๐Ÿ›’ Limited-Time Offer: Grab the limited-time offer to save more on your purchase of Starry Sky Rose seeds.

๐Ÿ›’ Become a Lucky Owner: Join the select few who possess the magic of Starry Sky Roses and showcase your unique taste to the world!

Purchase Starry Sky Rose seeds now and let your garden bloom with the enigmatic beauty of the cosmos!

๐ŸŒฑ Here is a detailed step-by-step guide on how to plant Starry Sky Rose seeds:

Step 1: Prepare the Soil

Choose a well-draining and fertile soil for planting the Starry Sky Rose seeds. The soil should be loamy and rich in organic matter. Ensure that the soil pH is around 6.5 to 7.5, slightly acidic to neutral.

Step 2: Germination

  1. Soak the Starry Sky Rose seeds in room temperature water for 24 hours before planting. This will help to soften the seed coat and improve germination rates.
  2. Prepare small pots or seed trays with drainage holes to prevent waterlogging.
  3. Fill the pots or seed trays with the prepared soil, leaving about 0.5 inches of space at the top.

Step 3: Sowing the Seeds

  1. Plant one Starry Sky Rose seed in each pot or seed tray, placing it about 0.5 to 1 inch deep into the soil.
  2. Cover the seeds with a thin layer of soil and gently pat it down to ensure good seed-to-soil contact.

Step 4: Watering

  1. Water the soil gently immediately after sowing to ensure it is evenly moist.
  2. During the germination process, keep the soil consistently moist, but avoid overwatering to prevent rot.

Step 5: Germination Period

  1. Place the pots or seed trays in a warm and well-lit location, preferably with indirect sunlight.
  2. The germination period for Starry Sky Rose seeds is usually around 3 to 4 weeks, but it may vary.
  3. Be patient and keep a close eye on the pots to spot the first signs of sprouting.

Step 6: Transplanting

  1. Once the seedlings have grown to about 2 inches in height and developed at least two sets of leaves, they are ready for transplanting.
  2. Choose a sunny location in your garden or a larger pot with good sunlight exposure for the seedlings.

Step 7: Transplanting Process

  1. Carefully remove the seedlings from the original pots or seed trays, making sure not to damage the delicate roots.
  2. Dig a hole in the new location, slightly larger than the root ball of the seedling.
  3. Place the seedling into the hole and gently fill the space around it with soil, pressing it down gently.

Step 8: Watering and Care

  1. Water the transplanted seedlings thoroughly after planting to help them settle in the new location.
  2. Keep the soil consistently moist during the growing season, but avoid waterlogging.
  3. Fertilize the Starry Sky Roses once a month with a balanced liquid fertilizer to encourage healthy growth and blooming.

Step 9: Pruning

  1. Prune the Starry Sky Rose bushes regularly to maintain their shape and encourage more blooms.
  2. Remove any dead or faded flowers to encourage continuous blooming.

Step 10: Enjoy the Beauty

Sit back, relax, and enjoy the mesmerizing and enigmatic beauty of your blooming Starry Sky Roses. Admire the cosmos-like colors and feel the magic they bring to your garden!

Remember, each plant is unique, and it's essential to observe and cater to the specific needs of your Starry Sky Roses to ensure their optimal growth and beauty. Happy gardening!

๐Ÿ“ฆPackage:

50 Seeds/100 Seeds/200 Seeds(It depends on the quantity you purchased๏ผ‰

Processing

It usually takes 3-5 business days to prepare an order. If processing time take longer than that, an email will be sent to customer's registered email box.

โ™ป๏ธ14 Days Easy Return & Exchange
Items can be returned or exchanged within 14 days from the delivered day. 

AFTER-SALE SERVICE

  • Shipping - Worldwide Express Shipping is available
  • Returns>> Fast refund,100% Money Back Guarantee.
  • If for whatever reason you're not completely satisfied, then return the product within 90 days.

AT Our Store, WE HAVE STRONGLY CONFIDENCE ON OUR PRODUCTS. EVERY PRODUCT INCLUDES A 24-MONTH, WORRY-FREE GUARANTEE. IF YOU HAVE ANY PROBLEM OR SUGGESTION, PLEASE CONTACT US FREELY, WE WILL PROVIDE FRIENDLY SUPPORT FOR YOU IN 24 HR.

โœ…Payments Via PayPal®, Credit and Debit Card.
If you want to checkout with a Credit and Debit Card, just enter your * Card No, * Expiration Date, and * CV

Insured Worldwide Shipping:  Each order includes real-time tracking details and insurance coverage in the unlikely event that a package gets lost or stolen in transit.

Money-Back Guarantee: If your items arrive damaged or become defective within 15 days of normal usage, we will gladly issue out a replacement or refund.

24/7 Customer Support: We have a team of live reps ready to help and answer any questions you have within a 24-hour time frame, 7 days a week.

Safe & Secure Checkouts: We use state-of-the-art SSL Secure encryption to keep your personal and financial information 100% protected.

At GardenRo, we believe in the extraordinary power of small actions. With our "Seeds of Hope" campaign, your shopping experience takes on a whole new meaning.

Embark on a shopping experience with purpose! For each purchase, $1 will be donated to UNICEF — an initiative that plants seeds of hope in the lives of children worldwide. Join us in cultivating positive change while enjoying quality products.

Your purchase not only brings you exceptional products but also contributes to essential programs that support children's health, education, and well-being. Together, we are sowing the seeds of a better future.

Make your shopping matter. Choose quality, choose compassion.

Thank you for being a part of our Seeds of Hope Campaign!