🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
1 / 19
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9
50% OFF
flyeenn

🔥50% DE RÉDUCTION🔥-Nouveau produit-Pantalons tactiques étanches pour hommes Outdoor IX7/ IX9

€34.99 €69.98
7 ventes
Couleur
Taille
Quantité

REMARQUES SUR LA TAILLE :

>> La taille est petite, veuillez vous référer au tableau des tailles pour acheter la bonne taille pour vous, nous vous suggérons de choisir la plus grande taille


>> Si votre taille se situe entre deux tailles différentes que nous proposons, il est recommandé de choisir la taille la plus grande .
>> Par exemple, si votre taille est tour de taille : 88cm, il est préférable de commander la taille XL au lieu de la taille L

🔥Cliquez sur "AJOUTER AU PANIER" pour obtenir le vôtre maintenant !🔥
  • Expédier dans les 48 heures après paiement !
  • Livraison express mondiale disponible !
  • Certificats SSL pour une sécurité à 100 % !
  • Expédition dans le monde entier!

 

Les pantalons tactiques imperméables, les pantalons tactiques pour hommes les plus confortables sont de retour et meilleurs que jamais. Avec de nombreuses poches de rangement et une imperméabilité totale, ils sont conçus pour la randonnée, la randonnée et les déplacements - mais suffisamment élégants pour être portés tous les jours. Ils offrent une gamme impressionnante d'ajouts de conception.

Les marines s'appuient chaque jour sur ce même pantalon conçu par IX9, ce qui leur permet de donner le meilleur d'eux-mêmes. Ils sont confortables, respirants et entièrement imperméables. Parfait pour le trekking, la randonnée, l'escalade ou tout simplement un vêtement quotidien ultra-pratique sur lequel vous pouvez compter pour les années à venir.

CARACTÉRISTIQUES

  • DURABILITÉ ROBUSTE- Fabriqué avec un mélange de coton, de polyester et d'élasthanne, ce pantalon tactique pour homme présente des coutures améliorées pour une résistance à l'extérieur

  • COMFORT-FIT WAIST - Ces pantalons indéchirables légers disposent d'une taille extensible parfaite pour une réponse rapide, des exercices de plage ou hors service, ou un usage quotidien

  • CONFORT PROFESSIONNEL - Un design breveté aux États-Unis et dans l'UE, ce pantalon tactique comporte même des poches internes pour un rembourrage supplémentaire et des genouillères

  • RÉSISTANT AU CLIMAT - Que vous partiez à la chasse, à la randonnée, à la randonnée ou à la planification d'un assaut SWAT, les pantalons pour hommes peuvent résister à une variété de climats

  • POCHES À PROFIL BAS - Gardez les clips, les munitions, les premiers soins ou l'équipement tactique accessibles avec 10 poches porteuses situées à l'avant, à l'arrière et sur les cuisses.

