1/* stimulusFetch: 'lazy' */ 2import { Controller } from '@hotwired/stimulus'; 3 4// noinspection JSUnusedGlobalSymbols loaded via stimulus 5export default class extends Controller { 6 subtotal = 0; 7 accumulatedQty = 0; 8 unitPrice = 0; 9 /** @type {NodeListOf<HTMLElement>|null} */ 10 priceRows = null; 11 /** @type {NodeListOf<HTMLElementTagNameMap[string]>|null} */ 12 inputs= null; 13 /** @type {Intl.NumberFormat|null} */ 14 formatter = null; 15 16 active(inputs) { 17 inputs.forEach(input => { 18 input.labels[0]?.classList[input.checked ? 'add' : 'remove']('active'); 19 }); 20 } 21 22 setCurrent(elm) { 23 Array.prototype.find.call(this.priceRows, row => row.classList.contains('current'))?.classList.remove('current'); 24 elm.classList.add('current'); 25 } 26 27 /** 28 * @param {number} qty 29 * @returns {number} 30 */ 31 getPriceRowForQty(qty) { 32 for (let i = 0, n = this.priceRows.length; i < n; i++) { 33 if (i > 0 && parseFloat(this.priceRows[i].dataset.qty || '0') > qty) { 34 return i - 1; 35 } 36 } 37 return this.priceRows.length - 1; 38 } 39 40 /** 41 * @returns {number} 42 */ 43 getAccumulatedQty() { 44 return Array.prototype.reduce.call(this.inputs, 45 (carry, input) => { 46 const qty = parseInt(input.value || '0'); 47 if (qty > 0) { 48 carry += qty; 49 } 50 return carry; 51 }, 52 0 53 ); 54 } 55 56 updatePricing() { 57 const qty = this.getAccumulatedQty(); 58 const priceRowIndex = this.getPriceRowForQty(qty); 59 const priceRow = this.priceRows[priceRowIndex]; 60 this.accumulatedQty = qty; 61 this.setCurrent(priceRow); 62 this.unitPrice = parseFloat(priceRow.dataset.price); 63 this.subtotal = this.accumulatedQty * this.unitPrice; 64 /** @type {HTMLElement} */ 65 const element = this.element; 66 element.querySelector('[data-subtotal]').textContent = this.formatter.format(this.subtotal); 67 element.querySelector('[data-qtytotal]').textContent = this.accumulatedQty.toFixed(0); 68 if (priceRowIndex < this.priceRows.length - 1) { 69 const nextRow = this.priceRows[priceRowIndex + 1]; 70 element.querySelector('[data-next-qty]').textContent = (parseFloat(nextRow.dataset.qty) - qty).toFixed(0); 71 element.querySelector('[data-next-price]').textContent = this.formatter.format(parseFloat(priceRow.dataset.price) - parseFloat(nextRow.dataset.price)); 72 element.querySelector('.save-tier').classList.remove('hidden'); 73 } 74 } 75 76 connect() { 77 /** @type {HTMLElement} */ 78 const element = this.element; 79 this.formatter = new Intl.NumberFormat(document.documentElement.lang, { style: 'currency', currency: 'AUD' }); 80 this.inputs = element.querySelectorAll('input'); 81 this.priceRows = element.querySelectorAll('[data-price]'); 82 this.unitPrice = parseFloat(this.priceRows[0].dataset.price); 83 this.subtotal = 0; 84 this.accumulatedQty = 0; 85 this.inputs.forEach(input => { 86 input.addEventListener('change', () => { 87 this.updatePricing(); 88 }); 89 }); 90 this.updatePricing(); 91 } 92}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.