diff --git a/src/components/QRScanner/QRScannerDialog.vue b/src/components/QRScanner/QRScannerDialog.vue index 77534240..d7de3f69 100644 --- a/src/components/QRScanner/QRScannerDialog.vue +++ b/src/components/QRScanner/QRScannerDialog.vue @@ -298,14 +298,14 @@ export default class QRScannerDialog extends Vue { errorMessage = ""; created() { - console.log('[QRScannerDialog] created'); - console.log('[QRScannerDialog] Props received:', { + logger.log("[QRScannerDialog] created"); + logger.log("[QRScannerDialog] Props received:", { onScan: typeof this.onScan, onError: typeof this.onError, options: this.options, onClose: typeof this.onClose, }); - console.log('[QRScannerDialog] Initial state:', { + logger.log("[QRScannerDialog] Initial state:", { visible: this.visible, error: this.error, useQRReader: this.useQRReader, @@ -336,61 +336,69 @@ export default class QRScannerDialog extends Vue { } mounted() { - console.log('[QRScannerDialog] mounted'); + logger.log("[QRScannerDialog] mounted"); // Timer to warn if no QR code detected after 10 seconds this._scanTimeout = setTimeout(() => { if (!this.isScanning) { - console.warn('[QRScannerDialog] No QR code detected after 10 seconds'); + logger.warn("[QRScannerDialog] No QR code detected after 10 seconds"); } }, 10000); // Periodic timer to log waiting status every 5 seconds this._waitingInterval = setInterval(() => { - if (!this.isScanning && this.cameraStatus === 'Active') { - console.log('[QRScannerDialog] Still waiting for QR code detection...'); + if (!this.isScanning && this.cameraStatus === "Active") { + logger.log("[QRScannerDialog] Still waiting for QR code detection..."); } }, 5000); - console.log('[QRScannerDialog] Waiting interval started'); + logger.log("[QRScannerDialog] Waiting interval started"); } beforeUnmount() { if (this._scanTimeout) { clearTimeout(this._scanTimeout); - console.log('[QRScannerDialog] Scan timeout cleared'); + logger.log("[QRScannerDialog] Scan timeout cleared"); } if (this._waitingInterval) { clearInterval(this._waitingInterval); - console.log('[QRScannerDialog] Waiting interval cleared'); + logger.log("[QRScannerDialog] Waiting interval cleared"); } - console.log('[QRScannerDialog] beforeUnmount'); + logger.log("[QRScannerDialog] beforeUnmount"); } async onInit(promise: Promise): Promise { - console.log('[QRScannerDialog] onInit called'); + logger.log("[QRScannerDialog] onInit called"); if (this.isNativePlatform) { logger.log("Closing QR dialog on native platform"); this.$nextTick(() => this.close()); return; } this.isInitializing = true; - console.log('[QRScannerDialog] isInitializing set to', this.isInitializing); + logger.log("[QRScannerDialog] isInitializing set to", this.isInitializing); this.error = null; this.initializationStatus = "Checking camera access..."; - console.log('[QRScannerDialog] initializationStatus set to', this.initializationStatus); + logger.log( + "[QRScannerDialog] initializationStatus set to", + this.initializationStatus, + ); try { if (!navigator.mediaDevices) { - console.log('[QRScannerDialog] Camera API not available'); + logger.log("[QRScannerDialog] Camera API not available"); throw new Error( "Camera API not available. Please ensure you're using HTTPS.", ); } const devices = await navigator.mediaDevices.enumerateDevices(); - const videoDevices = devices.filter((device) => device.kind === "videoinput"); - console.log('[QRScannerDialog] videoDevices found:', videoDevices.length); + const videoDevices = devices.filter( + (device) => device.kind === "videoinput", + ); + logger.log("[QRScannerDialog] videoDevices found:", videoDevices.length); if (videoDevices.length === 0) { throw new Error("No camera found on this device"); } this.initializationStatus = "Requesting camera permission..."; - console.log('[QRScannerDialog] initializationStatus set to', this.initializationStatus); + logger.log( + "[QRScannerDialog] initializationStatus set to", + this.initializationStatus, + ); try { const stream = await navigator.mediaDevices.getUserMedia({ video: { @@ -401,10 +409,17 @@ export default class QRScannerDialog extends Vue { }); stream.getTracks().forEach((track) => track.stop()); this.initializationStatus = "Camera permission granted..."; - console.log('[QRScannerDialog] initializationStatus set to', this.initializationStatus); + logger.log( + "[QRScannerDialog] initializationStatus set to", + this.initializationStatus, + ); } catch (permissionError) { const error = permissionError as Error; - console.log('[QRScannerDialog] Camera permission error:', error.name, error.message); + logger.log( + "[QRScannerDialog] Camera permission error:", + error.name, + error.message, + ); if ( error.name === "NotAllowedError" || error.name === "PermissionDeniedError" @@ -429,67 +444,94 @@ export default class QRScannerDialog extends Vue { } } this.initializationStatus = "Starting QR scanner..."; - console.log('[QRScannerDialog] initializationStatus set to', this.initializationStatus); + logger.log( + "[QRScannerDialog] initializationStatus set to", + this.initializationStatus, + ); await promise; this.isInitializing = false; this.cameraStatus = "Ready"; - console.log('[QRScannerDialog] QR scanner initialized successfully'); - console.log('[QRScannerDialog] cameraStatus set to', this.cameraStatus); + logger.log("[QRScannerDialog] QR scanner initialized successfully"); + logger.log("[QRScannerDialog] cameraStatus set to", this.cameraStatus); } catch (error) { - const wrappedError = error instanceof Error ? error : new Error(String(error)); + const wrappedError = + error instanceof Error ? error : new Error(String(error)); this.error = wrappedError.message; this.cameraStatus = "Error"; - console.log('[QRScannerDialog] Error initializing QR scanner:', wrappedError.message); - console.log('[QRScannerDialog] cameraStatus set to', this.cameraStatus); + logger.log( + "[QRScannerDialog] Error initializing QR scanner:", + wrappedError.message, + ); + logger.log("[QRScannerDialog] cameraStatus set to", this.cameraStatus); if (this.onError) { this.onError(wrappedError); } } finally { this.isInitializing = false; - console.log('[QRScannerDialog] isInitializing set to', this.isInitializing); + logger.log( + "[QRScannerDialog] isInitializing set to", + this.isInitializing, + ); } } onCameraOn(): void { this.cameraStatus = "Active"; - console.log('[QRScannerDialog] Camera turned on successfully'); - console.log('[QRScannerDialog] cameraStatus set to', this.cameraStatus); + logger.log("[QRScannerDialog] Camera turned on successfully"); + logger.log("[QRScannerDialog] cameraStatus set to", this.cameraStatus); } onCameraOff(): void { this.cameraStatus = "Off"; - console.log('[QRScannerDialog] Camera turned off'); - console.log('[QRScannerDialog] cameraStatus set to', this.cameraStatus); + logger.log("[QRScannerDialog] Camera turned off"); + logger.log("[QRScannerDialog] cameraStatus set to", this.cameraStatus); } onDetect(result: DetectionResult | Promise): void { const ts = new Date().toISOString(); - console.log(`[QRScannerDialog] onDetect called at ${ts} with`, result); + logger.log(`[QRScannerDialog] onDetect called at ${ts} with`, result); this.isScanning = true; this.cameraStatus = "Detecting"; - console.log('[QRScannerDialog] isScanning set to', this.isScanning); - console.log('[QRScannerDialog] cameraStatus set to', this.cameraStatus); + logger.log("[QRScannerDialog] isScanning set to", this.isScanning); + logger.log("[QRScannerDialog] cameraStatus set to", this.cameraStatus); const processResult = (detection: DetectionResult | DetectionResult[]) => { try { - console.log(`[QRScannerDialog] onDetect exit at ${new Date().toISOString()} with detection:`, detection); + logger.log( + `[QRScannerDialog] onDetect exit at ${new Date().toISOString()} with detection:`, + detection, + ); // Fallback: If detection is an array, check the first element let rawValue: string | undefined; - if (Array.isArray(detection) && detection.length > 0 && 'rawValue' in detection[0]) { + if ( + Array.isArray(detection) && + detection.length > 0 && + "rawValue" in detection[0] + ) { rawValue = detection[0].rawValue; - } else if (detection && typeof detection === 'object' && 'rawValue' in detection && detection.rawValue) { - rawValue = (detection as any).rawValue; + } else if ( + detection && + typeof detection === "object" && + "rawValue" in detection && + detection.rawValue + ) { + rawValue = (detection as unknown).rawValue; } if (rawValue) { - console.log('[QRScannerDialog] Fallback: Detected rawValue, treating as scan:', rawValue); + logger.log( + "[QRScannerDialog] Fallback: Detected rawValue, treating as scan:", + rawValue, + ); this.isInitializing = false; - this.initializationStatus = 'QR code captured!'; + this.initializationStatus = "QR code captured!"; this.onScan(rawValue); try { - console.log('[QRScannerDialog] About to call close() after scan'); + logger.log("[QRScannerDialog] About to call close() after scan"); this.close(); - console.log('[QRScannerDialog] close() called successfully after scan'); + logger.log( + "[QRScannerDialog] close() called successfully after scan", + ); } catch (err) { - console.error('[QRScannerDialog] Error calling close():', err); + logger.error("[QRScannerDialog] Error calling close():", err); } } } catch (error) { @@ -497,8 +539,8 @@ export default class QRScannerDialog extends Vue { } finally { this.isScanning = false; this.cameraStatus = "Active"; - console.log('[QRScannerDialog] isScanning set to', this.isScanning); - console.log('[QRScannerDialog] cameraStatus set to', this.cameraStatus); + logger.log("[QRScannerDialog] isScanning set to", this.isScanning); + logger.log("[QRScannerDialog] cameraStatus set to", this.cameraStatus); } }; if (result instanceof Promise) { @@ -508,8 +550,11 @@ export default class QRScannerDialog extends Vue { .finally(() => { this.isScanning = false; this.cameraStatus = "Active"; - console.log('[QRScannerDialog] isScanning set to', this.isScanning); - console.log('[QRScannerDialog] cameraStatus set to', this.cameraStatus); + logger.log("[QRScannerDialog] isScanning set to", this.isScanning); + logger.log( + "[QRScannerDialog] cameraStatus set to", + this.cameraStatus, + ); }); } else { processResult(result); @@ -517,11 +562,12 @@ export default class QRScannerDialog extends Vue { } private handleError(error: unknown): void { - const wrappedError = error instanceof Error ? error : new Error(String(error)); + const wrappedError = + error instanceof Error ? error : new Error(String(error)); this.error = wrappedError.message; this.cameraStatus = "Error"; - console.log('[QRScannerDialog] handleError:', wrappedError.message); - console.log('[QRScannerDialog] cameraStatus set to', this.cameraStatus); + logger.log("[QRScannerDialog] handleError:", wrappedError.message); + logger.log("[QRScannerDialog] cameraStatus set to", this.cameraStatus); if (this.onError) { this.onError(wrappedError); } @@ -529,14 +575,24 @@ export default class QRScannerDialog extends Vue { onDecode(result: string): void { const ts = new Date().toISOString(); - console.log(`[QRScannerDialog] onDecode called at ${ts} with result:`, result); + logger.log( + `[QRScannerDialog] onDecode called at ${ts} with result:`, + result, + ); try { this.isInitializing = false; - this.initializationStatus = 'QR code captured!'; - console.log('[QRScannerDialog] UI state updated after scan: isInitializing set to', this.isInitializing, ', initializationStatus set to', this.initializationStatus); + this.initializationStatus = "QR code captured!"; + logger.log( + "[QRScannerDialog] UI state updated after scan: isInitializing set to", + this.isInitializing, + ", initializationStatus set to", + this.initializationStatus, + ); this.onScan(result); this.close(); - console.log(`[QRScannerDialog] onDecode exit at ${new Date().toISOString()}`); + logger.log( + `[QRScannerDialog] onDecode exit at ${new Date().toISOString()}`, + ); } catch (error) { this.handleError(error); } @@ -544,77 +600,95 @@ export default class QRScannerDialog extends Vue { toggleCamera(): void { const prevCamera = this.preferredCamera; - this.preferredCamera = this.preferredCamera === "user" ? "environment" : "user"; - console.log('[QRScannerDialog] toggleCamera from', prevCamera, 'to', this.preferredCamera); - console.log('[QRScannerDialog] preferredCamera set to', this.preferredCamera); + this.preferredCamera = + this.preferredCamera === "user" ? "environment" : "user"; + logger.log( + "[QRScannerDialog] toggleCamera from", + prevCamera, + "to", + this.preferredCamera, + ); + logger.log( + "[QRScannerDialog] preferredCamera set to", + this.preferredCamera, + ); } retryScanning(): void { - console.log('[QRScannerDialog] retryScanning called'); + logger.log("[QRScannerDialog] retryScanning called"); this.error = null; this.isInitializing = true; - console.log('[QRScannerDialog] isInitializing set to', this.isInitializing); - console.log('[QRScannerDialog] Scanning re-initialized'); + logger.log("[QRScannerDialog] isInitializing set to", this.isInitializing); + logger.log("[QRScannerDialog] Scanning re-initialized"); } close = async (): Promise => { - console.log('[QRScannerDialog] close called'); + logger.log("[QRScannerDialog] close called"); this.visible = false; - console.log('[QRScannerDialog] visible set to', this.visible); + logger.log("[QRScannerDialog] visible set to", this.visible); // Notify parent/service - if (typeof this.onClose === 'function') { - console.log('[QRScannerDialog] Calling onClose prop'); + if (typeof this.onClose === "function") { + logger.log("[QRScannerDialog] Calling onClose prop"); this.onClose(); } await this.$nextTick(); if (this.$el && this.$el.parentNode) { this.$el.parentNode.removeChild(this.$el); - console.log('[QRScannerDialog] Dialog element removed from DOM'); + logger.log("[QRScannerDialog] Dialog element removed from DOM"); } else { - console.log('[QRScannerDialog] Dialog element NOT removed from DOM'); + logger.log("[QRScannerDialog] Dialog element NOT removed from DOM"); } - } + }; onScanDetect(promisedResult) { const ts = new Date().toISOString(); - console.log(`[QRScannerDialog] onScanDetect called at ${ts} with`, promisedResult); + logger.log( + `[QRScannerDialog] onScanDetect called at ${ts} with`, + promisedResult, + ); promisedResult .then((result) => { - console.log(`[QRScannerDialog] onScanDetect exit at ${new Date().toISOString()} with result:`, result); + logger.log( + `[QRScannerDialog] onScanDetect exit at ${new Date().toISOString()} with result:`, + result, + ); this.onScan(result); }) .catch((error) => { - console.error(`[QRScannerDialog] onScanDetect error at ${new Date().toISOString()}:`, error); - this.errorMessage = error.message || 'Scan error'; + logger.error( + `[QRScannerDialog] onScanDetect error at ${new Date().toISOString()}:`, + error, + ); + this.errorMessage = error.message || "Scan error"; if (this.onError) this.onError(error); }); } onScanError(error) { const ts = new Date().toISOString(); - console.error(`[QRScannerDialog] onScanError called at ${ts}:`, error); - this.errorMessage = error.message || 'Camera error'; + logger.error(`[QRScannerDialog] onScanError called at ${ts}:`, error); + this.errorMessage = error.message || "Camera error"; if (this.onError) this.onError(error); } async startMobileScan() { try { - console.log('[QRScannerDialog] startMobileScan called'); + logger.log("[QRScannerDialog] startMobileScan called"); const scanner = QRScannerFactory.getInstance(); await scanner.startScan(); } catch (error) { - console.error('[QRScannerDialog] Error starting mobile scan:', error); + logger.error("[QRScannerDialog] Error starting mobile scan:", error); if (this.onError) this.onError(error); } } async copyLogs() { - console.log('[QRScannerDialog] copyLogs called'); + logger.log("[QRScannerDialog] copyLogs called"); try { await navigator.clipboard.writeText(logCollector.getLogs()); - alert('Logs copied to clipboard!'); + alert("Logs copied to clipboard!"); } catch (e) { - alert('Failed to copy logs: ' + (e instanceof Error ? e.message : e)); + alert("Failed to copy logs: " + (e instanceof Error ? e.message : e)); } } } diff --git a/src/services/QRScanner/WebDialogQRScanner.ts b/src/services/QRScanner/WebDialogQRScanner.ts index 811ea700..63be67d8 100644 --- a/src/services/QRScanner/WebDialogQRScanner.ts +++ b/src/services/QRScanner/WebDialogQRScanner.ts @@ -10,20 +10,20 @@ export class WebDialogQRScanner implements QRScannerService { private isScanning = false; private container: HTMLElement | null = null; private sessionId: number | null = null; - private failsafeTimeout: any = null; + private failsafeTimeout: unknown = null; constructor(private options?: QRScannerOptions) {} async checkPermissions(): Promise { try { - console.log("[QRScanner] Checking camera permissions..."); + logger.log("[QRScanner] Checking camera permissions..."); const permissions = await navigator.permissions.query({ name: "camera" as PermissionName, }); - console.log("[QRScanner] Permission state:", permissions.state); + logger.log("[QRScanner] Permission state:", permissions.state); return permissions.state === "granted"; } catch (error) { - console.error("[QRScanner] Error checking camera permissions:", error); + logger.error("[QRScanner] Error checking camera permissions:", error); return false; } } @@ -129,7 +129,9 @@ export class WebDialogQRScanner implements QRScannerService { try { this.isScanning = true; this.sessionId = Date.now(); - console.log(`[WebDialogQRScanner] Opening dialog, session: ${this.sessionId}`); + logger.log( + `[WebDialogQRScanner] Opening dialog, session: ${this.sessionId}`, + ); // Create and mount dialog component this.container = document.createElement("div"); @@ -147,23 +149,31 @@ export class WebDialogQRScanner implements QRScannerService { } }, onClose: () => { - console.log(`[WebDialogQRScanner] onClose received from dialog, session: ${this.sessionId}`); - this.stopScan('dialog onClose'); + logger.log( + `[WebDialogQRScanner] onClose received from dialog, session: ${this.sessionId}`, + ); + this.stopScan("dialog onClose"); }, options: this.options, sessionId: this.sessionId, }); - this.dialogComponent = this.dialogInstance.mount(this.container) as InstanceType; + this.dialogComponent = this.dialogInstance.mount( + this.container, + ) as InstanceType; // Failsafe: force cleanup after 60s if dialog is still open this.failsafeTimeout = setTimeout(() => { if (this.isScanning) { - console.warn(`[WebDialogQRScanner] Failsafe triggered, forcing cleanup for session: ${this.sessionId}`); - this.stopScan('failsafe timeout'); + logger.warn( + `[WebDialogQRScanner] Failsafe triggered, forcing cleanup for session: ${this.sessionId}`, + ); + this.stopScan("failsafe timeout"); } }, 60000); - console.log(`[WebDialogQRScanner] Failsafe timeout set for session: ${this.sessionId}`); + logger.log( + `[WebDialogQRScanner] Failsafe timeout set for session: ${this.sessionId}`, + ); } catch (error) { this.isScanning = false; const wrappedError = @@ -177,20 +187,26 @@ export class WebDialogQRScanner implements QRScannerService { } } - async stopScan(reason: string = 'manual') : Promise { + async stopScan(reason: string = "manual"): Promise { if (!this.isScanning) { return; } try { - console.log(`[WebDialogQRScanner] stopScan called, reason: ${reason}, session: ${this.sessionId}`); + logger.log( + `[WebDialogQRScanner] stopScan called, reason: ${reason}, session: ${this.sessionId}`, + ); if (this.dialogComponent) { await this.dialogComponent.close(); - console.log(`[WebDialogQRScanner] dialogComponent.close() called, session: ${this.sessionId}`); + logger.log( + `[WebDialogQRScanner] dialogComponent.close() called, session: ${this.sessionId}`, + ); } if (this.dialogInstance) { this.dialogInstance.unmount(); - console.log(`[WebDialogQRScanner] dialogInstance.unmount() called, session: ${this.sessionId}`); + logger.log( + `[WebDialogQRScanner] dialogInstance.unmount() called, session: ${this.sessionId}`, + ); } } catch (error) { const wrappedError = @@ -202,7 +218,9 @@ export class WebDialogQRScanner implements QRScannerService { if (this.failsafeTimeout) { clearTimeout(this.failsafeTimeout); this.failsafeTimeout = null; - console.log(`[WebDialogQRScanner] Failsafe timeout cleared, session: ${this.sessionId}`); + logger.log( + `[WebDialogQRScanner] Failsafe timeout cleared, session: ${this.sessionId}`, + ); } this.cleanupContainer(); } @@ -215,16 +233,20 @@ export class WebDialogQRScanner implements QRScannerService { private cleanupContainer(): void { if (this.container && this.container.parentNode) { this.container.parentNode.removeChild(this.container); - console.log(`[WebDialogQRScanner] Dialog container removed from DOM, session: ${this.sessionId}`); + logger.log( + `[WebDialogQRScanner] Dialog container removed from DOM, session: ${this.sessionId}`, + ); } else { - console.log(`[WebDialogQRScanner] Dialog container NOT removed from DOM, session: ${this.sessionId}`); + logger.log( + `[WebDialogQRScanner] Dialog container NOT removed from DOM, session: ${this.sessionId}`, + ); } this.container = null; } async cleanup(): Promise { try { - await this.stopScan('cleanup'); + await this.stopScan("cleanup"); } catch (error) { const wrappedError = error instanceof Error ? error : new Error(String(error)); diff --git a/src/utils/LogCollector.ts b/src/utils/LogCollector.ts index 14ca0159..0e9fd5fa 100644 --- a/src/utils/LogCollector.ts +++ b/src/utils/LogCollector.ts @@ -2,20 +2,22 @@ type LogLevel = "log" | "info" | "warn" | "error"; interface LogEntry { level: LogLevel; - message: any[]; + message: unknown[]; timestamp: string; } class LogCollector { private logs: LogEntry[] = []; private originalConsole: Partial< - Record void> + Record void> > = {}; constructor() { (["log", "info", "warn", "error"] as LogLevel[]).forEach((level) => { + // eslint-disable-next-line no-console this.originalConsole[level] = console[level]; - console[level] = (..._args: any[]) => { + // eslint-disable-next-line no-console + console[level] = (..._args: unknown[]) => { this.logs.push({ level, message: _args,