1(function () { 2 var ratesConfig = []; 3 4 var state = { 5 country: null, 6 deliveryMethod: null, 7 paymentMethod: null, 8 lastDirection: true, 9 }; 10 11 var flagMap = { CA: '<img src="wp-content/themes/kabayanremitv2/img/flags/canada-flag.svg"/>', GB: '<img src="wp-content/themes/kabayanremitv2/img/flags/united-kingdom-flag.svg"/>', UK: '<img src="wp-content/themes/kabayanremitv2/img/flags/united-kingdom-flag.svg"/>', US: '<img src="wp-content/themes/kabayanremitv2/img/flags/united-states-of-america-flag.svg"/>' }; 12 13 var deliveryMethodDisplay = { 14 'payment.delivery_methods.credit_to_account': { label: 'Credit to account', icon: 'ti-credit-card' }, 15 'payment.delivery_methods.cash_collection': { label: 'Cash collection', icon: 'ti-cash' }, 16 'payment.delivery_methods.bills_payment': { label: 'Bills payment', icon: 'ti-file-invoice' }, 17 'payment.delivery_methods.mobile_e_wallet_top_up': { label: 'Mobile e-wallet top-up', icon: 'ti-device-mobile' }, 18 }; 19 20 var paymentMethodDisplay = { 21 'payment.payment_methods.bank_transfer': { 22 getLabel: function (cc) { return cc === 'CA' ? 'e-Transfer' : 'Online bank transfer'; }, 23 icon: 'ti-building-bank', 24 }, 25 'payment.payment_methods.debit_card': { 26 getLabel: function () { return 'Debit card'; }, 27 icon: 'ti-credit-card', 28 }, 29 'payment.payment_methods.ach_transfer': { 30 getLabel: function () { return 'ACH Transfer'; }, 31 icon: 'ti-building-bank', 32 }, 33 'payment.payment_methods.open_banking': { 34 getLabel: function () { return 'Pay by bank app'; }, 35 icon: 'ti-building-bank', 36 }, 37 }; 38 39 var defaultAmounts = { GB: 100, UK: 100, CA: 100, US: 100 }; 40 41 // --- Dropdown open/close --- 42 43 function initDropdowns() { 44 document.querySelectorAll('.custom-select').forEach(function (select) { 45 var trigger = select.querySelector('.select-trigger'); 46 if (!trigger) return; 47 trigger.addEventListener('click', function (e) { 48 e.stopPropagation(); 49 var isOpen = select.classList.contains('open'); 50 document.querySelectorAll('.custom-select').forEach(function (s) { 51 s.classList.remove('open'); 52 }); 53 if (!isOpen) select.classList.add('open'); 54 }); 55 }); 56 57 document.addEventListener('click', function () { 58 document.querySelectorAll('.custom-select').forEach(function (s) { 59 s.classList.remove('open'); 60 }); 61 }); 62 } 63 64 // --- Country dropdown --- 65 66 function populateCountryDropdown() { 67 var countrySelect = document.querySelector('.custom-select[data-type="country"]'); 68 if (!countrySelect) return; 69 var ul = countrySelect.querySelector('.select-dropdown'); 70 ul.innerHTML = ''; 71 ratesConfig.forEach(function (country) { 72 var flag = flagMap[country.countryCode] || ''; 73 var code = country.currencyCode || country.countryCode; 74 var li = document.createElement('li'); 75 li.dataset.value = country.countryCode; 76 li.innerHTML = '<span>' + flag + '</span> ' + code; 77 li.addEventListener('click', function () { 78 countrySelect.classList.remove('open'); 79 selectCountry(country.countryCode); 80 }); 81 ul.appendChild(li); 82 }); 83 } 84 85 function selectCountry(countryCode) { 86 state.country = ratesConfig.find(function (c) { return c.countryCode === countryCode; }); 87 if (!state.country) return; 88 89 var countrySelect = document.querySelector('.custom-select[data-type="country"]'); 90 if (countrySelect) { 91 var flag = flagMap[countryCode] || ''; 92 var flagEl = countrySelect.querySelector('.select-flag'); 93 var textEl = countrySelect.querySelector('.select-text'); 94 if (flagEl) flagEl.innerHTML = flag; 95 if (textEl) textEl.textContent = state.country.currencyCode || state.country.currency; 96 } 97 98 document.querySelectorAll('.currency-symbol').forEach(function (el) { 99 el.textContent = state.country.currency; 100 }); 101 102 document.getElementById('youPay').value = formatNumber(defaultAmounts[countryCode] || 100); 103 state.lastDirection = true; 104 105 refreshDeliveryMethods(); 106 } 107 108 // --- Delivery methods --- 109 110 function refreshDeliveryMethods() { 111 var seen = []; 112 var methods = []; 113 state.country.paymentOptions.forEach(function (opt) { 114 if (seen.indexOf(opt.deliveryMethod) === -1) { 115 seen.push(opt.deliveryMethod); 116 methods.push(opt.deliveryMethod); 117 } 118 }); 119 120 var preferred = 'payment.delivery_methods.credit_to_account'; 121 var idx = methods.indexOf(preferred); 122 if (idx > 0) { methods.splice(idx, 1); methods.unshift(preferred); } 123 124 var howToSendInput = document.getElementById('howToSend'); 125 var deliverySelect = howToSendInput && howToSendInput.closest('.custom-select'); 126 if (!deliverySelect) return; 127 128 var ul = deliverySelect.querySelector('.select-dropdown'); 129 ul.innerHTML = ''; 130 131 methods.forEach(function (dm) { 132 var display = deliveryMethodDisplay[dm] || { label: dm, icon: '' }; 133 var li = document.createElement('li'); 134 li.dataset.value = dm; 135 li.innerHTML = (display.icon ? '<i class="ti ' + display.icon + '"></i> ' : '') + display.label; 136 li.addEventListener('click', function () { 137 state.deliveryMethod = dm; 138 howToSendInput.value = dm; 139 setTriggerLabel(deliverySelect, display.label, display.icon); 140 deliverySelect.classList.remove('open'); 141 refreshPaymentMethods(); 142 }); 143 ul.appendChild(li); 144 }); 145 146 state.deliveryMethod = methods[0]; 147 howToSendInput.value = methods[0]; 148 var def = deliveryMethodDisplay[methods[0]] || { label: methods[0], icon: '' }; 149 setTriggerLabel(deliverySelect, def.label, def.icon); 150 151 refreshPaymentMethods(); 152 } 153 154 // --- Payment methods --- 155 156 function refreshPaymentMethods() { 157 var options = state.country.paymentOptions.filter(function (opt) { 158 return opt.deliveryMethod === state.deliveryMethod; 159 }); 160 161 var howToPayInput = document.getElementById('howToPay'); 162 var paymentSelect = howToPayInput && howToPayInput.closest('.custom-select'); 163 if (!paymentSelect) return; 164 165 var ul = paymentSelect.querySelector('.select-dropdown'); 166 ul.innerHTML = ''; 167 168 options.forEach(function (opt) { 169 var pm = opt.paymentMethod; 170 var display = paymentMethodDisplay[pm] || { getLabel: function () { return pm; }, icon: '' }; 171 var label = display.getLabel(state.country.countryCode); 172 var li = document.createElement('li'); 173 li.dataset.value = pm; 174 li.innerHTML = (display.icon ? '<i class="ti ' + display.icon + '"></i> ' : '') + label; 175 li.addEventListener('click', function () { 176 state.paymentMethod = pm; 177 howToPayInput.value = pm; 178 setTriggerLabel(paymentSelect, label, display.icon); 179 paymentSelect.classList.remove('open'); 180 recalculate(); 181 }); 182 ul.appendChild(li); 183 }); 184 185 if (options.length > 0) { 186 state.paymentMethod = options[0].paymentMethod; 187 howToPayInput.value = state.paymentMethod; 188 var pmDisplay = paymentMethodDisplay[state.paymentMethod] || { getLabel: function () { return state.paymentMethod; }, icon: '' }; 189 setTriggerLabel(paymentSelect, pmDisplay.getLabel(state.country.countryCode), pmDisplay.icon); 190 } 191 192 recalculate(); 193 } 194 195 // --- Calculation --- 196 197 function recalculate() { 198 if (!state.country || !state.deliveryMethod || !state.paymentMethod) return; 199 200 var option = state.country.paymentOptions.find(function (opt) { 201 return opt.paymentMethod === state.paymentMethod && opt.deliveryMethod === state.deliveryMethod; 202 }); 203 if (!option || !option.ranges || option.ranges.length === 0) return; 204 205 var upperLimit = getUpperLimit(option); 206 if (upperLimit !== null) { 207 var ulEl = document.querySelector('.upper-limit-send'); 208 if (ulEl) ulEl.textContent = formatNumber(upperLimit); 209 } 210 211 var rawStr, amount, result; 212 213 if (state.lastDirection) { 214 rawStr = document.getElementById('youPay').value.replace(/,/g, ''); 215 amount = parseFloat(rawStr); 216 if (isNaN(amount) || amount <= 0) return; 217 result = calculateFromSend(amount, option); 218 if (!result) return; 219 document.getElementById('recipientGets').value = formatNumber(result.recipientGets); 220 } else { 221 rawStr = document.getElementById('recipientGets').value.replace(/,/g, ''); 222 amount = parseFloat(rawStr); 223 if (isNaN(amount) || amount <= 0) return; 224 result = calculateFromReceive(amount, option); 225 if (!result) return; 226 document.getElementById('youPay').value = formatNumber(result.youPay); 227 } 228 229 var isPref = result.preferentialRate && result.preferentialRate > result.rate; 230 var displayFee = isPref ? 0 : result.fee; 231 var totalYouPay = parseFloat(result.youPay) + parseFloat(displayFee); 232 233 setText('.exchangeRate', formatNumber(result.effectiveRate)); 234 setText('.normalExchangeRate', formatNumber(result.rate)); 235 setText('.transferFee', formatNumber(displayFee)); 236 setText('.normalTransferFee', formatNumber(result.fee)); 237 setText('.weSend', formatNumber(totalYouPay)); 238 239 document.querySelectorAll('.info-badge-pref').forEach(function (el) { 240 el.style.display = isPref ? '' : 'none'; 241 }); 242 document.querySelectorAll('.info-usual').forEach(function (el) { 243 el.style.display = isPref ? '' : 'none'; 244 }); 245 } 246 247 function calculateFromSend(youPay, option) { 248 var range = findRange(option.ranges, youPay); 249 if (!range) return null; 250 var effectiveRate = (range.preferentialRate && range.preferentialRate > range.rate) ? range.preferentialRate : range.rate; 251 return { 252 fee: range.fee, 253 rate: range.rate, 254 preferentialRate: range.preferentialRate || null, 255 effectiveRate: effectiveRate, 256 youPay: youPay, 257 recipientGets: youPay * effectiveRate, 258 }; 259 } 260 261 function calculateFromReceive(recipientGets, option) { 262 for (var i = 0; i < option.ranges.length; i++) { 263 var range = option.ranges[i]; 264 var effectiveRate = (range.preferentialRate && range.preferentialRate > range.rate) ? range.preferentialRate : range.rate; 265 var transferAmount = recipientGets / effectiveRate; 266 var rangeMax = range.to > range.from ? range.to : Infinity; 267 if (transferAmount >= range.from && transferAmount <= rangeMax) { 268 return { 269 fee: range.fee, 270 rate: range.rate, 271 preferentialRate: range.preferentialRate || null, 272 effectiveRate: effectiveRate, 273 youPay: transferAmount, 274 recipientGets: recipientGets, 275 }; 276 } 277 } 278 var last = option.ranges[option.ranges.length - 1]; 279 var lastRate = (last.preferentialRate && last.preferentialRate > last.rate) ? last.preferentialRate : last.rate; 280 return { 281 fee: last.fee, 282 rate: last.rate, 283 preferentialRate: last.preferentialRate || null, 284 effectiveRate: lastRate, 285 youPay: recipientGets / lastRate, 286 recipientGets: recipientGets, 287 }; 288 } 289 290 function findRange(ranges, amount) { 291 for (var i = 0; i < ranges.length; i++) { 292 var r = ranges[i]; 293 var max = r.to > r.from ? r.to : Infinity; 294 if (amount >= r.from && amount <= max) return r; 295 } 296 return ranges[ranges.length - 1]; 297 } 298 299 function getUpperLimit(option) { 300 if (!option || !option.ranges || option.ranges.length === 0) return null; 301 var maxTo = null;
302 option.ranges.forEach(function (r) { 303 if (r.to > r.from && (maxTo === null || r.to > maxTo)) maxTo = r.to; 304 }); 305 return maxTo; 306 } 307 308 // --- Helpers --- 309 310 function setTriggerLabel(select, label, iconClass) { 311 var textEl = select.querySelector('.select-trigger .select-text'); 312 var iconEl = select.querySelector('.select-trigger i'); 313 if (textEl) textEl.textContent = label; 314 if (iconEl && iconClass) iconEl.className = 'ti ' + iconClass; 315 } 316 317 function setText(selector, value) { 318 var el = document.querySelector(selector); 319 if (el) el.textContent = value; 320 } 321 322 function formatNumber(num) { 323 return parseFloat(num).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ','); 324 } 325 326 function isDecimalKey(e) { 327 var code = e.which || e.keyCode; 328 if (code !== 46 && code > 31 && (code < 48 || code > 57)) { 329 e.preventDefault(); 330 } 331 } 332 333 // --- Boot --- 334 335 function initCalculator() { 336 if (!ratesConfig || ratesConfig.length === 0) return; 337 338 populateCountryDropdown(); 339 selectCountry(ratesConfig[0].countryCode); 340 341 var youPayEl = document.getElementById('youPay'); 342 var recipientGetsEl = document.getElementById('recipientGets'); 343 344 youPayEl.addEventListener('input', function () { 345 state.lastDirection = true; 346 recalculate(); 347 }); 348 youPayEl.addEventListener('blur', function () { 349 var raw = parseFloat(this.value.replace(/,/g, '')); 350 if (!isNaN(raw) && raw > 0) this.value = formatNumber(raw); 351 }); 352 youPayEl.addEventListener('keypress', isDecimalKey); 353 354 recipientGetsEl.removeAttribute('readonly'); 355 recipientGetsEl.addEventListener('input', function () { 356 state.lastDirection = false; 357 recalculate(); 358 }); 359 recipientGetsEl.addEventListener('keypress', isDecimalKey); 360 } 361 362 function fetchRatesConfig() { 363 var params = new URLSearchParams({ action: 'kabayan_get_rates_config' }); 364 return fetch(window.kabayanCalculator.ajaxUrl + '?' + params.toString()) 365 .then(function (res) { return res.json(); }) 366 .then(function (json) { 367 ratesConfig = (json && json.success && json.data) || []; 368 }) 369 .catch(function () { 370 ratesConfig = []; 371 }); 372 } 373 374 document.addEventListener('DOMContentLoaded', function () { 375 initDropdowns(); 376 fetchRatesConfig().then(initCalculator); 377 }); 378})();
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.