From 4325f9e0e617af207586883043b7558a6d156a14 Mon Sep 17 00:00:00 2001 From: swdee Date: Fri, 16 Jan 2026 13:49:26 +1300 Subject: [PATCH] when a part is scanned and not found, the scanner did not redraw so scanning subsequent parts was not possible without reloading the browser page. fixed the barcode scanner initialization and shutdown so it redraws properly after part not found --- .../pages/barcode_scan_controller.js | 54 ++++++++++++++----- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/assets/controllers/pages/barcode_scan_controller.js b/assets/controllers/pages/barcode_scan_controller.js index 200dd2a7..29db5de5 100644 --- a/assets/controllers/pages/barcode_scan_controller.js +++ b/assets/controllers/pages/barcode_scan_controller.js @@ -23,15 +23,14 @@ import {Controller} from "@hotwired/stimulus"; import {Html5QrcodeScanner, Html5Qrcode} from "@part-db/html5-qrcode"; /* stimulusFetch: 'lazy' */ + export default class extends Controller { - - //codeReader = null; - _scanner = null; - + _submitting = false; connect() { - console.log('Init Scanner'); + // Prevent double init if connect fires twice + if (this._scanner) return; //This function ensures, that the qrbox is 70% of the total viewport let qrboxFunction = function(viewfinderWidth, viewfinderHeight) { @@ -45,8 +44,8 @@ export default class extends Controller { } //Try to get the number of cameras. If the number is 0, then the promise will fail, and we show the warning dialog - Html5Qrcode.getCameras().catch((devices) => { - document.getElementById('scanner-warning').classList.remove('d-none'); + Html5Qrcode.getCameras().catch(() => { + document.getElementById("scanner-warning")?.classList.remove("d-none"); }); this._scanner = new Html5QrcodeScanner(this.element.id, { @@ -54,22 +53,49 @@ export default class extends Controller { qrbox: qrboxFunction, experimentalFeatures: { //This option improves reading quality on android chrome - useBarCodeDetectorIfSupported: true - } + useBarCodeDetectorIfSupported: true, + }, }, false); this._scanner.render(this.onScanSuccess.bind(this)); } disconnect() { - this._scanner.pause(); - this._scanner.clear(); + // If we already stopped/cleared before submit, nothing to do. + const scanner = this._scanner; + this._scanner = null; + this._submitting = false; + + if (!scanner) return; + + try { + const p = scanner.clear?.(); + if (p && typeof p.then === "function") p.catch(() => {}); + } catch (_) { + // ignore + } } - onScanSuccess(decodedText, decodedResult) { + async onScanSuccess(decodedText) { + if (this._submitting) return; + this._submitting = true; + //Put our decoded Text into the input box - document.getElementById('scan_dialog_input').value = decodedText; + const input = document.getElementById("scan_dialog_input"); + if (input) input.value = decodedText; + + // Stop scanner BEFORE submitting to avoid camera transition races + try { + if (this._scanner?.clear) { + await this._scanner.clear(); + } + } catch (_) { + // ignore + } finally { + this._scanner = null; + } + //Submit form - document.getElementById('scan_dialog_form').requestSubmit(); + document.getElementById("scan_dialog_form")?.requestSubmit(); } }