Buy 4 Get 1 Free + Buy Over $50 Save 10%, No upper limit!!!
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
2 / 27
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor
0% OFF

1pc, Christmas Tree Decoration Grinch Letter Pendant, A~Z Letters Home Holiday Acrylic DIY Pendant Xmas New Year Decor Ornament, Christmas Decor, Home Decor, Holiday Decor, Room Decor

$5.99
102 sold
Style
Qty 11 in stock

Description

[Christmas Grinch Ornaments] The cheerful and bright color design, along with the cute and amusing characters, make the entire Christmas tree decoration more fresh and unique. It will make your Christmas tree warmer and more creative.

[Cartoon Design] Each piece is a unique letter that can represent oneself, making it a healing and lovely gift for family, loved ones, and friends. The details are exquisite. These Christmas tree ornaments will bring back wonderful memories and make your Christmas season fun.

[Widely Used] Christmas ornaments can be decorated anywhere you want, whether it's great indoor Christmas decorations or outdoor ones, such as offices, schools, homes, outdoor yards, etc. They are very suitable for use. They will become decorations for your Christmas tree and any place where you can hang them, making this Christmas season more exciting.

[Celebrate Your Christmas] With Christmas approaching, these exquisite Christmas tree pendants are perfect as Christmas gifts for neighbors, extended family, friends, etc. It will be the perfect way to create lasting and love-filled memories.

