jQuery(document).ready(function($) { // Check if we're on the builder page to avoid conflicts with invoice-builder.js const isBuilderPage = window.location.href.indexOf('easy-invoice-new') !== -1 || window.location.href.indexOf('page=easy-invoice-new') !== -1 || window.location.href.indexOf('easy-invoice-edit') !== -1 || window.location.href.indexOf('page=easy-invoice-edit') !== -1; // If we're on the builder page, don't initialize the old invoice builder // as it will conflict with the new invoice-builder.js if (isBuilderPage) { return; } // Initialize invoice builder function initInvoiceBuilder() { // Wait for the template to be available const template = document.getElementById('invoice-item-template'); if (!template) { // Invoice item template not found return; } // Initialize tabs initTabs(); // Add event listener for "Add Item" button - now handled in invoice-builder.js // Add event listener for removing items $(document).on('click', '.remove-item', function() { const item = $(this).closest('.invoice-item'); item.addClass('opacity-0'); setTimeout(() => { item.remove(); updatePreview(); }, 200); }); // Add event listener for collapsing/expanding items $(document).on('click', '.item-collapse-toggle', function() { const item = $(this).closest('.invoice-item'); const itemContent = item.find('.item-content'); const summaryElement = item.find('.item-collapsed-summary'); const icon = $(this).find('i'); // Update the summary before collapsing if (itemContent.is(':visible')) { updateItemSummary(item); // Collapse itemContent.slideUp(200); summaryElement.slideDown(200); icon.removeClass('fa-chevron-down').addClass('fa-chevron-right'); } else { // Expand itemContent.slideDown(200); summaryElement.slideUp(200); icon.removeClass('fa-chevron-right').addClass('fa-chevron-down'); } }); // Add event listeners for all form inputs $('#invoice-form').on('input', 'input, textarea', function() { updatePreview(); }); // Add event listeners for taxable item clicking $(document).on('click', '.taxable-item-container', function(e) { // Don't toggle if clicking directly on the checkbox (let the default behavior handle it) if (e.target.type === 'checkbox') { return; } // Prevent default behavior if this is a label click to avoid double toggling if (e.target.tagName.toLowerCase() === 'label') { e.preventDefault(); } const checkbox = $(this).find('input[type="checkbox"]'); checkbox.prop('checked', !checkbox.prop('checked')); updatePreview(); }); // Add event listener for taxable checkbox changes $(document).on('change', 'input[name="item-taxable[]"]', function() { updatePreview(); }); // Add auto-calculate for quantity and price $(document).on('input', 'input[name="item-quantity[]"], input[name="item-price[]"]', function() { const item = $(this).closest('.invoice-item'); calculateItemTotal(item); }); // Add keyboard shortcuts $(document).on('keydown', function(e) { // Ctrl/Cmd + Enter to save if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { e.preventDefault(); $('button:contains("Save Draft")').click(); } // Ctrl/Cmd + Shift + Enter to send if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'Enter') { e.preventDefault(); $('button:contains("Send Invoice")').click(); } }); // Initialize with one item } // Initialize tab functionality function initTabs() { // Check if we're on an invoice page - if so, let invoice-builder.js handle tabs if (window.location.href.includes('easy-invoice-builder') || window.location.href.includes('easy-invoice-new') || $('.invoice-item').length > 0) { return; } // Add click event listeners to tab buttons $('.tab-button').on('click', function() { const tabId = $(this).data('tab'); // Remove active class from all tabs and buttons $('.tab-button').removeClass('active'); $('.tab-button').removeClass('text-indigo-600').addClass('text-gray-500'); $('.tab-button').removeClass('border-indigo-500').addClass('border-transparent'); $('.tab-content').removeClass('active').addClass('hidden'); // Add active class to clicked tab and its content $(this).addClass('active'); $(this).removeClass('text-gray-500').addClass('text-indigo-600'); $(this).removeClass('border-transparent').addClass('border-indigo-500'); $('#' + tabId).removeClass('hidden').addClass('active'); // If the items tab is active, make sure the items are properly sized if (tabId === 'items-tab') { updateItemSummaries(); } }); // Handle tab navigation via keyboard $('.tab-button').on('keydown', function(e) { // Arrow right or arrow down if (e.key === 'ArrowRight' || e.key === 'ArrowDown') { e.preventDefault(); const nextTab = $(this).next('.tab-button'); if (nextTab.length) { nextTab.click(); nextTab.focus(); } } // Arrow left or arrow up if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') { e.preventDefault(); const prevTab = $(this).prev('.tab-button'); if (prevTab.length) { prevTab.click(); prevTab.focus(); } } }); } // Update all item summaries function updateItemSummaries() { $('.invoice-item').each(function() { updateItemSummary($(this)); }); } // Add a new invoice item // Calculate total for a single item function calculateItemTotal(item) { const quantity = parseFloat(item.find('input[name="item-quantity[]"]').val()) || 0; const price = parseFloat(item.find('input[name="item-price[]"]').val()) || 0; const isTaxable = item.find('input[name="item-taxable[]"]').is(':checked'); const pricesIncludeTax = $('#prices-include-tax').val() === 'yes'; const taxRate = parseFloat($('#tax-rate').val()) || 0; let total = quantity * price; // We don't need to adjust the displayed total in the item form // The tax/non-tax calculation is handled in the updatePreview function item.find('input[name="item-total[]"]').val(total.toFixed(2)); // Update the summary fields updateItemSummary(item); updatePreview(); } // Update the collapsed summary of an item function updateItemSummary(item) { const quantity = parseFloat(item.find('input[name="item-quantity[]"]').val()) || 0; const price = parseFloat(item.find('input[name="item-price[]"]').val()) || 0; const total = quantity * price; item.find('.quantity-summary').text(quantity); item.find('.price-summary').text(price.toFixed(2)); item.find('.total-summary').text(total.toFixed(2)); } // Update the preview panel function updatePreview() { // Add loading state $('#preview-items').addClass('loading'); // Update customer info $('#preview-customer-name').text($('#customer-name').val() || 'Customer Name'); $('#preview-customer-email').text($('#customer-email').val() || 'customer@example.com'); // Update invoice details $('#preview-invoice-number').text($('#invoice-number').val()); $('#preview-invoice-date').text(formatDate($('#invoice-date').val())); $('#preview-due-date').text(formatDate($('#due-date').val())); $('#preview-invoice-title').text($('#invoice-title').val() || 'Invoice Title'); $('#preview-invoice-description').text($('#invoice-description').val() || 'Invoice description will appear here.'); // Get tax settings const taxRate = parseFloat($('#tax-rate').val()) || 0; const pricesIncludeTax = $('#prices-include-tax').val() === 'yes'; // Update items let subtotal = 0; let taxableSubtotal = 0; const previewItemsContainer = $('#preview-items'); previewItemsContainer.empty(); $('.invoice-item').each(function() { const title = $(this).find('input[name="item-title[]"]').val() || 'Item Title'; const description = $(this).find('textarea[name="item-description[]"]').val() || ''; const quantity = parseFloat($(this).find('input[name="item-quantity[]"]').val()) || 0; let price = parseFloat($(this).find('input[name="item-price[]"]').val()) || 0; const isTaxable = $(this).find('input[name="item-taxable[]"]').is(':checked'); // If prices include tax and this item is taxable, we need to extract the tax // to get the real pre-tax price for calculations let displayPrice = price; if (pricesIncludeTax && isTaxable) { price = price / (1 + (taxRate / 100)); } const total = quantity * price; subtotal += total; if (isTaxable) { taxableSubtotal += total; } const itemRow = `