const LOCAL_STORAGE = "tl-cart-goal-local-storage"; class CartGoalEmbed { constructor(cartGoalRules, giftSVG, discountSVG, freeShippingSVG, currencySymbol, cartTotal, template, defaultImage, showTrademark, productIdMapCollection, displaySettings, translation) { this.giftSVG = giftSVG; this.discountSVG = discountSVG; this.freeShippingSVG = freeShippingSVG; this.template = template; this.defaultImage = defaultImage; this.showTrademark = showTrademark; this.productIdMapCollection = new Map(productIdMapCollection); this.currency = currencySymbol; this.currencyRate = 1; if (Shopify && Shopify.currency) { this.currency = Shopify.currency.active; this.currencyRate = Number(Shopify.currency.rate); } this.cartTotal = cartTotal; this.cartGoal = {}; const listRule = Object.values(cartGoalRules); for (let i = listRule.length - 1; i >= 0; i--) { const cartGoalRule = listRule[i]; if (cartGoalRule.status && this.checkActiveDate(cartGoalRule.start_at, cartGoalRule.end_at)) { this.cartGoal = cartGoalRule; break; } } if (Object.keys(this.cartGoal).length) { this.milestones = []; if (this.cartGoal.milestones) { this.milestones = this.cartGoal.milestones.map((milestone) => ({ ...milestone, cart_value: milestone.cart_value * this.currencyRate, reward_value: milestone.discount_type === "decrease_amount" && milestone.reward_type !== this.REWARD_TYPE.FREE_GIFT ? milestone.reward_value * this.currencyRate : milestone.reward_value })); } if (displaySettings && displaySettings.progress_bar) { this.customColor = displaySettings.progress_bar.progress_bar_style; this.containerStyle = displaySettings.progress_bar.container_style; this.sectionRewardStyle = displaySettings.progress_bar.section_reward_style; this.giftModalStyle = displaySettings.progress_bar.gift_modal_style; this.cartDrawDisplay = displaySettings.progress_bar.cart_draw_display; this.cartDisplay = displaySettings.progress_bar.cart_display; this.currencyFormat = displaySettings.progress_bar.currency_format; this.currencyDisplay = displaySettings.progress_bar.currency_display; } else { this.customColor = this.cartGoal?.color ? JSON.parse(this.cartGoal.color) : this.DEFAULT_STYLE_PROGRESS_BAR; this.containerStyle = this.cartGoal?.container_style ? JSON.parse(this.cartGoal.container_style) : this.DEFAULT_STYLE_CONTAINER; this.sectionRewardStyle = this.cartGoal?.section_reward_style ? JSON.parse(this.cartGoal.section_reward_style) : this.DEFAULT_STYLE_SECTION_REWARD; this.giftModalStyle = this.cartGoal?.gift_modal_style ? JSON.parse(this.cartGoal.gift_modal_style) : this.DEFAULT_STYLE_GIFT_MODAL; this.cartDrawDisplay = JSON.parse(this.cartGoal.cart_draw_display); this.cartDisplay = JSON.parse(this.cartGoal.cart_display); this.currencyFormat = this.cartGoal.currency_format; this.currencyDisplay = JSON.parse(this.cartGoal.currency_display || "{}"); } let customTranslation = null; if (translation) { const locale = Shopify?.locale || "en"; customTranslation = translation.progress_bar[locale] ? translation.progress_bar[locale] : null; } else { let sectionRewardStyle = this.cartGoal?.section_reward_style ? JSON.parse(this.cartGoal.section_reward_style) : this.DEFAULT_STYLE_SECTION_REWARD; let giftModalStyle = this.cartGoal?.gift_modal_style ? JSON.parse(this.cartGoal.gift_modal_style) : this.DEFAULT_STYLE_GIFT_MODAL; customTranslation = { milestone: { achieve_all: this.cartGoal.achieve_title }, auto_apply_btn: { gift: sectionRewardStyle.selected_gifts_button_text, order_discount: sectionRewardStyle.apply_order_discount_button_text?.applied, shipping_discount: sectionRewardStyle.apply_shipping_discount_button_text?.applied }, manual_apply_btn: { gift: { before_apply: sectionRewardStyle.select_gifts_button_text, after_apply: sectionRewardStyle.selected_gifts_button_text }, order_discount: { before_apply: sectionRewardStyle.apply_order_discount_button_text?.unapply, after_apply: sectionRewardStyle.apply_order_discount_button_text?.applied }, shipping_discount: { before_apply: sectionRewardStyle.apply_shipping_discount_button_text?.unapply, after_apply: sectionRewardStyle.apply_shipping_discount_button_text?.applied } }, gift_modal: { title: giftModalStyle.title, free_text_content: giftModalStyle.free_text_content, confirm_btn: giftModalStyle.confirm_button_content, cancel_btn: giftModalStyle.cancel_button_content, warning_msg: giftModalStyle.warning_message } }; } this.translation = customTranslation ? this.deepMergeObject(this.DEFAULT_TRANSLATION, customTranslation) : this.DEFAULT_TRANSLATION; this.gifts = []; this.position = []; this.cartId = ""; this.isAppliedGiftDc = false; this.itemIdsInCart = []; this.giftIdMapPrice = /* @__PURE__ */ new Map(); this.appliedMilestoneIndex = -1; this.currentGiftMilestoneIndexApplied = -1; this.isClickButtonConfirm = false; this.giftCommingAddIds = []; this.passedMilestone = { gift: -1, indexOfPassedFreeGift: -1, freeShipping: -1, discount: -1, lastest: -1 }; this.giftsIdMapQuantityInCart = /* @__PURE__ */ new Map(); this.appliedDiscounts = []; let url = "/"; if (window.Shopify && window.Shopify.routes) { url = window.Shopify.routes.root; } this.ROOT_SELECTOR_ELEMENT = `form[action='${url}cart']`; this.ROOT_SELECTOR_POSITION = "afterbegin"; this.discountCode = { product_discount: JSON.parse(this.cartGoal.product_discount).code, order_discount: JSON.parse(this.cartGoal.order_discount).code, shipping_discount: JSON.parse(this.cartGoal.shipping_discount).code }; if (displaySettings && displaySettings.progress_bar && displaySettings.progress_bar.custom_css && displaySettings.progress_bar.custom_css.trim() !== "") { this.applyCustomCss(displaySettings.progress_bar.custom_css); } this.applyCustomStyle(); this.getCartGoalsMarginValues(); this.initializeLocalStorage(); this.#getStoreAccess(); this.getDataFromAjax().then(() => { this.getPassedMilestone(); this.renderAllCartGoals(); if (this.cartGoal.auto_remove_gift && this.giftsIdMapQuantityInCart.size && !this.isAppliedGiftDc) { let cartTotalIncludeGift = this.cartTotal; this.getPassedMilestone(cartTotalIncludeGift); } }); tlCartGoalEmbedOverride(); } } PROXY_URL = "apps/salepify"; API_VERSION = "2024-04"; PROPERTY = "_salepify-cart-upsell"; #storeAccessToken; CART_GOAL_REWARD_STACK = { ALL_MILESTONES: "all", ONLY_LASTEST_MILESTONE: "lastest" }; CART_GOAL_REWARD_TYPE = { FREE_GIFT: "gift", CART_DISCOUNT: "discount", FREE_SHIPPING: "free_ship" }; DEFAULT_STYLE_PROGRESS_BAR = { title_label: "#303030", milestone_label: "#303030", filled_bar: "#9e58bb", filter_bar_color: "invert(44%) sepia(24%) saturate(1498%) hue-rotate(238deg) brightness(90%) contrast(81%)" }; DEFAULT_STYLE_CONTAINER = { background_color: "#ffffff", border_color: "#303030", border_radius: 0, border_width: 0, opacity: 1 }; DEFAULT_STYLE_GIFT_MODAL = { background_color: "#ffffff", border_color: "#9e58bb", button_color: "#9e58bb", check_box_color: "#9e58bb", free_text_color: "#9e58bb", border_width: 0, border_radius: 5 }; DEFAULT_STYLE_SECTION_REWARD = { button_color: "#9e58bb", button_selected_color: "#d9cdcd", hide_claim_reward: false }; TRIGGER_CONDITION = { ALL: "all", COLLECTION: "collection", PRODUCT: "product" }; DEFAULT_TRANSLATION = { milestone: { achieve_all: "Congratulation! you have achieved all milestones", gift: { title: "Free gift", before_achieve: "You are {{amount}} away from getting {{title}}", after_achieve: "Congratulations! You have unlocked a reward!" }, order_discount: { title: "Cart discount", before_achieve: "You are {{amount}} away from getting {{title}}", after_achieve: "Congratulations! You have unlocked a reward!" }, shipping_discount: { title: "Shipping discount", before_achieve: "You are {{amount}} away from getting {{title}}", after_achieve: "Congratulations! You have unlocked a reward!" } }, auto_apply_btn: { gift: "Reward Claimed", order_discount: "Reward Claimed", shipping_discount: "Reward Claimed" }, manual_apply_btn: { gift: { before_apply: "Select gifts", after_apply: "Selected gifts" }, order_discount: { before_apply: "Apply Code", after_apply: "Applied Code" }, shipping_discount: { before_apply: "Apply Code", after_apply: "Applied Code" } }, gift_modal: { title: "You can choose any {{amount}} rewards", free_text_content: "Free", confirm_btn: "Confirm", cancel_btn: "Cancel", warning_msg: "Select up to {{amount}} items only" } }; applyCustomCss = (custom_css) => { var styleElement = document.getElementById("tl_custom_css_progress_bar"); if (!styleElement) { styleElement = document.createElement("style"); styleElement.id = "tl_custom_css_progress_bar"; document.head.appendChild(styleElement); } styleElement.innerHTML = custom_css; }; initializeLocalStorage = () => { const initialTime = (/* @__PURE__ */ new Date()).getTime() + 24 * 3600 * 1e3; let initialData = { gift: -1, discount: -1, freeShipping: -1, appliedDiscounts: [], selectedGifts: [[]], expired: initialTime }; let tlCartGoalLocalStorage = localStorage.getItem(LOCAL_STORAGE); if (!tlCartGoalLocalStorage || this.cartTotal <= 0) { localStorage.setItem(LOCAL_STORAGE, JSON.stringify(initialData)); } else { let tlCartGoalLocalStorageData = JSON.parse(tlCartGoalLocalStorage); let expiredTime = tlCartGoalLocalStorageData.expired || 0; if ((/* @__PURE__ */ new Date()).getTime() > expiredTime) { localStorage.setItem(LOCAL_STORAGE, JSON.stringify(initialData)); } else { let passedDiscount = tlCartGoalLocalStorageData.discount; if (passedDiscount !== -1) { let totalPrice = this.cartTotal; let discountData = this.milestones?.[passedDiscount]; if (discountData?.discount_type) { if (discountData.discount_type === "percentage") { totalPrice = totalPrice / (100 - discountData.reward_value) * 100; } else { totalPrice = totalPrice + discountData.reward_value; } } this.cartTotal = totalPrice; } this.position = tlCartGoalLocalStorageData.selectedGifts; this.appliedDiscounts = tlCartGoalLocalStorageData.appliedDiscounts; this.currentGiftMilestoneIndexApplied = tlCartGoalLocalStorageData.gift; tlCartGoalLocalStorageData.expired = initialTime; localStorage.setItem(LOCAL_STORAGE, JSON.stringify(tlCartGoalLocalStorageData)); } } }; getCartGoalsMarginValues = () => { let n = this.milestones.length; let marginValues = Array(n).fill(0); marginValues[0] = 10; marginValues[n - 1] = 99; let dx = 90 / (n - 1); for (let i = 1; i < n - 1; i++) { marginValues[i] = Math.ceil(10 + dx * i); } return marginValues; }; #getStoreAccess = async () => { const getShopAccessReq = await fetch(window.Shopify.routes.root + `${this.PROXY_URL}/shop`); const getShopAccessRes = await getShopAccessReq.json(); this.#storeAccessToken = getShopAccessRes.data; }; getVariantData = async (nonGlobalId) => { const idBase64 = btoa(`gid://shopify/ProductVariant/${nonGlobalId}`); try { const getVariantReq = await fetch(`https://${Shopify.shop}/api/${this.API_VERSION}/graphql.json`, { method: "POST", headers: { "Content-Type": "application/json", "X-Shopify-Storefront-Access-Token": this.#storeAccessToken }, body: JSON.stringify({ query: ` query { node(id: "${idBase64}") { ... on ProductVariant { product { id collections(first: 250){ nodes { id } } } } } }` }) }); const getVariantRes = await getVariantReq.json(); if (getVariantRes.data) { const listCollectionId = []; getVariantRes.data.node.product.collections.nodes.map((collection) => { listCollectionId.push(collection.id.split("/").pop()); }); const productId = getVariantRes.data.node.product.id.split("/").pop(); this.productIdMapCollection.set(productId, listCollectionId); return getVariantRes.data.node; } else { return null; } } catch (error) { console.log("Error when getVariantData - Cart Goal: ", error); } }; updateCartTotal = () => { if (Object.keys(this.cartGoal).length) { fetch("/cart.js").then((res) => res.json()).then(async (data) => { let ratio = 1; this.cartId = data.token; for (let i = 0; i < data.items.length; i++) { const item = data.items[i]; if (!isNaN(item.price / item.presentment_price)) { ratio = item.price / item.presentment_price; break; } } let cartTotal = parseFloat(data.original_total_price) / ratio; this.itemIdsInCart = []; let totalAmount = 0; if (this.cartGoal.trigger_condition == this.TRIGGER_CONDITION.PRODUCT) { let productsData = JSON.parse(this.cartGoal.trigger_condition_ids); let productIds = productsData.map((a) => a.shopify_id); let deductedItemIds = []; data.items.forEach((item) => { const itemId = String(item.id); if (productIds.includes(item.product_id.toString())) { totalAmount += item.original_line_price / ratio; if (this.giftsIdMapQuantityInCart.get(itemId) && !deductedItemIds.includes(itemId)) { totalAmount -= item.price * Number(this.giftsIdMapQuantityInCart.get(itemId)) / ratio; deductedItemIds.push(itemId); } } this.itemIdsInCart.push(itemId); }); cartTotal = totalAmount; } else if (this.cartGoal.trigger_condition == this.TRIGGER_CONDITION.COLLECTION) { let collectionsData = JSON.parse(this.cartGoal.trigger_condition_ids); let collectionIds = collectionsData.map((a) => a.shopify_id); let deductedItemIds = []; for (let i = 0; i < data.items.length; i++) { const item = data.items[i]; const itemId = String(item.id); let collections = this.productIdMapCollection.get(item.product_id.toString()); if (!collections) { await this.getVariantData(String(item.id)); collections = this.productIdMapCollection.get(item.product_id.toString()); } if (collections) { const setCollectionIds = new Set(collectionIds); if (collections.some((item2) => setCollectionIds.has(item2))) { totalAmount += item.original_line_price / ratio; if (this.giftsIdMapQuantityInCart.get(itemId) && !deductedItemIds.includes(itemId)) { totalAmount -= item.price * Number(this.giftsIdMapQuantityInCart.get(itemId)) / ratio; deductedItemIds.push(itemId); } } } this.itemIdsInCart.push(itemId); } cartTotal = totalAmount; } else { let deductedItemIds = []; data.items.map((item) => { const itemId = String(item.id); if (this.giftsIdMapQuantityInCart.get(itemId) && !deductedItemIds.includes(itemId)) { cartTotal -= item.price * Number(this.giftsIdMapQuantityInCart.get(itemId)) / ratio; deductedItemIds.push(itemId); } this.itemIdsInCart.push(itemId); }); } let giftVariants = this.gifts[this.passedMilestone.indexOfPassedFreeGift]; if (giftVariants) { this.position[this.passedMilestone.gift] = []; for (let i = 0; i < giftVariants.length; i++) { this.itemIdsInCart.forEach((item) => { if (giftVariants[i].id == item) { this.position[this.passedMilestone.gift].push(i); } }); } } this.cartTotal = cartTotal; this.getPassedMilestone(); this.trackingCartDrawerWhenAddtoCart(); }); this.renderAllCartGoals(); } }; trackingCartDrawerWhenAddtoCart = () => { this.updateAllCartGoals(); let targetNode; const MAX_PARENTS_LEVEL = 2; let currentLevel = 1; if (this.cartDrawDisplay.selector) { targetNode = document.querySelector(this.cartDrawDisplay.selector); } else { targetNode = document.querySelector(this.ROOT_SELECTOR_ELEMENT); } while (targetNode && currentLevel <= MAX_PARENTS_LEVEL) { targetNode = targetNode.parentElement; currentLevel++; } const config = { attributes: true, childList: true, subtree: true }; let timeID; const callback = (mutationList, observer) => { clearTimeout("timeID", timeID); if (mutationList.length) { if (mutationList[0].target.className.includes("tl__cart-goal__gift-modal") || mutationList[0].target.className.includes("tl__cart-goal__check-box")) { observer.disconnect(); } else { timeID = setTimeout(() => { this.updateAllCartGoals(); observer.disconnect(); }, 500); } } }; if (targetNode) { const observer = new MutationObserver(callback); observer.observe(targetNode, config); } }; hexToRgba(hex, alpha) { hex = hex.replace(/^#/, ""); const r = parseInt(hex.substring(0, 2), 16); const g = parseInt(hex.substring(2, 4), 16); const b = parseInt(hex.substring(4, 6), 16); return `rgba(${r}, ${g}, ${b}, ${alpha.toFixed(2)})`; } applyCustomStyle() { if (Object.keys(this.customColor).length) { document.documentElement.style.setProperty("--tl__cart-goal__filled-bar-color", this.customColor.filled_bar); document.documentElement.style.setProperty("--tl__cart-goal__filter-bar-color", this.customColor.filter_bar_color); document.documentElement.style.setProperty("--tl__cart-goal__milestone-label-color", this.customColor.milestone_label); document.documentElement.style.setProperty("--tl__cart-goal__title_label-color", this.customColor.title_label); } if (Object.keys(this.containerStyle).length) { document.documentElement.style.setProperty("--tl__cart-goal__container__background", this.hexToRgba(this.containerStyle.background_color, this.containerStyle?.opacity ? this.containerStyle.opacity : 1)); document.documentElement.style.setProperty("--tl__cart-goal__container__border-color", this.containerStyle.border_color); document.documentElement.style.setProperty("--tl__cart-goal__container__border-width", `${this.containerStyle.border_width}px`); document.documentElement.style.setProperty("--tl__cart-goal__container__border-radius", `${this.containerStyle.border_radius}px`); } if (Object.keys(this.sectionRewardStyle).length) { document.documentElement.style.setProperty("--tl__cart-goal__section-reward__button-color", this.sectionRewardStyle.button_color); document.documentElement.style.setProperty("--tl__cart-goal__section-reward__button-selected-color", this.sectionRewardStyle.button_selected_color); } if (Object.keys(this.giftModalStyle).length) { document.documentElement.style.setProperty("--tl__cart-goal__gift-modal__free-text", this.giftModalStyle.free_text_color); document.documentElement.style.setProperty("--tl__cart-goal__gift-modal__check-box", this.giftModalStyle.check_box_color); document.documentElement.style.setProperty("--tl__cart-goal__gift-modal__background", this.giftModalStyle.background_color); document.documentElement.style.setProperty("--tl__cart-goal__gift-modal__button-color", this.giftModalStyle.button_color); document.documentElement.style.setProperty("--tl__cart-goal__gift-modal__border-color", this.giftModalStyle.border_color); document.documentElement.style.setProperty("--tl__cart-goal__gift-modal__border-width", `${this.giftModalStyle.border_width}px`); document.documentElement.style.setProperty("--tl__cart-goal__gift-modal__border-radius", `${this.giftModalStyle.border_radius}px`); } } getProcessBarWidth = () => { let marginValues = this.getCartGoalsMarginValues(); let nextMilestone; let currentMilestone; for (let i = 0; i < this.milestones.length; i++) { nextMilestone = i; if (this.cartTotal <= this.milestones[i].cart_value) { break; } } currentMilestone = nextMilestone - 1; if (this.cartTotal >= this.milestones[this.milestones.length - 1].cart_value) { return marginValues[this.milestones.length - 1]; } if (currentMilestone > -1) { let distanceBetweenTwoMilestones = this.milestones[nextMilestone].cart_value - this.milestones[currentMilestone].cart_value; return marginValues[currentMilestone] + (this.cartTotal - this.milestones[currentMilestone].cart_value) / distanceBetweenTwoMilestones * (marginValues[nextMilestone] - marginValues[currentMilestone]); } else { return this.cartTotal / this.milestones[nextMilestone].cart_value * marginValues[nextMilestone]; } }; getRewardTitleByType = (milestone) => { let imgSrc, title, beforeAchieve, afterAchieve; switch (milestone.reward_type) { case "gift": imgSrc = this.giftSVG; title = this.translation.milestone.gift.title; beforeAchieve = this.replaceVariables(this.translation.milestone.gift.before_achieve, milestone, title); afterAchieve = this.replaceVariables(this.translation.milestone.gift.after_achieve, milestone, title); break; case "discount": imgSrc = this.discountSVG; title = this.translation.milestone.order_discount.title; beforeAchieve = this.replaceVariables(this.translation.milestone.order_discount.before_achieve, milestone, title); afterAchieve = this.replaceVariables(this.translation.milestone.order_discount.after_achieve, milestone, title); break; case "free_ship": imgSrc = this.freeShippingSVG; title = this.translation.milestone.shipping_discount.title; beforeAchieve = this.replaceVariables(this.translation.milestone.shipping_discount.before_achieve, milestone, title); afterAchieve = this.replaceVariables(this.translation.milestone.shipping_discount.after_achieve, milestone, title); break; } return [title, beforeAchieve, afterAchieve, imgSrc]; }; replaceVariables(string, milestone, title) { const cartValue = milestone.cart_value; return string.replace( /{{discount}}/g, `${cartValue} ${milestone.discount_type === "percentage" ? `${cartValue}%` : this.formatMoney(cartValue * 100, this.currencyFormat, this.currencyDisplay)}` ).replace(/{{amount}}/g, this.formatMoney((cartValue - this.cartTotal) * 100, this.currencyFormat, this.currencyDisplay)).replace(/{{title}}/g, title); } getLeftAmountText = () => { let milestone = null; for (let i = 0; i < this.milestones.length; i++) { if (this.cartTotal < this.milestones[i].cart_value) { milestone = this.milestones[i]; break; } } if (milestone && this.cartTotal < milestone.cart_value) { const [title, beforeAchieve, afterAchieve, imgSrc] = this.getRewardTitleByType(milestone); return beforeAchieve; } else { return this.translation.milestone.achieve_all; } }; applyDiscountCode = async (discountCode) => { try { let applyDiscounts = this.appliedDiscounts; if (this.cartGoal.reward_stack === this.CART_GOAL_REWARD_STACK.ALL_MILESTONES) { applyDiscounts.push(discountCode); applyDiscounts = Array.from(new Set(applyDiscounts)); await fetch( window.Shopify.routes.root + `${this.PROXY_URL}/cart-goal/apply-discount?cartId=${this.cartId}&discountCodes=${applyDiscounts.join(",")}` ); } else { applyDiscounts = [discountCode]; await fetch(`/discount/${discountCode}`); } this.appliedDiscounts = applyDiscounts; } catch (e) { console.log("Error when apply discount code", e); } }; renderAllCartGoals = () => { let customRootElementCartPage = this.cartDisplay; let customRootElementCartDraw = this.cartDrawDisplay; let tlCartGoalLocalStorage = JSON.parse(localStorage.getItem(LOCAL_STORAGE)); if (document.querySelectorAll(".tl__cart-goal__container__drawer")) { document.querySelectorAll(".tl__cart-goal__container__drawer").forEach((ele) => ele.remove()); } if (customRootElementCartPage.selector || customRootElementCartDraw.selector) { if (customRootElementCartPage.selector) { if (customRootElementCartPage.position === "prepend") { document.querySelectorAll(customRootElementCartPage.selector).forEach((ele, index) => { let htmlObject = document.createElement("div"); htmlObject.classList.add("tl-custom-cart-goal-container"); htmlObject.innerHTML = this.renderCartGoal(index); ele.prepend(htmlObject); }); } else { let position = customRootElementCartPage.position === "before" ? "beforebegin" : "afterend"; document.querySelectorAll(customRootElementCartPage.selector).forEach((ele, index) => ele.insertAdjacentHTML(position, this.renderCartGoal(index))); } } if (customRootElementCartDraw.selector) { let position; if (customRootElementCartDraw.position === "prepend") { position = "prepend"; document.querySelectorAll(customRootElementCartDraw.selector).forEach((ele, index) => { let htmlObject = document.createElement("div"); htmlObject.classList.add("tl-custom-cart-goal-container"); htmlObject.innerHTML = this.renderCartGoal(index); ele.prepend(htmlObject); }); } else { position = customRootElementCartDraw.position === "before" ? "beforebegin" : "afterend"; document.querySelectorAll(customRootElementCartDraw.selector).forEach((ele, index) => ele.insertAdjacentHTML(position, this.renderCartGoal(index))); } } } else { if (this.cartTotal === 0) { this.ROOT_SELECTOR_POSITION = "beforebegin"; } document.querySelectorAll(this.ROOT_SELECTOR_ELEMENT).forEach((ele, index) => { ele.insertAdjacentHTML(this.ROOT_SELECTOR_POSITION, this.renderCartGoal(index)); }); } if (this.passedMilestone.gift !== -1) { tlCartGoalLocalStorage.selectedGifts[this.passedMilestone.gift]?.map((idx) => { this.renderSelectedGift(this.passedMilestone.gift); }); } }; renderCartGoal = (cartGoalIndex) => { if (document.querySelectorAll(this.ROOT_SELECTOR_ELEMENT).length || this.cartDrawDisplay.selector || this.cartDisplay.selector) { let milestonesHTMLInCartDrawer = ``; let closestGoal = -1; let marginValues = this.getCartGoalsMarginValues(); this.milestones.map((milestone, index) => { if (closestGoal === -1 && milestone.cart_value > this.cartTotal) { closestGoal = index; } const [milestoneTitle, beforeAchieve, afterAchieve, imgSrc] = this.getRewardTitleByType(milestone); milestonesHTMLInCartDrawer += `

${this.formatMoney(milestone.cart_value * 100, this.currencyFormat, this.currencyDisplay)}

tl-cart-goal

${milestoneTitle}

`; }); let trademarkHTMLInCartDrawer = this.showTrademark ? `

Powered by Salepify App

` : ""; let cartGoalHTMLInCartDrawer = `

${this.getLeftAmountText(this.milestones[closestGoal])}

${milestonesHTMLInCartDrawer}

${this.renderReward(cartGoalIndex)}
${trademarkHTMLInCartDrawer}
`; return cartGoalHTMLInCartDrawer; } }; updateAllCartGoals = () => { let cartGoalsContainerElements = document.querySelectorAll(".tl__cart-goal__container__drawer"); if (cartGoalsContainerElements.length) { cartGoalsContainerElements.forEach((ele, index) => { let rewardsContainer = document.querySelector(`.tl__cart-goal__free-gift-container-${index}`); if (rewardsContainer) { rewardsContainer.innerHTML = this.updateCartGoal(index); } }); } else { this.renderAllCartGoals(); } }; updateCartGoal = (cartGoalIndex) => { let processBars = document.querySelectorAll(".tl__cart-goal__goal-process__drawer"); processBars.forEach((ele) => { ele.style.width = `${this.getProcessBarWidth()}%`; }); let titles = document.querySelectorAll(".tl__cart-goal__reward-description__drawer"); if (titles.length) { titles.forEach((ele) => ele.innerHTML = `${this.getLeftAmountText()}`); } let cartGoalElements = document.querySelectorAll(".tl__cart-goal__goal-check-point__drawer"); let cartGoalImgElements = document.querySelectorAll(".tl__cart-goal__goal-check-point__drawer img"); let cartGoalsValueElement = document.querySelectorAll(".tl__cart-goal__goal-check-point-value"); let cartGoalsTitleElement = document.querySelectorAll(".tl__cart-goal__goal-check-point-title"); let closestPoint = -1; for (let i = 0; i < this.milestones.length; i++) { if (closestPoint === -1 && this.milestones[i].cart_value > this.cartTotal) { closestPoint = i; } if (this.cartTotal >= this.milestones[i].cart_value) { if (cartGoalElements[i]) { cartGoalElements[i].style.borderColor = "var(--tl__cart-goal__filled-bar-color)"; } if (cartGoalElements[i + this.milestones.length]) { cartGoalElements[i + this.milestones.length].style.borderColor = "var(--tl__cart-goal__filled-bar-color)"; } if (cartGoalImgElements[i]) { cartGoalImgElements[i].style.filter = "var(--tl__cart-goal__filter-bar-color)"; } if (cartGoalImgElements[i + this.milestones.length]) { cartGoalImgElements[i + this.milestones.length].style.filter = "var(--tl__cart-goal__filter-bar-color)"; } } else { if (cartGoalElements[i]) { cartGoalElements[i].style.borderColor = "black"; } if (cartGoalElements[i + this.milestones.length]) { cartGoalElements[i + this.milestones.length].style.borderColor = "black"; } if (cartGoalImgElements[i]) { cartGoalImgElements[i].style.filter = "invert(0%) sepia(0%) saturate(3%) hue-rotate(177deg) brightness(100%) contrast(100%)"; } if (cartGoalImgElements[i + this.milestones.length]) { cartGoalImgElements[i + this.milestones.length].style.filter = "invert(0%) sepia(0%) saturate(3%) hue-rotate(177deg) brightness(100%) contrast(100%)"; } } if (cartGoalsValueElement[i]) { cartGoalsValueElement[i].style.visibility = ""; } if (cartGoalsValueElement[i + this.milestones.length]) { cartGoalsValueElement[i + this.milestones.length].style.visibility = ""; } if (cartGoalsTitleElement[i]) { cartGoalsTitleElement[i].style.visibility = ""; } if (cartGoalsTitleElement[i + this.milestones.length]) { cartGoalsTitleElement[i + this.milestones.length].style.visibility = ""; } if (closestPoint === i) { if (cartGoalsValueElement[i]) { cartGoalsValueElement[i].style.visibility = "visible"; } if (cartGoalsValueElement[i + this.milestones.length]) { cartGoalsValueElement[i + this.milestones.length].style.visibility = "visible"; } if (cartGoalsTitleElement[i]) { cartGoalsTitleElement[i].style.visibility = "visible"; } if (cartGoalsTitleElement[i + this.milestones.length]) { cartGoalsTitleElement[i + this.milestones.length].style.visibility = "visible"; } } } return this.renderReward(cartGoalIndex); }; showError(message) { const blockErrors = document.querySelectorAll("#salepify-cart-goal-block-error"); blockErrors.forEach((element) => { element.style = "display: flex; align-items: center;"; element.innerHTML = ` ${message} `; }); setTimeout(() => { blockErrors.forEach((element) => { element.style = "display: none;"; }); }, "3000"); } renderShippingReward = () => { const tlCartGoalLocalStorage = JSON.parse(localStorage.getItem(LOCAL_STORAGE)); const aplliedFreeShipping = tlCartGoalLocalStorage.freeShipping !== -1; const milestone = this.milestones[this.passedMilestone.freeShipping]; const [title, beforeAchieve, afterAchieve] = this.getRewardTitleByType(milestone); return `

${title}

${afterAchieve}

${this.cartGoal.auto_add_reward ? aplliedFreeShipping ? `
${this.translation.auto_apply_btn.shipping_discount}
` : `` : `
${!aplliedFreeShipping ? `${this.translation.manual_apply_btn.shipping_discount.before_apply}` : `${this.translation.manual_apply_btn.shipping_discount.after_apply}`}
`}
`; }; renderCartDcReward = () => { const tlCartGoalLocalStorage = JSON.parse(localStorage.getItem(LOCAL_STORAGE)); const aplliedCartDiscount = tlCartGoalLocalStorage.discount !== -1; const milestone = this.milestones[this.passedMilestone.discount]; const [title, beforeAchieve, afterAchieve] = this.getRewardTitleByType(milestone); return `

${title}

${afterAchieve}

${this.cartGoal.auto_add_reward ? aplliedCartDiscount ? `
${this.translation.auto_apply_btn.order_discount}
` : `` : `
${!aplliedCartDiscount ? `${this.translation.manual_apply_btn.order_discount.before_apply}` : `${this.translation.manual_apply_btn.order_discount.after_apply}`}
`}

`; }; renderFreeGiftReward = (cartGoalIndex) => { const tlCartGoalLocalStorage = JSON.parse(localStorage.getItem(LOCAL_STORAGE)); const passedFreeGift = this.passedMilestone.gift; const aplliedFreeGift = tlCartGoalLocalStorage.gift >= passedFreeGift; let giftItemHTML = ""; let giftVariants = this.gifts[this.passedMilestone.indexOfPassedFreeGift]; giftVariants.map((variant, variantIndex) => { giftItemHTML += `
product-image

${variant.name}

${this.formatMoney(variant.price, this.cartGoal.currency_format, this.cartGoal.currency_display)} ${this.translation.gift_modal.free_text_content} ${this.milestones[passedFreeGift].specific_quantity ? "x" + variant.specificQuantity + `${variant.specificQuantity > 1 ? " items" : " item"}` : "x1 item"}
`; }); const milestone = this.milestones[passedFreeGift]; const [title, beforeAchieve, afterAchieve] = this.getRewardTitleByType(milestone); return `

${title}

${afterAchieve}

${this.cartGoal.auto_add_reward && giftVariants.length ? aplliedFreeGift ? `
${this.translation.auto_apply_btn.gift}
` : `` : `
${aplliedFreeGift ? `${this.translation.manual_apply_btn.gift.after_apply}` : `${this.translation.manual_apply_btn.gift.before_apply}`}
`}
${giftVariants.length !== 0 ? `
${this.translation.gift_modal.title.replace( "{{amount}}", `${this.milestones[passedFreeGift].reward_value}` )}
${giftItemHTML}
${this.translation.gift_modal.cancel_btn}
${this.translation.gift_modal.confirm_btn}
` : `
Sorry, but there's no gift available
${this.translation.gift_modal.cancel_btn}
`}

`; }; renderReward = (cartGoalIndex) => { let innerHTML = ""; if (!this.sectionRewardStyle.hide_claim_reward) { const { ALL_MILESTONES } = this.CART_GOAL_REWARD_STACK; const { FREE_SHIPPING, FREE_GIFT } = this.CART_GOAL_REWARD_TYPE; if (this.cartGoal.reward_stack == ALL_MILESTONES) { const shippingRewardHTML = this.passedMilestone.freeShipping !== -1 ? this.renderShippingReward() : ""; const cartDcRewardHTML = this.passedMilestone.discount !== -1 ? this.renderCartDcReward() : ""; const freeGiftRewardHTML = this.passedMilestone.gift !== -1 ? this.renderFreeGiftReward(cartGoalIndex) : ""; innerHTML = ` ${freeGiftRewardHTML} ${cartDcRewardHTML} ${shippingRewardHTML} `; } else if (this.passedMilestone.lastest !== -1) { const lastestMileStoneIdx = this.passedMilestone.lastest; const lastestMileStone = this.milestones[lastestMileStoneIdx]; innerHTML = lastestMileStone.reward_type == FREE_SHIPPING ? this.renderShippingReward() : lastestMileStone.reward_type == FREE_GIFT ? this.renderFreeGiftReward(cartGoalIndex) : this.renderCartDcReward(); } } return innerHTML; }; getDataFromAjax = async () => { let cartJsResponse = await fetch("/cart.js"); let cartData = await cartJsResponse.json(); let ratio = 1; cartData.items.map((item) => { if (item.price > 0) { ratio = item.price / item.presentment_price; } }); let total = parseFloat(cartData.original_total_price) / ratio; this.cartId = cartData.token; cartData.items.forEach((item) => { let itemId = String(item.id); let itemQuantity = String(item.quantity); if (item.original_price == 0 && item.properties[this.PROPERTY]) { this.isAppliedGiftDc = true; this.giftsIdMapQuantityInCart.set(itemId, itemQuantity); } else { item.discounts.forEach((discount) => { if (discount.title === this.discountCode.product_discount) { total -= parseFloat(discount.amount) / ratio; this.isAppliedGiftDc = true; this.giftsIdMapQuantityInCart.set(itemId, itemQuantity); } }); } this.itemIdsInCart.push(itemId); }); let totalAmount = 0; if (this.cartGoal.trigger_condition == this.TRIGGER_CONDITION.PRODUCT) { let productsData = JSON.parse(this.cartGoal.trigger_condition_ids); let productIds = productsData.map((a) => a.shopify_id); let deductedItemIds = []; cartData.items.forEach((item) => { if (productIds.includes(item.product_id.toString())) { totalAmount += item.original_line_price / ratio; const itemId = String(item.id); if (this.giftsIdMapQuantityInCart.get(itemId) && !deductedItemIds.includes(itemId)) { totalAmount -= item.price * Number(this.giftsIdMapQuantityInCart.get(itemId)) / ratio; deductedItemIds.push(itemId); } } }); total = totalAmount; } else if (this.cartGoal.trigger_condition == this.TRIGGER_CONDITION.COLLECTION) { let collectionsData = JSON.parse(this.cartGoal.trigger_condition_ids); let collectionIds = collectionsData.map((a) => a.shopify_id); let deductedItemIds = []; cartData.items.forEach((item) => { let collections = this.productIdMapCollection.get(item.product_id.toString()); const setCollectionIds = new Set(collectionIds); if (collections.some((item2) => setCollectionIds.has(item2))) { totalAmount += item.original_line_price / ratio; const itemId = String(item.id); if (this.giftsIdMapQuantityInCart.get(itemId) && !deductedItemIds.includes(itemId)) { totalAmount -= item.price * Number(this.giftsIdMapQuantityInCart.get(itemId)) / ratio; deductedItemIds.push(itemId); } } }); total = totalAmount; } this.cartTotal = total; let milestonesHaveGifts = this.milestones.filter((milestone) => { return JSON.parse(milestone.gifts).length; }); let giftsData = milestonesHaveGifts.map((milestone) => JSON.parse(milestone.gifts)); const data = milestonesHaveGifts.map((milestone) => JSON.parse(milestone.gifts)); let listHandle = []; giftsData.map((arr) => listHandle = [...listHandle, ...arr]); let formattedGiftsData = []; listHandle = Array.from(new Set(listHandle.map((item) => item.handle))); try { let allGiftVariantsData = await Promise.all(listHandle.map(async (item) => { let res = await fetch(window.Shopify.routes.root + `products/${item}.js`); return await res.json(); })); giftsData.map((gifts, index) => { formattedGiftsData.push([]); gifts.map((gift, idx) => { allGiftVariantsData.map((product) => { if (gift.handle === product.handle && product.available) { product.variants.map((variant) => { if (gift.id.includes(variant.id)) { this.giftIdMapPrice.set(String(variant.id), variant.price); variant.specificQuantity = data[index][idx].specificQuantity; if (!variant.featured_image) { if (product.featured_image) { variant.featured_image = product.featured_image.src ? product.featured_image.src : product.featured_image; } else { variant.featured_image = this.defaultImage; } } formattedGiftsData[index].push(JSON.parse(JSON.stringify(variant))); } }); } }); }); }); this.gifts = [...formattedGiftsData]; } catch (e) { console.log("Error when format gifts data:", e); } }; getPassedMilestone = async (cartTotal = this.cartTotal) => { const passedMilestone = { gift: -1, indexOfPassedFreeGift: -1, freeShipping: -1, discount: -1, lastest: -1 }; this.milestones.map((milestone, index) => { if (milestone.cart_value <= cartTotal) { passedMilestone.lastest = index; switch (milestone.reward_type) { case this.CART_GOAL_REWARD_TYPE.FREE_GIFT: passedMilestone.gift = index; passedMilestone.indexOfPassedFreeGift++; break; case this.CART_GOAL_REWARD_TYPE.CART_DISCOUNT: passedMilestone.discount = index; break; case this.CART_GOAL_REWARD_TYPE.FREE_SHIPPING: passedMilestone.freeShipping = index; break; } } }); let tlCartGoalLocalStorage = JSON.parse(localStorage.getItem(LOCAL_STORAGE)); this.passedMilestone = passedMilestone; if (passedMilestone.discount === -1) { tlCartGoalLocalStorage.discount = -1; tlCartGoalLocalStorage.appliedDiscounts = tlCartGoalLocalStorage.appliedDiscounts.splice( tlCartGoalLocalStorage.appliedDiscounts.indexOf(this.discountCode.order_discount), 1 ); } if (passedMilestone.freeShipping === -1) { tlCartGoalLocalStorage.freeShipping = -1; tlCartGoalLocalStorage.appliedDiscounts = tlCartGoalLocalStorage.appliedDiscounts.splice( tlCartGoalLocalStorage.appliedDiscounts.indexOf(this.discountCode.shipping_discount), 1 ); } localStorage.setItem(LOCAL_STORAGE, JSON.stringify(tlCartGoalLocalStorage)); if (tlCartGoalLocalStorage.gift === -1 && this.giftsIdMapQuantityInCart.size || tlCartGoalLocalStorage.gift > passedMilestone.gift) { if (this.cartGoal.auto_remove_gift) { const res = await this.handleRemoveGift(); if (res.status == 200) { if (!window.TLCustomEventCartGoal) { window.location.reload(); } else if (window.TLCustomEventCartGoal == 1) { window.dispatchEvent(new CustomEvent("TLCustomEvent:CartGoal-getPassedMilestone")); } } } } else if (tlCartGoalLocalStorage.gift < passedMilestone.gift) { this.setLocalStorage("gift", -1); } if (this.cartGoal.reward_stack === this.CART_GOAL_REWARD_STACK.ONLY_LASTEST_MILESTONE && this.cartGoal.auto_add_reward) { if (passedMilestone.discount > -1 || passedMilestone.freeShipping > -1 || passedMilestone.gift > -1) { if (passedMilestone.discount > passedMilestone.freeShipping && passedMilestone.discount > passedMilestone.gift && tlCartGoalLocalStorage.discount != passedMilestone.discount) { this.handleApplyDiscountCode(); } else if (passedMilestone.freeShipping > passedMilestone.discount && passedMilestone.freeShipping > passedMilestone.gift && tlCartGoalLocalStorage.freeShipping != passedMilestone.freeShipping) { this.handleApplyFreeShippingCode(); } else if (passedMilestone.gift > passedMilestone.discount && passedMilestone.gift > passedMilestone.freeShipping && tlCartGoalLocalStorage.gift != passedMilestone.gift) { this.handleAutoAddGift(passedMilestone.gift); } } } else if (this.cartGoal.reward_stack === this.CART_GOAL_REWARD_STACK.ALL_MILESTONES && this.cartGoal.auto_add_reward) { if (passedMilestone.discount > -1 && tlCartGoalLocalStorage.discount != passedMilestone.discount) { await this.handleApplyDiscountCode(); } if (passedMilestone.freeShipping > -1 && tlCartGoalLocalStorage.freeShipping != passedMilestone.freeShipping) { await this.handleApplyFreeShippingCode(); } if (passedMilestone.gift > -1 && tlCartGoalLocalStorage.gift != passedMilestone.gift) { await this.handleAutoAddGift(passedMilestone.gift); } } }; toggleGifts = (cartGoalIndex, isOpen = true) => { let selector = `.tl__cart-goal__gift-modal-${cartGoalIndex}`; let modal = document.querySelector(selector); if (modal) { if (isOpen) { this.renderSelectedGift(this.passedMilestone.gift); modal.style.display = "block"; this.getQuantitySelected(); } else { modal.style.display = "none"; } } }; renderSelectedGift = (index) => { let checkBoxes = document.querySelectorAll(`.tl__cart-goal__check-box-${index}`); checkBoxes.forEach((ele) => ele.classList.remove("tl__cart-goal__check-box--active")); checkBoxes.forEach((ele) => { this.itemIdsInCart.forEach((item) => { if (item == ele.getAttribute("tl__cart-goal_data_id")) { ele.classList.add("tl__cart-goal__check-box--active"); } }); }); this.position[this.passedMilestone.gift] = []; for (let i = 0; i < this.gifts[this.passedMilestone.indexOfPassedFreeGift].length; i++) { this.itemIdsInCart.forEach((item) => { if (item == this.gifts[this.passedMilestone.indexOfPassedFreeGift][i].id) { this.position[this.passedMilestone.gift].push(i); } }); } }; getQuantitySelected = () => { let countQuantity = 0; let giftsData = JSON.parse(this.milestones[this.passedMilestone.gift].gifts); const selectedQuantitys = document.querySelectorAll(".tl_selected_quantity"); this.position[this.passedMilestone.gift] = Array.from(new Set(this.position[this.passedMilestone.gift])); this.position[this.passedMilestone.gift].map((item) => { countQuantity += giftsData[item].specificQuantity ? giftsData[item].specificQuantity : 1; }); selectedQuantitys.forEach((element) => { if (countQuantity > this.milestones[this.passedMilestone.gift].reward_value) { element.style = "border-radius: 40%; padding: 3px; background: #E8E7EC; font-weight: 600; color: red"; } else { element.style = "border-radius: 40%; padding: 3px; background: #E8E7EC; font-weight: 600; color: black"; } element.innerHTML = `${countQuantity}/${this.milestones[this.passedMilestone.gift].reward_value}`; }); }; handleChangeGift = (index, variantIndex) => { if (!this.position[index]) { this.position[index] = []; } let existedIndex = this.position[index].indexOf(variantIndex); if (existedIndex !== -1) { this.position[index].splice(existedIndex, 1); } else { this.position[index].push(variantIndex); } let selectedBoxs = document.querySelectorAll(`.tl__cart-goal__check-box-${index}-${variantIndex}`); selectedBoxs.forEach((ele) => { if (ele.classList.contains("tl__cart-goal__check-box--active")) { ele.classList.remove("tl__cart-goal__check-box--active"); } else { ele.classList.add("tl__cart-goal__check-box--active"); } }); this.getQuantitySelected(); }; handleAutoAddGift = async (index) => { try { const items = []; let giftsData = JSON.parse(this.milestones[index].gifts); giftsData.forEach((gift) => { const itemId = gift.id.split("/")[4]; items.push({ "id": itemId, "quantity": this.milestones[index].specific_quantity ? gift.specificQuantity : 1, "properties": !gift.price ? { [this.PROPERTY]: this.cartGoal.name } : void 0 }); }); if (this.currentGiftMilestoneIndexApplied !== -1 && this.currentGiftMilestoneIndexApplied !== index) { await this.handleRemoveGift(); } if (items.length && this.gifts[this.passedMilestone.indexOfPassedFreeGift].length) { await this.applyDiscountCode(this.discountCode.product_discount); await fetch(window.Shopify.routes.root + "cart/add.js?app=salepify", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ "items": items }) }); this.setLocalStorage("gift", index); if (!window.TLCustomEventCartGoal) { window.location.reload(); } else if (window.TLCustomEventCartGoal == 1) { window.dispatchEvent(new CustomEvent("TLCustomEvent:CartGoal-handleAutoAddGift")); } } } catch (e) { console.log("Error when auto add to cart", e); } }; handleAddtoCart = async (milestoneIndex, cartGoalIndex) => { try { const buttons = document.querySelectorAll(".tl__cart-goal__button-add-gift"); buttons.forEach((ele) => { ele.innerHTML = `
`; ele.onclick = null; }); let giftsData = JSON.parse(this.milestones[this.passedMilestone.gift].gifts); let countQuantity = 0; const items = []; const listItemsIds = []; this.position[this.passedMilestone.gift] = Array.from(new Set(this.position[this.passedMilestone.gift])); this.position[this.passedMilestone.gift].map((item) => { countQuantity += giftsData[item].specificQuantity ? giftsData[item].specificQuantity : 1; }); let listSelected = document.querySelectorAll(`.tl__cart-goal__gift-modal-${cartGoalIndex} .tl__cart-goal__check-box--active`); listSelected.forEach((ele) => { if (ele.getAttribute("tl__cart-goal_data_id")) { listItemsIds.push(ele.getAttribute("tl__cart-goal_data_id")); } }); this.position[milestoneIndex] = []; listItemsIds.forEach((itemId) => { for (let i = 0; i < giftsData.length; i++) { if (giftsData[i].id.split("/")[4] == itemId) { this.position[milestoneIndex].push(i); } } }); this.position[milestoneIndex].map((item) => { const itemId = giftsData[item].id.split("/")[4]; items.push({ "id": itemId, "quantity": this.milestones[this.passedMilestone.gift].specific_quantity ? giftsData[item].specificQuantity : 1, "properties": !item.price ? { [this.PROPERTY]: this.cartGoal.name } : void 0 }); }); if (countQuantity <= this.milestones[this.passedMilestone.gift].reward_value) { await this.handleRemoveGift(); await this.applyDiscountCode(this.discountCode.product_discount); if (items.length) { await fetch(window.Shopify.routes.root + "cart/add.js?app=salepify", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ "items": items }) }); } this.setLocalStorage("gift", milestoneIndex); if (!window.TLCustomEventCartGoal) { window.location.reload(); } else if (window.TLCustomEventCartGoal == 1) { window.dispatchEvent(new CustomEvent("TLCustomEvent:CartGoal-handleAddtoCart")); } } else { this.showError(this.translation.gift_modal.warning_msg.replace("{{amount}}", `${this.milestones[this.passedMilestone.gift].reward_value}`)); const passedFreeGift = this.passedMilestone.gift; buttons.forEach((ele) => { ele.innerHTML = this.translation.gift_modal.confirm_btn; ele.onclick = function() { window.tlCartGoalEmbed.handleAddtoCart(passedFreeGift, cartGoalIndex); this.isClickButtonConfirm = true; }; }); } } catch (e) { console.log("Error when add to cart", e); } }; handleRemoveGift = async () => { try { if (this.giftsIdMapQuantityInCart.size) { let cartDataReq = await fetch("/cart.js"); let cartDataRes = await cartDataReq.json(); const updates = {}; let deductedQuantities = /* @__PURE__ */ new Map(); for (let i = 0; i < cartDataRes.items.length; i++) { const item = cartDataRes.items[i]; const giftId = String(item.id); if (this.giftsIdMapQuantityInCart.get(giftId)) { const quantityInCart = this.giftsIdMapQuantityInCart.get(giftId); if (quantityInCart) { const alreadyDeducted = deductedQuantities.get(giftId) || 0; const remainingToDeduct = quantityInCart - alreadyDeducted; if (remainingToDeduct > 0) { const quantityToDeduct = Math.min(item.quantity, remainingToDeduct); updates[item.key] = item.quantity - quantityToDeduct; deductedQuantities.set(giftId, alreadyDeducted + quantityToDeduct); } } } } this.itemIdsInCart = []; this.giftsIdMapQuantityInCart = /* @__PURE__ */ new Map(); this.setLocalStorage("gift", -1); return await fetch(window.Shopify.routes.root + "cart/update.js?app=salepify", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ updates }) }); } } catch (error) { console.log("Error when handleRemoveGift: ", error); } }; handleApplyDiscountCode = async () => { try { let selector = ".tl-cart-goal-apply-discount-code-btn__cart-drawer"; document.querySelectorAll(selector).forEach((ele) => { ele.innerHTML = `
`; ele.style.pointerEvents = "none"; }); await this.applyDiscountCode(this.discountCode.order_discount); if (this.cartGoal.reward_stack === this.CART_GOAL_REWARD_STACK.ONLY_LASTEST_MILESTONE) { await this.handleRemoveGift(); } this.setLocalStorage("discount", this.passedMilestone.discount); if (!window.TLCustomEventCartGoal) { window.location.reload(); } else if (window.TLCustomEventCartGoal == 1) { window.dispatchEvent(new CustomEvent("TLCustomEvent:CartGoal-handleApplyDiscountCode")); } } catch (e) { console.log("Error when apply discount code", e); } }; handleApplyFreeShippingCode = async () => { try { let selector = ".tl-cart-goal-apply-free-shipping-btn__cart-drawer"; document.querySelectorAll(selector).forEach((ele) => { ele.innerHTML = `
`; ele.style.pointerEvents = "none"; }); if (this.cartGoal.reward_stack === this.CART_GOAL_REWARD_STACK.ONLY_LASTEST_MILESTONE) { await this.handleRemoveGift(); } this.setLocalStorage("freeShipping", this.passedMilestone.freeShipping); this.renderAllCartGoals(); } catch (e) { console.log("Error when apply free shipping code", e); } }; setLocalStorage = (type, milestoneIndex) => { let tlCartGoalLocalStorage = JSON.parse(localStorage.getItem(LOCAL_STORAGE)); if (this.cartGoal.reward_stack === this.CART_GOAL_REWARD_STACK.ONLY_LASTEST_MILESTONE && milestoneIndex !== -1) { tlCartGoalLocalStorage.discount = -1; tlCartGoalLocalStorage.freeShipping = -1; tlCartGoalLocalStorage.gift = -1; } switch (type) { case "gift": tlCartGoalLocalStorage.gift = milestoneIndex; tlCartGoalLocalStorage.selectedGifts = this.position; if (milestoneIndex == -1) { tlCartGoalLocalStorage.appliedDiscounts = tlCartGoalLocalStorage.appliedDiscounts.splice( tlCartGoalLocalStorage.appliedDiscounts.indexOf(this.discountCode.product_discount), 1 ); } break; case "discount": tlCartGoalLocalStorage.discount = milestoneIndex; break; case "freeShipping": tlCartGoalLocalStorage.freeShipping = milestoneIndex; break; } tlCartGoalLocalStorage.appliedDiscounts = this.appliedDiscounts; localStorage.setItem(LOCAL_STORAGE, JSON.stringify(tlCartGoalLocalStorage)); }; isJson(str) { try { JSON.parse(str); } catch (e) { return false; } return true; } deepMergeObject(a, b) { const result = { ...a }; for (const key in b) { if (b.hasOwnProperty(key)) { if (a && typeof a[key] === "object" && typeof b[key] === "object" && !Array.isArray(a[key])) { result[key] = this.deepMergeObject(a[key], b[key]); } else if (b[key] !== void 0) { result[key] = b[key]; } } } return result; } formatMoney = function(t, currencyFormat, currencyDisplay) { const regex = /\{\{amount\}\}/; var e; if (currencyDisplay?.[this.currency]?.display_format && regex.test(currencyDisplay[this.currency].display_format)) { e = currencyDisplay[this.currency].display_format.replace("{{amount}}", currencyFormat ? `{{${currencyFormat}}}` : "{{amount_with_period_and_space_separator}}"); } else { e = currencyFormat ? `{{${currencyFormat}}}${this.currency}` : `{{amount_with_period_and_space}}${this.currency}`; } function n(t2, e2) { return void 0 === t2 ? e2 : t2; } function o(t2, e2, o2, i2) { if (e2 = n(e2, 2), o2 = n(o2, ","), i2 = n(i2, "."), isNaN(t2) || null == t2) return 0; var r2 = (t2 = (t2 / 100).toFixed(e2)).split("."); return r2[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1" + o2) + (r2[1] ? i2 + r2[1] : ""); } "string" == typeof t && (t = t.replace(".", "")); var i = "", r = /\{\{\s*(\w+)\s*\}\}/, a = e || this.money_format; switch (a.match(r)[1]) { case "amount": i = o(t, 2); break; case "amount_no_decimals": i = o(t, 0); break; case "amount_with_comma_separator": i = o(t, 2, ".", ","); break; case "amount_with_space_separator": i = o(t, 2, " ", ","); break; case "amount_with_period_and_space_separator": i = o(t, 2, " ", "."); break; case "amount_no_decimals_with_comma_separator": i = o(t, 0, ".", ","); break; case "amount_no_decimals_with_space_separator": i = o(t, 0, " "); break; case "amount_with_apostrophe_separator": i = o(t, 2, "'", "."); } return a.replace(r, i); }; checkActiveDate = (startAt, endAt) => { let activeDate = false; if (new Date(startAt) <= /* @__PURE__ */ new Date()) { if (endAt) { if (new Date(endAt) > /* @__PURE__ */ new Date()) { activeDate = true; } } else { activeDate = true; } } return activeDate; }; checkGiftsInCart = async (cartData, lineChangeIndex, quantity) => { this.giftsIdMapQuantityInCart = /* @__PURE__ */ new Map(); cartData.items.forEach((item, index) => { if (index === lineChangeIndex && quantity === 0) { this.setLocalStorage("gift", -1); return; } let itemId = String(item.id); let itemQuantity = String(item.quantity); if (item.original_price == 0 && item.properties[this.PROPERTY]) { this.giftsIdMapQuantityInCart.set(itemId, itemQuantity); } else { item.discounts.forEach((discount) => { if (discount.title === this.discountCode.product_discount) { if (index === lineChangeIndex && quantity > 0) { itemQuantity = String(quantity); } this.giftsIdMapQuantityInCart.set(itemId, itemQuantity); } }); } }); }; } const tlCartGoalEmbedOverride = function() { if (!window || !window.Shopify) return; const CartEvents = { add: "TLCARTGOAL:add", update: "TLCARTGOAL:update", change: "TLCARTGOAL:change", clear: "TLCARTGOAL:clear", mutate: "TLCARTGOAL:mutate" }; const ShopifyCartURLs = [ "/cart/add", "/cart/update", "/cart/change", "/cart/clear", "/cart/add.js", "/cart/update.js", "/cart/change.js", "/cart/clear.js", "/cart/add.js?upcart=1&opens_cart=maybe" ]; function isShopifyCartURL(url) { if (url instanceof URL) url = url.href; if (typeof url == "object" && url.url) url = url.url; if (!url) return false; try { let path = url.split("/").pop(); path = path.split("?").shift(); return ShopifyCartURLs.includes(`/cart/${path}`); } catch (e) { console.log("Not a normal URL: ", e); return false; } } function updateType(url) { if (!url || url.includes("app=salepify")) return false; if (url.includes("cart/add")) { return "add"; } else if (url.includes("cart/update")) { return "update"; } else if (url.includes("cart/change")) { return "change"; } else if (url.includes("cart/clear")) { return "clear"; } else return false; } function dispatchEvent(url, detail) { if (typeof detail === "string") { try { detail = JSON.parse(detail); } catch { } } window.dispatchEvent(new CustomEvent(CartEvents.mutate, { detail })); const type = updateType(url); switch (type) { case "add": window.dispatchEvent(new CustomEvent(CartEvents.add, { detail })); break; case "update": window.dispatchEvent(new CustomEvent(CartEvents.update, { detail })); break; case "change": window.dispatchEvent(new CustomEvent(CartEvents.change, { detail })); break; case "clear": window.dispatchEvent(new CustomEvent(CartEvents.clear, { detail })); break; } } function XHROverride() { if (!window.XMLHttpRequest) return; const originalOpen = window.XMLHttpRequest.prototype.open; window.XMLHttpRequest.prototype.open = function() { const url = arguments[1]; this.addEventListener("load", function() { if (isShopifyCartURL(url)) { dispatchEvent(url, this.response); } }); return originalOpen.apply(this, arguments); }; } function fetchOverride() { if (!window.fetch || typeof window.fetch !== "function") return; const originalFetch = window.fetch; window.fetch = async function() { let [resource, config] = [...arguments]; const response = originalFetch.apply(this, arguments); if (isShopifyCartURL(arguments[0])) { const cartDataReq = await originalFetch("/cart.js", { method: "GET", headers: { "Content-Type": "application/json" } }); const cartDataRes = await cartDataReq.json(); isChangeCartLine = true; let items = JSON.parse(JSON.stringify(cartDataRes.items)); let lineChangeIndex = null; let quantity = 1; if (!resource.includes("add")) { const bodyArgument = JSON.parse(config.body); let newLineQty = Number(bodyArgument.quantity); if (bodyArgument.line) { lineChangeIndex = Number(bodyArgument.line) - 1; } else if (bodyArgument.id) { items.map((item, index) => { if (item.key === bodyArgument.id) { lineChangeIndex = index; } }); } else if (bodyArgument.updates) { const updates = bodyArgument.updates; items.map((item, index) => { if (updates[item.key] === item.quantity !== Number(updates[item.key])) { lineChangeIndex = index; newLineQty = Number(updates[item.key]); } }); } quantity = newLineQty; await window.tlCartGoalEmbed.checkGiftsInCart(cartDataRes, lineChangeIndex, quantity); } response.then((res) => { res.clone().json().then((data) => dispatchEvent(res.url, data)); }); } return response; }; } window.addEventListener("TLCARTGOAL:add", (event) => { window.tlCartGoalEmbed.updateCartTotal(); }); window.addEventListener("TLCARTGOAL:change", (event) => { window.tlCartGoalEmbed.updateCartTotal(); }); window.addEventListener("TLCARTGOAL:update", (event) => { window.tlCartGoalEmbed.updateCartTotal(); }); fetchOverride(); XHROverride(); }; window.tlCartGoalEmbed = window.tlCartGoalEmbed || new CartGoalEmbed( tlCartGoalRules, tlCartGoalGiftSVG, tlCartGoalDiscountSVG, tlCartGoalFreeShippingSVG, tlCartGoalCurrencySymbol, tlCartGoalCartTotal, tlCartGoalTemplate, tlCartGoalDefaultImage, tlCartGoalShowTrademark, tlCartGoalProductIdMapCollection, tlCartGoalDisplaySetting, tlCartGoalTranslation );