/** * Formipay Checkout Shipping Integration * Handles country selection, shipping method display, and cost calculation */ (function($) { 'use strict'; const FormipayCheckoutShipping = { selectedCountry: '', selectedMethod: '', availableMethods: [], formId: null, init() { this.formId = $('form[data-form-id]').data('form-id'); if (!this.formId) { return; } this.bindEvents(); this.initializeCountrySelector(); }, bindEvents() { // Country selection change $(document).on('change', '.formipay-shipping-country', (e) => { this.onCountryChange($(e.currentTarget).val()); }); // Shipping method selection change $(document).on('change', '.formipay-shipping-method', (e) => { this.onShippingMethodChange($(e.currentTarget).val()); }); }, initializeCountrySelector() { // Check if this form has shipping enabled if (this.isShippingEnabled()) { // Add country selector before payment options this.insertCountrySelector(); } }, isShippingEnabled() { // Check if shipping is enabled for this form // With form-level shipping, we check shipping_enabled setting return window.formipayFormData?.shipping_enabled && window.formipayFormData.shipping_enabled !== 'no_shipping'; }, insertCountrySelector() { const orderReviewTable = $('#formipay-review-order'); if (orderReviewTable.length === 0) { return; } // Create country selector row before subtotal const countryRow = ` `; orderReviewTable.find('tbody').append(countryRow); // Populate countries from settings this.loadCountries(); }, loadCountries() { // Get supported countries from shipping settings $.ajax({ url: formipay_admin.ajaxUrl, type: 'POST', data: { action: 'formipay_get_supported_countries', nonce: formipay_admin.nonce, form_id: this.formId }, success: (response) => { if (response.success && response.data.countries) { this.populateCountries(response.data.countries); } }, error: () => { // Fallback: show all countries this.populateCountries(this.getAllCountries()); } }); }, populateCountries(countries) { const select = $(`#shipping-country-${this.formId}`); select.find('option:not([value=""])').remove(); $.each(countries, (code, name) => { select.append(``); }); }, getAllCountries() { // Fallback country list return { 'ID': 'Indonesia', 'MY': 'Malaysia', 'SG': 'Singapore', 'TH': 'Thailand', 'VN': 'Vietnam', 'PH': 'Philippines', 'TW': 'Taiwan', 'HK': 'Hong Kong', 'IN': 'India', 'CN': 'China', 'JP': 'Japan', 'KR': 'South Korea', 'AU': 'Australia', 'NZ': 'New Zealand', 'GB': 'United Kingdom', 'US': 'United States', 'CA': 'Canada', 'FR': 'France', 'DE': 'Germany', 'IT': 'Italy', 'ES': 'Spain', 'NL': 'Netherlands', 'BE': 'Belgium', 'CH': 'Switzerland', 'AT': 'Austria', 'IE': 'Ireland', 'DK': 'Denmark', 'SE': 'Sweden', 'NO': 'Norway', 'FI': 'Finland', }; }, onCountryChange(countryCode) { this.selectedCountry = countryCode; if (!countryCode) { this.hideShippingMethods(); return; } // Get available shipping methods for this country this.fetchShippingMethods(countryCode); }, fetchShippingMethods(countryCode) { const spinner = $('.formipay-loading-spinner'); spinner.show(); $.ajax({ url: formipay_admin.ajaxUrl, type: 'POST', data: { action: 'formipay_get_shipping_methods', nonce: formipay_public.nonce, form_id: this.formId, country: countryCode, currency: formipay.currency_code || 'IDR' }, success: (response) => { spinner.hide(); if (response.success) { this.availableMethods = response.data.methods || []; this.displayShippingMethods(this.availableMethods, response.data.default_method); } else { this.showError(response.data.message || 'Unable to load shipping methods'); } }, error: () => { spinner.hide(); this.showError('Unable to connect to shipping service'); } }); }, displayShippingMethods(methods, defaultMethod) { // Remove existing shipping method selector if any $('.formipay-shipping-method-row').remove(); if (methods.length === 0) { this.showError('Shipping is not available for this form'); return; } // Get order total for percentage calculations const orderTotal = this.getOrderTotal(); let methodsHtml = '
'; methodsHtml += ``; $.each(methods, (index, method) => { const methodId = method.id; const isFree = method.cost === 0; const isPercentage = method.type === 'percentage'; // Calculate actual cost let actualCost = method.cost; let costDisplay = ''; if (isFree) { costDisplay = 'FREE'; } else if (isPercentage) { actualCost = (orderTotal * method.cost) / 100; costDisplay = `${method.cost}% (${this.formatCost(actualCost, method.currency)})`; } else { costDisplay = this.formatCost(method.cost, method.currency); } methodsHtml += `
`; }); methodsHtml += '
'; // Insert after country selector const countryRow = $('.formipay-shipping-row'); const shippingRow = ` ${methodsHtml} `; countryRow.after(shippingRow); // Bind shipping method change events $('.formipay-shipping-method').on('change', (e) => { const target = $(e.currentTarget); const cost = parseFloat(target.data('cost')); const type = target.data('type'); const baseCost = parseFloat(target.data('base-cost')); const method = target.val(); // For percentage, recalculate in case order total changed let finalCost = cost; if (type === 'percentage') { finalCost = (this.getOrderTotal() * baseCost) / 100; } // Update hidden input $('.formipay-shipping-method-input').val(method); // Update order total this.updateOrderTotal(finalCost); }); // Trigger change on default method to set initial cost $(`input[name="shipping_method_display"][value="${defaultMethod}"]`).trigger('change'); }, hideShippingMethods() { $('.formipay-shipping-method-row').remove(); }, getOrderTotal() { // Get current order total (excluding shipping) const subtotalRow = $('.formipay-total-row td').text(); const subtotal = this.parseCurrency(subtotalRow); return subtotal; }, updateOrderTotal(shippingCost) { const currentTotal = this.getOrderTotal(); const newTotal = currentTotal + shippingCost; // Update the total display const totalRow = $('.formipay-grand-total-row td'); totalRow.text(this.formatCost(newTotal)); // Update submit button const submitBtn = $('.formipay-submit-button'); const currentText = submitBtn.attr('data-button-text'); submitBtn.html(`${currentText} - ${this.formatCost(newTotal)}`); }, formatCost(cost, currency) { // Format cost using same format as product prices const formatted = cost.toFixed(formipay.decimal_digits || 2); return (currency || formipay.currency || '') + ' ' + formatted; }, parseCurrency(text) { // Parse currency string to get numeric value // Removes currency symbols and formats const numeric = text.replace(/[^\d.-]/g, ''); return parseFloat(numeric) || 0; }, showError(message) { const errorHtml = `

${message}

`; $('.formipay-shipping-method-row').html(`${errorHtml}`); } }; // Initialize when document is ready $(document).ready(() => { if (typeof formipay_shipping !== 'undefined' && typeof formipay_shipping.labels !== 'undefined') { FormipayCheckoutShipping.init(); } }); // Expose for global access window.FormipayCheckoutShipping = FormipayCheckoutShipping; })(jQuery);