This commit is contained in:
@@ -288,6 +288,106 @@ function showSnackbar(message, type = '') {
|
|||||||
}, 3000);
|
}, 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
|
// Handle disclaimer modal
|
||||||
function setupDisclaimer() {
|
function setupDisclaimer() {
|
||||||
const modal = document.getElementById('disclaimerModal');
|
const modal = document.getElementById('disclaimerModal');
|
||||||
@@ -313,5 +413,6 @@ function setupDisclaimer() {
|
|||||||
// Initialize when DOM is ready
|
// Initialize when DOM is ready
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
setupDisclaimer();
|
setupDisclaimer();
|
||||||
|
setupPdfImport();
|
||||||
init();
|
init();
|
||||||
});
|
});
|
||||||
|
|||||||
+32
-9
@@ -61,15 +61,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Vehicle Registration -->
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label" for="regNumber">Vehicle Registration Number</label>
|
|
||||||
<input type="text" id="regNumber" class="form-input"
|
|
||||||
placeholder="X0X0000" required
|
|
||||||
pattern="[A-Za-z0-9]+" maxlength="10">
|
|
||||||
<span class="form-hint">Letters and numbers only</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Date Range -->
|
<!-- Date Range -->
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -83,6 +74,36 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Divider -->
|
||||||
|
<div class="form-divider">
|
||||||
|
<span>Vehicle Details</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Import from PDF -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Import from Registration PDF</label>
|
||||||
|
<label class="btn btn-outline" id="importPdfBtn">
|
||||||
|
<span class="material-icons">upload_file</span>
|
||||||
|
Import PDF
|
||||||
|
<input type="file" id="pdfInput" accept=".pdf" hidden>
|
||||||
|
</label>
|
||||||
|
<span class="form-hint">Upload vehicle registration PDF to auto-fill</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Divider -->
|
||||||
|
<div class="form-divider">
|
||||||
|
<span>or</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Vehicle Registration -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="regNumber">Vehicle Registration Number</label>
|
||||||
|
<input type="text" id="regNumber" class="form-input"
|
||||||
|
placeholder="X0X0000" required
|
||||||
|
pattern="[A-Za-z0-9]+" maxlength="10">
|
||||||
|
<span class="form-hint">Letters and numbers only</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Model Number -->
|
<!-- Model Number -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label" for="modelNumber">Model Number</label>
|
<label class="form-label" for="modelNumber">Model Number</label>
|
||||||
@@ -137,6 +158,8 @@
|
|||||||
<div id="snackbar" class="snackbar"></div>
|
<div id="snackbar" class="snackbar"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- PDF.js for PDF parsing -->
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
|
||||||
<!-- JsBarcode for barcode generation -->
|
<!-- JsBarcode for barcode generation -->
|
||||||
<script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.11.6/dist/JsBarcode.all.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.11.6/dist/JsBarcode.all.min.js"></script>
|
||||||
<!-- jsPDF for PDF generation -->
|
<!-- jsPDF for PDF generation -->
|
||||||
|
|||||||
+37
@@ -342,6 +342,26 @@ body {
|
|||||||
gap: 16px;
|
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 */
|
/* Button Styles */
|
||||||
.btn {
|
.btn {
|
||||||
font: var(--md-sys-typescale-label-large);
|
font: var(--md-sys-typescale-label-large);
|
||||||
@@ -372,6 +392,23 @@ body {
|
|||||||
transform: scale(0.98);
|
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 {
|
.btn .material-icons {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user