🎉Astuce : Si votre taille se situe entre deux tailles différentes que nous proposons, il est recommandé de choisir la taille supérieure. (Par exemple, si votre taille est de 32", il serait préférable pour vous de commander la taille M au lieu de la taille S)

QUESTIONS ET RÉPONSES:

Article 1 : Si j'effectue l'achat, combien de temps faudra-t-il pour recevoir les marchandises ?

Réponse : Cela dépend des jours de livraison que vous choisissez lorsque vous payez les marchandises. Nous avons deux options pour nous assurer que les marchandises peuvent arriver à temps

Élément 2 : d'où vient-il ? Puis-je le retourner et l'échanger gratuitement

Réponse : Il vient des États-Unis. Nous nous engageons à retourner et à échanger les marchandises gratuitement en cas de problème dans un délai d'un mois

Point 3 : S'il est étanche, comment puis-je le nettoyer ?

Réponse : Ne vous inquiétez pas. Nous avons des instructions pour nettoyer le pantalon. N'ont rencontré aucun rétrécissement ou décoloration.

LE FORFAIT COMPREND :

  • 1 x pantalon imperméable tactique

POURQUOI LES USA ?

  • Nous travaillons directement avec des fabricants du monde entier pour garantir la meilleure qualité de nos produits. Nous avons un service de contrôle qualité qui nous aide à tenir notre promesse !
  • Le prix est toujours compétitif.
  • Service client génial
  • Des produits étonnants avec une haute qualité

Notre entrepôt

NOTRE GARANTIE

Expédition mondiale assurée : chaque commande comprend des détails de suivi en temps réel et une couverture d'assurance dans le cas peu probable où un colis serait perdu ou volé en transit.

Garantie de remboursement : si vos articles arrivent endommagés ou deviennent défectueux dans les 30 jours d'utilisation normale, nous nous ferons un plaisir de procéder à un remplacement ou à un remboursement.

✉️ Assistance client 24h/24 et 7j/7 : nous avons une équipe de représentants en direct prêts à vous aider et à répondre à toutes vos questions dans un délai de 24 heures, 7 jours sur 7.

Paiements sûrs et sécurisés : Nous utilisons un cryptage SSL Secure de pointe pour protéger vos informations personnelles et financières à 100 %.

 

1. Dois-je avoir un compte pour commander ?
Non, vous pouvez également passer une commande en tant qu'invité. Mais vous bénéficiez de certains avantages si vous avez un compte chez nous :

Processus de paiement rapide
Visualisez facilement l'état et l'historique de votre commande.
Recevez des mises à jour détaillant nos nouveautés et nos promotions spéciales.


2. Quels modes de paiement acceptez-vous ?
Nous acceptons toutes les principales cartes de crédit (VISA, Mastercard, Discover, AMEX) et les paiements PayPal.



3. Ma commande en ligne est-elle sécurisée ?
Lorsque vous achetez en ligne en utilisant votre carte de crédit, toutes vos informations sont saisies sur une page Web sécurisée par SSL. Vos informations sont ensuite cryptées par SSL et envoyées directement au réseau de notre fournisseur de carte de crédit, où votre carte et la transaction sont autorisées et approuvées. Les informations relatives à votre carte de crédit ne sont pas stockées sur nos serveurs.



4. Y a-t-il des taux de change ?
Toutes nos transactions sont basées sur l'euro. Si votre carte de crédit est libellée dans une autre devise, le total de votre commande sera calculé sur la base du taux de change quotidien à partir de la date à laquelle l'émetteur de votre carte traite la transaction.



5. comment définir mon adresse de livraison ?
Notre site et nos services étant basés sur le français, toutes les informations que vous saisissez doivent l'être en français, y compris la ponctuation. Si certaines des lettres de votre adresse contiennent des lettres non françaises, nous vous recommandons de les remplacer par des lettres françaises similaires. Par exemple, vous pouvez remplacer la lettre " ?". pour "c"



6. Puis-je modifier mon adresse de livraison après avoir passé une commande ?
Nous vous informons que votre adresse de livraison ne peut pas être modifiée après le traitement ou l'expédition de la commande. Veuillez mettre à jour votre adresse de livraison à votre adresse résidentielle plutôt qu'à votre adresse de vacances, car nous ne savons pas combien de temps le service des douanes du pays de destination gardera le colis en attente.



7. combien de temps dure la livraison et comment puis-je suivre mon colis ?
Le délai de livraison dépend de l'option d'expédition que vous avez choisie. Une fois la commande expédiée, nous vous enverrons par courriel votre numéro de suivi et le site Web de suivi. Nous ne sommes pas responsables des retards causés par le service des douanes de votre pays.



8. Que dois-je faire si des articles manquent dans ma commande ?
Si un article est toujours manquant, veuillez nous contacter immédiatement à service@bonusvogue.com.



Si vous avez encore des questions, veuillez nous contacter directement à l'adresse e-mail service@bonusvogue.com

87.3% des clients ont également acheté Je n'aime pas ça?
/** @private {string} */ class SpzCustomAnchorScroll extends SPZ.BaseElement { static deferredMount() { return false; } constructor(element) { super(element); /** @private {Element} */ this.scrollableContainer_ = null; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } buildCallback() { this.viewport_ = this.getViewport(); this.initActions_(); } setTarget(containerId, targetId) { this.containerId = '#' + containerId; this.targetId = '#' + targetId; } scrollToTarget() { const container = document.querySelector(this.containerId); const target = container.querySelector(this.targetId); const {scrollTop} = container; const eleOffsetTop = this.getOffsetTop_(target, container); this.viewport_ .interpolateScrollIntoView_( container, scrollTop, scrollTop + eleOffsetTop ); } initActions_() { this.registerAction( 'scrollToTarget', (invocation) => this.scrollToTarget(invocation?.caller) ); this.registerAction( 'setTarget', (invocation) => this.setTarget(invocation?.args?.containerId, invocation?.args?.targetId) ); } /** * @param {Element} element * @param {Element} container * @return {number} * @private */ getOffsetTop_(element, container) { if (!element./*OK*/ getClientRects().length) { return 0; } const rect = element./*OK*/ getBoundingClientRect(); if (rect.width || rect.height) { return rect.top - container./*OK*/ getBoundingClientRect().top; } return rect.top; } } SPZ.defineElement('spz-custom-anchor-scroll', SpzCustomAnchorScroll); const STRENGTHEN_TRUST_URL = "/api/strengthen_trust/settings"; class SpzCustomStrengthenTrust extends SPZ.BaseElement { constructor(element) { super(element); this.renderElement_ = null; } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } buildCallback() { this.xhr_ = SPZServices.xhrFor(this.win); const renderId = this.element.getAttribute('render-id'); SPZCore.Dom.waitForChild( document.body, () => !!document.getElementById(renderId), () => { this.renderElement_ = SPZCore.Dom.scopedQuerySelector( document.body, `#${renderId}` ); if (this.renderElement_) { this.render_(); } this.registerAction('track', (invocation) => { this.track_(invocation.args); }); } ); } render_() { this.fetchData_().then((data) => { if (!data) { return; } SPZ.whenApiDefined(this.renderElement_).then((apis) => { apis?.render(data); document.querySelector('#strengthen-trust-render-1710495796818').addEventListener('click',(event)=>{ if(event.target.nodeName == 'A'){ this.track_({type: 'trust_content_click'}); } }) }); }); } track_(data = {}) { const track = window.sa && window.sa.track; if (!track) { return; } track('trust_enhancement_event', data); } parseJSON_(string) { let result = {}; try { result = JSON.parse(string); } catch (e) {} return result; } fetchData_() { return this.xhr_ .fetchJson(STRENGTHEN_TRUST_URL) .then((responseData) => { if (!responseData || !responseData.data) { return null; } const data = responseData.data; const moduleSettings = (data.module_settings || []).reduce((result, moduleSetting) => { return result.concat(Object.assign(moduleSetting, { logos: (moduleSetting.logos || []).map((item) => { return moduleSetting.logos_type == 'custom' ? this.parseJSON_(item) : item; }) })); }, []); return Object.assign(data, { module_settings: moduleSettings, isEditor: window.self !== window.top, }); }); } } SPZ.defineElement('spz-custom-strengthen-trust', SpzCustomStrengthenTrust);

