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

Configure Feed

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

fix: trader customer groups bug

+549 -5
+1 -1
config.json
··· 1 1 { 2 - "name": "cart icon animation", 2 + "name": "fix trader customer groups bug", 3 3 "version": "6.10.0", 4 4 "template_engine": "handlebars_v4", 5 5 "meta": {
+86
templates/components/cart/totals.html
··· 42 42 console.error('Error fetching trader data:', error); 43 43 } 44 44 </script> 45 + {{else if customer_group_name '===' 'New Trader'}} 46 + <script type="module"> 47 + try { 48 + const response = await fetch('https://purrform-apps-027e.onrender.com/getCreditSystemTraders', { 49 + method: 'GET', 50 + headers: { 51 + 'Content-Type': 'application/json', 52 + } 53 + }); 54 + 55 + if (response.ok) { 56 + const traders = await response.json(); // { bc_customer_email: string, credit_ceiling: number, current_balance: number, has_overdue: boolean, id: number }[] 57 + const traderInCreditSystem = traders.find(t => t.bc_customer_email === '{{customer.email}}'); 58 + 59 + if (traderInCreditSystem) { 60 + // Update the credit balance display 61 + const creditBalanceElement = document.querySelector('.cart-total-credit-balance .cart-total-value'); 62 + creditBalanceElement.textContent = `£${traderInCreditSystem.current_balance.toFixed(2)}`; 63 + const creditBalanceContainer = document.querySelector('.cart-total-credit-balance'); 64 + creditBalanceContainer.style.display = 'flex'; 65 + 66 + const cartTotal = Number('{{cart.grand_total.value}}'); 67 + 68 + // Add overdue message if applicable 69 + const creditErrorMessageEl = document.querySelector('.credit-balance-message'); 70 + if (traderInCreditSystem.has_overdue) { 71 + creditErrorMessageEl.innerHTML = '<span>You have overdue order(s) unpaid. New orders will not be processed until payment is made. <a href="/account.php?action=order_status">Click here</a> to see the overdue order(s) in your account.</span>'; 72 + creditErrorMessageEl.style.display = 'block'; 73 + } else if (cartTotal > traderInCreditSystem.current_balance) { 74 + creditErrorMessageEl.textContent = 'Your cart total exceeds your credit limit. You can either remove some items or pay the balance to process your order.'; 75 + creditErrorMessageEl.style.display = 'block'; 76 + } 77 + 78 + const needToDisableCheckout = traderInCreditSystem.has_overdue || cartTotal > traderInCreditSystem.current_balance; 79 + const agreeCheckbox = document.querySelector('.validate-cart'); 80 + agreeCheckbox.parentNode.style.display = needToDisableCheckout ? 'none' : 'block'; 81 + 82 + } 83 + } 84 + } catch (error) { 85 + console.error('Error fetching trader data:', error); 86 + } 87 + </script> 88 + {{else if customer_group_name '===' 'Trade TNC'}} 89 + <script type="module"> 90 + try { 91 + const response = await fetch('https://purrform-apps-027e.onrender.com/getCreditSystemTraders', { 92 + method: 'GET', 93 + headers: { 94 + 'Content-Type': 'application/json', 95 + } 96 + }); 97 + 98 + if (response.ok) { 99 + const traders = await response.json(); // { bc_customer_email: string, credit_ceiling: number, current_balance: number, has_overdue: boolean, id: number }[] 100 + const traderInCreditSystem = traders.find(t => t.bc_customer_email === '{{customer.email}}'); 101 + 102 + if (traderInCreditSystem) { 103 + // Update the credit balance display 104 + const creditBalanceElement = document.querySelector('.cart-total-credit-balance .cart-total-value'); 105 + creditBalanceElement.textContent = `£${traderInCreditSystem.current_balance.toFixed(2)}`; 106 + const creditBalanceContainer = document.querySelector('.cart-total-credit-balance'); 107 + creditBalanceContainer.style.display = 'flex'; 108 + 109 + const cartTotal = Number('{{cart.grand_total.value}}'); 110 + 111 + // Add overdue message if applicable 112 + const creditErrorMessageEl = document.querySelector('.credit-balance-message'); 113 + if (traderInCreditSystem.has_overdue) { 114 + creditErrorMessageEl.innerHTML = '<span>You have overdue order(s) unpaid. New orders will not be processed until payment is made. <a href="/account.php?action=order_status">Click here</a> to see the overdue order(s) in your account.</span>'; 115 + creditErrorMessageEl.style.display = 'block'; 116 + } else if (cartTotal > traderInCreditSystem.current_balance) { 117 + creditErrorMessageEl.textContent = 'Your cart total exceeds your credit limit. You can either remove some items or pay the balance to process your order.'; 118 + creditErrorMessageEl.style.display = 'block'; 119 + } 120 + 121 + const needToDisableCheckout = traderInCreditSystem.has_overdue || cartTotal > traderInCreditSystem.current_balance; 122 + const agreeCheckbox = document.querySelector('.validate-cart'); 123 + agreeCheckbox.parentNode.style.display = needToDisableCheckout ? 'none' : 'block'; 124 + 125 + } 126 + } 127 + } catch (error) { 128 + console.error('Error fetching trader data:', error); 129 + } 130 + </script> 45 131 {{/if}} 46 132 47 133 <div data-cart-totals class="cart-free-delivery" style="border: none;">
-1
templates/pages/cart.html
··· 62 62 .then(data => data.data.site.product); 63 63 64 64 if (charityProduct) { 65 - console.log('Charity product data', charityProduct); 66 65 const charitySection = document.querySelector('.charity-product'); 67 66 68 67 const charityTitle = charitySection.querySelector('h4');
+462 -3
templates/pages/checkout.html
··· 124 124 } 125 125 126 126 // if customer group is trade, hide coupons 127 - if ('{{customer_group_name}}' === 'Trade') { 127 + if ('{{customer_group_name}}' === 'Trade' || '{{customer_group_name}}' === 'New Trader' || '{{customer_group_name}}' === 'Trade TNC') { 128 128 couponsEl.style.display = 'none'; 129 129 } 130 130 ··· 247 247 " 248 248 >You are currently blocked for shopping. Please contact admin for more info</p> 249 249 </div> 250 - {{/if}} {{#if customer}} {{#unless customer_group_name '===' 'Trade'}} 250 + {{/if}} {{#if customer}} 251 + {{#if customer_group_name '===' 'Personal'}} 252 + 253 + <script> 254 + // Handles the loyalty points 255 + const parentSelectorDesktop = '.cart.optimizedCheckout-orderSummary'; 256 + const parentSelectorMobile = 257 + '.cart-modal-body.optimizedCheckout-orderSummary'; 258 + 259 + ready(parentSelectorDesktop, (parentElement) => { 260 + loyaltyInitialize(parentElement); 261 + }); 262 + 263 + ready(parentSelectorMobile, (parentElement) => { 264 + loyaltyInitialize(parentElement); 265 + }); 266 + 267 + function loyaltyInitialize(elementToAppend) { 268 + // Fetch loyalty points 269 + fetchLoyalty().then((points) => { 270 + // Create a new div element for displaying loyalty points 271 + const pointsDiv = document.createElement('section'); 272 + const pointsDesc = document.createElement('p'); 273 + pointsDesc.id = 'pointsDesc'; 274 + if (points == null) { 275 + pointsDesc.innerHTML = "Could not find loyalty points for this account, make sure you are logged in or refresh the page."; 276 + } else { 277 + pointsDesc.innerHTML = `Loyalty points balance ${points}`; 278 + } 279 + pointsDiv.appendChild(pointsDesc); 280 + pointsDiv.className = 'cart-section optimizedCheckout-orderSummary-cartSection loyalty-points'; 281 + 282 + // Create a label and input for entering points to use 283 + const label = document.createElement('label'); 284 + label.setAttribute('for', 'points-input'); 285 + label.classList.add('loyaltyLabel'); 286 + pointsDiv.appendChild(label); 287 + 288 + const pointsInput = document.createElement('input'); 289 + pointsInput.type = 'number'; 290 + pointsInput.id = 'points-input'; 291 + pointsInput.min = 0; 292 + pointsInput.max = points; 293 + pointsInput.placeholder = 'How many?'; 294 + pointsDiv.appendChild(pointsInput); 295 + 296 + pointsInput.addEventListener('input', () => { 297 + if (Number(pointsInput.value) > points) { 298 + pointsInput.value = points; 299 + } 300 + }); 301 + 302 + const confirmButton = document.createElement('button'); 303 + confirmButton.textContent = 'Apply discount'; 304 + confirmButton.id = 'loyaltyPointsBtn'; 305 + confirmButton.className = 'btn btn-primary'; 306 + pointsDiv.appendChild(confirmButton); 307 + 308 + const cancelButton = document.createElement('button'); 309 + cancelButton.textContent = 'Cancel discount'; 310 + cancelButton.id = 'cancelLoyaltyPointsBtn'; 311 + cancelButton.className = 'btn btn-secondary'; 312 + cancelButton.style.display = document.querySelector( 313 + '[data-test="cart-discount"] [data-test="cart-price-value"]' 314 + ) 315 + ? 'block' 316 + : 'none'; 317 + pointsDiv.appendChild(cancelButton); 318 + 319 + const errorMessage = document.createElement('p'); 320 + errorMessage.id = 'usedPointsError'; 321 + errorMessage.classList.add('warning'); 322 + errorMessage.textContent = 323 + 'There was an error applying the discount. Please try again later.'; 324 + errorMessage.style.display = 'none'; 325 + pointsDiv.appendChild(errorMessage); 326 + 327 + // Mount the entire loyalty points div to the parent element 328 + elementToAppend.appendChild(pointsDiv); 329 + 330 + generateNewSummary(points); 331 + 332 + loyaltyPointsBtn.addEventListener('click', () => { 333 + if (pointsInput.value === '') { 334 + return; 335 + } 336 + 337 + loyaltyPointsBtn.setAttribute('disabled', 'true'); 338 + loyaltyPointsBtn.textContent = 'Processing'; 339 + 340 + fetch( 341 + `https://purrform-apps-027e.onrender.com/applyDiscountToCheckout?checkoutId={{cart_id}}&loyaltyPointsUsed=${pointsInput.value}&max_points=${points}` 342 + ) 343 + .then((response) => { 344 + if (!response.ok) { 345 + // do something here to let the user know the discount failed 346 + throw new Error('Failed to apply discount'); 347 + } 348 + 349 + loyaltyPointsBtn.removeAttribute('disabled'); 350 + errorMessage.style.display = 'none'; 351 + cancelButton.style.display = 'block'; 352 + window.location.reload(); 353 + }) 354 + .catch((err) => { 355 + // do something here to let the user know the discount failed 356 + loyaltyPointsBtn.removeAttribute('disabled'); 357 + loyaltyPointsBtn.textContent = 'Apply discount'; 358 + pointsInput.value = ''; 359 + errorMessage.style.display = 'block'; 360 + }); 361 + }); 362 + 363 + cancelButton.addEventListener('click', () => { 364 + cancelButton.setAttribute('disabled', 'true'); 365 + cancelButton.textContent = 'Removing...'; 366 + fetch( 367 + `https://purrform-apps-027e.onrender.com/applyDiscountToCheckout?checkoutId={{cart_id}}&loyaltyPointsUsed=0` 368 + ) 369 + .then((response) => { 370 + if (!response.ok) { 371 + throw new Error('Failed to remove discount'); 372 + } 373 + cancelButton.removeAttribute('disabled'); 374 + errorMessage.style.display = 'none'; 375 + cancelButton.style.display = 'none'; 376 + window.location.reload(); 377 + }) 378 + .catch((err) => { 379 + // do something here to let the user know the discount failed 380 + cancelButton.removeAttribute('disabled'); 381 + cancelButton.textContent = 'Remove Discount'; 382 + pointsInput.value = ''; 383 + errorMessage.style.display = 'block'; 384 + }); 385 + }); 386 + }); 387 + } 388 + 389 + function generateNewSummary(currentUserPoints) { 390 + const masterContainer = document.createElement('div'); 391 + const masterText = document.createElement('p'); 392 + masterText.classList.add('loyalty-summary'); 393 + masterText.textContent = 'Loyalty Points Summary'; 394 + masterContainer.appendChild(masterText); 395 + 396 + const discountEl = document.querySelector( 397 + '[data-test="cart-discount"] [data-test="cart-price-value"]' 398 + ); 399 + const subtotalEl = document.querySelector( 400 + '[data-test="cart-subtotal"] [data-test="cart-price-value"]' 401 + ); 402 + const couponDiscountEl = document.querySelector( 403 + '[data-test="cart-coupon"] [data-test="cart-price-value"]' 404 + ); 405 + const pointsInput = document.getElementById('points-input'); 406 + 407 + let discountPriceValue = 0; 408 + let discountLoyalPointValue = 0; 409 + let earningPriceValue = 0; 410 + let earningLoyalPointValue = 0; 411 + 412 + if (discountEl) { 413 + // Discount Div 414 + const discountContainer = document.createElement('div'); 415 + discountContainer.classList.add('cart-summaryItem'); 416 + 417 + const discountDescription = document.createElement('div'); 418 + const discountValue = document.createElement('div'); 419 + 420 + discountDescription.textContent = 'Points redeemed'; 421 + 422 + discountPriceValue = discountEl.innerHTML.replace(/[^\d.-]/g, ''); 423 + discountPriceValue = Math.abs(Number(discountPriceValue)); 424 + discountLoyalPointValue = Math.floor(discountPriceValue * 100); 425 + 426 + discountValue.textContent = `-${discountLoyalPointValue}`; 427 + 428 + discountContainer.appendChild(discountDescription); 429 + discountContainer.appendChild(discountValue); 430 + masterContainer.appendChild(discountContainer); 431 + } 432 + if (subtotalEl) { 433 + // Earning Div 434 + const earningContainer = document.createElement('div'); 435 + earningContainer.classList.add('cart-summaryItem'); 436 + 437 + const earningDescription = document.createElement('div'); 438 + const earningValue = document.createElement('div'); 439 + 440 + earningDescription.textContent = 'Points earned'; 441 + earningPriceValue = subtotalEl.innerHTML.replace(/[^\d.-]/g, ''); 442 + earningPriceValue = Number(earningPriceValue); // Use parseFloat to handle decimal values 443 + if (discountEl) { 444 + earningPriceValue = earningPriceValue - discountPriceValue; 445 + } 446 + 447 + if (couponDiscountEl) { 448 + earningPriceValue -= Math.floor( 449 + Math.abs( 450 + Number( 451 + couponDiscountEl.innerHTML.replace(/[^\d.-]/g, '') 452 + ) 453 + ) 454 + ); 455 + } 456 + 457 + earningLoyalPointValue = Math.floor(earningPriceValue / 2); 458 + 459 + if (earningLoyalPointValue < 0) { 460 + earningLoyalPointValue = 0; 461 + earningValue.textContent = `0`; 462 + } else { 463 + earningValue.textContent = `+${earningLoyalPointValue}`; 464 + } 465 + 466 + earningContainer.appendChild(earningDescription); 467 + earningContainer.appendChild(earningValue); 468 + masterContainer.appendChild(earningContainer); 469 + } 470 + 471 + const finalContainer = document.createElement('div'); 472 + const finalResult = document.createElement('div'); 473 + const finalResultText = document.createElement('p'); 474 + 475 + const finalType = document.createElement('div'); 476 + const finalTypeText = document.createElement('p'); 477 + finalTypeText.textContent = 'Estimated total after purchase:'; 478 + 479 + if (discountEl) { 480 + finalResultText.textContent = `${ 481 + currentUserPoints + 482 + earningLoyalPointValue - 483 + discountLoyalPointValue 484 + }`; 485 + } else { 486 + finalResultText.textContent = `${ 487 + currentUserPoints + earningLoyalPointValue 488 + }`; 489 + } 490 + 491 + finalType.appendChild(finalTypeText); 492 + finalResult.appendChild(finalResultText); 493 + finalContainer.appendChild(finalType); 494 + finalContainer.appendChild(finalResult); 495 + finalContainer.classList.add('cart-resultItem'); 496 + 497 + masterContainer.appendChild(finalContainer); 498 + // pointsDiv.insertAdjacentHTML('afterend', finalContainer.innerHTML); 499 + pointsInput.insertAdjacentHTML('afterend', masterContainer.outerHTML); 251 500 501 + // fix for mobile not showing button 502 + const parentSelectorMobile = 503 + '.cart-modal-body.optimizedCheckout-orderSummary'; 504 + if (document.querySelector(parentSelectorMobile)) { 505 + const confirmButton = document.querySelector('#loyaltyPointsBtn'); 506 + confirmButton.focus(); 507 + } 508 + } 509 + 510 + function fetchLoyalty() { 511 + return fetch('/graphql', { 512 + method: 'POST', 513 + credentials: 'same-origin', 514 + headers: { 515 + 'Content-Type': 'application/json', 516 + Authorization: 'Bearer {{ settings.storefront_api.token }}', 517 + }, 518 + body: JSON.stringify({ 519 + query: ` 520 + query loyaltyQuery{ 521 + customer { 522 + attributes { 523 + attribute(entityId: 1) { 524 + value 525 + name 526 + } 527 + } 528 + } 529 + } 530 + `, 531 + }), 532 + }) 533 + .then((res) => res.json()) 534 + .then((json) => { 535 + const attribute = json.data.customer.attributes.attribute; 536 + const points = attribute ? attribute.value : '0'; // Default to '0' if attribute is not found 537 + return Number(points); 538 + }) 539 + .catch((error) => { 540 + console.error('Error fetching loyalty points:', error); 541 + return 0; // Return '0' in case of error 542 + }); 543 + } 544 + </script> 545 + {{else if customer_group_name '===' 'Breeder'}} 252 546 <script> 253 547 // Handles the loyalty points 254 548 const parentSelectorDesktop = '.cart.optimizedCheckout-orderSummary'; ··· 541 835 }); 542 836 } 543 837 </script> 544 - {{/unless}} {{/if}} 838 + {{/if}} 839 + {{/if}} 545 840 546 841 <script> 547 842 // ------------------------------------------------------// ··· 959 1254 </script> 960 1255 961 1256 {{#if customer_group_name '===' 'Trade'}} 1257 + <script type="module"> 1258 + let hasOverdue = false; 1259 + let lowBalance = false; 1260 + 1261 + try { 1262 + const response = await fetch('https://purrform-apps-027e.onrender.com/getCreditSystemTraders', { 1263 + method: 'GET', 1264 + headers: { 1265 + 'Content-Type': 'application/json', 1266 + } 1267 + }); 1268 + 1269 + if (response.ok) { 1270 + const traders = await response.json(); // { bc_customer_email: string, credit_ceiling: number, current_balance: number, has_overdue: boolean, id: number }[] 1271 + const traderInCreditSystem = traders.find(t => t.bc_customer_email === '{{customer.email}}'); 1272 + 1273 + if (traderInCreditSystem) { 1274 + // Put the credit balance info before the cart subtotal 1275 + ready('div[data-test="cart-subtotal"]', (element) => { 1276 + element.insertAdjacentHTML( 1277 + 'beforebegin', 1278 + `<div class="creditBalanceInfo"> 1279 + <div>Credit Balance </div> 1280 + <div class="creditBalanceAmount">£${traderInCreditSystem.current_balance.toFixed(2)}</div> 1281 + </div>` 1282 + ); 1283 + }); 1284 + 1285 + // Add any overdue / low balance message to the cart total section 1286 + ready('div[data-test="cart-total"]', (element) => { 1287 + hasOverdue = traderInCreditSystem.has_overdue; 1288 + 1289 + if (hasOverdue) { 1290 + element.insertAdjacentHTML( 1291 + 'beforeend', 1292 + `<div class="credit-balance-message"> 1293 + You have overdue order(s) unpaid. New orders will not be processed until payment is made. <a href="/account.php?action=order_status">Click here</a> to see the overdue order(s) in your account. 1294 + </div>` 1295 + ); 1296 + } else { 1297 + const cartTotalText = document.querySelector( 1298 + 'div[data-test="cart-total"] span[data-test="cart-price-value"]' 1299 + ).textContent; 1300 + const cartTotal = Number(cartTotalText.replace('£', '')); 1301 + lowBalance = cartTotal > traderInCreditSystem.current_balance; 1302 + 1303 + if (lowBalance) { 1304 + element.insertAdjacentHTML( 1305 + 'beforeend', 1306 + `<div class="credit-balance-message"> 1307 + Your cart total exceeds your credit limit. You can either remove some items or pay the balance to process your order. 1308 + </div>` 1309 + ); 1310 + } 1311 + 1312 + } 1313 + 1314 + }); 1315 + 1316 + 1317 + if (hasOverdue || lowBalance) { 1318 + // Hide the payment button if there is an overdue order or low balance 1319 + ready('#fakeButton', (element) => { 1320 + element.remove() 1321 + }); 1322 + 1323 + ready('#proceedButton', (element) => { 1324 + element.style.display = hasOverdue || lowBalance ? 'none' : 'block'; 1325 + }); 1326 + 1327 + ready('#checkoutPaymentContinue', (element) => { 1328 + element.style.display = hasOverdue || lowBalance ? 'none' : 'block'; 1329 + }); 1330 + } 1331 + } 1332 + } 1333 + } catch (error) { 1334 + console.error('Error fetching trader data:', error); 1335 + } 1336 + 1337 + </script> 1338 + {{else if customer_group_name '===' 'New Trader'}} 1339 + <script type="module"> 1340 + let hasOverdue = false; 1341 + let lowBalance = false; 1342 + 1343 + try { 1344 + const response = await fetch('https://purrform-apps-027e.onrender.com/getCreditSystemTraders', { 1345 + method: 'GET', 1346 + headers: { 1347 + 'Content-Type': 'application/json', 1348 + } 1349 + }); 1350 + 1351 + if (response.ok) { 1352 + const traders = await response.json(); // { bc_customer_email: string, credit_ceiling: number, current_balance: number, has_overdue: boolean, id: number }[] 1353 + const traderInCreditSystem = traders.find(t => t.bc_customer_email === '{{customer.email}}'); 1354 + 1355 + if (traderInCreditSystem) { 1356 + // Put the credit balance info before the cart subtotal 1357 + ready('div[data-test="cart-subtotal"]', (element) => { 1358 + element.insertAdjacentHTML( 1359 + 'beforebegin', 1360 + `<div class="creditBalanceInfo"> 1361 + <div>Credit Balance </div> 1362 + <div class="creditBalanceAmount">£${traderInCreditSystem.current_balance.toFixed(2)}</div> 1363 + </div>` 1364 + ); 1365 + }); 1366 + 1367 + // Add any overdue / low balance message to the cart total section 1368 + ready('div[data-test="cart-total"]', (element) => { 1369 + hasOverdue = traderInCreditSystem.has_overdue; 1370 + 1371 + if (hasOverdue) { 1372 + element.insertAdjacentHTML( 1373 + 'beforeend', 1374 + `<div class="credit-balance-message"> 1375 + You have overdue order(s) unpaid. New orders will not be processed until payment is made. <a href="/account.php?action=order_status">Click here</a> to see the overdue order(s) in your account. 1376 + </div>` 1377 + ); 1378 + } else { 1379 + const cartTotalText = document.querySelector( 1380 + 'div[data-test="cart-total"] span[data-test="cart-price-value"]' 1381 + ).textContent; 1382 + const cartTotal = Number(cartTotalText.replace('£', '')); 1383 + lowBalance = cartTotal > traderInCreditSystem.current_balance; 1384 + 1385 + if (lowBalance) { 1386 + element.insertAdjacentHTML( 1387 + 'beforeend', 1388 + `<div class="credit-balance-message"> 1389 + Your cart total exceeds your credit limit. You can either remove some items or pay the balance to process your order. 1390 + </div>` 1391 + ); 1392 + } 1393 + 1394 + } 1395 + 1396 + }); 1397 + 1398 + 1399 + if (hasOverdue || lowBalance) { 1400 + // Hide the payment button if there is an overdue order or low balance 1401 + ready('#fakeButton', (element) => { 1402 + element.remove() 1403 + }); 1404 + 1405 + ready('#proceedButton', (element) => { 1406 + element.style.display = hasOverdue || lowBalance ? 'none' : 'block'; 1407 + }); 1408 + 1409 + ready('#checkoutPaymentContinue', (element) => { 1410 + element.style.display = hasOverdue || lowBalance ? 'none' : 'block'; 1411 + }); 1412 + } 1413 + } 1414 + } 1415 + } catch (error) { 1416 + console.error('Error fetching trader data:', error); 1417 + } 1418 + 1419 + </script> 1420 + {{else if customer_group_name '===' 'Trade TNC'}} 962 1421 <script type="module"> 963 1422 let hasOverdue = false; 964 1423 let lowBalance = false;