# easy-invoice/2.3.6/assets/js/invoice-form.js

Easy Invoice – Invoice Generator, PDF Quotes &amp; Payments, version 2.3.6. 490 lines.

- Page: https://pluginprobe.com/plugins/easy-invoice/2.3.6/code/assets/js/invoice-form.js
- Raw: https://pluginprobe.com/plugins/easy-invoice/2.3.6/raw/assets/js/invoice-form.js
- Modified: 2026-05-21T08:29:24+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/easy-invoice/2.3.6/code/assets/js/invoice-form.js#L10-L20`.

```javascript
jQuery(document).ready(function($) {
    // Determine if this is a quote form
    const isQuoteForm = window.isQuoteForm || false;
    const formType = isQuoteForm ? 'quote' : 'invoice';
    const templateFieldName = isQuoteForm ? 'quote_template' : 'invoice_template';
    const previewClass = isQuoteForm ? 'quote-preview' : 'invoice-preview';
    
    // Function to get URL parameter
    function getUrlParameter(name) {
        name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
        var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
        var results = regex.exec(location.search);
        return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
    }
    
    // Function to switch to a specific tab
    function switchToTab(tabId) {
        if (tabId && $('#' + tabId).length) {
            // Remove active state from all tabs
            $('.tab-button').removeClass('border-indigo-500 text-indigo-600').addClass('border-transparent text-gray-500');
            $('.tab-content').addClass('hidden');
            
            // Activate the specified tab
            $('.tab-button[data-tab="' + tabId + '"]').addClass('border-indigo-500 text-indigo-600');
            $('#' + tabId).removeClass('hidden');
            
            // Update URL without page reload
            var url = new URL(window.location);
            url.searchParams.set('tab', tabId);
            window.history.replaceState({}, '', url);
        }
    }
    
    // Make switchToTab globally available
    window.switchToTab = switchToTab;
    
    // Check for tab parameter on page load
    var initialTab = getUrlParameter('tab');
    if (initialTab) {
        switchToTab(initialTab);
    }
    
    // Tab switching
    $('.tab-button').on('click', function() {
        var tabId = $(this).data('tab');
        switchToTab(tabId);
    });
    
    // Remove the updateTemplatePreview function and all quote-specific template preview logic
    // (No need to handle quote template preview here anymore)
    
    // Handle template selection after page reload
    const selectedTemplate = sessionStorage.getItem('selectedTemplate');
    if (selectedTemplate) {

        
        // Update the hidden input field
        $('input[name="' + templateFieldName + '"][type="hidden"]').val(selectedTemplate);
        
        // Update the radio button if it exists
        let radioInput = $('input[name="' + templateFieldName + '"][type="radio"][value="' + selectedTemplate + '"]');
        if (radioInput.length > 0) {
            $('input[name="' + templateFieldName + '"][type="radio"]').prop('checked', false);
            radioInput.prop('checked', true);
        }
        
        // Update the visual state and trigger click event
        $('.template-card').removeClass('selected');
        const selectedCard = $('.template-card[data-template-id="' + selectedTemplate + '"]');
        if (selectedCard.length > 0) {
            selectedCard.addClass('selected');
            // Trigger click event to ensure all handlers are executed
            selectedCard.trigger('click');
        }
        
        // Clear the sessionStorage
        sessionStorage.removeItem('selectedTemplate');
    } else {
        // Handle initial template state for existing invoices/quotes
        const currentTemplate = $('input[name="' + templateFieldName + '"][type="hidden"]').val();
        
        if (currentTemplate) {
    
            
            // Update the radio button if it exists
            let radioInput = $('input[name="' + templateFieldName + '"][type="radio"][value="' + currentTemplate + '"]');
            if (radioInput.length > 0) {
                $('input[name="' + templateFieldName + '"][type="radio"]').prop('checked', false);
                radioInput.prop('checked', true);
            }
            
            // Update the visual state
            $('.template-card').removeClass('selected');
            const selectedCard = $('.template-card[data-template-id="' + currentTemplate + '"]');
            if (selectedCard.length > 0) {
                selectedCard.addClass('selected');
            }
            
            // Update the preview
            //updateTemplatePreview(currentTemplate);
        }
    }
    
    
    
    // Initialize item counter
    let itemCounter = $('.invoice-item, .quote-item').length;
    
    // Auto-calculate totals when quantity or price changes
    $(document).on('input', 'input[name="item-quantity[]"], input[name="item-price[]"]', function() {
        // This will be handled by invoice-builder.js
        if (window.EasyInvoiceBuilder && typeof window.EasyInvoiceBuilder.calculateItemTotal === 'function') {
            window.EasyInvoiceBuilder.calculateItemTotal($(this).closest('.invoice-item, .quote-item'));
        }
    });
    
    // Both buttons should open the template gallery - using event delegation for better reliability
    $(document).on('click', '#browse-all-templates, #browse-templates-btn', function(e) {
        e.preventDefault();
        e.stopPropagation();
        
        // Check if this is the free version
        const isFreeVersion = !window.easyInvoice || !window.easyInvoice.isPro;
        
        if (isFreeVersion) {
            // Show premium upgrade modal for free users
            if (typeof EasyInvoiceConfirmation !== 'undefined' && EasyInvoiceConfirmation.showFeatureUpgrade) {
                const title = window.easyInvoice && window.easyInvoice.translations ? window.easyInvoice.translations.premiumTemplates : 'Premium Templates';
                const description = window.easyInvoice && window.easyInvoice.translations ? window.easyInvoice.translations.premiumTemplatesDescription : 'Access all premium templates including Modern, Professional, Classic, and more to give your invoices a unique and professional look.';
                EasyInvoiceConfirmation.showFeatureUpgrade(title, description);
            } else {
                const message = window.easyInvoice && window.easyInvoice.translations ? window.easyInvoice.translations.premiumFeatureMessage : 'This is a premium feature. Please upgrade to Pro to access all templates.';
                if (typeof EasyInvoiceToast !== 'undefined') {
                    EasyInvoiceToast.show('info', message);
                }
            }
        } else {
            // Pro users can browse all templates
            $('#template-gallery-modal').fadeIn();
            
            // Highlight the currently selected template in the gallery
            const currentTemplate = $('input[name="' + templateFieldName + '"]:checked').val();
            if (currentTemplate) {
                $('.gallery-template-card').removeClass('selected');
                $('.gallery-template-card[data-template-id="' + currentTemplate + '"]').addClass('selected');
            }
        }
    });
    


    // Template card click handler in main grid
    $('.template-card').on('click', function(e) {
        // If clicking on premium upgrade button, handle separately
        if ($(e.target).hasClass('premium-upgrade-btn') || $(e.target).closest('.premium-upgrade-btn').length) {
            return;
        }
        
        const templateId = $(this).data('template-id');
        const radioInput = $(this).find('input[type="radio"]');
        
        // Check if this is a premium template in free version
        const isPremium = $(this).attr('data-is-premium') === 'true';
        const isFreeVersion = !window.easyInvoice || !window.easyInvoice.isPro;
        
        if (isPremium && isFreeVersion) {
            // Show premium upgrade modal instead of selecting the template
            if (typeof EasyInvoiceConfirmation !== 'undefined' && EasyInvoiceConfirmation.showFeatureUpgrade) {
                const title = window.easyInvoice && window.easyInvoice.translations ? window.easyInvoice.translations.premiumTemplates : 'Premium Templates';
                const description = window.easyInvoice && window.easyInvoice.translations ? window.easyInvoice.translations.premiumTemplatesDescription : 'Access all premium templates including Modern, Professional, Classic, and more to give your invoices a unique and professional look.';
                EasyInvoiceConfirmation.showFeatureUpgrade(title, description);
            } else {
                const message = window.easyInvoice && window.easyInvoice.translations ? window.easyInvoice.translations.premiumFeatureMessage : 'This is a premium feature. Please upgrade to Pro to access all templates.';
                if (typeof EasyInvoiceToast !== 'undefined') {
                    EasyInvoiceToast.show('info', message);
                }
            }
            return;
        }
        
        // Check the radio input within this card
        radioInput.prop('checked', true);
        
        // Update the hidden input field value
        $('input[name="' + templateFieldName + '"][type="hidden"]').val(templateId);
        
        // Update the visual state
        $('.template-card').removeClass('selected');
        $(this).addClass('selected');
        
        // No need to call updateTemplatePreview for quotes
    });
    

    
    // Apply button click handler
    $('#apply-selected-template').on('click', function() {
        // Get the selected template from the gallery
        const selectedGalleryCard = $('.gallery-template-card.selected');
        
        if (selectedGalleryCard.length === 0) {
            // If no template is selected, show an error message and return
            const message = window.easyInvoice && window.easyInvoice.translations ? window.easyInvoice.translations.selectTemplateFirst : 'Please select a template first';
            if (typeof EasyInvoiceToast !== 'undefined') {
                EasyInvoiceToast.show('error', message);
            }
            return;
        }
        
        const templateId = selectedGalleryCard.data('template-id');
        const templateName = selectedGalleryCard.find('.font-medium').text();
        const templateDescription = selectedGalleryCard.find('.text-sm.text-gray-600').text();
        const templateIcon = selectedGalleryCard.find('i').attr('class');
        const isPremium = selectedGalleryCard.data('is-premium') === 'true';

        // Store the selected template in sessionStorage for after page reload
        sessionStorage.setItem('selectedTemplate', templateId);
        
        // Update the hidden input field value
        $('input[name="' + templateFieldName + '"][type="hidden"]').val(templateId);
        
        // Update the main template grid
        updateMainTemplateGrid(templateId, templateName, templateDescription, templateIcon, isPremium);
        
        // Close the modal
        $('#template-gallery-modal').fadeOut();
    });
    
    // Close gallery modal
    $('.close-gallery-modal, .gallery-close-btn').on('click', function() {
        $('#template-gallery-modal').fadeOut();
    });
    
    // Close gallery when clicking outside of it
    $(window).on('click', function(e) {
        if ($(e.target).is('#template-gallery-modal')) {
            $('#template-gallery-modal').fadeOut();
        }
    });
    
    // Gallery template card click handler - just selects the template visually
    $('.gallery-template-card').on('click', function(e) {
        // If clicking on the favorite icon, handle separately
        if ($(e.target).hasClass('template-favorite') || $(e.target).closest('.template-favorite').length) {
            return;
        }
        
        // Update the visual state in the gallery
        $('.gallery-template-card').removeClass('selected');
        $(this).addClass('selected');
        

    });
    

    


    // Client selection functionality - only for invoice forms, not quote forms
    if (!isQuoteForm) {
        $('#select-client').on('change', function() {
            const selectedClientId = $(this).val();
            const $clientInfoDisplay = $('#client-info-display');
            const $noClientMessage = $('#no-client-message');
            const $clientIdField = $('#client-id');

            if (selectedClientId) {
                // Set the hidden client ID field
                $clientIdField.val(selectedClientId);
                
                // Get client information via AJAX
                loadClientInformation(selectedClientId);
                
                // Show client info display, hide no client message
                $clientInfoDisplay.removeClass('hidden');
                $noClientMessage.addClass('hidden');
            } else {
                // Clear the hidden client ID field
                $clientIdField.val('');
                
                // Hide client info display, show no client message
                $clientInfoDisplay.addClass('hidden');
                $noClientMessage.removeClass('hidden');
                
                // Clear all display fields
                clearClientDisplay();
            }
        });
    }

    // Function to load client information
    function loadClientInformation(clientId) {
        // First check if we have client data already loaded from PHP
        if (typeof easyInvoice !== 'undefined' && easyInvoice.clientData && easyInvoice.clientData.id == clientId) {
            const clientData = easyInvoice.clientData;
            populateClientDisplay(clientData);
            return;
        }
        
        // If we don't have the client data pre-loaded, we should load it via PHP
        // This should not happen in normal circumstances since client data is loaded on page load
                    // Client data not found in pre-loaded data
                clearClientDisplay();
    }

    // Function to populate client display
    function populateClientDisplay(clientData) {
        $('#display-client-name').text(clientData.name || '-');
        $('#display-client-email').text(clientData.email || '-');
        $('#display-client-phone').text(clientData.phone || '-');
        $('#display-client-company').text(clientData.company || '-');
        $('#display-client-address').text(clientData.address || '-');
        $('#display-client-website').text(clientData.website || '-');
    }

    // Function to clear client display
    function clearClientDisplay() {
        $('#display-client-name').text('-');
        $('#display-client-email').text('-');
        $('#display-client-phone').text('-');
        $('#display-client-company').text('-');
        $('#display-client-address').text('-');
        $('#display-client-website').text('-');
    }

    // Function to update main template grid when template is selected from popup
    function updateMainTemplateGrid(templateId, templateName, templateDescription, templateIcon, isPremium) {
        const $mainGrid = $('#main-templates-grid');
        const $existingCards = $mainGrid.find('.template-card');
        
        // Check if the selected template already exists in the main grid
        const $existingCard = $mainGrid.find('.template-card[data-template-id="' + templateId + '"]');
        
        if ($existingCard.length > 0) {
            // Template already exists, just select it and don't add duplicates
            $existingCard.addClass('selected');
            $existingCard.find('input[type="radio"]').prop('checked', true);
            $mainGrid.find('.template-card').not($existingCard).removeClass('selected');
            return;
        }
        
        // If we have 3 templates and the new one doesn't exist, replace the currently selected one
        if ($existingCards.length >= 3) {
            const $selectedCard = $mainGrid.find('.template-card.selected');
            if ($selectedCard.length > 0) {
                $selectedCard.remove();
            } else {
                // If no template is selected, remove the first one
                $existingCards.first().remove();
            }
        }
        
        // Create new template card HTML
        const isFreeVersion = !window.easyInvoice || !window.easyInvoice.isPro;
        const premiumClasses = (isPremium && isFreeVersion) ? 'premium-template-blurred' : '';
        const disabledAttr = (isPremium && isFreeVersion) ? 'disabled' : '';
        
        const newCardHtml = `
            <div class="template-card selected ${premiumClasses}" data-template-id="${templateId}" data-is-premium="${isPremium}">
                <input type="radio" id="template-${templateId}" name="${templateFieldName}" value="${templateId}" class="template-radio" checked ${disabledAttr}>
                <div class="p-4 border rounded-lg">
                    <div class="flex items-center mb-2">
                        <i class="${templateIcon} text-indigo-600 mr-2"></i>
                        <span class="font-medium">${templateName}</span>
                    </div>
                    <p class="text-sm text-gray-600">${templateDescription}</p>
                    <div class="mt-2 flex-grow">
                        <div class="template-preview bg-gray-100 rounded h-16 flex items-center justify-center ${templateId}">
                        </div>
                    </div>
                </div>
            </div>
        `;
        
        // Add the new template card to the main grid
        $mainGrid.append(newCardHtml);
        
        // Update the visual state - ensure only the new template is selected
        $mainGrid.find('.template-card').removeClass('selected');
        $mainGrid.find('.template-card[data-template-id="' + templateId + '"]').addClass('selected');
    }
    
    // Save to Item Library functionality
    $(document).on('click', '.save-to-library-btn', function(e) {
        e.preventDefault();
        
        var $btn = $(this);
        var itemIndex = $btn.data('item-index');
        // Find the closest item container (either invoice-item or quote-item)
        var $itemContainer = $btn.closest('.invoice-item, .quote-item');

        if (!$itemContainer.length) {
            return;
        }
        
        // Get item data from the form
        var itemData = {
            title: '',
            description: '',
            price: 0,
            quantity: 0,
            taxable: 0
        };
        
        // Extract data from the item fields
        $itemContainer.find('input, textarea, select').each(function() {
            var $field = $(this);
            var name = $field.attr('name');
            var value = $field.val();
            var type = $field.attr('type');
            
            if (name) {
                // Handle array names like items[0][title] or quote_items[0][title]
                var matches = name.match(/(items|quote_items)\[\d+\]\[(.+)\]/);
                if (matches && matches[2]) {
                    if (type === 'checkbox' || type === 'radio') {
                        itemData[matches[2]] = $field.is(':checked') ? 1 : 0;
                    } else {
                        itemData[matches[2]] = value;
                    }
                }
            }
        });
        
        // Convert numeric fields
        itemData.price = parseFloat(itemData.price) || 0;
        itemData.quantity = parseInt(itemData.quantity) || 0;
        itemData.taxable = parseInt(itemData.taxable) || 0;

        // Validate required fields
        if (!itemData.title || !itemData.title.trim()) {
            if (typeof EasyInvoiceToast !== 'undefined') {
                EasyInvoiceToast.error('Please fill in item title before saving to library');
            } else {
                alert('Please fill in item title before saving to library');
            }
            return;
        }
        
        if (!itemData.price || itemData.price <= 0) {
            if (typeof EasyInvoiceToast !== 'undefined') {
                EasyInvoiceToast.error('Please fill in item price before saving to library');
            } else {
                alert('Please fill in item price before saving to library');
            }
            return;
        }
        
        // Show loading state
        var originalHtml = $btn.html();
        $btn.html('<i class="fas fa-spinner fa-spin"></i>').prop('disabled', true);
        
        // AJAX call to save to item library
        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'easy_invoice_pro_add_item',
                nonce: $btn.data('nonce'),
                item_data: JSON.stringify(itemData)
            },
            success: function(response) {
                if (response.success) {
                    if (typeof EasyInvoiceToast !== 'undefined') {
                        EasyInvoiceToast.success('Item saved to library successfully!');
                    } else {
                        alert('Item saved to library successfully!');
                    }
                } else {
                    if (typeof EasyInvoiceToast !== 'undefined') {
                        EasyInvoiceToast.error(response.data.message || 'Failed to save item');
                    } else {
                        alert('Failed to save item: ' + (response.data.message || 'Unknown error'));
                    }
                }
            },
            error: function() {
                if (typeof EasyInvoiceToast !== 'undefined') {
                    EasyInvoiceToast.error('Error saving item to library');
                } else {
                    alert('Error saving item to library');
                }
            },
            complete: function() {
                // Restore button
                $btn.html(originalHtml).prop('disabled', false);
            }
        });
    });
}); 
```
