⏰Last Day Promotion 59% OFF - Car Dual Sides LED Dual Color Light
${function() {
const minInventory = parseInt('73');
const maxInventory = parseInt('138');
const randomInventory = Math.round(Math.random() * (maxInventory - minInventory)) + minInventory;
const customText = "Only {stock} item(s) left in stock!".replace(/\{stock\}/g, '' + randomInventory + '');
const barWidth = (randomInventory / maxInventory) * 100 + '%';
return `
`;
}()}
${function() {
const variantData = data.variant || {"id":"c4bfe75e-8cf7-4bf9-8024-9f6c60cf49ad","product_id":"f5822f34-683b-4534-922b-e263d2d03202","title":"Set-1(White+Yellow+Yellow)","weight_unit":"kg","inventory_quantity":1000,"sku":"","barcode":"","position":1,"option1":"Set-1(White+Yellow+Yellow)","option2":"","option3":"","note":"","image":{"src":"\/\/img.staticdj.com\/1f4eaafd33676820157acaa3ab1b872d.jpeg","path":"1f4eaafd33676820157acaa3ab1b872d.jpeg","width":750,"height":750,"alt":"","aspect_ratio":1},"wholesale_price":[{"price":22.98,"min_quantity":1}],"weight":"0","compare_at_price":"39.99","price":"22.98","retail_price":"39.99","available":true,"url":"\/products\/car-lights?variant=c4bfe75e-8cf7-4bf9-8024-9f6c60cf49ad","available_quantity":999999999,"options":[{"name":"Color","value":"Set-1(White+Yellow+Yellow)"}],"off_ratio":43,"flashsale_info":[],"sales":5482};
const saveType = "amount";
const productLabelDiscountOn = true;
return `
-
${saveType == 'percentage'
? `-${variantData.off_ratio}%`
: `-`
}
`;
}()}
The current produc does not participate any Rebate. Switch the participating product to check the design.
(This prompt will not be displayed on the client-side.)
var theme = window.C_SETTINGS && C_SETTINGS.theme && C_SETTINGS.theme.merchant_theme_name;
var isFlash = /Flash/gi.test(theme);
var isGeek = /Geek/gi.test(theme);
var isNova23 = /Nova 2023/gi.test(theme);
var isWind = /Wind/gi.test(theme);
var isOnePage = /OnePage/gi.test(theme);
var isHero = /Hero/gi.test(theme);
var isBoost = /Boost/gi.test(theme);
var isEva = /Eva/gi.test(theme);
var isFarida = /Farida/gi.test(theme);
var isPluto = /Pluto/gi.test(theme);
var isLifeStyle = /Life Style/gi.test(theme);
if(window.self === window.top) {
(window.disabled_exts ||=[]).push('product_detail_rebate');
}
class SpzRebateComponent extends SPZ.BaseElement {
constructor(element) {
super(element);
}
xhr_ = SPZServices.xhrFor(this.win);
viewport_ = this.getViewport();
action_ = null;
lang = document.documentElement.lang || 'en-US';
landPage = "\/promotions\/rebate\/";
pageType = 1;
cart = [];
initData = null;
rebateInfo = null;
renderData = null;
footerImage = `${this.win.SHOPLAZZA["image_domain"]}oss/operation/e8ebb03dbb710457ca3b4b6a70898ab2.svg`;
isLayoutSupported(layout) {
return layout == SPZCore.Layout.LOGIC;
}
buildCallback() {
this.initData = this.getProduct();
this.action_ = SPZServices.actionServiceForDoc(this.element);
this.registerAction("triggerGetRenderData", () => {
const event = SPZUtils.Event.create(this.win, "triggerGetRenderData", this.renderData);
this.action_.trigger(this.element, "getRenderData", event);
});
this.registerAction("bindPropagation", () => {
document.querySelector(".product_detail_rebate_list").addEventListener("click", e => {
e.stopPropagation();
this.win.sa &&
this.win.sa.track("plugin_rebate_promotion_click", {
plugin_timestamp: Date.now(),
plugin_location: "info",
product_id: this.initData.product.id,
discount_id: this.rebateInfo.discount_list.map((item) => item.discount_id)[0],
});
});
});
}
async mountCallback() {
document.addEventListener("dj.variantChange", e => {
const data = e.detail;
if (document.querySelector("#product-select-modal.show")) return;
this.initData = this.getProductJson(data);
if (this.initData && this.initData.product && data.product && this.initData.product.id === data.product.id) {
this.initRebate(this.initData, true);
} else {
this.getRebateInfo();
}
});
document.addEventListener("dj.addToCart", e => {
const v = e.detail;
this.rebateInfo &&
this.win.sa &&
this.win.sa.track("plugin_rebate_atc", {
variant_discount_id: this.getVariantDiscountId(v.variant_id).map(item => item.discount_id),
discount_ids: this.rebateInfo.discount_list.map(item => item.discount_id),
variant_id: v.variant_id,
product_id: v.product_id,
price: v.item_price,
number: v.number,
});
});
await this.getRebateInfo();
setTimeout(()=>{
if (document.querySelector(".plugin-container__bottom-fixed")) {
this.showDiscountPopupsInfoBar();
} else {
this.win.addEventListener("extloaded", () => {
this.showDiscountPopupsInfoBar();
});
}
},1000)
}
getProductJson = (mergeData = {}) => {
const productJson = document.querySelector("#product-json");
let productJsonData = {};
if (productJson && productJson.textContent) {
try {
productJsonData = JSON.parse(productJson.textContent);
} catch (e) {}
}
// 深度合并函数
const deepMerge = (target, source) => {
if (source === null || source === undefined) {
return target;
}
if (typeof source !== 'object' || Array.isArray(source)) {
return source;
}
const result = { ...target };
for (const key in source) {
if (source.hasOwnProperty(key)) {
if (
typeof source[key] === 'object' &&
source[key] !== null &&
!Array.isArray(source[key]) &&
typeof target[key] === 'object' &&
target[key] !== null &&
!Array.isArray(target[key])
) {
result[key] = deepMerge(target[key], source[key]);
} else {
result[key] = source[key];
}
}
}
return result;
};
return deepMerge(productJsonData, mergeData);
}
getProduct = (() => {
document.addEventListener("dj.variantChange", e => {
if (!e.detail || !e.detail.product) return;
let productJsonData = getProductJson(e.detail);
if (this.win.jQuery && this.win.jQuery.fn && this.win.jQuery(document).data("djproduct") && productJsonData) {
this.win.jQuery(document).data("djproduct", productJsonData);
}
});
return () => {
let productData = null;
if (this.win.jQuery && this.win.jQuery.fn) {
try {
let product = this.win.jQuery(document).data("djproduct");
if (product) {
productData = JSON.parse(JSON.stringify(product));
} else {
productData = null;
}
} catch (error) {
productData = null;
}
}
if (!productData) {
const productJson = document.querySelector("#product-json");
productData = (productJson && productJson.textContent && JSON.parse(productJson.textContent)) || null;
}
return productData;
};
})();
clearRebateInfoDom = () => {
// 1. 清除 apis.render 渲染的 DOM (app_rebate_section)
const rebateSection = document.getElementById('app_rebate_section');
if (rebateSection) {
const rebateRuleSection = rebateSection.querySelector('.rebate_rule_section');
if (rebateRuleSection) {
rebateRuleSection.remove();
}
}
// 2. 清除 templates_.renderTemplate 渲染的 DOM (app_rebate_block)
const rebateBlock = document.getElementById('app_rebate_block');
if (rebateBlock) {
const appRebateList = rebateBlock.querySelector('.app_rebate_list');
if (appRebateList) {
appRebateList.remove();
}
}
// 3. 清除 insertProductDetailRebateTag 插入的 DOM
// 清除所有 rebate-tag 元素
document.querySelectorAll('.slider-discount-tag.dj_skin_product_title.rebate-tag').forEach(tag => {
tag.remove();
});
// 移除 data-rebate-tag 属性
const productContainer = document.querySelector('.product-details, .product-details, .page_container, .product-images, [data-section-type="product"]');
if (productContainer && productContainer.hasAttribute('data-rebate-tag')) {
productContainer.removeAttribute('data-rebate-tag');
}
};
initRebate = this.win.SPZCore.Types.debounce(
this.win,
(async (data) => {
let discount_list = Object.assign([], this.rebateInfo?.discount_list);
/* 按子商品的多少对优惠信息进行排序 */
discount_list &&
discount_list.sort((a, b) => {
return b.variant_ids.length - a.variant_ids.length;
});
/* 选中子商品时 筛选子商品的优惠信息 */
if (data.selected && data.selected.id) {
discount_list = this.getVariantDiscountId(data.selected.id);
}
/* 无满减信息 */
if (!(discount_list && discount_list.length)) {
this.clearRebateInfoDom();
return;
}
const isSection = !!document.querySelector(
`div[data-section-type^="shoplazza://apps/publicapp/blocks/rebate"] #rebate_custom_component`
);
if (
(this.rebateInfo.rebate_type == "sku" && data && data.selected && data.selected.id) ||
this.rebateInfo.rebate_type == "spu"
) {
let nowLandpage = this.landPage;
if (discount_list[0]) {
nowLandpage = this.landPage + discount_list[0].discount_id || "";
}
const info = {
rebate: discount_list[0],
maxShowCount: this.win.innerWidth > 768 ? 3 : 1,
landPage: nowLandpage,
modalFooterImg: `url(${`${this.win.SHOPLAZZA["image_domain"]}oss/operation/e8ebb03dbb710457ca3b4b6a70898ab2.svg`})`,
};
this.renderData = info;
if(isSection) {
SPZ.whenApiDefined(
document.getElementById("app_rebate_section")
).then(apis => {
apis.render(info, true);
});
} else {
// 重新渲染 抖动问题处理
this.templates_ = SPZServices.templatesForDoc(this.element);
const rebateBlockHost = document.getElementById('app_rebate_block');
const newTplDom = await this.templates_.findAndRenderTemplate(rebateBlockHost, info)
const parentDiv = document.querySelector('#app_rebate_block');
const oldDom = parentDiv.querySelector('.app_rebate_list');
if(oldDom){
parentDiv.replaceChild(newTplDom, oldDom);
} else {
parentDiv.appendChild(newTplDom);
}
}
}
this.insertProductDetailRebateTag(this.rebateInfo.tag);
var pluginCurrencyEvent = new CustomEvent("plugin_currency_update");
document.dispatchEvent(pluginCurrencyEvent);
}).bind(this),
10
);
getRebateInfo = async () => {
if (this.initData && this.initData.product && this.initData.product.id) {
var variant_ids = this.initData.product.variants.map(variant => variant.id);
const res = await this.xhr_.fetchJson(
"\/api\/discount-rebate\/product-discount",
{
method: "POST",
body: {
product_id: this.initData.product.id,
product_type: this.initData.product.product_type,
variant_ids: variant_ids,
},
}
);
if (!SPZCore.Types.isEmptyObject(res.rebate_info)) {
res.rebate_info.tag = res.tag;
res.rebate_info.rebate_type = res.rebate_type;
this.rebateInfo = res.rebate_info;
this.initRebate(this.initData);
} else {
if (this.win.top !== this.win.self) {
const noActivity = document.getElementById("no-rebate-activity");
noActivity && (noActivity["style"].display = "block");
}
}
}
};
getVariantDiscountId = (variant_id) => {
if (!variant_id || !this.rebateInfo) return [];
var rebateId = this.rebateInfo.variant_discount_map[variant_id];
return this.rebateInfo.discount_list.filter(item => item.discount_id == rebateId) || [];
};
insertProductDetailRebateTag = (tag) => {
if (!tag) return
// 旧判断逻辑
const productSelectModal = document.querySelector('#product-select-modal');
if (productSelectModal && productSelectModal.classList.contains('show')) {
return;
}
setTimeout(() => {
var $tag_container = [];
if (isNova23) {
$tag_container = document.querySelectorAll('.product-details .product-images-container');
} else if (isFlash) {
$tag_container = document.querySelectorAll('.product-detail .product-images .product-main-images-container');
} else if (isGeek) {
$tag_container = document.querySelectorAll('.product-images #product-images-inner-container spz-carousel .i-spzhtml-slide-item');
} else if (isWind) {
$tag_container = document.querySelectorAll('.product-detail .product-images-container .i-spzhtml-slides-container');
} else if (isOnePage) {
$tag_container = document.querySelectorAll('.product-details .product-main-images');
} else if (isHero) {
$tag_container = document.querySelectorAll('.product-detail #product-images-container #product-images-carousel .spz-carousel-slide');
} else if (isBoost) {
$tag_container = document.querySelectorAll('.boost-product-detail .product-image__layout-list .slides .slides-item .product-info__slide .slider-zoom');
} else if (isEva) {
$tag_container = document.querySelectorAll('.page_container [data-section-type="product"] .support-slick');
} else if (isFarida) {
$tag_container = document.querySelectorAll('.product-details .product-images-container');
} else if (isLifeStyle) {
$tag_container = document.querySelectorAll('.page_container [data-section-type="product_detail"] .sep-slider,.support-slick');
} else if (isPluto) {
$tag_container = document.querySelectorAll('.page_container [data-section-type="product_detail"] .sep-slider,.support-slick');
}
if($tag_container.length === 0) return;
// 给商祥页添加满送插件的标识属性
const $product_container = document.querySelector('.product-details, .product-details, .page_container, .product-images, [data-section-type="product"]')
if($product_container) {
$product_container.setAttribute('data-rebate-tag', 'true');
}
// 部分主题需要调整样式
if (isWind) {
Array.from($tag_container).forEach(container => {
container.style.position = 'relative';
});
}
document.querySelectorAll('.slider-discount-tag.dj_skin_product_title.rebate-tag').forEach(tag => tag.remove());
// 遍历所有容器并插入标签
Array.from($tag_container).forEach(container => {
container.insertAdjacentHTML('beforeend', `<div class="slider-discount-tag dj_skin_product_title rebate-tag">${tag}</div>`);
});
}, 1000)
};
fetchInfoBar = async () => {
let discount_ids = [];
if (this.pageType === 1) {
discount_ids = this.rebateInfo && this.rebateInfo.discount_list.map(item => item.discount_id);
} else if (this.pageType === 38) {
discount_ids = [this.win.rebateObj.rebateCollection_id] || [];
}
const productObj = this.getProduct();
const { cart } = await this.xhr_.fetchJson('/api/cart')
return this.xhr_.fetchJson("\/api\/discount-rebate\/global-text", {
method: "POST",
body: {
product_type: productObj && productObj.product && productObj.product.product_type,
line_items: (cart?.line_items || []).map(item => ({
variant_id: item.variant_id,
product_id: item.product_id,
quantity: item.quantity,
price: item.price,
selected: !item.unchecked,
})),
discount_ids: discount_ids,
},
});
};
renderBottomBanner = res => {
if (!res.tips) return;
document.querySelector(".discount__info-bar")?.remove();
var bar_style = `background:linear-gradient(90deg,${res.config.background_color_start},${res.config.background_color_end}); color:${res.config.color};`;
let data = { tips: res.tips, landPage: this.landPage + res.id, bar_style };
const html = SPZCore.Dom.htmlFor(this.element);
const banner = html([
`<a impr="1" imprevt="1" id="rebate_bottom_bar" href=${data.landPage} class="discount__info-bar text-truncate" data-activity-type="rebate" style="${data.bar_style}">${data.tips}</a>`,
]);
document.querySelector(".plugin-container__bottom-fixed").appendChild(banner);
const pluginCurrencyEvent = new CustomEvent("plugin_currency_update");
document.dispatchEvent(pluginCurrencyEvent);
if (res.id) {
var trackParams = {
page: this.pageType,
discount_id: res.id,
product_id: this.getProduct()?.product.id,
};
banner.addEventListener("click", () => {
this.win.sa &&
this.win.sa.track("plugin_rebate_promotion_click", {
plugin_timestamp: Date.now(),
plugin_location: "bottom_bar",
product_id: trackParams.product_id,
discount_id: trackParams.discount_id,
});
});
this.win.sa && this.win.sa.track("plugin_rebate_banner_pv", trackParams);
}
};
showDiscountPopupsInfoBar = () => {
if ([13, 14, 19, 30, 31].includes(this.pageType)) return;
if (document.querySelector(".plugin-container__bottom-fixed .discount__info-bar")) return;
this.fetchInfoBar().then(this.renderBottomBanner);
document.addEventListener("dj.cartChange", () => {
this.fetchInfoBar().then(this.renderBottomBanner);
});
};
}
SPZ.defineElement("spz-custom-rebate", SpzRebateComponent);
${function(){
const tipText = "Please select a {{ name }}".replace(/\{\{\s+name\s+\}\}/g, data);
return `${tipText}
`
}()}
Product was out of stock.
Product is unavailable.
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: "快捷支付按钮组件仅支持配置到商品详情卡片内",
legacy_discontinued_tips: "{channelName} 已下架,买家端将不再展示该按钮",
}
};
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.",
legacy_discontinued_tips: "{channelName} has been deprecated and will no longer be displayed to buyers.",
}
};
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-11');
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-11')
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 fireLoaded = 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();
};
if (window.FillyEC) {
fireLoaded();
return;
}
const existing = document.querySelector('script[src*="' + tag + '"]');
if (existing) {
existing.addEventListener('load', fireLoaded, {once: true});
return;
}
const script = document.createElement('script');
script.type = 'text/javaScript';
script.src = `//static.staticdj.com/${tag}`;
script.onload = fireLoaded;
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-11');
const coreData = function () {
const {getProduct} = dom.commonUtils;
let productDetail = getProduct();
let productPrice = productDetail?.selected?.price
|| 22.98;
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-11`;
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-11')
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};
}
}
if (isPreview() && (!themeFormData.product_id || !themeFormData.variant_id)) {
const previewProduct = (dom.commonUtils.getProduct() || {}).product;
if (previewProduct) {
themeFormData.product_id = themeFormData.product_id || previewProduct.id;
const previewVariant = previewProduct.selected_or_first_available_variant || (previewProduct.variants || [])[0];
themeFormData.variant_id = themeFormData.variant_id || (previewVariant && previewVariant.id);
}
}
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;
},
getEcLegacyLists() {
const dc = window?.C_SETTINGS?.payment_settings?.dynamic_config || {};
const asArray = (v) => (Array.isArray(v) ? v : []);
return {
ec_legacy_apple_pay_block_store_ids: asArray(dc.ec_legacy_apple_pay_block_store_ids),
ec_legacy_google_pay_block_store_ids: asArray(dc.ec_legacy_google_pay_block_store_ids)
};
},
isLegacyShopKept(storeIds) {
const legacyShopId = String(window?.C_SETTINGS?.shop?.shop_id || '');
return Array.isArray(storeIds) &&
storeIds.some((id) => !!legacyShopId && String(id).trim() === legacyShopId);
},
getLegacyDiscontinuedChannels() {
const legacyCfg = _businessUtils.getEcLegacyLists();
const discontinued = [];
if (true &&
!_businessUtils.isLegacyShopKept(legacyCfg?.ec_legacy_google_pay_block_store_ids)) {
discontinued.push('Google Pay');
}
if (true &&
!_businessUtils.isLegacyShopKept(legacyCfg?.ec_legacy_apple_pay_block_store_ids)) {
discontinued.push('Apple Pay');
}
return discontinued;
},
blockChannelHandler() {
const legacyCfg = _businessUtils.getEcLegacyLists();
const keepApple = _businessUtils.isLegacyShopKept(legacyCfg?.ec_legacy_apple_pay_block_store_ids);
const keepGoogle = _businessUtils.isLegacyShopKept(legacyCfg?.ec_legacy_google_pay_block_store_ids);
const block_googlePay = keepGoogle &&
true &&
"shoplazzagoogle";
const block_applePay = keepApple &&
true &&
"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 = (keepApple || keepGoogle) &&
(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,
paymentMode: _businessUtils.isSubscription() ? 'subscription' : 'payment'
}
},
}
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-11');
const containerDOM = 'pm-payment-express-button-container-1539149753700-11';
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-11",
"pm-payment-express-more-button-1539149753700-11",
"pm-payment-express-mock-tips-1539149753700-11",
"pm-payment-express-skeletonLayer-1539149753700-11",
]
const resetHtmlList = [
"pm-payment-express-skeletonLayer-title-content-1539149753700-11",
"pm-payment-express-skeletonLayer-content-1539149753700-11",
"pm-payment-express-mock-tips-1539149753700-11",
"pm-payment-express-error-tips-1539149753700-11",
"pm-payment-express-button-container-1539149753700-11",
"pm-payment-express-more-button-1539149753700-11",
]
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-11');
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-11');
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-11-${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-11');
if (!isPreview()) {
return;
}
if (!tipsDom) {
return;
}
tipsDom.style.display = 'block';
const id = 'pm-payment-express-error-tips-1539149753700-11-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-11');
if (!isPreview()) {
return;
}
if (!tipsDom) {
return;
}
tipsDom.style.display = 'block';
const id = 'pm-payment-express-error-tips-1539149753700-11-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-11';
const skeletonLayerDOM = document.getElementById(skeletonLayerDOMId);
const titleDOM = document.getElementById('pm-payment-express-skeletonLayer-title-content-1539149753700-11');
const contentDOM = document.getElementById('pm-payment-express-skeletonLayer-content-1539149753700-11');
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-11');
if (!tipsDOM) {
return;
}
tipsDOM.style.display = 'block';
tipsDOM.innerHTML = i18n('ec.mock_tips');
},
showLegacyDiscontinuedTips(channelNames) {
const tipsDom = document.getElementById('pm-payment-express-error-tips-1539149753700-11');
if (!isPreview()) {
return;
}
if (!tipsDom || !channelNames?.length) {
return;
}
tipsDom.style.display = 'block';
channelNames.forEach((channelName) => {
const id = `pm-payment-express-error-tips-1539149753700-11-discontinued-${channelName.replace(/\s/g, '')}`;
const hasDom = document.getElementById(id);
if (!hasDom) {
const dom = document.createElement('div');
dom.id = id;
dom.innerHTML = i18n('ec.legacy_discontinued_tips', {channelName});
tipsDom.appendChild(dom);
}
});
}
}
}
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-11');
const moreDOM = document.getElementById('pm-payment-express-more-button-1539149753700-11');
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-11');
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-11');
function start() {
const {track} = dom.commonUtils;
const {showMoreButton, getMoreButtonConfig} = dom.renderMoreUtils;
const {
showECButtonHandler,
getECConfig,
blockChannelHandler,
getLegacyDiscontinuedChannels,
isAllowTheme,
getThemeFormData
} = dom.businessUtils;
const {
disabledThemTips,
showChannelNotOpenTips,
showSkeletonLayerTips,
showMockTips,
notFindFormTips,
showLegacyDiscontinuedTips
} = 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();
showLegacyDiscontinuedTips(getLegacyDiscontinuedChannels());
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 {
showLegacyDiscontinuedTips(getLegacyDiscontinuedChannels());
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-11');
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) {
}
${function(){
const variantData = data.variant || {"id":"c4bfe75e-8cf7-4bf9-8024-9f6c60cf49ad","product_id":"f5822f34-683b-4534-922b-e263d2d03202","title":"Set-1(White+Yellow+Yellow)","weight_unit":"kg","inventory_quantity":1000,"sku":"","barcode":"","position":1,"option1":"Set-1(White+Yellow+Yellow)","option2":"","option3":"","note":"","image":{"src":"\/\/img.staticdj.com\/1f4eaafd33676820157acaa3ab1b872d.jpeg","path":"1f4eaafd33676820157acaa3ab1b872d.jpeg","width":750,"height":750,"alt":"","aspect_ratio":1},"wholesale_price":[{"price":22.98,"min_quantity":1}],"weight":"0","compare_at_price":"39.99","price":"22.98","retail_price":"39.99","available":true,"url":"\/products\/car-lights?variant=c4bfe75e-8cf7-4bf9-8024-9f6c60cf49ad","available_quantity":999999999,"options":[{"name":"Color","value":"Set-1(White+Yellow+Yellow)"}],"off_ratio":43,"flashsale_info":[],"sales":5482};
return `
`
}()}
TIPS: Our goods are authentic, with genuine patents, counterfeit must be investigated! Customers, please identify our products!
🔌💡These amber white strobe Pod lights are a perfect addition to any vehicle needing to be seen. The white spotlight will help you see what is in front (or behind) you with ease. Using these on a plow truck . or tow truck will increase your safety. The flashing amber lights are a great way to add visibility to your car or truck. 🔌💡
- Equipped with fully aluminum housing, and vertical cooling fins on the back for maximum heat dispersion. The energy-efficient design paired with a quick cooling heat sink effectively extends the Bar’s life-span beyond 30,000 hours.
- The new design of Full Reflector Side Luminate LED pods to consist of 121-degree (spot beam of white) & 30-degree (dual side flood beam of white or yellow) combo beam type. Dual side shooters could project out far and wide for excellent coverage.
- A high-quality vent valve can effectively extend the lifetime of the light bar to over 50,000 hours. Low power consumption than stock halogen bulbs, Energy Saving.
- With adjustable mounting brackets, the cube light can be adjusted to about 45 degrees, which makes it easier to change the direction of the light beam. The lamp can be uninstalled by sliding it off from the bracket.
- Applications Widely Support, except for off-road vehicle lighting, it can also be applied to Material handling, Agricultural machinery lighting, Marine LED lighting, and Emergency & rescue LED lights. Such as ATV, SUV, truck, train, motorbike, bus, engineering vehicles.
Specifications
- Power: 36W/PCS
- Voltage: 12-36V DC
- LED Chips: High-Intensity LEDs
- Lumen: 4000lm/Pair
- Material: Durable Die-casting Aluminum Alloy Housing, Tough PC Lens
- Color Temperature: 6000K
- Lifespan: 30000Hours
- Waterproof: IP67
- Used or emergency. tow. race . or just to be seen
How to install
- Black Wire for Negative
- Red Wire for Spot Light
- Yellow Wire for DRL and Strobe Modes
Notes: You could connect the black wire and the yellow wire together to a switch, then you could switch modes between the DRL and strobe function through this switch. (wire switch is not included)
What include the package :
- 1/2 x LED Pods
- Universal Mount Bracket for Pods
Click on "BUY IT NOW" to get yours now!
WHY CHOOSE US
🌎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 you bought it and felt that it is not for you, don't worry. Just shoot us a message at contact 📪support@hoaptitoele.com, and we will make it right by offering you a replacement or refund. 100% Simple & Risk-Free process.
✉️ 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.
OUR GUARANTEE
🏺We take pride in our products as we believe they are amazing. However, we understand that buying things online can be daunting, especially for the first time, so we offer a 100% satisfaction guarantee.
💎If you don't have a positive experience for any reason, we will do whatever it takes to make sure you are 100% satisfied with your purchase.
HOW TO PAY
✅Payments Via PayPal®, Credit, and Debit Card.
If you want to checkout with a Credit and Debit Card, enter your
Card No,
Expiration Date, and
CVV.