class SpzSmartBlockComponent extends SPZ.BaseElement { constructor(element) { super(element); this.templates_ = null; this.container_ = null; this.i18n_ = {}; this.config_ = {}; this.show_type_ = 3; this.product_resource_id_ = ''; this.collection_resource_id_ = ''; this.cart_items_ = []; this.customer_id_ = ''; this.order_id_ = ''; } static deferredMount() { return false; } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } buildCallback() { const template_type = window.SHOPLAZZA.meta.page.template_type; if (template_type === 1) { this.show_type_ = 3; this.product_resource_id_ = window.SHOPLAZZA.meta.page.resource_id; } else if (template_type === 2) { this.show_type_ = 4; this.collection_resource_id_ = window.SHOPLAZZA.meta.page.resource_id; } else if (template_type === 15){ this.show_type_ = 5; } else if (template_type === 13){ this.show_type_ = 6; } else if (template_type === 20){ this.show_type_ = 7; this.customer_id_ = window.SHOPLAZZA.customer.customer_id; } else if (template_type === 35){ this.show_type_ = 8; this.order_id_ = window.location.pathname.split('/').pop(); } this.templates_ = SPZServices.templatesForDoc(this.element); this.setAction_(); } mountCallback() { console.log('smart mounted'); const that = this; const themeName = window.SHOPLAZZA.theme.merchant_theme_name; const isGeek = /Geek/.test(themeName); this.fetchRules().then((res) => { if (res && res.rules && res.rules.length) { const blockEl = document.getElementById('smart_recommend_block'); SPZ.whenApiDefined(blockEl).then((api) => { api.render({data: res}, true).then(() => { if (isGeek && that.show_type_ === 6) { blockEl.querySelector('.plugin_container_wrpper').style.padding = '30px 0'; } const recommendStyle = document.createElement('style'); recommendStyle.innerHTML = ` .plugin__recommend_container,.app-recommend-card { display: none !important; } `; document.head.appendChild(recommendStyle); const fetchList = []; res.rules.forEach((rule) => { fetchList.push(this.fetchRuleProductList(rule.id)); }); const fetchAll = Promise.all(fetchList); fetchAll.then((p_res) => { res.rules.forEach((rule, index) => { rule.products = p_res[index] && p_res[index].products; const ruleEl = document.getElementById('smart_recommend_rule_' + rule.id); SPZ.whenApiDefined(ruleEl).then((api) => { api.render({data: rule}, true).then(() => { that.impressListen(`#smart_recommend_rule_ul_${rule.id}`, function(){ that.trackRuleImpress(rule); }); const btnElList = document.querySelectorAll(`#smart_recommend_rule_ul_${rule.id} button`); btnElList.forEach((btnEl) => { if (btnEl && rule.config && rule.config.quick_shop_button_bg_color && rule.config.quick_shop_button_text_color) { btnEl.style.backgroundColor = rule.config.quick_shop_button_bg_color; btnEl.style.color = rule.config.quick_shop_button_text_color; } }) }); }); }); }); }) }) } else { if (window.top !== window.self) { const template_type = window.SHOPLAZZA.meta.page.template_type; const holderEl = document.getElementById('smart_recommend_preview_no_data_placeholder'); SPZ.whenApiDefined(holderEl).then((api) => { api.render({data: { isCart: template_type === 13, isCollection: template_type === 2, isProduct: template_type === 1, isIndex: template_type === 15 }}, true); }); } } }); } setAction_() { this.registerAction('quickShop', (data) => { const that = this; const product_id = data.args.product_id; const productIndex = data.args.productIndex; const rule_id = data.args.rule_id; const ssp = data.args.ssp; const scm = data.args.scm; const cfb = data.args.cfb; const ifb = data.args.ifb; const modalRender = document.getElementById('smart_recommend_product_modal_render'); if (product_id) { this.fetchProductData(product_id).then((res) => { const product = res.products && res.products.length && res.products[0] || {}; product.cfb = cfb; product.ifb = ifb; SPZ.whenApiDefined(modalRender).then((api) => { api.render({product: product, productIndex: productIndex, rule_id: rule_id, ssp: ssp, scm: scm, show_type: that.show_type_}, true).then(() => { const modalEl = document.getElementById('smart_recommend_product_modal'); SPZ.whenApiDefined(modalEl).then((modal) => { that.impressListen('#smart_recommend_product_modal', function(){ that.trackQuickShop({ rule_id: rule_id, product_id: product_id }); }); modal.open(); }); const formEl = document.getElementById('smart_recommend_product_form'); SPZ.whenApiDefined(formEl).then((form) => { form.setProduct(product); }); const variantEl = document.getElementById('smart_recommend_product_variants'); SPZ.whenApiDefined(variantEl).then((variant) => { variant.handleRender(product); }); }); }) }); } }); this.registerAction('handleScroll', (data) => { this.directTo(data.args.rule_id, data.args.direction); }); this.registerAction('handleProductChange', (data) => { const variant = data.args.data.variant; const product = data.args.data.product; const imageRenderEl = document.getElementById('smart_recommend_product_image'); SPZ.whenApiDefined(imageRenderEl).then((api) => { api.render({ variant: variant, product: product }, true); }); }); this.registerAction('handleAtcSuccess', (detail) => { const data = detail.args; data.data.product = data.data.product || {}; data.data.variant = data.data.variant || {}; const product_id = data.data.product.id; const product_title = data.data.product.title; const variant_id = data.data.variant.id; const price = data.data.variant.price; const rule_id = data.rule_id; const aid = `smart_recommend.${this.show_type_}.${rule_id}`; const ifb = data.data.product.ifb; const cfb = data.data.product.cfb; const ssp = data.ssp; const scm = data.scm; const spm = `smart_recommend_${this.show_type_}.${data.spmIndex}`; const params = { id: product_id, product_id: product_id, number: 1, name: product_title, variant_id: variant_id, childrenId: variant_id, item_price: price, source: 'add_to_cart', _extra: { aid: aid, ifb: ifb, cfb: cfb, scm: scm, spm: `..${window.SHOPLAZZA.meta.page.template_name}.${spm}`, ssp: ssp, } }; this.tranckAddToCart(params); }); this.registerAction('addATCHook', (data) => { const params = data.args; const spm = `smart_recommend_${this.show_type_}.${params.spmIndex}`; this.myInterceptor_ = window.djInterceptors && window.djInterceptors.track.use({ event: 'dj.addToCart', params: { aid: `smart_recommend.${this.show_type_}.` + params.rule_id, ssp: params.ssp, scm: params.scm, cfb: params.cfb, spm: `..${window.SHOPLAZZA.meta.page.template_name}.${spm}`, }, once: true }); }); } tranckAddToCart(detail) { if (window.$) { window.$(document.body).trigger('dj.addToCart', detail); } } fetchRules() { const payload = { show_type: this.show_type_, }; let that = this; if (this.show_type_ === 6) { let line_items = []; return this.fetchCart().then((res) => { if (res && res.cart && res.cart.line_items) { line_items = res.cart.line_items.map((item) => { return { product_id: item.product_id, variant_id: item.variant_id, quantity: item.quantity, price: item.price } }); } payload.line_items = line_items; that.cart_items_ = line_items; return that.fetchRulesRequest(payload); }); } else { if (this.show_type_ === 3) { payload.line_items = [{ product_id: this.product_resource_id_ }]; } else if (this.show_type_ === 4) { payload.collection_id = this.collection_resource_id_; } else if (this.show_type_ === 7) { payload.customer_id = this.customer_id_; } else if (this.show_type_ === 8) { payload.order_id = this.order_id_; } return this.fetchRulesRequest(payload); } } fetchRulesRequest(payload) { return fetch(window.SHOPLAZZA.routes.root + "/api/possum/recommend_query", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }).then(function(res){ if(res.ok){ return res.json(); } }); } fetchCart() { return fetch(`/api/cart/cart-select?r=${Math.random().toString(36).slice(-4)}`) .then((res) => { if (res.ok) { return res.json(); } }); } fetchRuleProductList(rule_id) { const payload = { page: 1, limit: 100, fields: ["title", "url", "image", "min_price_variant.price", "min_price_variant.compare_at_price"], rule_id: rule_id, }; if (this.show_type_ === 3) { payload.line_items = [{ product_id: this.product_resource_id_ }]; } else if (this.show_type_ === 4) { payload.collection_id = this.collection_resource_id_; } else if (this.show_type_ === 6) { payload.line_items = this.cart_items_; } else if (this.show_type_ === 7) { payload.customer_id = this.customer_id_; } else if (this.show_type_ === 8) { payload.order_id = this.order_id_; } return fetch(window.SHOPLAZZA.routes.root + "/api/possum/recommend_products", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }).then(function(res){ if(res.ok){ return res.json(); } }).catch(function(err){ console.log(err); }); } fetchProductData(product_id) { return fetch(window.SHOPLAZZA.routes.root + "/api/possum/products", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ product_ids: [product_id], fields: [ "images", "options", "min_price_variant", "variants"] }) }).then(function(res){ if(res.ok){ return res.json(); } }).catch(function(err){ console.log(err); const loadingEl = document.getElementById('smart_recommend_loading'); if (loadingEl) { loadingEl.style.display = 'none'; } }); } getStyle(ele, style) { if (!ele) return; if (window.getComputedStyle) { return window.getComputedStyle(ele)[style]; } return ele.currentStyle[style]; } directTo(id, direction) { const scrollElement = document.getElementById(`smart_recommend_rule_ul_${id}`); const blockWidth = parseInt(this.getStyle(scrollElement, 'width')); const scrollLength = (blockWidth * 0.19 - 12) * 5; const scrollPoint = scrollElement.scrollWidth - scrollElement.clientWidth; if (!scrollElement) return; if (direction === 'left') { if (document.dir === 'rtl') { scrollElement.scrollTo({ left: Math.abs(scrollElement.scrollLeft) >= scrollPoint - 100 ? 0 : scrollElement.scrollLeft - scrollLength, behavior: 'smooth' }); return; } scrollElement.scrollTo({ left: Math.max(scrollElement.scrollLeft - scrollLength, 0), behavior: 'smooth' }); } else { if (document.dir === 'rtl') { scrollElement.scrollTo({ left: Math.abs(scrollElement.scrollLeft) >= scrollPoint + 100 ? 0 : scrollElement.scrollLeft + scrollLength, behavior: 'smooth' }); return; } scrollElement.scrollTo({ left: scrollElement.scrollLeft >= scrollPoint - 100 ? 0 : scrollElement.scrollLeft + scrollLength, behavior: 'smooth' }); } } trackRuleImpress(rule) { if (window.sa && window.sa.track) { window.sa.track("plugin_common", { plugin_name: "upsell", event_type: "impressions", rule_id: rule.id, ssp: rule.ssp, scm: rule.scm, show_type: this.show_type_, support_app_block: window.SHOPLAZZA.theme.support_app_block }); window.sa.track("module_impressions", { aid: `smart_recommend.${this.show_type_}.${rule.id}`, support_app_block: window.SHOPLAZZA.theme.support_app_block }); } } trackQuickShop(data) { window.sa && sa.track && sa.track("plugin_common", { plugin_name: "upsell", event_type: "quick_shop", rule_id: data.rule_id, product_id: data.product_id, show_type: this.show_type_, }); } impressListen(selector, cb) { const el = document.querySelector(selector); const onImpress = (e) => { if (e) { e.stopPropagation(); } cb(); }; if (el && !el.getAttribute('imprsd')) { el.addEventListener('impress', onImpress) } else if (el) { onImpress(); } } } SPZ.defineElement('spz-custom-smart-block', SpzSmartBlockComponent);
The current item does not participate in the discount gift campaign. Switch the participating items to check the design.
(This prompt will not be displayed on the client-side)
class SpzSmartBlockComponent extends SPZ.BaseElement { constructor(element) { super(element); this.templates_ = null; this.container_ = null; this.i18n_ = {}; this.config_ = {}; this.show_type_ = 3; this.product_resource_id_ = ''; this.collection_resource_id_ = ''; this.cart_items_ = []; this.customer_id_ = ''; this.order_id_ = ''; } static deferredMount() { return false; } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } buildCallback() { const template_type = window.SHOPLAZZA.meta.page.template_type; if (template_type === 1) { this.show_type_ = 3; this.product_resource_id_ = window.SHOPLAZZA.meta.page.resource_id; } else if (template_type === 2) { this.show_type_ = 4; this.collection_resource_id_ = window.SHOPLAZZA.meta.page.resource_id; } else if (template_type === 15){ this.show_type_ = 5; } else if (template_type === 13){ this.show_type_ = 6; } else if (template_type === 20){ this.show_type_ = 7; this.customer_id_ = window.SHOPLAZZA.customer.customer_id; } else if (template_type === 35){ this.show_type_ = 8; this.order_id_ = window.location.pathname.split('/').pop(); } this.templates_ = SPZServices.templatesForDoc(this.element); this.setAction_(); } mountCallback() { console.log('smart mounted'); const that = this; const themeName = window.SHOPLAZZA.theme.merchant_theme_name; const isGeek = /Geek/.test(themeName); this.fetchRules().then((res) => { if (res && res.rules && res.rules.length) { const blockEl = document.getElementById('smart_recommend_block'); SPZ.whenApiDefined(blockEl).then((api) => { api.render({data: res}, true).then(() => { if (isGeek && that.show_type_ === 6) { blockEl.querySelector('.plugin_container_wrpper').style.padding = '30px 0'; } const recommendStyle = document.createElement('style'); recommendStyle.innerHTML = ` .plugin__recommend_container,.app-recommend-card { display: none !important; } `; document.head.appendChild(recommendStyle); const fetchList = []; res.rules.forEach((rule) => { fetchList.push(this.fetchRuleProductList(rule.id)); }); const fetchAll = Promise.all(fetchList); fetchAll.then((p_res) => { res.rules.forEach((rule, index) => { rule.products = p_res[index] && p_res[index].products; const ruleEl = document.getElementById('smart_recommend_rule_' + rule.id); SPZ.whenApiDefined(ruleEl).then((api) => { api.render({data: rule}, true).then(() => { that.impressListen(`#smart_recommend_rule_ul_${rule.id}`, function(){ that.trackRuleImpress(rule); }); const btnElList = document.querySelectorAll(`#smart_recommend_rule_ul_${rule.id} button`); btnElList.forEach((btnEl) => { if (btnEl && rule.config && rule.config.quick_shop_button_bg_color && rule.config.quick_shop_button_text_color) { btnEl.style.backgroundColor = rule.config.quick_shop_button_bg_color; btnEl.style.color = rule.config.quick_shop_button_text_color; } }) }); }); }); }); }) }) } else { if (window.top !== window.self) { const template_type = window.SHOPLAZZA.meta.page.template_type; const holderEl = document.getElementById('smart_recommend_preview_no_data_placeholder'); SPZ.whenApiDefined(holderEl).then((api) => { api.render({data: { isCart: template_type === 13, isCollection: template_type === 2, isProduct: template_type === 1, isIndex: template_type === 15 }}, true); }); } } }); } setAction_() { this.registerAction('quickShop', (data) => { const that = this; const product_id = data.args.product_id; const productIndex = data.args.productIndex; const rule_id = data.args.rule_id; const ssp = data.args.ssp; const scm = data.args.scm; const cfb = data.args.cfb; const ifb = data.args.ifb; const modalRender = document.getElementById('smart_recommend_product_modal_render'); if (product_id) { this.fetchProductData(product_id).then((res) => { const product = res.products && res.products.length && res.products[0] || {}; product.cfb = cfb; product.ifb = ifb; SPZ.whenApiDefined(modalRender).then((api) => { api.render({product: product, productIndex: productIndex, rule_id: rule_id, ssp: ssp, scm: scm, show_type: that.show_type_}, true).then(() => { const modalEl = document.getElementById('smart_recommend_product_modal'); SPZ.whenApiDefined(modalEl).then((modal) => { that.impressListen('#smart_recommend_product_modal', function(){ that.trackQuickShop({ rule_id: rule_id, product_id: product_id }); }); modal.open(); }); const formEl = document.getElementById('smart_recommend_product_form'); SPZ.whenApiDefined(formEl).then((form) => { form.setProduct(product); }); const variantEl = document.getElementById('smart_recommend_product_variants'); SPZ.whenApiDefined(variantEl).then((variant) => { variant.handleRender(product); }); }); }) }); } }); this.registerAction('handleScroll', (data) => { this.directTo(data.args.rule_id, data.args.direction); }); this.registerAction('handleProductChange', (data) => { const variant = data.args.data.variant; const product = data.args.data.product; const imageRenderEl = document.getElementById('smart_recommend_product_image'); SPZ.whenApiDefined(imageRenderEl).then((api) => { api.render({ variant: variant, product: product }, true); }); }); this.registerAction('handleAtcSuccess', (detail) => { const data = detail.args; data.data.product = data.data.product || {}; data.data.variant = data.data.variant || {}; const product_id = data.data.product.id; const product_title = data.data.product.title; const variant_id = data.data.variant.id; const price = data.data.variant.price; const rule_id = data.rule_id; const aid = `smart_recommend.${this.show_type_}.${rule_id}`; const ifb = data.data.product.ifb; const cfb = data.data.product.cfb; const ssp = data.ssp; const scm = data.scm; const spm = `smart_recommend_${this.show_type_}.${data.spmIndex}`; const params = { id: product_id, product_id: product_id, number: 1, name: product_title, variant_id: variant_id, childrenId: variant_id, item_price: price, source: 'add_to_cart', _extra: { aid: aid, ifb: ifb, cfb: cfb, scm: scm, spm: `..${window.SHOPLAZZA.meta.page.template_name}.${spm}`, ssp: ssp, } }; this.tranckAddToCart(params); }); this.registerAction('addATCHook', (data) => { const params = data.args; const spm = `smart_recommend_${this.show_type_}.${params.spmIndex}`; this.myInterceptor_ = window.djInterceptors && window.djInterceptors.track.use({ event: 'dj.addToCart', params: { aid: `smart_recommend.${this.show_type_}.` + params.rule_id, ssp: params.ssp, scm: params.scm, cfb: params.cfb, spm: `..${window.SHOPLAZZA.meta.page.template_name}.${spm}`, }, once: true }); }); } tranckAddToCart(detail) { if (window.$) { window.$(document.body).trigger('dj.addToCart', detail); } } fetchRules() { const payload = { show_type: this.show_type_, }; let that = this; if (this.show_type_ === 6) { let line_items = []; return this.fetchCart().then((res) => { if (res && res.cart && res.cart.line_items) { line_items = res.cart.line_items.map((item) => { return { product_id: item.product_id, variant_id: item.variant_id, quantity: item.quantity, price: item.price } }); } payload.line_items = line_items; that.cart_items_ = line_items; return that.fetchRulesRequest(payload); }); } else { if (this.show_type_ === 3) { payload.line_items = [{ product_id: this.product_resource_id_ }]; } else if (this.show_type_ === 4) { payload.collection_id = this.collection_resource_id_; } else if (this.show_type_ === 7) { payload.customer_id = this.customer_id_; } else if (this.show_type_ === 8) { payload.order_id = this.order_id_; } return this.fetchRulesRequest(payload); } } fetchRulesRequest(payload) { return fetch(window.SHOPLAZZA.routes.root + "/api/possum/recommend_query", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }).then(function(res){ if(res.ok){ return res.json(); } }); } fetchCart() { return fetch(`/api/cart/cart-select?r=${Math.random().toString(36).slice(-4)}`) .then((res) => { if (res.ok) { return res.json(); } }); } fetchRuleProductList(rule_id) { const payload = { page: 1, limit: 100, fields: ["title", "url", "image", "min_price_variant.price", "min_price_variant.compare_at_price"], rule_id: rule_id, }; if (this.show_type_ === 3) { payload.line_items = [{ product_id: this.product_resource_id_ }]; } else if (this.show_type_ === 4) { payload.collection_id = this.collection_resource_id_; } else if (this.show_type_ === 6) { payload.line_items = this.cart_items_; } else if (this.show_type_ === 7) { payload.customer_id = this.customer_id_; } else if (this.show_type_ === 8) { payload.order_id = this.order_id_; } return fetch(window.SHOPLAZZA.routes.root + "/api/possum/recommend_products", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }).then(function(res){ if(res.ok){ return res.json(); } }).catch(function(err){ console.log(err); }); } fetchProductData(product_id) { return fetch(window.SHOPLAZZA.routes.root + "/api/possum/products", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ product_ids: [product_id], fields: [ "images", "options", "min_price_variant", "variants"] }) }).then(function(res){ if(res.ok){ return res.json(); } }).catch(function(err){ console.log(err); const loadingEl = document.getElementById('smart_recommend_loading'); if (loadingEl) { loadingEl.style.display = 'none'; } }); } getStyle(ele, style) { if (!ele) return; if (window.getComputedStyle) { return window.getComputedStyle(ele)[style]; } return ele.currentStyle[style]; } directTo(id, direction) { const scrollElement = document.getElementById(`smart_recommend_rule_ul_${id}`); const blockWidth = parseInt(this.getStyle(scrollElement, 'width')); const scrollLength = (blockWidth * 0.19 - 12) * 5; const scrollPoint = scrollElement.scrollWidth - scrollElement.clientWidth; if (!scrollElement) return; if (direction === 'left') { if (document.dir === 'rtl') { scrollElement.scrollTo({ left: Math.abs(scrollElement.scrollLeft) >= scrollPoint - 100 ? 0 : scrollElement.scrollLeft - scrollLength, behavior: 'smooth' }); return; } scrollElement.scrollTo({ left: Math.max(scrollElement.scrollLeft - scrollLength, 0), behavior: 'smooth' }); } else { if (document.dir === 'rtl') { scrollElement.scrollTo({ left: Math.abs(scrollElement.scrollLeft) >= scrollPoint + 100 ? 0 : scrollElement.scrollLeft + scrollLength, behavior: 'smooth' }); return; } scrollElement.scrollTo({ left: scrollElement.scrollLeft >= scrollPoint - 100 ? 0 : scrollElement.scrollLeft + scrollLength, behavior: 'smooth' }); } } trackRuleImpress(rule) { if (window.sa && window.sa.track) { window.sa.track("plugin_common", { plugin_name: "upsell", event_type: "impressions", rule_id: rule.id, ssp: rule.ssp, scm: rule.scm, show_type: this.show_type_, support_app_block: window.SHOPLAZZA.theme.support_app_block }); window.sa.track("module_impressions", { aid: `smart_recommend.${this.show_type_}.${rule.id}`, support_app_block: window.SHOPLAZZA.theme.support_app_block }); } } trackQuickShop(data) { window.sa && sa.track && sa.track("plugin_common", { plugin_name: "upsell", event_type: "quick_shop", rule_id: data.rule_id, product_id: data.product_id, show_type: this.show_type_, }); } impressListen(selector, cb) { const el = document.querySelector(selector); const onImpress = (e) => { if (e) { e.stopPropagation(); } cb(); }; if (el && !el.getAttribute('imprsd')) { el.addEventListener('impress', onImpress) } else if (el) { onImpress(); } } } SPZ.defineElement('spz-custom-smart-block', SpzSmartBlockComponent);