The repo for Purrform's main BigCommerce store.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #5 from Teser301/4-loyalty-points-refactor

4 loyalty points refactor

authored by

Rogerio Romao and committed by
GitHub
bb644856 02e7fa39

+128 -198
+1 -1
config.json
··· 1 1 { 2 - "name": "DEV Theme - Fix delivery dates 5", 2 + "name": "DEV Theme - Fix loyalty points", 3 3 "version": "6.10.0", 4 4 "template_engine": "handlebars_v4", 5 5 "meta": {
+127 -197
templates/pages/checkout.html
··· 93 93 </div> 94 94 {{/if}} {{#if customer}} {{#unless customer_group_name '===' 'Trade'}} 95 95 <script> 96 - // Handles the loyalty points 97 - var jsContext = JSON.parse({{jsContext}}); 96 + // Handles the loyalty points 97 + var jsContext = JSON.parse({{jsContext}}); 98 + const checkoutId = jsContext.checkoutId; 98 99 100 + const parentSelectorDesktop = '.cart.optimizedCheckout-orderSummary' 101 + const parentSelectorMobile = '.cart-modal-body.optimizedCheckout-orderSummary' 99 102 100 - let loyaltyInterval = setInterval(loyaltyCheck, 1000); 101 - function loyaltyCheck() { 102 - const elementParentType = document.querySelector('.layout-main') 103 - if (elementParentType) { 104 - const couponApply = document.querySelector('#applyRedeemableButton') 105 - const couponRemove = document.querySelector('[data-test="cart-price-callback"]') 106 - if (couponApply) { 107 - couponApply.addEventListener('click', () => { 108 - setTimeout(function () { 109 - window.location.reload() 110 - }, 1500); //delay is in milliseconds 111 - }) 112 - } 113 - if (couponRemove) { 114 - couponRemove.addEventListener('click', () => { 115 - window.location.reload() 103 + ready(parentSelectorDesktop, (parentElement) => { 104 + loyaltyInitialize(parentElement); 105 + }) 116 106 117 - }) 118 - } 119 - const nextSibling = elementParentType.nextElementSibling; 120 - // Check if mobile or desktop view 121 - if (nextSibling && (nextSibling.classList.contains('layout-cart'))) { 122 - // Desktop View 123 - // Check if desktop loyalty already exists 124 - const desktopLoyalty = document.querySelector('.cart-section.optimizedCheckout-orderSummary-cartSection.loyalty-points') 125 - if (!desktopLoyalty) { 126 - // define location and start func 127 - const element = document.querySelector('.cart.optimizedCheckout-orderSummary') 128 - loyaltyInitialize(element); 129 - } 130 - } else if (nextSibling && (nextSibling.classList.contains('cartDrawer'))) { 131 - // Mobile View 132 - // Check if mobile modal is open 133 - const mobileModal = document.querySelector('.ReactModalPortal .modal') 134 - if (mobileModal) { 135 - // Check if mobile loyalty already exists 136 - const mobileLoyalty = document.querySelector('.modal-body .cart-section.optimizedCheckout-orderSummary-cartSection.loyalty-points') 137 - if (!mobileLoyalty) { 138 - // define location and start func 139 - const element = document.querySelector('.cart-modal-body.optimizedCheckout-orderSummary') 140 - loyaltyInitialize(element); 141 - } 142 - } 143 - } 144 - } 145 - } 107 + ready(parentSelectorMobile, (parentElement) => { 108 + loyaltyInitialize(parentElement); 109 + }) 146 110 147 - function loyaltyInitialize(elementToAppend) { 148 - // Fetch loyalty points 149 - fetchLoyalty().then(points => { 150 - // Create a new div element for displaying loyalty points 151 - const pointsDiv = document.createElement('section'); 152 - const pointsDesc = document.createElement('p'); 153 - pointsDesc.id = 'pointsDesc' 154 - if (points === null) { 155 - pointsDesc.innerHTML = `Could not find loyalty points for this account`; 156 - } else { 111 + function loyaltyInitialize(elementToAppend) { 112 + // Fetch loyalty points 113 + fetchLoyalty().then(points => { 114 + // Create a new div element for displaying loyalty points 115 + const pointsDiv = document.createElement('section'); 116 + const pointsDesc = document.createElement('p'); 117 + pointsDesc.id = 'pointsDesc' 157 118 pointsDesc.innerHTML = `Loyalty points balance ${points}`; 158 - } 159 - pointsDiv.appendChild(pointsDesc); 160 - pointsDiv.className = 'cart-section optimizedCheckout-orderSummary-cartSection loyalty-points'; // Add a class name for styling if needed 161 - // Create a label and input for entering points to use 162 - const label = document.createElement('label'); 163 - label.setAttribute('for', 'points-input'); 164 - label.classList.add('loyaltyLabel') 119 + pointsDiv.appendChild(pointsDesc); 120 + pointsDiv.className = 'cart-section optimizedCheckout-orderSummary-cartSection loyalty-points'; 121 + // Create a label and input for entering points to use 122 + const label = document.createElement('label'); 123 + label.setAttribute('for', 'points-input'); 124 + label.classList.add('loyaltyLabel') 125 + pointsDiv.appendChild(label); 165 126 166 - const confirmButton = document.createElement('button') 167 - confirmButton.textContent = "Apply discount"; 168 - confirmButton.id = "loyaltyPointsBtn"; 169 - confirmButton.className = "btn btn-primary"; 127 + const pointsInput = document.createElement('input'); 128 + pointsInput.type = 'number'; 129 + pointsInput.id = 'points-input'; 130 + pointsInput.min = 0; 131 + pointsInput.max = points; 132 + pointsInput.placeholder = 'How many?'; 133 + pointsDiv.appendChild(pointsInput); 170 134 171 - const input = document.createElement('input'); 172 - input.type = 'number'; 173 - input.id = 'points-input'; 174 - input.pattern = '[0-9]'; 175 - input.min = '0'; 176 - input.max = points; 177 - input.placeholder = 'How many?'; 135 + const confirmButton = document.createElement('button') 136 + confirmButton.textContent = "Apply discount"; 137 + confirmButton.id = "loyaltyPointsBtn"; 138 + confirmButton.className = "btn btn-primary"; 139 + pointsDiv.appendChild(confirmButton); 178 140 179 - const cancelButton = document.createElement('button') 180 - cancelButton.textContent = "Cancel discount"; 181 - cancelButton.id = "cancelLoyaltyPointsBtn"; 182 - cancelButton.className = "btn btn-secondary"; 141 + const cancelButton = document.createElement('button') 142 + cancelButton.textContent = "Cancel discount"; 143 + cancelButton.id = "cancelLoyaltyPointsBtn"; 144 + cancelButton.className = "btn btn-secondary"; 145 + cancelButton.style.display = document.querySelector('[data-test="cart-discount"] [data-test="cart-price-value"]') ? 'block' : 'none'; 146 + pointsDiv.appendChild(cancelButton); 183 147 184 - cancelButton.addEventListener('click', () => { 185 - console.log("Received Click"); 186 - const ID = jsContext.checkoutId; 187 - fetch(`https://purrform-apps-027e.onrender.com/applyDiscountToCheckout?checkoutId=${ID}&loyaltyPointsUsed=0`) 188 - .then((response) => { 189 - cancelButton.setAttribute('disabled', 'true') 190 - cancelButton.textContent = 'Removing...' 191 - if (!response.ok) { 192 - // do something here to let the user know the discount failed 193 - cancelButton.removeAttribute('disabled') 194 - input.value = '' 195 - console.log('Fail') 196 - } 197 - cancelButton.removeAttribute('disabled') 198 - window.location.reload() 199 - console.log('Ok') 200 - }) 201 - .catch(err => { 202 - // do something here to let the user know the discount failed 203 - cancelButton.removeAttribute('disabled') 204 - cancelButton.textContent = 'Remove Discount' 205 - input.value = '' 206 - }) 207 - }) 208 - 209 - 210 - // Add event listener to ensure the input does not exceed the maximum points 211 - input.addEventListener('input', function () { 212 - const value = parseInt(this.value, 10); 213 - if (value > points) { 214 - this.value = points; 215 - } 216 - }); 148 + const errorMessage = document.createElement('p'); 149 + errorMessage.id = 'usedPointsError'; 150 + errorMessage.classList.add('warning'); 151 + errorMessage.textContent = 'There was an error applying the discount. Please try again later.'; 152 + errorMessage.style.display = 'none'; 153 + pointsDiv.appendChild(errorMessage); 217 154 218 - // Append the label and input to the usePointsDiv 219 - pointsDiv.appendChild(label); 220 - pointsDiv.appendChild(input); 221 - pointsDiv.appendChild(confirmButton); 222 - if (document.querySelector('[data-test="cart-discount"]')) { 223 - pointsDiv.appendChild(cancelButton); 224 - } 225 - if (elementToAppend) { 226 - const duplicates = document.querySelectorAll('.cart-section.optimizedCheckout-orderSummary-cartSection.loyalty-points') 227 - if (duplicates.length === 0) { 228 - elementToAppend.appendChild(pointsDiv); 229 - generateNewSummary(points) 230 - } 231 - } 155 + // Mount the entire loyalty points div to the parent element 156 + elementToAppend.appendChild(pointsDiv); 232 157 233 - const loyaltyPointsBtn = document.querySelector('#loyaltyPointsBtn') 158 + generateNewSummary(points) 234 159 235 - if (loyaltyPointsBtn) { 236 160 loyaltyPointsBtn.addEventListener('click', () => { 237 - console.log("Received Click"); 238 - if (input.value === '') { 161 + if (pointsInput.value === '') { 239 162 return; 240 163 } 241 - const ID = jsContext.checkoutId; 242 - const loyaltyPoints = document.querySelector('#points-input').value 243 - if (loyaltyPoints === "") { 244 - console.log("The input is empty."); 245 - } 246 - if (loyaltyPoints) { 247 - console.log(loyaltyPoints) 248 - } 249 - fetch(`https://purrform-apps-027e.onrender.com/applyDiscountToCheckout?checkoutId=${ID}&loyaltyPointsUsed=${loyaltyPoints}`) 250 - .then((response) => { 251 - loyaltyPointsBtn.setAttribute('disabled', 'true') 252 - loyaltyPointsBtn.textContent = 'Processing' 164 + 165 + loyaltyPointsBtn.setAttribute('disabled', 'true') 166 + loyaltyPointsBtn.textContent = 'Processing' 167 + 168 + fetch(`https://purrform-apps-027e.onrender.com/applyDiscountToCheckout?checkoutId=${checkoutId}&loyaltyPointsUsed=${pointsInput.value}`) 169 + .then((response) => { 253 170 if (!response.ok) { 254 171 // do something here to let the user know the discount failed 255 - loyaltyPointsBtn.removeAttribute('disabled') 256 - input.value = '' 257 - console.log('Fail') 172 + throw new Error('Failed to apply discount') 258 173 } 259 - loyaltyPointsBtn.removeAttribute('disabled') 260 - window.location.reload() 261 - console.log('Ok') 174 + 175 + loyaltyPointsBtn.removeAttribute('disabled') 176 + errorMessage.style.display = 'none'; 177 + cancelButton.style.display = 'block'; 178 + window.location.reload(); 179 + 262 180 }) 263 181 .catch(err => { 264 182 // do something here to let the user know the discount failed 265 183 loyaltyPointsBtn.removeAttribute('disabled') 266 184 loyaltyPointsBtn.textContent = 'Apply discount' 267 - input.value = '' 185 + pointsInput.value = '' 186 + errorMessage.style.display = 'block'; 268 187 }) 269 - }); 270 - } 271 - }).catch(error => { 272 - console.error('Error fetching loyalty points:', error); 273 - }); 188 + }) 189 + 190 + cancelButton.addEventListener('click', () => { 191 + cancelButton.setAttribute('disabled', 'true') 192 + cancelButton.textContent = 'Removing...' 193 + fetch(`https://purrform-apps-027e.onrender.com/applyDiscountToCheckout?checkoutId=${checkoutId}&loyaltyPointsUsed=0`) 194 + .then((response) => { 195 + if (!response.ok) { 196 + throw new Error('Failed to remove discount') 197 + } 198 + cancelButton.removeAttribute('disabled') 199 + errorMessage.style.display = 'none'; 200 + cancelButton.style.display = 'none'; 201 + window.location.reload(); 202 + 203 + }) 204 + .catch(err => { 205 + // do something here to let the user know the discount failed 206 + cancelButton.removeAttribute('disabled') 207 + cancelButton.textContent = 'Remove Discount' 208 + pointsInput.value = '' 209 + errorMessage.style.display = 'block'; 210 + }) 211 + 212 + }) 213 + 214 + }) 274 215 } 275 216 276 217 function generateNewSummary(currentUserPoints) { 277 - currentUserPoints = Number(currentUserPoints); 278 - 279 218 const masterContainer = document.createElement('div'); 280 219 const masterText = document.createElement('p'); 281 220 masterText.classList.add("loyalty-summary") ··· 283 222 masterContainer.appendChild(masterText) 284 223 285 224 const discountEl = document.querySelector('[data-test="cart-discount"] [data-test="cart-price-value"]') 286 - const earningsEl = document.querySelector('[data-test="cart-subtotal"] [data-test="cart-price-value"]') 287 - let VAT = document.querySelector('[data-test="cart-taxes"] [data-test="cart-price-value"]') 288 - let couponDiscount = document.querySelector('[data-test="cart-coupon"] [data-test="cart-price-value"]') 289 - const existingDiv = document.getElementById('points-input'); 290 - let earningPriceValue 291 - let earningLoyalPointValue 225 + const subtotalEl = document.querySelector('[data-test="cart-subtotal"] [data-test="cart-price-value"]') 226 + const couponDiscountEl = document.querySelector('[data-test="cart-coupon"] [data-test="cart-price-value"]') 227 + const pointsInput = document.getElementById('points-input'); 228 + 229 + let discountPriceValue = 0; 230 + let discountLoyalPointValue = 0; 231 + let earningPriceValue = 0; 232 + let earningLoyalPointValue = 0; 292 233 293 - let discountPriceValue 294 - let discountLoyalPointValue 295 234 296 235 if (discountEl) { 297 236 // Discount Div 298 237 const discountContainer = document.createElement('div'); 299 238 discountContainer.classList.add('cart-summaryItem') 300 239 301 - const discountName = document.createElement('div'); 240 + const discountDescription = document.createElement('div'); 302 241 const discountValue = document.createElement('div'); 303 242 304 - discountName.textContent = "Points redeemed" 243 + discountDescription.textContent = "Points redeemed" 305 244 306 245 discountPriceValue = discountEl.innerHTML.replace(/[^\d.-]/g, '') 307 - discountPriceValue = discountPriceValue.replace(/[^\d.-]/g, ''); // Remove non-numeric characters 308 - discountPriceValue = Number(discountPriceValue); 309 - discountPriceValue = Math.abs(discountPriceValue); 310 - discountLoyalPointValue = discountPriceValue * 100 311 - discountLoyalPointValue = Math.floor(discountLoyalPointValue); 246 + discountPriceValue = Math.abs(Number(discountPriceValue)); 247 + discountLoyalPointValue = Math.floor(discountPriceValue * 100) 312 248 313 249 discountValue.textContent = `-${discountLoyalPointValue}` 314 250 315 - discountContainer.appendChild(discountName) 251 + discountContainer.appendChild(discountDescription) 316 252 discountContainer.appendChild(discountValue) 317 253 masterContainer.appendChild(discountContainer) 318 254 } 319 - if (earningsEl) { 255 + if (subtotalEl) { 320 256 // Earning Div 321 257 const earningContainer = document.createElement('div'); 322 258 earningContainer.classList.add('cart-summaryItem') 323 259 324 - const earningName = document.createElement('div'); 260 + const earningDescription = document.createElement('div'); 325 261 const earningValue = document.createElement('div'); 326 262 327 - earningName.textContent = "Points earned" 328 - earningPriceValue = earningsEl.innerHTML 329 - earningPriceValue = earningPriceValue.replace(/[^\d.-]/g, ''); // Remove non-numeric characters 263 + earningDescription.textContent = "Points earned" 264 + earningPriceValue = subtotalEl.innerHTML.replace(/[^\d.-]/g, ''); 330 265 earningPriceValue = Number(earningPriceValue); // Use parseFloat to handle decimal values 331 266 if (discountEl) { 332 267 earningPriceValue = earningPriceValue - discountPriceValue 333 268 } 334 - /* 335 - if (VAT) { 336 - VAT = Math.round(Number(VAT.innerHTML.replace(/[^\d.-]/g, ''))); 337 - earningPriceValue -= VAT; 338 - } 339 - */ 340 - if (couponDiscount) { 341 - earningPriceValue -= Math.floor(Math.abs(Number(couponDiscount.innerHTML.replace(/[^\d.-]/g, '')))); 269 + 270 + if (couponDiscountEl) { 271 + earningPriceValue -= Math.floor(Math.abs(Number(couponDiscountEl.innerHTML.replace(/[^\d.-]/g, '')))); 342 272 } 343 273 344 - earningLoyalPointValue = earningPriceValue / 2; 274 + earningLoyalPointValue = Math.floor(earningPriceValue / 2); 345 275 346 - earningLoyalPointValue = Math.floor(earningLoyalPointValue); 347 276 if (earningLoyalPointValue < 0) { 348 - earningValue.textContent = `+0` 277 + earningLoyalPointValue = 0; 278 + earningValue.textContent = `0` 349 279 } else { 350 280 earningValue.textContent = `+${earningLoyalPointValue}` 351 281 } 352 282 353 - earningContainer.appendChild(earningName) 283 + earningContainer.appendChild(earningDescription) 354 284 earningContainer.appendChild(earningValue) 355 285 masterContainer.appendChild(earningContainer) 356 286 } 287 + 357 288 const finalContainer = document.createElement('div'); 358 289 const finalResult = document.createElement('div'); 359 290 const finalResultText = document.createElement('p'); ··· 361 292 const finalType = document.createElement('div'); 362 293 const finalTypeText = document.createElement('p'); 363 294 finalTypeText.textContent = 'Estimated total after purchase:' 364 - if (earningsEl && discountEl && currentUserPoints) { 295 + 296 + if (discountEl) { 365 297 finalResultText.textContent = `${(currentUserPoints + earningLoyalPointValue - discountLoyalPointValue)}` 366 - } else if (earningsEl && currentUserPoints){ 367 - finalResultText.textContent = `${currentUserPoints + earningLoyalPointValue}` 368 298 } else { 369 - finalResultText.textContent = `${earningLoyalPointValue}` 299 + finalResultText.textContent = `${currentUserPoints + earningLoyalPointValue}` 370 300 } 301 + 371 302 finalType.appendChild(finalTypeText) 372 303 finalResult.appendChild(finalResultText) 373 304 finalContainer.appendChild(finalType) ··· 375 306 finalContainer.classList.add('cart-resultItem') 376 307 377 308 masterContainer.appendChild(finalContainer) 378 - existingDiv.insertAdjacentElement('afterend', masterContainer); 309 + pointsInput.insertAdjacentElement('afterend', masterContainer); 379 310 } 380 311 381 - // Append the usePointsDiv to the target element 382 312 function fetchLoyalty() { 383 313 return fetch('/graphql', { 384 314 method: 'POST', ··· 406 336 .then(json => { 407 337 const attribute = json.data.customer.attributes.attribute; 408 338 const points = attribute ? attribute.value : '0'; // Default to '0' if attribute is not found 409 - return points; 339 + return Number(points); 410 340 }) 411 341 .catch(error => { 412 342 console.error('Error fetching loyalty points:', error); 413 - return '0'; // Return '0' in case of error 343 + return 0;// Return '0' in case of error 414 344 }); 415 345 } 416 346 </script>