Legal Billing Software

Legal Billing Software

Manage clients, track time, and generate invoices seamlessly.

Billing Dashboard

Total Hours Logged (All Time)

0.00

Total Unbilled Amount

$0.00

Active Cases

0

Manage Clients & Cases

Add a New Client

Add a New Case

Existing Clients and Cases

No clients added yet.

Log Time or Expense

Generate Invoice

Your generated invoice will appear here.

Firm & Billing Configuration

Your Firm's Details

Billing Settings

Total Due: ${formatCurrency(totalAmount)}

${invoiceEntries.length} entries found. Click "Download PDF" for a detailed breakdown.

`; document.getElementById('invoice-preview-container').innerHTML = previewHTML; document.getElementById('download-btn-container').style.display = 'block'; } async function handlePdfDownload() { if (!currentInvoiceData) return; const { firm, client, timeEntries, expenseEntries, timeSubtotal, expenseSubtotal, totalAmount, invoiceDate, invoiceNumber } = currentInvoiceData; const contentHTML = `

INVOICE

Invoice #: ${invoiceNumber}

Date: ${invoiceDate}

${firm.firmName}
${firm.firmAddress.replace(/\n/g, '
')}
${firm.firmEmail}
${firm.firmPhone}
BILL TO:
${client.name}
${client.contact}
${client.email}
Total Amount Due:

${formatCurrency(totalAmount)}

Professional Services

${timeEntries.map(e => ``).join('')}
DateDescriptionHoursRateAmount
${e.date}${e.description}${e.hours.toFixed(2)}${formatCurrency(firm.defaultRate)}${formatCurrency(e.hours * firm.defaultRate)}
Subtotal${formatCurrency(timeSubtotal)}

Expenses

${expenseEntries.map(e => ``).join('')}
DateDescriptionAmount
${e.date}${e.description}${formatCurrency(e.amount)}
Subtotal${formatCurrency(expenseSubtotal)}
Services Total${formatCurrency(timeSubtotal)}
Expenses Total${formatCurrency(expenseSubtotal)}
TOTAL DUE${formatCurrency(totalAmount)}

Notes: Please make payment within 30 days. Thank you for your business.

`; document.getElementById('pdf-invoice-content').innerHTML = contentHTML; const pdfContainer = document.getElementById('pdf-container'); const { jsPDF } = window.jspdf; const button = document.getElementById('downloadPdfBtn'); button.textContent = 'Generating...'; button.disabled = true; pdfContainer.classList.remove('invisible'); try { const canvas = await html2canvas(pdfContainer, { scale: 2 }); const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const imgProps = pdf.getImageProperties(imgData); const imgHeight = (imgProps.height * pdfWidth) / imgProps.width; pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, imgHeight); pdf.save(`Invoice_${invoiceNumber}_${client.name}.pdf`); // Mark entries as invoiced currentInvoiceData.timeEntries.forEach(e => { const entry = state.entries.find(se => se.id === e.id); if(entry) entry.invoiced = true; }); currentInvoiceData.expenseEntries.forEach(e => { const entry = state.entries.find(se => se.id === e.id); if(entry) entry.invoiced = true; }); renderDashboard(); showToast('Invoice downloaded and entries marked as billed.'); } catch(error) { console.error("PDF generation error:", error); showToast('Failed to generate PDF.', false); } finally { button.textContent = 'Download Invoice as PDF'; button.disabled = false; pdfContainer.classList.add('invisible'); document.getElementById('invoice-preview-container').innerHTML = `

Invoice has been processed. Generate a new one.

`; document.getElementById('download-btn-container').style.display = 'none'; currentInvoiceData = null; } } // --- INITIALIZATION --- nextBtn.addEventListener('click', () => changeTab(currentTab + 1)); prevBtn.addEventListener('click', () => changeTab(currentTab - 1)); tabButtons.forEach(button => button.addEventListener('click', () => changeTab(parseInt(button.dataset.tab)))); renderAll(); renderConfigForm(); // Populate config form on load updateTabDisplay(); });
Scroll to Top