document.addEventListener('DOMContentLoaded', function() { const templateUpload = document.getElementById('templateUpload'); const uploadTemplateBtn = document.getElementById('uploadTemplateBtn'); const scanPdfBtn = document.getElementById('scanPdfBtn'); const previewPdfBtn = document.getElementById('previewPdfBtn'); const csvPreview = document.getElementById('csvPreview'); const rowSelection = document.getElementById('rowSelection'); const generatePdfBtn = document.getElementById('generatePdfBtn'); const downloadSection = document.getElementById('downloadSection'); const downloadLink = document.getElementById('downloadLink'); let csvData = []; let headers = []; let pdfDoc = null; let pdfFields = []; // Handle template PDF locally uploadTemplateBtn.addEventListener('click', async () => { let file; const localPathInput = document.getElementById('localPath'); if (localPathInput.value) { try { // Handle local path input if (!localPathInput.value.startsWith('http') && !localPathInput.value.startsWith('file://')) { alert('Local paths must start with "file://" (e.g., file:///C:/path/to/file.pdf)'); return; } const response = await fetch(localPathInput.value, { mode: 'cors', headers: { 'Content-Type': 'application/pdf' } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const blob = await response.blob(); if (blob.size === 0) { throw new Error('Empty file received'); } file = new File([blob], localPathInput.value.split('/').pop() || 'document.pdf', { type: 'application/pdf' }); } catch (error) { console.error('File loading error:', error); alert(`Error loading file: ${error.message}\n\nMake sure:\n1. Path starts with file://\n2. File exists\n3. CORS is enabled for local files`); return; } } else if (templateUpload.files.length) { file = templateUpload.files[0]; } else { alert('Please select a PDF file or enter a local path first'); return; } const today = new Date(); const dateString = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`; try { // Initialize PDF.js pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.worker.min.js'; const fileHandle = await todayDirHandle.getFileHandle(file.name, { create: true }); const writable = await fileHandle.createWritable(); await writable.write(file); await writable.close(); }); // Display PDF preview const pdfViewer = document.getElementById('pdfViewer'); pdfViewer.src = URL.createObjectURL(file); // Load PDF and extract form fields const fileReader = new FileReader(); fileReader.onload = async function() { const typedArray = new Uint8Array(this.result); pdfDoc = await pdfjsLib.getDocument(typedArray).promise; // Get form fields (this is a simplified approach) const page = await pdfDoc.getPage(1); const textContent = await page.getTextContent(); const textItems = textContent.items.map(item => item.str); // Filter out empty strings and common PDF text pdfFields = textItems.filter(text => text.trim().length > 0 && !text.match(/page|©|http|www|\.com|\.org|\.net/i) ); // Display found fields const fieldsList = document.getElementById('invoiceFieldsList'); fieldsList.innerHTML = ''; pdfFields.forEach(field => { const li = document.createElement('li'); li.className = 'list-group-item'; li.textContent = field; fieldsList.appendChild(li); }); // Show the fields section document.getElementById('pdfPreview').classList.remove('d-none'); }; fileReader.readAsArrayBuffer(file); } catch (error) { console.error('Error uploading template:', error); alert('Failed to upload template'); } }); // Add new field functionality document.getElementById('addFieldBtn').addEventListener('click', () => { const nameInput = document.getElementById('newFieldName'); const valueInput = document.getElementById('newFieldValue'); const fieldsList = document.getElementById('newFieldsList'); if (!nameInput.value.trim()) { alert('Please enter a field name'); return; } const fieldItem = document.createElement('div'); fieldItem.className = 'list-group-item d-flex justify-content-between align-items-center'; fieldItem.innerHTML = ` ${nameInput.value}: ${valueInput.value} `; fieldsList.appendChild(fieldItem); // Clear inputs nameInput.value = ''; valueInput.value = ''; // Add remove functionality fieldItem.querySelector('.remove-field').addEventListener('click', () => { fieldItem.remove(); }); }); // Handle PDF scanning scanPdfBtn.addEventListener('click', async () => { if (!pdfDoc) { alert('Please upload and process a PDF file first'); return; } // Extract common invoice fields (simplified example) const invoiceNumber = pdfFields.find(field => field.match(/invoice|מספר|חשבונית|מספר חשבונית/i) ); const dateField = pdfFields.find(field => field.match(/date|תאריך|date issued/i) ); const reasonField = pdfFields.find(field => field.match(/treatment|reason|service|סוג|שירות/i) ); // Update UI with found fields document.getElementById('invoiceNumber').textContent = invoiceNumber || 'Not found in PDF'; document.getElementById('invoiceDate').textContent = dateField || 'Not found in PDF'; document.getElementById('treatmentReason').textContent = reasonField || 'Not found in PDF'; }); // Initialize PDF.js pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.worker.min.js'; // Handle PDF preview previewPdfBtn.addEventListener('click', async () => { if (!templateUpload.files.length) { alert('Please upload a PDF file first'); return; } const file = templateUpload.files[0]; const pdfViewer = document.getElementById('pdfViewer'); const fileReader = new FileReader(); fileReader.onload = async function() { const typedArray = new Uint8Array(this.result); try { // Load the PDF document const pdf = await pdfjsLib.getDocument(typedArray).promise; // Get the first page const page = await pdf.getPage(1); // Set the scale and viewport const scale = 1.5; const viewport = page.getViewport({ scale }); // Create canvas for rendering const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); canvas.height = viewport.height; canvas.width = viewport.width; // Clear previous content pdfViewer.innerHTML = ''; pdfViewer.appendChild(canvas); pdfViewer.style.height = '600px'; // Render PDF page await page.render({ canvasContext: context, viewport: viewport }).promise; } catch (error) { console.error('Error rendering PDF:', error); alert('Error loading PDF. Please try another file.'); } }; fileReader.readAsArrayBuffer(file); }); // Handle CSV upload const csvUpload = document.getElementById('csvUpload'); csvUpload?.addEventListener('change', function(e) { const file = e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = function(e) { const content = e.target.result; const lines = content.split('\n'); if (lines.length === 0) { alert('CSV file is empty'); return; } // Parse CSV headers = lines[0].split(','); csvData = lines.slice(1).map(line => line.split(',')); // Display headers const thead = csvPreview.querySelector('thead'); thead.innerHTML = ''; const headerRow = document.createElement('tr'); headers.forEach(header => { const th = document.createElement('th'); th.textContent = header; headerRow.appendChild(th); }); thead.appendChild(headerRow); // Display first 5 rows const tbody = csvPreview.querySelector('tbody'); tbody.innerHTML = ''; csvData.slice(0, 5).forEach(row => { const tr = document.createElement('tr'); row.forEach(cell => { const td = document.createElement('td'); td.textContent = cell; tr.appendChild(td); }); tbody.appendChild(tr); }); // Populate row selection rowSelection.innerHTML = ''; csvData.forEach((_, index) => { const option = document.createElement('option'); option.value = index; option.textContent = `Row ${index + 1}`; rowSelection.appendChild(option); }); }; reader.readAsText(file); }); // Generate PDFs locally generatePdfBtn.addEventListener('click', async () => { if (csvData.length === 0) { alert('Please upload and process CSV data first'); return; } const selectedRows = Array.from(rowSelection.selectedOptions).map(opt => parseInt(opt.value)); if (selectedRows.length === 0) { alert('Please select at least one row to process'); return; } try { // Create a zip file with all generated PDFs const zip = new JSZip(); const today = new Date(); const dateString = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`; // Generate a PDF for each selected row for (const rowIndex of selectedRows) { const rowData = csvData[rowIndex]; const fileName = `invoice_${rowIndex + 1}.pdf`; // Create a simple PDF (in a real app, use a proper PDF generation library) const pdfContent = ` Invoice Details -------------- Invoice Number: ${rowData[0] || 'N/A'} Date: ${rowData[1] || 'N/A'} Treatment: ${rowData[2] || 'N/A'} Amount: ${rowData[3] || 'N/A'} `; zip.file(fileName, pdfContent); } // Generate the zip file const zipContent = await zip.generateAsync({type: 'blob'}); const zipUrl = URL.createObjectURL(zipContent); // Update download link downloadLink.href = zipUrl; downloadLink.textContent = selectedRows.length > 1 ? `Download ${selectedRows.length} PDFs (ZIP)` : `Download PDF`; downloadLink.setAttribute('download', `invoices_${dateString}.zip`); downloadSection.classList.remove('d-none'); } catch (error) { console.error('Error generating PDFs:', error); alert('Failed to generate PDFs'); } }); });