PageSourceSearch

https://kabayanremit.com/wp-content/themes/kabayanremitv2/js/calculator.js?ver=1785324113

js kabayanremit.com collected 2026-09-24 10:13:59 UTC 13,772 bytes, 378 lines download raw bytes

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.