diff --git a/app.js b/app.js index 5e881ae..7a2ec2f 100644 --- a/app.js +++ b/app.js @@ -288,6 +288,106 @@ function showSnackbar(message, type = '') { }, 3000); } +// Set PDF.js worker +if (typeof pdfjsLib !== 'undefined') { + pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js'; +} + +// Handle PDF import +async function setupPdfImport() { + const pdfInput = document.getElementById('pdfInput'); + const importBtn = document.getElementById('importPdfBtn'); + + if (!pdfInput || !importBtn) return; + + pdfInput.addEventListener('change', async (e) => { + const file = e.target.files[0]; + if (!file) return; + + importBtn.classList.add('loading'); + + try { + const text = await extractTextFromPdf(file); + const data = parseRegistrationData(text); + fillFormWithData(data); + showSnackbar('Data imported successfully!', 'success'); + } catch (error) { + console.error('PDF import failed:', error); + showSnackbar('Failed to import PDF', 'error'); + } finally { + importBtn.classList.remove('loading'); + pdfInput.value = ''; // Reset input + } + }); +} + +// Extract text from PDF using PDF.js +async function extractTextFromPdf(file) { + const arrayBuffer = await file.arrayBuffer(); + const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise; + + let fullText = ''; + for (let i = 1; i <= pdf.numPages; i++) { + const page = await pdf.getPage(i); + const textContent = await page.getTextContent(); + const pageText = textContent.items.map(item => item.str).join(' '); + fullText += pageText + '\n'; + } + + return fullText; +} + +// Parse registration data from extracted text +function parseRegistrationData(text) { + const data = {}; + + // Registry Number + const regMatch = text.match(/Registry Number\s*([A-Z0-9]+)/i); + if (regMatch) data.regNumber = regMatch[1]; + + // Model Number + const modelMatch = text.match(/Model Number\s*([A-Z0-9\-\.]+)/i); + if (modelMatch) data.modelNumber = modelMatch[1]; + + // Chassis Number + const chassisMatch = text.match(/Chassis Number\s*([A-Z0-9]+)/i); + if (chassisMatch) data.chassisNumber = chassisMatch[1]; + + // Engine Number/Motor Serial No + const engineMatch = text.match(/Engine Number\/Motor Serial No\s*([A-Z0-9\-]+)/i); + if (engineMatch) data.engineSerial = engineMatch[1]; + + // Engine/Motor Capacity + const capacityMatch = text.match(/Engine\/Motor Capacity\s*(\d+)/i); + if (capacityMatch) data.engineCapacity = capacityMatch[1] + '.000'; + + return data; +} + +// Fill form with parsed data +function fillFormWithData(data) { + if (data.regNumber) { + regNumberInput.value = data.regNumber; + } + if (data.modelNumber) { + modelNumberInput.value = data.modelNumber; + } + if (data.chassisNumber) { + chassisNumberInput.value = data.chassisNumber; + } + if (data.engineSerial) { + engineSerialInput.value = data.engineSerial; + } + if (data.engineCapacity) { + engineCapacityInput.value = data.engineCapacity; + } + + // Update preview + if (currentTemplateId) { + renderTemplate(currentTemplateId); + } +} + // Handle disclaimer modal function setupDisclaimer() { const modal = document.getElementById('disclaimerModal'); @@ -313,5 +413,6 @@ function setupDisclaimer() { // Initialize when DOM is ready document.addEventListener('DOMContentLoaded', () => { setupDisclaimer(); + setupPdfImport(); init(); }); diff --git a/index.html b/index.html index 5fd87db..d5a867b 100644 --- a/index.html +++ b/index.html @@ -61,15 +61,6 @@ - -
- - - Letters and numbers only -
-
@@ -83,6 +74,36 @@
+ +
+ Vehicle Details +
+ + +
+ + + Upload vehicle registration PDF to auto-fill +
+ + +
+ or +
+ + +
+ + + Letters and numbers only +
+
@@ -137,6 +158,8 @@
+ + diff --git a/styles.css b/styles.css index 85a6af4..25c01e7 100644 --- a/styles.css +++ b/styles.css @@ -342,6 +342,26 @@ body { gap: 16px; } +/* Form Divider */ +.form-divider { + display: flex; + align-items: center; + text-align: center; + color: var(--md-sys-color-outline); + font-size: 0.875rem; +} + +.form-divider::before, +.form-divider::after { + content: ''; + flex: 1; + border-bottom: 1px solid var(--md-sys-color-outline-variant); +} + +.form-divider span { + padding: 0 16px; +} + /* Button Styles */ .btn { font: var(--md-sys-typescale-label-large); @@ -372,6 +392,23 @@ body { transform: scale(0.98); } +.btn-outline { + background-color: transparent; + color: var(--md-sys-color-primary); + border: 2px solid var(--md-sys-color-primary); + cursor: pointer; +} + +.btn-outline:hover { + background-color: var(--md-sys-color-primary); + color: var(--md-sys-color-on-primary); +} + +.btn-outline.loading { + pointer-events: none; + opacity: 0.7; +} + .btn .material-icons { font-size: 20px; }