forked from trent_larson/crowd-funder-for-time-pwa
- Fix Vue template syntax in App.vue by using proper event handler format - Update Vite config to properly handle ESM imports and crypto modules - Add manual chunks for better code splitting - Improve environment variable handling in vite-env.d.ts - Fix TypeScript linting errors in App.vue
75 lines
2.0 KiB
TypeScript
75 lines
2.0 KiB
TypeScript
import type { QRScannerService, ScanListener } from './types'
|
|
import QRScannerDialog from './QRScannerDialog.vue'
|
|
import { createApp, type App } from 'vue'
|
|
import { logger } from '../../utils/logger'
|
|
|
|
// Import platform-specific flags from Vite config
|
|
declare const __USE_QR_READER__: boolean
|
|
|
|
export class WebDialogQRScanner implements QRScannerService {
|
|
private dialogApp: App | null = null
|
|
private dialogElement: HTMLDivElement | null = null
|
|
private scanListener: ScanListener | null = null
|
|
|
|
async checkPermissions(): Promise<boolean> {
|
|
return navigator?.mediaDevices !== undefined
|
|
}
|
|
|
|
async requestPermissions(): Promise<boolean> {
|
|
try {
|
|
const stream = await navigator.mediaDevices.getUserMedia({ video: true })
|
|
stream.getTracks().forEach((track) => track.stop())
|
|
return true
|
|
} catch (error) {
|
|
logger.error('Failed to get camera permissions:', error)
|
|
return false
|
|
}
|
|
}
|
|
|
|
async isSupported(): Promise<boolean> {
|
|
return Promise.resolve(
|
|
__USE_QR_READER__ && navigator?.mediaDevices !== undefined
|
|
)
|
|
}
|
|
|
|
async startScan(): Promise<void> {
|
|
if (!(await this.isSupported())) {
|
|
throw new Error('QR scanning is not supported in this environment')
|
|
}
|
|
|
|
this.dialogElement = document.createElement('div')
|
|
document.body.appendChild(this.dialogElement)
|
|
|
|
this.dialogApp = createApp(QRScannerDialog, {
|
|
onScan: (result: string) => {
|
|
if (this.scanListener) {
|
|
this.scanListener.onScan(result)
|
|
}
|
|
},
|
|
onClose: () => {
|
|
this.stopScan()
|
|
}
|
|
})
|
|
|
|
this.dialogApp.mount(this.dialogElement)
|
|
}
|
|
|
|
async stopScan(): Promise<void> {
|
|
if (this.dialogApp && this.dialogElement) {
|
|
this.dialogApp.unmount()
|
|
this.dialogElement.remove()
|
|
this.dialogApp = null
|
|
this.dialogElement = null
|
|
}
|
|
}
|
|
|
|
addListener(listener: ScanListener): void {
|
|
this.scanListener = listener
|
|
}
|
|
|
|
async cleanup(): Promise<void> {
|
|
await this.stopScan()
|
|
this.scanListener = null
|
|
}
|
|
}
|