Enjoy Free Express Shipping on orders over $30

Hassle-free returns. 30-day postage paid returns

Enjoy Free Express Shipping on orders over $30

Hassle-free returns. 30-day postage paid returns
class SpzCustomDiscountAtcAction extends SPZ.BaseElement { constructor(element) { super(element); this.xhr_ = SPZServices.xhrFor(this.win); this.product_title = ""; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } async getProductTitle_ (data){ this.product_title = data.product_title; } handleLoading_ (event) { const { type, action } = event; const loadingElementId = '#apps-discount-whole-loading'; const loadingElement = document.querySelector(loadingElementId); if (loadingElement) { SPZ.whenApiDefined(loadingElement).then((api) => { if (action === 'show') { api.show_(); } else { api.close_(); } }); } } // 渲染加购弹窗内容 async renderQuickShop_ (data) { this.handleLoading_({type: 'whole', action: 'show'}); const apply_scenario = data.apply_scenario; const discount_id = data.discount_id; const product_id = data.product_id; const limit_purchase = data.limit_purchase; this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product?product_id=${product_id}&discount_id=${discount_id}&apply_scenario=${apply_scenario}`, { method: "get", }).then(async(res)=>{ 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}; data.need_atc = true; data.limit_purchase = limit_purchase; $quickShop.render(data); // 打开加购弹窗 SPZ.whenApiDefined(document.querySelector(`#apps-discount-quick-view`)).then((api)=>{ api.open(); }); }).catch((err)=>{ this.handleLoading_({type: 'whole', action: 'close'}); }) } // 加入购物车 addToCart_(data) { const apply_scenario = data.apply_scenario; const discount_id = data.discount_id; const product_id = data.product_id; this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product?product_id=${data.product_id}&discount_id=${discount_id}&apply_scenario=${apply_scenario}`, { method: "get", }).then(async(res)=>{ // 单款式加购 const variant_id = res.product.variants[0]?.id; const $productFormInput = document.querySelector(`#apps-discount-product-form-${data.product_id} input[name='variant_id'`); $productFormInput.value = variant_id; SPZ.whenApiDefined(document.querySelector(`#apps-discount-product-form-${data.product_id}`)).then((api)=>{ api.handleAddToCart_(); }); }).catch((err)=> { this.handleLoading_({type: 'whole', action: 'close'}); }) } // 加购弹窗未参与活动 加购按钮不可点击 handleNotHitDiscount_(data) { const $quickShopBody = document.querySelector('#apps-discount-quick-shop-body'); const $limitTip = document.querySelector('.apps_discount_limit_purchase_tip'); //当前子框式未命中活动 if(data.variant.is_hit_discount == false) { $quickShopBody.setAttribute('variantstatus', 'notHitDiscount'); $limitTip && $limitTip.setAttribute('selectedvariantstatus', 'notHitDiscount'); } else { $quickShopBody.setAttribute('variantstatus', ''); $limitTip && $limitTip.setAttribute('selectedvariantstatus', '') } } setupAction_() { this.registerAction('renderQuickShop', (invocation) => { const data = invocation.args; this.renderQuickShop_(data); }); // 加购 this.registerAction('addToCart', (invocation) => { const data = invocation.args; this.addToCart_(data); }); // 子款式 未参与活动 this.registerAction('handleNotHitDiscount', (invocation) => { const data = invocation.args.data; this.handleNotHitDiscount_(data); }); this.registerAction('getCartCount', (invocation) => { //一些老主题还未用spz重构,需要手动触发一次老方法以更新购物车图标的数量 window.$ && $(document).trigger('dj.common.cart.change'); }); this.registerAction('getProductTitle', (invocation) => { const data = invocation.args; this.getProductTitle_(data); }); this.registerAction('handleButton', (invocation) => { const data = invocation.args; window.location.href = this.product_title; }); }; buildCallback() { this.setupAction_(); }; // 同一页里 flashsale_collection(首页限时促销卡片) 与凑单弹窗容器都渲染了本快速加购栈, // 会产生重复 fixed id——尤其加购弹窗 #apps-discount-quick-view。它“打开”走 querySelector, // “关闭”走声明式动作 apps-discount-quick-view.close(按 id 解析),重复时二者可能命中不同副本, // 导致加购成功后弹窗第一次关不掉、第二次才关。参考 toast 的处理,运行时保证这些单例只保留一份。 mountCallback() { const funcs = document.querySelectorAll('#appDiscountRenderQuickShopFunc'); // 逻辑元件重复:仅保留第一个,其余移除自身,保证按 id 解析到的动作实例唯一。 if (funcs.length > 1 && this.element !== funcs[0]) { this.element.remove(); return; } // 加购弹窗重复:保留第一个,移除多余(移除弹窗即连带移除其内部 render/表单等子节点)。 const modals = document.querySelectorAll('#apps-discount-quick-view'); Array.from(modals).slice(1).forEach((el) => el.remove()); } } SPZ.defineElement('spz-custom-discount-atc-action', SpzCustomDiscountAtcAction);
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.discountInfoApi = "\/api\/storefront\/promotion\/home_page\/campaign?discount_id=" this.product_display = {}; this.model = { loading: false, page: 2, limit: 20, total: 0, //已展示的商品数量 params: { count: 0, has_more: false, sort: { by: "recommend", direction: "asc" } } }; this.discount_id= ""; this.image_size="100%"; this.discount_info = {}; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } async getDiscountList() { const data = await this.xhr_.fetchJson(this.discountInfoApi + this.discount_id, { method: "GET", }).then(res => { this.model.params = { count: res.product_info.count, has_more: res.product_info.has_more, sort: { by: "recommend", direction: "asc" } } if(!res.product_info.product.length) return; this.model.total = res.product_info.product.length; this.product_display = res.home_page_info.product_display; this.discount_info = res.discount_info; res.product_info.product.forEach((product) => { product.url = appDiscountUtils.globalizePath(product.url); }) res.image_domain = this.win.SHOPLAZZA.image_domain; res.isMobile = appDiscountUtils.judgeMobile(); SPZ.whenApiDefined(document.getElementById("appDiscountIndexFlashsale")) .then(apis => { apis.render(res).then(() => { const hiddenArraw = res.home_page_info.banner.enabled ? res.product_info.product.length < 5 : res.product_info.product.length < 6 if(hiddenArraw) { document.querySelectorAll('.app_discount_flashsale_arrow').forEach((item) => { item.style.display="none"; }) } SPZ.whenApiDefined(document.getElementById("flashsaleProductsRender")).then((api) => { res.product_info.product_display = this.product_display; res.product_info.discount_id = this.discount_id; res.product_info.apply_scenario = 1; res.product_info.limit_purchase = this.discount_info.limit_user_product_discount; res.product_info.discount_image_size = this.image_size; api.render(res.product_info,true).then(() => {this.bindEvent_()}); }) }) }) }).catch(err => { console.error(err); }) return data; }; // 获取加载的商品数据,拼接html模板 async loadData(cb) { // 请求数据 this.model.loading = true; //查询活动商品接口 const reqBody = { discount_id: this.discount_id, page: this.model.page, limit: this.model.limit, apply_scenario: 1, sort: this.model.params.sort, sales_channel: { sale_channel_type: "online", sale_channel_id: '2424937' } } this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product/list`, { method: "post", body: reqBody }).then(async(res)=>{ const count = res.count; this.model.params.has_more = res.has_more; this.model.total = this.model.total + res.products.length; if (count > 0) { this.model.page++; if (res.products && res.products.length > 0) { res.products.forEach((product) => { product.url = appDiscountUtils.globalizePath(product.url); }) res.product_display = this.product_display; res.discount_id = this.discount_id; res.apply_scenario = 1; res.limit_purchase = this.discount_info.limit_user_product_discount; res.discount_image_size = this.image_size; // 获取商品列表渲染模板, dom挂载 const $content = document.querySelector(".app_discount_products_list_wrapper"); this.templates_ = SPZServices.templatesForDoc(); this.templates_.renderTemplate(document.querySelector('#apps-discounts_product_list_template'), res).then((el) => { const childNodes = el.querySelectorAll('.as-render-product-item'); if (childNodes && childNodes.length > 0) { $content.append(...childNodes); } }) // 监听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_products_list_wrapper"); const action = data.args.direct === "right"; const scrollwidth = action ? $el.offsetWidth : -$el.offsetWidth; $el.scrollBy({ left: scrollwidth, behavior: 'smooth' }); }); this.registerAction('changeFlashSaleLimitPurchase', (invocation) => { const data = invocation.args.data; this.handleFlashsaleTip_(data); }); }; //切换快速加购弹窗内限时促销限购提示 handleFlashsaleTip_(data) { const flashsaleEl = document.querySelector('#quick-shop-flashsale-tip'); SPZ.whenApiDefined(flashsaleEl).then((api) => { api.render(data); }); } bindEvent_() { // 监听滚动,请求数据 const $el = document.querySelector(".app_discount_products_list_wrapper"); if($el) { $el.addEventListener("scroll", this.win.SPZCore.Types.debounce( this.win, () => { const isRightEnd = $el.scrollLeft + $el.offsetWidth + 10 >= $el.scrollWidth; const isLeftEnd = Math.abs($el.scrollLeft) + $el.offsetWidth + 10 >= $el.scrollWidth; const isRTL = document.documentElement.getAttribute('dir') == 'rtl'; const isEnd = isRTL ? isLeftEnd : isRightEnd; if(isEnd && this.model.params.has_more && !this.model.loading && this.model.total < 100) { this.loadData(); } }, 50 )) }; }; buildCallback() { this.setupAction_(); }; mountCallback() { const $el = document.querySelector("#appDiscountFlashsale") this.discount_id = $el.getAttribute('flashsale-id'); this.image_size = $el.getAttribute('image-size'); if(!this.discount_id) return; this.getDiscountList(); }; } SPZ.defineElement('spz-custom-discount-flashsale', SpzCustomDiscountFlashsale);
  • Home
  • All Products
  • More links
  • Home
  • All Products
  • More links
class SpzCustomDiscountAtcAction extends SPZ.BaseElement { constructor(element) { super(element); this.xhr_ = SPZServices.xhrFor(this.win); this.product_title = ""; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } async getProductTitle_ (data){ this.product_title = data.product_title; } handleLoading_ (event) { const { type, action } = event; const loadingElementId = '#apps-discount-whole-loading'; const loadingElement = document.querySelector(loadingElementId); if (loadingElement) { SPZ.whenApiDefined(loadingElement).then((api) => { if (action === 'show') { api.show_(); } else { api.close_(); } }); } } // 渲染加购弹窗内容 async renderQuickShop_ (data) { this.handleLoading_({type: 'whole', action: 'show'}); const apply_scenario = data.apply_scenario; const discount_id = data.discount_id; const product_id = data.product_id; const limit_purchase = data.limit_purchase; this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product?product_id=${product_id}&discount_id=${discount_id}&apply_scenario=${apply_scenario}`, { method: "get", }).then(async(res)=>{ 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}; data.need_atc = true; data.limit_purchase = limit_purchase; $quickShop.render(data); // 打开加购弹窗 SPZ.whenApiDefined(document.querySelector(`#apps-discount-quick-view`)).then((api)=>{ api.open(); }); }).catch((err)=>{ this.handleLoading_({type: 'whole', action: 'close'}); }) } // 加入购物车 addToCart_(data) { const apply_scenario = data.apply_scenario; const discount_id = data.discount_id; const product_id = data.product_id; this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product?product_id=${data.product_id}&discount_id=${discount_id}&apply_scenario=${apply_scenario}`, { method: "get", }).then(async(res)=>{ // 单款式加购 const variant_id = res.product.variants[0]?.id; const $productFormInput = document.querySelector(`#apps-discount-product-form-${data.product_id} input[name='variant_id'`); $productFormInput.value = variant_id; SPZ.whenApiDefined(document.querySelector(`#apps-discount-product-form-${data.product_id}`)).then((api)=>{ api.handleAddToCart_(); }); }).catch((err)=> { this.handleLoading_({type: 'whole', action: 'close'}); }) } // 加购弹窗未参与活动 加购按钮不可点击 handleNotHitDiscount_(data) { const $quickShopBody = document.querySelector('#apps-discount-quick-shop-body'); const $limitTip = document.querySelector('.apps_discount_limit_purchase_tip'); //当前子框式未命中活动 if(data.variant.is_hit_discount == false) { $quickShopBody.setAttribute('variantstatus', 'notHitDiscount'); $limitTip && $limitTip.setAttribute('selectedvariantstatus', 'notHitDiscount'); } else { $quickShopBody.setAttribute('variantstatus', ''); $limitTip && $limitTip.setAttribute('selectedvariantstatus', '') } } setupAction_() { this.registerAction('renderQuickShop', (invocation) => { const data = invocation.args; this.renderQuickShop_(data); }); // 加购 this.registerAction('addToCart', (invocation) => { const data = invocation.args; this.addToCart_(data); }); // 子款式 未参与活动 this.registerAction('handleNotHitDiscount', (invocation) => { const data = invocation.args.data; this.handleNotHitDiscount_(data); }); this.registerAction('getCartCount', (invocation) => { //一些老主题还未用spz重构,需要手动触发一次老方法以更新购物车图标的数量 window.$ && $(document).trigger('dj.common.cart.change'); }); this.registerAction('getProductTitle', (invocation) => { const data = invocation.args; this.getProductTitle_(data); }); this.registerAction('handleButton', (invocation) => { const data = invocation.args; window.location.href = this.product_title; }); }; buildCallback() { this.setupAction_(); }; // 同一页里 flashsale_collection(首页限时促销卡片) 与凑单弹窗容器都渲染了本快速加购栈, // 会产生重复 fixed id——尤其加购弹窗 #apps-discount-quick-view。它“打开”走 querySelector, // “关闭”走声明式动作 apps-discount-quick-view.close(按 id 解析),重复时二者可能命中不同副本, // 导致加购成功后弹窗第一次关不掉、第二次才关。参考 toast 的处理,运行时保证这些单例只保留一份。 mountCallback() { const funcs = document.querySelectorAll('#appDiscountRenderQuickShopFunc'); // 逻辑元件重复:仅保留第一个,其余移除自身,保证按 id 解析到的动作实例唯一。 if (funcs.length > 1 && this.element !== funcs[0]) { this.element.remove(); return; } // 加购弹窗重复:保留第一个,移除多余(移除弹窗即连带移除其内部 render/表单等子节点)。 const modals = document.querySelectorAll('#apps-discount-quick-view'); Array.from(modals).slice(1).forEach((el) => el.remove()); } } SPZ.defineElement('spz-custom-discount-atc-action', SpzCustomDiscountAtcAction);
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.discountInfoApi = "\/api\/storefront\/promotion\/home_page\/campaign?discount_id=" this.product_display = {}; this.model = { loading: false, page: 2, limit: 20, total: 0, //已展示的商品数量 params: { count: 0, has_more: false, sort: { by: "recommend", direction: "asc" } } }; this.discount_id= ""; this.image_size="100%"; this.discount_info = {}; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } async getDiscountList() { const data = await this.xhr_.fetchJson(this.discountInfoApi + this.discount_id, { method: "GET", }).then(res => { this.model.params = { count: res.product_info.count, has_more: res.product_info.has_more, sort: { by: "recommend", direction: "asc" } } if(!res.product_info.product.length) return; this.model.total = res.product_info.product.length; this.product_display = res.home_page_info.product_display; this.discount_info = res.discount_info; res.product_info.product.forEach((product) => { product.url = appDiscountUtils.globalizePath(product.url); }) res.image_domain = this.win.SHOPLAZZA.image_domain; res.isMobile = appDiscountUtils.judgeMobile(); SPZ.whenApiDefined(document.getElementById("appDiscountIndexFlashsale")) .then(apis => { apis.render(res).then(() => { const hiddenArraw = res.home_page_info.banner.enabled ? res.product_info.product.length < 5 : res.product_info.product.length < 6 if(hiddenArraw) { document.querySelectorAll('.app_discount_flashsale_arrow').forEach((item) => { item.style.display="none"; }) } SPZ.whenApiDefined(document.getElementById("flashsaleProductsRender")).then((api) => { res.product_info.product_display = this.product_display; res.product_info.discount_id = this.discount_id; res.product_info.apply_scenario = 1; res.product_info.limit_purchase = this.discount_info.limit_user_product_discount; res.product_info.discount_image_size = this.image_size; api.render(res.product_info,true).then(() => {this.bindEvent_()}); }) }) }) }).catch(err => { console.error(err); }) return data; }; // 获取加载的商品数据,拼接html模板 async loadData(cb) { // 请求数据 this.model.loading = true; //查询活动商品接口 const reqBody = { discount_id: this.discount_id, page: this.model.page, limit: this.model.limit, apply_scenario: 1, sort: this.model.params.sort, sales_channel: { sale_channel_type: "online", sale_channel_id: '2424937' } } this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product/list`, { method: "post", body: reqBody }).then(async(res)=>{ const count = res.count; this.model.params.has_more = res.has_more; this.model.total = this.model.total + res.products.length; if (count > 0) { this.model.page++; if (res.products && res.products.length > 0) { res.products.forEach((product) => { product.url = appDiscountUtils.globalizePath(product.url); }) res.product_display = this.product_display; res.discount_id = this.discount_id; res.apply_scenario = 1; res.limit_purchase = this.discount_info.limit_user_product_discount; res.discount_image_size = this.image_size; // 获取商品列表渲染模板, dom挂载 const $content = document.querySelector(".app_discount_products_list_wrapper"); this.templates_ = SPZServices.templatesForDoc(); this.templates_.renderTemplate(document.querySelector('#apps-discounts_product_list_template'), res).then((el) => { const childNodes = el.querySelectorAll('.as-render-product-item'); if (childNodes && childNodes.length > 0) { $content.append(...childNodes); } }) // 监听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_products_list_wrapper"); const action = data.args.direct === "right"; const scrollwidth = action ? $el.offsetWidth : -$el.offsetWidth; $el.scrollBy({ left: scrollwidth, behavior: 'smooth' }); }); this.registerAction('changeFlashSaleLimitPurchase', (invocation) => { const data = invocation.args.data; this.handleFlashsaleTip_(data); }); }; //切换快速加购弹窗内限时促销限购提示 handleFlashsaleTip_(data) { const flashsaleEl = document.querySelector('#quick-shop-flashsale-tip'); SPZ.whenApiDefined(flashsaleEl).then((api) => { api.render(data); }); } bindEvent_() { // 监听滚动,请求数据 const $el = document.querySelector(".app_discount_products_list_wrapper"); if($el) { $el.addEventListener("scroll", this.win.SPZCore.Types.debounce( this.win, () => { const isRightEnd = $el.scrollLeft + $el.offsetWidth + 10 >= $el.scrollWidth; const isLeftEnd = Math.abs($el.scrollLeft) + $el.offsetWidth + 10 >= $el.scrollWidth; const isRTL = document.documentElement.getAttribute('dir') == 'rtl'; const isEnd = isRTL ? isLeftEnd : isRightEnd; if(isEnd && this.model.params.has_more && !this.model.loading && this.model.total < 100) { this.loadData(); } }, 50 )) }; }; buildCallback() { this.setupAction_(); }; mountCallback() { const $el = document.querySelector("#appDiscountFlashsale") this.discount_id = $el.getAttribute('flashsale-id'); this.image_size = $el.getAttribute('image-size'); if(!this.discount_id) return; this.getDiscountList(); }; } SPZ.defineElement('spz-custom-discount-flashsale', SpzCustomDiscountFlashsale);
  • class SpzCustomDiscountAtcAction extends SPZ.BaseElement { constructor(element) { super(element); this.xhr_ = SPZServices.xhrFor(this.win); this.product_title = ""; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } async getProductTitle_ (data){ this.product_title = data.product_title; } handleLoading_ (event) { const { type, action } = event; const loadingElementId = '#apps-discount-whole-loading'; const loadingElement = document.querySelector(loadingElementId); if (loadingElement) { SPZ.whenApiDefined(loadingElement).then((api) => { if (action === 'show') { api.show_(); } else { api.close_(); } }); } } // 渲染加购弹窗内容 async renderQuickShop_ (data) { this.handleLoading_({type: 'whole', action: 'show'}); const apply_scenario = data.apply_scenario; const discount_id = data.discount_id; const product_id = data.product_id; const limit_purchase = data.limit_purchase; this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product?product_id=${product_id}&discount_id=${discount_id}&apply_scenario=${apply_scenario}`, { method: "get", }).then(async(res)=>{ 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}; data.need_atc = true; data.limit_purchase = limit_purchase; $quickShop.render(data); // 打开加购弹窗 SPZ.whenApiDefined(document.querySelector(`#apps-discount-quick-view`)).then((api)=>{ api.open(); }); }).catch((err)=>{ this.handleLoading_({type: 'whole', action: 'close'}); }) } // 加入购物车 addToCart_(data) { const apply_scenario = data.apply_scenario; const discount_id = data.discount_id; const product_id = data.product_id; this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product?product_id=${data.product_id}&discount_id=${discount_id}&apply_scenario=${apply_scenario}`, { method: "get", }).then(async(res)=>{ // 单款式加购 const variant_id = res.product.variants[0]?.id; const $productFormInput = document.querySelector(`#apps-discount-product-form-${data.product_id} input[name='variant_id'`); $productFormInput.value = variant_id; SPZ.whenApiDefined(document.querySelector(`#apps-discount-product-form-${data.product_id}`)).then((api)=>{ api.handleAddToCart_(); }); }).catch((err)=> { this.handleLoading_({type: 'whole', action: 'close'}); }) } // 加购弹窗未参与活动 加购按钮不可点击 handleNotHitDiscount_(data) { const $quickShopBody = document.querySelector('#apps-discount-quick-shop-body'); const $limitTip = document.querySelector('.apps_discount_limit_purchase_tip'); //当前子框式未命中活动 if(data.variant.is_hit_discount == false) { $quickShopBody.setAttribute('variantstatus', 'notHitDiscount'); $limitTip && $limitTip.setAttribute('selectedvariantstatus', 'notHitDiscount'); } else { $quickShopBody.setAttribute('variantstatus', ''); $limitTip && $limitTip.setAttribute('selectedvariantstatus', '') } } setupAction_() { this.registerAction('renderQuickShop', (invocation) => { const data = invocation.args; this.renderQuickShop_(data); }); // 加购 this.registerAction('addToCart', (invocation) => { const data = invocation.args; this.addToCart_(data); }); // 子款式 未参与活动 this.registerAction('handleNotHitDiscount', (invocation) => { const data = invocation.args.data; this.handleNotHitDiscount_(data); }); this.registerAction('getCartCount', (invocation) => { //一些老主题还未用spz重构,需要手动触发一次老方法以更新购物车图标的数量 window.$ && $(document).trigger('dj.common.cart.change'); }); this.registerAction('getProductTitle', (invocation) => { const data = invocation.args; this.getProductTitle_(data); }); this.registerAction('handleButton', (invocation) => { const data = invocation.args; window.location.href = this.product_title; }); }; buildCallback() { this.setupAction_(); }; // 同一页里 flashsale_collection(首页限时促销卡片) 与凑单弹窗容器都渲染了本快速加购栈, // 会产生重复 fixed id——尤其加购弹窗 #apps-discount-quick-view。它“打开”走 querySelector, // “关闭”走声明式动作 apps-discount-quick-view.close(按 id 解析),重复时二者可能命中不同副本, // 导致加购成功后弹窗第一次关不掉、第二次才关。参考 toast 的处理,运行时保证这些单例只保留一份。 mountCallback() { const funcs = document.querySelectorAll('#appDiscountRenderQuickShopFunc'); // 逻辑元件重复:仅保留第一个,其余移除自身,保证按 id 解析到的动作实例唯一。 if (funcs.length > 1 && this.element !== funcs[0]) { this.element.remove(); return; } // 加购弹窗重复:保留第一个,移除多余(移除弹窗即连带移除其内部 render/表单等子节点)。 const modals = document.querySelectorAll('#apps-discount-quick-view'); Array.from(modals).slice(1).forEach((el) => el.remove()); } } SPZ.defineElement('spz-custom-discount-atc-action', SpzCustomDiscountAtcAction);
    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.discountInfoApi = "\/api\/storefront\/promotion\/home_page\/campaign?discount_id=" this.product_display = {}; this.model = { loading: false, page: 2, limit: 20, total: 0, //已展示的商品数量 params: { count: 0, has_more: false, sort: { by: "recommend", direction: "asc" } } }; this.discount_id= ""; this.image_size="100%"; this.discount_info = {}; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } async getDiscountList() { const data = await this.xhr_.fetchJson(this.discountInfoApi + this.discount_id, { method: "GET", }).then(res => { this.model.params = { count: res.product_info.count, has_more: res.product_info.has_more, sort: { by: "recommend", direction: "asc" } } if(!res.product_info.product.length) return; this.model.total = res.product_info.product.length; this.product_display = res.home_page_info.product_display; this.discount_info = res.discount_info; res.product_info.product.forEach((product) => { product.url = appDiscountUtils.globalizePath(product.url); }) res.image_domain = this.win.SHOPLAZZA.image_domain; res.isMobile = appDiscountUtils.judgeMobile(); SPZ.whenApiDefined(document.getElementById("appDiscountIndexFlashsale")) .then(apis => { apis.render(res).then(() => { const hiddenArraw = res.home_page_info.banner.enabled ? res.product_info.product.length < 5 : res.product_info.product.length < 6 if(hiddenArraw) { document.querySelectorAll('.app_discount_flashsale_arrow').forEach((item) => { item.style.display="none"; }) } SPZ.whenApiDefined(document.getElementById("flashsaleProductsRender")).then((api) => { res.product_info.product_display = this.product_display; res.product_info.discount_id = this.discount_id; res.product_info.apply_scenario = 1; res.product_info.limit_purchase = this.discount_info.limit_user_product_discount; res.product_info.discount_image_size = this.image_size; api.render(res.product_info,true).then(() => {this.bindEvent_()}); }) }) }) }).catch(err => { console.error(err); }) return data; }; // 获取加载的商品数据,拼接html模板 async loadData(cb) { // 请求数据 this.model.loading = true; //查询活动商品接口 const reqBody = { discount_id: this.discount_id, page: this.model.page, limit: this.model.limit, apply_scenario: 1, sort: this.model.params.sort, sales_channel: { sale_channel_type: "online", sale_channel_id: '2424937' } } this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product/list`, { method: "post", body: reqBody }).then(async(res)=>{ const count = res.count; this.model.params.has_more = res.has_more; this.model.total = this.model.total + res.products.length; if (count > 0) { this.model.page++; if (res.products && res.products.length > 0) { res.products.forEach((product) => { product.url = appDiscountUtils.globalizePath(product.url); }) res.product_display = this.product_display; res.discount_id = this.discount_id; res.apply_scenario = 1; res.limit_purchase = this.discount_info.limit_user_product_discount; res.discount_image_size = this.image_size; // 获取商品列表渲染模板, dom挂载 const $content = document.querySelector(".app_discount_products_list_wrapper"); this.templates_ = SPZServices.templatesForDoc(); this.templates_.renderTemplate(document.querySelector('#apps-discounts_product_list_template'), res).then((el) => { const childNodes = el.querySelectorAll('.as-render-product-item'); if (childNodes && childNodes.length > 0) { $content.append(...childNodes); } }) // 监听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_products_list_wrapper"); const action = data.args.direct === "right"; const scrollwidth = action ? $el.offsetWidth : -$el.offsetWidth; $el.scrollBy({ left: scrollwidth, behavior: 'smooth' }); }); this.registerAction('changeFlashSaleLimitPurchase', (invocation) => { const data = invocation.args.data; this.handleFlashsaleTip_(data); }); }; //切换快速加购弹窗内限时促销限购提示 handleFlashsaleTip_(data) { const flashsaleEl = document.querySelector('#quick-shop-flashsale-tip'); SPZ.whenApiDefined(flashsaleEl).then((api) => { api.render(data); }); } bindEvent_() { // 监听滚动,请求数据 const $el = document.querySelector(".app_discount_products_list_wrapper"); if($el) { $el.addEventListener("scroll", this.win.SPZCore.Types.debounce( this.win, () => { const isRightEnd = $el.scrollLeft + $el.offsetWidth + 10 >= $el.scrollWidth; const isLeftEnd = Math.abs($el.scrollLeft) + $el.offsetWidth + 10 >= $el.scrollWidth; const isRTL = document.documentElement.getAttribute('dir') == 'rtl'; const isEnd = isRTL ? isLeftEnd : isRightEnd; if(isEnd && this.model.params.has_more && !this.model.loading && this.model.total < 100) { this.loadData(); } }, 50 )) }; }; buildCallback() { this.setupAction_(); }; mountCallback() { const $el = document.querySelector("#appDiscountFlashsale") this.discount_id = $el.getAttribute('flashsale-id'); this.image_size = $el.getAttribute('image-size'); if(!this.discount_id) return; this.getDiscountList(); }; } SPZ.defineElement('spz-custom-discount-flashsale', SpzCustomDiscountFlashsale);
  • Log in
  • Create an account
  • (function(){ let w = window.innerWidth; function setHeaderCssVar() { const headerEle = document.getElementById('shoplaza-section-header'); if(!headerEle){ return }; document.body.style.setProperty('--window-height', `${window.innerHeight}px`); document.body.style.setProperty('--header-height', `${headerEle.clientHeight}px`); const mdScorllHideEle = headerEle.querySelector('.header__mobile .header__scroll_hide'); if (mdScorllHideEle) { document.body.style.setProperty('--header-scroll-hide-height-md', `${mdScorllHideEle.clientHeight}px`); } const pcScorllHideEle = headerEle.querySelector('.header__desktop .header__scroll_hide'); if (pcScorllHideEle) { document.body.style.setProperty('--header-scroll-hide-height-pc', `${pcScorllHideEle.clientHeight}px`); } } function handlResize() { if(w == window.innerWidth){return}; w = window.innerWidth; setHeaderCssVar(); }; function init(){ setHeaderCssVar(); window.removeEventListener('resize', window._theme_header_listener) window._theme_header_listener = handlResize; window.addEventListener('resize', window._theme_header_listener); } init(); })();

    Privacy Policy

    Privacy Policy

    PRIVACY STATEMENT

    We take your privacy seriously and this privacy statement explains how bundleclear(collectively, “we,” “us,” or “our”) collect, use, share and process your information.

    Collection and Use of Personal Data

    Personal data is information that can be used to directly or indirectly identify you. Personal data also includes anonymous data that is linked to information that can be used to directly or indirectly identify you. Personal data does not include data that has been irreversibly anonymized or aggregated so that it can no longer enable us, whether in combination with other information or otherwise, to identify you.

    Promoting safety and security

    We abide by the principles of legality, legitimacy, and transparency, use, and process the least data within a limited scope of purpose, and take technical and administrative measures to protect the security of the data. We use personal data to help verify accounts and user activity, as well as to promote safety and security, such as by monitoring fraud and investigating suspicious or potentially illegal activity or violations of our terms or policies. Such processing is based on our legitimate interest in helping ensure the safety of our products and services.

    Here is a description of the types of personal data we may collect and how we may use it:

    What Personal Data We Collect

    ⅰ. Data you provide: 

    We collect the personal data you provide when you use our products and services or otherwise interact with us, such as when you create an account, contact us, participate in an online survey, use our online help or online chat tool. If you make a purchase, we collect personal data in connection with the purchase, and other account and authentication information, as well as billing, shipping, and contact details.

    ⅱ. Data about use of our services and products:

    When you visit our website/application, we may collect data about the type of device you use, your device's unique identifier, the IP address of your device, your operating system, the type of Internet browser that you use, usage information, diagnostic information, and location information from or about the computers, phones, or other devices on which you install or access our products or services. Where available, our services may use GPS, your IP address, and other technologies to determine a device's approximate location to allow us to improve our products and services.

    How We Use Your Personal Data

    Generally speaking, we use personal data to provide, improve, and develop our products and services, to communicate with you, to offer you targeted advertisements and services, and to protect us and our customers.

    ⅰ. Providing, improving, and developing our products and services:

    We use personal data to help us provide, improve, and develop our products, services, and advertising. This includes using personal data for purposes such as data analysis, research, and audits. Such processing is based on our legitimate interest in offering you products and services and for business continuity. If you enter a contest, or other promotion, we may use the personal data you provide to administer those programs. Some of these activities have additional rules, which may contain further data about how we use personal data, so we encourage you to read those rules carefully before participating.

    ⅱ. Communicating with you:

    Subject to your prior express consent, we may use personal data to send you marketing communications in relation to our own products and services, communicate with you about your account or transactions, and inform you about our policies and terms. If you no longer wish to receive email communications for marketing purposes, please contact us to opt-out. We also may use your data to process and respond to your requests when you contact us. Subject to your prior express consent, we may share your personal data with third party partners who may send you marketing communications in relation to their products and services. Subject to your prior express consent, we may use personal data to personalize your experience with our products and services and on third-party websites and applications and to determine the effectiveness of our promotional campaigns.

    NOTE: For any of the uses of your data described above that require your prior express consent, note that you may withdraw your consent by contacting us.

    Definition of "Cookies"

    Cookies are small pieces of text used to store information on web browsers. Cookies are widely used to store and receive identifiers and other information on computers, phones, and other devices. We also use other technologies, including data we store on your web browser or device, identifiers associated with your device, and other software, for similar purposes. In this Cookie Statement, we refer to all of these technologies as "cookies."

    Use of Cookies

    We use cookies to provide, protect, and improve our products and services, such as by personalizing content, offering and measuring advertisements, understanding user behavior, and providing a safer experience. Please note that the specific cookies we may use vary depending on the specific websites and services you use.

    Disclosure of Personal Data

    We make certain personal data available to strategic partners that work with us to provide our products and services or help us market to customers. Personal data will only be shared by us with these companies in order to provide or improve our products, services, and advertising; it will not be shared with third parties for their own marketing purposes without your prior express consent.

    Data Disclosure or Storage, Transfer, and Processing

    ⅰ. Fulfilment of legal obligations:

    Due to the mandatory laws of the European Economic Area or the country in which the user lives, certain legal acts exist or have occurred and certain legal obligations need to be fulfilled. Treatment of personal data of EEA residents ---As described below, if you reside within the European Economic Area (EEA), our processing of your personal data will be legitimized: Whenever we require your consent for the processing of your personal data such processing will be justified pursuant to Article 6(1) of the General Data Protection Regulation (EU) ("GDPR").

    ⅱ. For the purpose of reasonable implementation or application of this article:

    We may share personal data with all our-affiliated companies. In the event of a merger, reorganization, acquisition, joint venture, assignment, spin-off, transfer, or sale or disposition of all or any portion of our business, including in connection with any bankruptcy or similar proceedings, we may transfer any and all personal data to the relevant third party.  We may also disclose personal data if we determine in good faith that disclosure is reasonably necessary to protect our rights and pursue available remedies, enforce our terms and conditions, investigate fraud, or protect our operations or users.

    ⅲ. Legal Compliance and Security or Protect Other Rights

    It may be necessary—by law, legal process, litigation, and/or requests from public and governmental authorities within or outside your country of residence—for us to disclose personal data. We may also disclose personal data if we determine that for purposes of national security, law enforcement, or other issues of public importance, disclosure is necessary or appropriate.

    Your Rights

    We take reasonable steps to ensure that your personal data is accurate, complete, and up to date. You have the right to access, correct, or delete the personal data that we collect. You are also entitled to restrict or object, at any time, to the further processing of your personal data. You have the right to receive your personal data in a structured and standard format. You may lodge a complaint with the competent data protection authority regarding the processing of your personal data.  To protect the privacy and the security of your personal data, we may request data from you to enable us to confirm your identity and right to access such data, as well as to search for and provide you with the personal data we maintain. There are instances where applicable laws or regulatory requirements allow or require us to refuse to provide or delete some or all of the personal data that we maintain. You may contact us to exercise your rights. We will respond to your request in a reasonable timeframe, and in any event in less than 30 days.

    Third-Party Websites and Services

    When a customer operates a link to a third-party website that has a relationship with us, we do not assume any obligation or responsibility for such policy because of the third party's privacy policy. Our website, products, and services may contain links to or the ability for you to access third-party websites, products, and services. We are not responsible for the privacy practices employed by those third parties, nor are we responsible for the information or content their products and services contain. This Privacy Statement applies solely to data collected by us through our products and services. We encourage you to read the privacy policies of any third party before proceeding to use their websites, products, or services.

    Data Security, Integrity, and Retention

    We use reasonable technical, administrative, and physical security measures designed to safeguard and help prevent unauthorized access to your data, and to correctly use the data we collect. We will retain your personal data for as long as it is necessary to fulfill the purposes outlined in this Privacy Statement, unless a longer retention period is required or permitted by law.

    Changes to this Privacy Statement

    We may periodically change this Privacy Statement to keep pace with new technologies, industry practices, and regulatory requirements, among other reasons. If you do not agree to the revised contact us Privacy Statement, please refrain from using our products or services and contact us to close any account you may have created.

    Storage and Transfer of Your Personal Data

    When you access or use our services, your personal data may be processed or transferred outside your country of residence. The data protection laws of such countries or jurisdictions may differ in certain respects or be less protective than the laws of the jurisdiction in which you reside. If you do not want your information to be transferred, processed or maintained outside the country or jurisdiction in which you reside, you should immediately stop accessing or using the services.