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');
}
});
});