❤️ASTUCE : Tous nos produits sont authentiques, avec de vrais brevets, les contrefaçons doivent être examinées ! Veuillez marquer nos produits !!!

😊Si vous n'êtes pas satisfait des articles reçus, veuillez nous contacter dans les 15 jours suivant la réception et nous vous apporterons la meilleure assistance possible !

🚢Livraison >> Livraison express efficace disponible dans toute la France.

🔥98,9 % de nos clients achètent 2 articles ou plus. Obtenez le vôtre dès maintenant !

Si vous avez encore des questions, veuillez nous contacter directement à l'adresse e-mail 👉 service@bonusvogue.com

émettre un commentaire
Commentaire de clients
tu as atteint le fond
Le plus récent
Le plus aimé
Meilleures notes
Notes les plus basses
×
class SpzCustomFileUpload extends SPZ.BaseElement { constructor(element) { super(element); this.uploadCount_ = 0; this.fileList_ = []; } buildCallback() { this.action = SPZServices.actionServiceForDoc(this.element); this.registerAction('upload', (data) => { this.handleFileUpload_(data.event?.detail?.data || []); }); this.registerAction('delete', (data) => { this.handleFileDelete_(data?.args?.data); }); this.registerAction('preview', (data) => { this.handleFilePreview_(data?.args?.data); }); this.registerAction('limit', (data) => { this.handleFileLimit_(); }); this.registerAction('sizeLimit', (data) => { this.handleFileSizeLimit_(); }); } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } setData_(count, file) { this.uploadCount_ = count; this.fileList_ = file; } handleFileUpload_(data) { data.forEach(i => { if(this.fileList_.some(j => j.url === i.url)) return; this.fileList_.push(i); }) this.uploadCount_++; sessionStorage.setItem('fileList', JSON.stringify(this.fileList_)); this.triggerEvent_("handleFileUpload", { count: this.uploadCount_, files: this.fileList_}); if(this.fileList_.length >= 5){ document.querySelector('#review_upload').style.display = 'none'; } if(this.fileList_.length > 0){ document.querySelector('.apps-reviews-write-anonymous-box').style.marginTop = '8px'; } } handleFileDelete_(index) { this.fileList_.splice(index, 1); this.uploadCount_--; sessionStorage.setItem('fileList', JSON.stringify(this.fileList_)); this.triggerEvent_("handleFileDelete", { count: this.uploadCount_, files: this.fileList_}); document.querySelector('#review_upload').style.display = 'block'; if(this.fileList_?.length === 0){ document.querySelector('.apps-reviews-write-anonymous-box').style.marginTop = '132px'; } } handleFilePreview_(index) { const finalPreviewData = this.fileList_[index]; const filePreviewModal = document.getElementById('filePreviewModal'); const fullScreenVideo = document.getElementById('fullScreenVideo'); const fullScreenImage = document.getElementById('fullScreenImage'); const previewModalClose = document.getElementById('previewModalClose'); const previewLoading = document.getElementById('previewLoading'); filePreviewModal.style.display = 'block'; previewLoading.style.display = 'flex'; if(finalPreviewData?.type === 'video'){ const media = this.mediaParse_(this.fileList_[index]?.url); fullScreenVideo.addEventListener('canplaythrough', function() { previewLoading.style.display = 'none'; }); fullScreenImage.src = ''; fullScreenImage.style.display = 'none'; fullScreenVideo.style.display = 'block'; fullScreenVideo.src = media.mp4 || ''; } else { fullScreenImage.onload = function() { previewLoading.style.display = 'none'; }; fullScreenVideo.src = ''; fullScreenVideo.style.display = 'none'; fullScreenImage.style.display = 'block'; fullScreenImage.src = finalPreviewData.url; } previewModalClose.addEventListener('click', function() { filePreviewModal.style.display = 'none'; }); } handleFileLimit_() { alert(window.AppReviewsLocale.comment_file_limit || 'please do not upload files more than 5'); this.triggerEvent_("handleFileLimit"); } handleFileSizeLimit_() { alert(window.AppReviewsLocale.comment_file_size_limit || 'File size does not exceed 10M'); } clear(){ this.fileList_ = []; this.uploadCount_ = 0; sessionStorage.setItem('fileList', JSON.stringify(this.fileList_)); this.triggerEvent_("handleClear", { count: this.uploadCount_, files: this.fileList_}); document.querySelector('#review_upload').style.display = 'block'; } mediaParse_(url) { var result = {}; try { url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) { try { result[key] = decodeURIComponent(value); } catch (e) { result[key] = value; } }); result.preview_image = url.split('?')[0]; } catch (e) {}; return result; } triggerEvent_(name, data) { const event = SPZUtils.Event.create(this.win, name, data); this.action.trigger(this.element, name, event); } } SPZ.defineElement('spz-custom-file-upload', SpzCustomFileUpload);
The review would not show in product details on storefront since it does not support to.
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);
const TAG = 'spz-custom-painter-button-animation'; const MAX_ITERATION_COUNT = 99999999; const SITE = (window.C_SETTINGS && window.C_SETTINGS.routes && window.C_SETTINGS.routes.root) || ''; const ADD_TO_CART_ANIMATION_SETTING = `${SITE}/api/marketing_atmosphere_app/add_to_cart_btn_animation/setting`; class SpzCustomPainterButtonAnimation extends SPZ.BaseElement { /**@override */ static deferredMount() { return false; } /** @param {!SpzElement} element */ constructor(element) { super(element); /** @private {!../../src/service/xhr-impl.Xhr} */ this.xhr_ = SPZServices.xhrFor(this.win); /** @private {Object} */ this.data_ = null; /** @private {Element} */ this.addToCartButton_ = null; /** @private {boolean} */ this.productAvailable_ = true; /** @private {number} */ this.timerId_ = null; /** @private {number} */ this.animationExecutionCount_ = 0; /** @private {boolean} */ this.selectedVariantAvailable_ = true; /** @private {number} */ this.delay_ = 5000; /** @private {number} */ this.iterationCount_ = 5; /** @private {string} */ this.animationClass_ = ''; } /** @override */ isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } /** @override */ buildCallback() { this.productAvailable_ = this.element.hasAttribute('product-available'); this.selectedVariantAvailable_ = this.element.hasAttribute('selected-variant-available'); } /** @override */ mountCallback() { this.render_(); } /** @private */ render_() { if (!this.productAvailable_) { return; } this.fetch_().then((data) => { if (!data) { return; } this.data_ = data; this.animationClass_ = `painter-${data.animation_name}-animation`; this.iterationCount_ = data.animation_iteration_count === 'infinite' ? MAX_ITERATION_COUNT : data.animation_iteration_count; const animationDuration = 1; const animationDelay = data.animation_delay || 5; this.delay_ = (animationDuration + animationDelay) * 1000; this.handleButtonEffect_(); }); } /** * @param {JsonObject} data * @return {(null|Object)} * @private */ parseJson_(data) { try { return JSON.parse(data); } catch (e) { return null; } } /** * @return {Promise} * @private */ fetch_() { return this.xhr_.fetchJson(ADD_TO_CART_ANIMATION_SETTING).then((data) => { if (!data || !data.enabled) { return null; } return this.parseJson_(data.detail); }); } /** @private */ getAddToCartButton_() { this.addToCartButton_ = SPZCore.Dom.scopedQuerySelector( document.body, '[data-section-type="product"] [role="addToCart"], [data-section-type="product_detail"] [role="addToCart"], [data-section-type="product_detail"] [data-click="addToCart"], [data-section-type="product"] [data-click="addToCart"]' ); } /** @private */ restartAnimation_() { this.addToCartButton_.classList.remove(this.animationClass_); this.addToCartButton_./* OK */ offsetWidth; this.addToCartButton_.classList.add(this.animationClass_); this.animationExecutionCount_++; } /** @private */ clearTimer_() { this.win.clearInterval(this.timerId_); this.timerId_ = null; } /** @private */ setupTimer_() { this.timerId_ = this.win.setInterval(() => { this.restartAnimation_(); if (this.animationExecutionCount_ >= this.iterationCount_) { this.removeAnimationClass_(); this.clearTimer_(); } }, this.delay_); } /** @private */ restartTimer_() { if (this.animationExecutionCount_ >= this.iterationCount_) { this.removeAnimationClass_(); return; } this.setupTimer_(); } /** @private */ listenVariantChange_() { SPZUtils.Event.listen(self.document, 'dj.variantChange', (e) => { const selectedVariant = e.detail && e.detail.selected; if (!selectedVariant) { return; } const {available} = selectedVariant; if (this.selectedVariantAvailable_ !== available) { this.selectedVariantAvailable_ = available; this.clearTimer_(); if (available) { this.restartTimer_(); } } }); } /** @private */ removeAnimationClass_() { this.win.setTimeout(() => { this.addToCartButton_.classList.remove(this.animationClass_); }, 1000); } /** @private */ handleButtonEffect_() { this.getAddToCartButton_(); if (!this.addToCartButton_) { return; } if (this.selectedVariantAvailable_) { ++this.animationExecutionCount_; this.addToCartButton_.classList.add(this.animationClass_); if (this.iterationCount_ === 1) { this.removeAnimationClass_(); return; } this.setupTimer_(); } this.listenVariantChange_(); } } SPZ.defineElement(TAG, SpzCustomPainterButtonAnimation);