window.Results = { currentImageUrl: null, render: function (result, file) { this._hideAll(); Utils.$('#results-data').classList.remove('hidden'); if (file) { this.showImagePreview(file); } this.renderOverallResult(result); this.renderExtractionInfo(result); this.renderFields(result); this.renderChecks(result.checks || {}); this.renderConfidence(result.confidence || {}, result.doc_type); this.renderRawText(result.raw_text || []); this.renderMachineData(result); }, showImagePreview: function (file) { if (this.currentImageUrl) { URL.revokeObjectURL(this.currentImageUrl); } var container = Utils.$('#image-preview-container'); container.classList.remove('hidden'); this.currentImageUrl = URL.createObjectURL(file); Utils.$('#image-preview').src = this.currentImageUrl; }, hideImagePreview: function () { Utils.$('#image-preview-container').classList.add('hidden'); }, renderOverallResult: function (result) { var banner = Utils.$('#overall-result-banner'); var overall = result.overall_result || 'unknown'; banner.className = 'overall-result-banner result-' + overall; var icon = overall === 'pass' ? '✓' : overall === 'fail' ? '✗' : '⚠'; var label = overall === 'pass' ? 'PASS' : overall === 'fail' ? 'FAIL' : 'INCONCLUSIVE'; banner.innerHTML = '' + icon + ' ' + label; }, renderExtractionInfo: function (result) { var el = Utils.$('#extraction-info'); var parts = []; if (result.doc_type) { parts.push('' + Utils.docTypeLabel(result.doc_type) + ''); } if (result.extraction_method) { parts.push('' + result.extraction_method + ''); } el.innerHTML = parts.join(' '); }, renderFields: function (result) { var tbody = Utils.$('#fields-table tbody'); tbody.innerHTML = ''; var fields = result.fields || {}; var fieldOrder = Utils.fieldsForDocType(result.doc_type); for (var i = 0; i < fieldOrder.length; i++) { var key = fieldOrder[i]; var value = fields[key]; var tr = document.createElement('tr'); var tdLabel = document.createElement('td'); tdLabel.textContent = Utils.fieldLabel(key); var tdValue = document.createElement('td'); if (value) { tdValue.textContent = value; } else { tdValue.textContent = 'Not detected'; tdValue.className = 'field-missing'; } tr.appendChild(tdLabel); tr.appendChild(tdValue); tbody.appendChild(tr); } }, renderChecks: function (checks) { var section = Utils.$('#checks-section'); section.innerHTML = ''; var checkOrder = ['image_quality', 'id_number_valid', 'barcode_valid', 'mrz_valid', 'data_crosscheck', 'dob_crosscheck', 'gender_crosscheck']; for (var i = 0; i < checkOrder.length; i++) { var key = checkOrder[i]; var val = checks[key]; if (val === undefined) continue; var span = document.createElement('span'); if (val === 'passed') { span.className = 'validation-check pass'; span.innerHTML = '✓ ' + Utils.checkLabel(key); } else if (val === 'failed') { span.className = 'validation-check fail'; span.innerHTML = '✗ ' + Utils.checkLabel(key); } else { span.className = 'validation-check na'; span.innerHTML = '— ' + Utils.checkLabel(key); } section.appendChild(span); } }, renderConfidence: function (confidence, docType) { var section = Utils.$('#confidence-section'); section.innerHTML = ''; var fieldOrder = Utils.fieldsForDocType(docType); for (var i = 0; i < fieldOrder.length; i++) { var key = fieldOrder[i]; var val = confidence[key]; if (val === undefined || val === null) continue; var row = document.createElement('div'); row.className = 'confidence-row'; var label = document.createElement('span'); label.className = 'confidence-label'; label.textContent = Utils.fieldLabel(key); var bar = document.createElement('div'); bar.className = 'confidence-bar'; var fill = document.createElement('div'); fill.className = 'confidence-fill ' + Utils.confidenceLevel(val); fill.style.width = Utils.formatConfidence(val); fill.textContent = Utils.formatConfidence(val); bar.appendChild(fill); row.appendChild(label); row.appendChild(bar); section.appendChild(row); } }, renderRawText: function (rawText) { var content = Utils.$('#raw-text-content'); content.innerHTML = ''; for (var i = 0; i < rawText.length; i++) { var line = document.createElement('div'); line.textContent = rawText[i]; content.appendChild(line); } }, renderMachineData: function (result) { var section = Utils.$('#machine-data-section'); var content = Utils.$('#machine-data-content'); content.innerHTML = ''; var data = result.barcode_data || result.mrz_data; if (!data) { section.classList.add('hidden'); return; } section.classList.remove('hidden'); var label = result.barcode_data ? 'Barcode Data' : 'MRZ Data'; Utils.$('#machine-data-section summary').textContent = label; var pre = document.createElement('pre'); pre.textContent = JSON.stringify(data, null, 2); content.appendChild(pre); }, showLoading: function (file) { this._hideAll(); if (file) { this.showImagePreview(file); } Utils.$('#results-loading').classList.remove('hidden'); this._startTimer(); }, hideLoading: function () { Utils.$('#results-loading').classList.add('hidden'); this._stopTimer(); }, showEmpty: function () { this._hideAll(); Utils.$('#results-empty').classList.remove('hidden'); }, showError: function (message) { this._hideAll(); Utils.$('#results-error').classList.remove('hidden'); Utils.$('#error-message').textContent = message; }, renderSerial: function (result, file) { this._hideAll(); Utils.$('#serial-results').classList.remove('hidden'); if (file) this.showImagePreview(file); // Banner var banner = Utils.$('#serial-result-banner'); var hasSerial = !!result.serial_number; banner.className = 'overall-result-banner ' + (hasSerial ? 'result-pass' : 'result-fail'); banner.innerHTML = hasSerial ? ' SERIAL NUMBER FOUND' : ' ' + (result.failure_reason || 'NO SERIAL NUMBER DETECTED'); // Failure guidance var failGuidance = Utils.$('#serial-fail-guidance'); if (!hasSerial) { failGuidance.classList.remove('hidden'); failGuidance.innerHTML = ''; var tips = []; if (result.quality && result.quality.issues && result.quality.issues.length > 0) { for (var q = 0; q < result.quality.issues.length; q++) { tips.push(result.quality.issues[q]); } } if (result.quality && !result.quality.usable) { tips.push('Image quality is too low for reliable extraction'); } if (tips.length === 0) { tips.push('Try better lighting, hold the label steady, or move closer'); } var ul = document.createElement('ul'); for (var t = 0; t < tips.length; t++) { var li = document.createElement('li'); li.textContent = tips[t]; ul.appendChild(li); } failGuidance.appendChild(ul); } else { failGuidance.classList.add('hidden'); failGuidance.innerHTML = ''; } // Cropped image preview var cropContainer = Utils.$('#serial-crop-container'); if (result.cropped_image) { cropContainer.classList.remove('hidden'); Utils.$('#serial-crop-preview').src = 'data:image/jpeg;base64,' + result.cropped_image; } else { cropContainer.classList.add('hidden'); } // Fields table var tbody = Utils.$('#serial-fields-table tbody'); tbody.innerHTML = ''; var confidenceClass = ''; if (result.confidence === 'high') confidenceClass = 'confidence-high'; else if (result.confidence === 'medium') confidenceClass = 'confidence-medium'; else if (result.confidence === 'low') confidenceClass = 'confidence-low'; var rows = [ ['Serial Number', result.serial_number || 'Not detected', !result.serial_number ? 'field-missing' : ''], ['Extraction Source', result.extraction_source || '-', ''], ['Confidence', result.confidence || '-', confidenceClass], ]; for (var i = 0; i < rows.length; i++) { var tr = document.createElement('tr'); var tdLabel = document.createElement('td'); tdLabel.textContent = rows[i][0]; var tdValue = document.createElement('td'); tdValue.textContent = rows[i][1]; if (rows[i][2]) tdValue.className = rows[i][2]; tr.appendChild(tdLabel); tr.appendChild(tdValue); tbody.appendChild(tr); } // Validation details (styled pills instead of raw JSON) var valContent = Utils.$('#serial-validation-content'); valContent.innerHTML = ''; if (result.validation) { var validPill = document.createElement('span'); validPill.className = 'validation-pill ' + (result.validation.valid ? 'pill-pass' : 'pill-fail'); validPill.textContent = result.validation.valid ? 'Valid' : 'Invalid'; valContent.appendChild(validPill); if (result.validation.prefix_match) { var prefixPill = document.createElement('span'); prefixPill.className = 'validation-pill pill-info'; prefixPill.textContent = result.validation.prefix_match; valContent.appendChild(prefixPill); } if (result.validation.issues && result.validation.issues.length > 0) { for (var j = 0; j < result.validation.issues.length; j++) { var issuePill = document.createElement('span'); issuePill.className = 'validation-pill pill-warn'; issuePill.textContent = result.validation.issues[j]; valContent.appendChild(issuePill); } } } else { valContent.textContent = 'No validation data'; } }, _hideAll: function () { Utils.$('#results-empty').classList.add('hidden'); Utils.$('#results-loading').classList.add('hidden'); Utils.$('#results-data').classList.add('hidden'); Utils.$('#serial-results').classList.add('hidden'); Utils.$('#results-error').classList.add('hidden'); Utils.$('#image-preview-container').classList.add('hidden'); this._stopTimer(); }, _timerInterval: null, _timerStart: 0, _startTimer: function () { this._timerStart = performance.now(); var el = Utils.$('#elapsed-timer'); var self = this; el.textContent = 'Elapsed: 0s'; this._timerInterval = setInterval(function () { var secs = Math.floor((performance.now() - self._timerStart) / 1000); el.textContent = 'Elapsed: ' + secs + 's'; }, 1000); }, _stopTimer: function () { if (this._timerInterval) { clearInterval(this._timerInterval); this._timerInterval = null; } }, };