invoicewizard-pro / script.js
vickey333's picture
site not working
59a3f60 verified
Raw History Blame Contribute Delete
11.4 kB
document.addEventListener('DOMContentLoaded', function() {
let itemCount = 0;
const itemsTable = document.getElementById('itemsTable');
// Load saved "From" details if they exist
const savedFromDetails = JSON.parse(localStorage.getItem('fromDetails')) || {};
if (savedFromDetails.businessName) {
document.querySelector('input[placeholder="Your Business Name"]').value = savedFromDetails.businessName;
}
if (savedFromDetails.address) {
document.querySelector('input[placeholder="Address"]').value = savedFromDetails.address;
}
if (savedFromDetails.cityStateZip) {
document.querySelector('input[placeholder="City, State, ZIP"]').value = savedFromDetails.cityStateZip;
}
if (savedFromDetails.email) {
document.querySelector('input[placeholder="Email"]').value = savedFromDetails.email;
}
if (savedFromDetails.phone) {
document.querySelector('input[placeholder="Phone"]').value = savedFromDetails.phone;
}
// Save "From" details when they change
const fromInputs = document.querySelectorAll('input[placeholder^="Your"]');
fromInputs.forEach(input => {
input.addEventListener('change', () => {
const fromDetails = {
businessName: document.querySelector('input[placeholder="Your Business Name"]').value,
address: document.querySelector('input[placeholder="Address"]').value,
cityStateZip: document.querySelector('input[placeholder="City, State, ZIP"]').value,
email: document.querySelector('input[placeholder="Email"]').value,
phone: document.querySelector('input[placeholder="Phone"]').value
};
localStorage.setItem('fromDetails', JSON.stringify(fromDetails));
});
});
const addItemBtn = document.getElementById('addItemBtn');
const generateBtn = document.getElementById('generateBtn');
const closeModalBtn = document.getElementById('closeModalBtn');
const printBtn = document.getElementById('printBtn');
const downloadBtn = document.getElementById('downloadBtn');
const invoiceModal = document.getElementById('invoiceModal');
const invoiceContent = document.getElementById('invoiceContent');
const taxRateInput = document.getElementById('taxRate');
// Add new item row
addItemBtn.addEventListener('click', addItemRow);
// Generate invoice
generateBtn.addEventListener('click', generateInvoice);
// Close modal
closeModalBtn.addEventListener('click', () => {
invoiceModal.classList.add('hidden');
});
// Print invoice
printBtn.addEventListener('click', () => {
window.print();
});
// Download as PDF (placeholder functionality)
downloadBtn.addEventListener('click', () => {
alert('PDF download functionality would be implemented here with a library like jsPDF');
});
// Recalculate totals when tax rate changes
taxRateInput.addEventListener('change', calculateTotals);
// Add initial item row
addItemRow();
function addItemRow() {
itemCount++;
const row = document.createElement('tr');
row.className = 'item-row';
row.innerHTML = `
<td class="px-6 py-4 whitespace-nowrap">
<input type="text" class="w-full px-2 py-1 border rounded description" placeholder="Item description">
</td>
<td class="px-6 py-4 whitespace-nowrap">
<input type="number" min="1" value="1" class="w-20 px-2 py-1 border rounded quantity">
</td>
<td class="px-6 py-4 whitespace-nowrap">
<input type="number" min="0" step="0.01" value="0.00" class="w-24 px-2 py-1 border rounded price">
</td>
<td class="px-6 py-4 whitespace-nowrap item-total font-medium">$0.00</td>
<td class="px-6 py-4 whitespace-nowrap">
<button class="delete-item text-red-500 hover:text-red-700">
<i data-feather="trash-2"></i>
</button>
</td>
`;
itemsTable.appendChild(row);
feather.replace();
// Add event listeners for the new row
const quantityInput = row.querySelector('.quantity');
const priceInput = row.querySelector('.price');
const deleteBtn = row.querySelector('.delete-item');
quantityInput.addEventListener('input', calculateRowTotal);
priceInput.addEventListener('input', calculateRowTotal);
deleteBtn.addEventListener('click', () => {
row.remove();
calculateTotals();
});
function calculateRowTotal() {
const quantity = parseFloat(quantityInput.value) || 0;
const price = parseFloat(priceInput.value) || 0;
const total = quantity * price;
row.querySelector('.item-total').textContent = `$${total.toFixed(2)}`;
calculateTotals();
}
}
function calculateTotals() {
const rows = document.querySelectorAll('.item-row');
let subtotal = 0;
rows.forEach(row => {
const totalText = row.querySelector('.item-total').textContent;
subtotal += parseFloat(totalText.replace('$', '')) || 0;
});
const taxRate = parseFloat(taxRateInput.value) || 0;
const taxAmount = subtotal * (taxRate / 100);
const total = subtotal + taxAmount;
document.getElementById('subtotal').textContent = `$${subtotal.toFixed(2)}`;
document.getElementById('taxAmount').textContent = `$${taxAmount.toFixed(2)}`;
document.getElementById('totalAmount').textContent = `$${total.toFixed(2)}`;
}
function generateInvoice() {
const fromName = document.querySelector('input[placeholder="Your Business Name"]').value || 'Your Business Name';
const fromAddress = document.querySelector('input[placeholder="Address"]').value || 'Your Address';
const fromCityStateZip = document.querySelector('input[placeholder="City, State, ZIP"]').value || 'City, State, ZIP';
const fromEmail = document.querySelector('input[placeholder="Email"]').value || 'your@email.com';
const fromPhone = document.querySelector('input[placeholder="Phone"]').value || '(123) 456-7890';
const toName = document.querySelector('input[placeholder="Client Name"]').value || 'Client Name';
const toAddress = document.querySelector('input[placeholder="Client Address"]').value || 'Client Address';
const toCityStateZip = document.querySelector('input[placeholder="City, State, ZIP"]').value || 'City, State, ZIP';
const toEmail = document.querySelector('input[placeholder="Client Email"]').value || 'client@email.com';
const toPhone = document.querySelector('input[placeholder="Client Phone"]').value || '(987) 654-3210';
const invoiceDate = new Date().toLocaleDateString();
const invoiceNumber = 'INV-' + Math.floor(Math.random() * 10000);
const subtotal = document.getElementById('subtotal').textContent;
const taxAmount = document.getElementById('taxAmount').textContent;
const totalAmount = document.getElementById('totalAmount').textContent;
const taxRate = taxRateInput.value;
let itemsHTML = '';
const rows = document.querySelectorAll('.item-row');
rows.forEach(row => {
const description = row.querySelector('.description').value || 'Item description';
const quantity = row.querySelector('.quantity').value || '1';
const price = row.querySelector('.price').value || '0.00';
const total = row.querySelector('.item-total').textContent;
itemsHTML += `
<tr>
<td class="py-2">${description}</td>
<td class="text-right py-2">${quantity}</td>
<td class="text-right py-2">$${parseFloat(price).toFixed(2)}</td>
<td class="text-right py-2">${total}</td>
</tr>
`;
});
invoiceContent.innerHTML = `
<div class="invoice-header flex justify-between mb-8">
<div>
<h1 class="text-3xl font-bold text-indigo-600">${fromName}</h1>
<p class="text-gray-600">${fromAddress}</p>
<p class="text-gray-600">${fromCityStateZip}</p>
<p class="text-gray-600">${fromEmail}</p>
<p class="text-gray-600">${fromPhone}</p>
</div>
<div class="text-right">
<h2 class="text-2xl font-bold text-gray-800">INVOICE</h2>
<p class="text-gray-600">Date: ${invoiceDate}</p>
<p class="text-gray-600">Invoice #: ${invoiceNumber}</p>
</div>
</div>
<div class="flex justify-between mb-8">
<div class="bill-to">
<h3 class="font-bold text-gray-700 mb-2">Bill To:</h3>
<p class="text-gray-600">${toName}</p>
<p class="text-gray-600">${toAddress}</p>
<p class="text-gray-600">${toCityStateZip}</p>
<p class="text-gray-600">${toEmail}</p>
<p class="text-gray-600">${toPhone}</p>
</div>
</div>
<table class="w-full mb-8">
<thead>
<tr class="border-b border-gray-300">
<th class="text-left py-2 font-semibold text-gray-700">Description</th>
<th class="text-right py-2 font-semibold text-gray-700">Qty</th>
<th class="text-right py-2 font-semibold text-gray-700">Unit Price</th>
<th class="text-right py-2 font-semibold text-gray-700">Amount</th>
</tr>
</thead>
<tbody>
${itemsHTML}
</tbody>
</table>
<div class="flex justify-end">
<div class="w-1/3">
<div class="flex justify-between py-2">
<span class="font-semibold text-gray-700">Subtotal:</span>
<span>${subtotal}</span>
</div>
<div class="flex justify-between py-2">
<span class="font-semibold text-gray-700">Tax (${taxRate}%):</span>
<span>${taxAmount}</span>
</div>
<div class="border-t border-gray-300 my-2"></div>
<div class="flex justify-between py-2 font-bold text-lg">
<span>Total:</span>
<span>${totalAmount}</span>
</div>
</div>
</div>
<div class="mt-12 pt-8 border-t border-gray-300 text-center text-gray-500">
<p>Thank you for your business!</p>
<p class="mt-2">Please make payment within 30 days</p>
</div>
`;
invoiceModal.classList.remove('hidden');
}
});