import { ref, readonly, computed } from 'vue' import { nextTick } from 'vue' import type { CheckInStatus } from '~/types/checkin' export interface UseQRGeneratorOptions { showSnackbar: (title: string, message: string, color: string, icon: string) => void generateRandomPatientId: () => string } export const useQRGenerator = (options: UseQRGeneratorOptions) => { const { showSnackbar, generateRandomPatientId } = options // State const generatePatientId = ref(generateRandomPatientId()) const generateStatus = ref('ALLOWED') const generatedQRData = ref('') // Generate random patient ID const generateRandomId = () => { generatePatientId.value = generateRandomPatientId() } // Quick generate QR for testing const generateQuickQR = (patientId: string, status: string) => { generatePatientId.value = patientId generateStatus.value = status as CheckInStatus generateQRCode() } // Generate QR Code function const generateQRCode = async () => { if (!generatePatientId.value) { showSnackbar('Error', 'Mohon isi ID Pasien', 'error', 'mdi-alert') return } generatedQRData.value = `${generatePatientId.value}|${generateStatus.value}` await nextTick() // Clear previous QR code const qrContainer = document.getElementById('qrcode') if (qrContainer) { qrContainer.innerHTML = '' try { // Use qrcode package that's already installed const QRCode = (await import('qrcode')).default // Create QR code as data URL const qrDataUrl = await QRCode.toDataURL(generatedQRData.value, { errorCorrectionLevel: 'M', type: 'image/png', quality: 0.92, margin: 1, color: { dark: '#000000', light: '#FFFFFF' }, width: 300 }) // Create img element and append to container const img = document.createElement('img') img.src = qrDataUrl img.alt = 'QR Code' img.style.width = '100%' img.style.maxWidth = '300px' img.style.height = 'auto' img.style.display = 'block' img.style.margin = '0 auto' qrContainer.appendChild(img) console.log('QR Code created successfully:', generatedQRData.value) showSnackbar('Berhasil!', 'QR Code berhasil di-generate. Silakan scan untuk testing', 'success', 'mdi-check-circle') } catch (error) { console.error('Error creating QR code:', error) showSnackbar('Error', 'Gagal membuat QR Code. Silakan coba lagi', 'error', 'mdi-alert') } } else { showSnackbar('Error', 'Container QR Code tidak ditemukan', 'error', 'mdi-alert') } } // Download QR Code const downloadQR = async () => { const img = document.querySelector('#qrcode img') as HTMLImageElement if (img && img.src) { try { // Convert img src (data URL) to blob const response = await fetch(img.src) const blob = await response.blob() const url = URL.createObjectURL(blob) const link = document.createElement('a') const fileName = `QR-Test-${generatePatientId.value}-${generateStatus.value}-${Date.now()}.png` link.download = fileName link.href = url link.style.display = 'none' document.body.appendChild(link) link.click() document.body.removeChild(link) URL.revokeObjectURL(url) showSnackbar('Berhasil!', `QR Code berhasil didownload: ${fileName}`, 'success', 'mdi-download') } catch (error) { console.error('Download error:', error) // Fallback: use img src directly const link = document.createElement('a') link.download = `QR-Test-${generatePatientId.value}-${generateStatus.value}.png` link.href = img.src link.click() showSnackbar('Berhasil!', 'QR Code berhasil didownload', 'success', 'mdi-download') } } else { showSnackbar('Error', 'QR Code belum di-generate. Silakan generate terlebih dahulu', 'error', 'mdi-alert') } } // Copy QR Code to Clipboard const copyQRToClipboard = async () => { const img = document.querySelector('#qrcode img') as HTMLImageElement if (img && img.src) { try { // Convert img src to blob const response = await fetch(img.src) const blob = await response.blob() try { await navigator.clipboard.write([ new ClipboardItem({ 'image/png': blob }) ]) showSnackbar('Berhasil!', 'QR Code berhasil disalin ke clipboard', 'success', 'mdi-content-copy') } catch (err: any) { console.error('Clipboard error:', err) // Fallback: download instead showSnackbar('Info', 'Copy ke clipboard tidak didukung. Gunakan tombol Download.', 'info', 'mdi-information') } } catch (error) { console.error('Copy error:', error) showSnackbar('Error', 'Gagal menyalin QR Code', 'error', 'mdi-alert') } } else { showSnackbar('Error', 'QR Code belum di-generate. Silakan generate terlebih dahulu', 'error', 'mdi-alert') } } // Share QR Code const shareQR = async () => { const img = document.querySelector('#qrcode img') as HTMLImageElement if (img && img.src) { try { // Convert img src to blob const response = await fetch(img.src) const blob = await response.blob() const file = new File([blob], `QR-Test-${generatePatientId.value}-${generateStatus.value}.png`, { type: 'image/png' }) if (navigator.share && navigator.canShare({ files: [file] })) { try { await navigator.share({ files: [file], title: 'QR Code Check-in Test', text: `QR Code untuk testing: ${generatedQRData.value}` }) showSnackbar('Berhasil!', 'QR Code berhasil dibagikan', 'success', 'mdi-share') } catch (err: any) { if (err.name !== 'AbortError') { // Fallback to copy or download copyQRToClipboard() } } } else { // Fallback: try copy to clipboard copyQRToClipboard() } } catch (error) { console.error('Share error:', error) showSnackbar('Error', 'Gagal membagikan QR Code', 'error', 'mdi-alert') } } else { showSnackbar('Error', 'QR Code belum di-generate. Silakan generate terlebih dahulu', 'error', 'mdi-alert') } } // Computed untuk v-model const generatePatientIdModel = computed({ get: () => generatePatientId.value, set: (value: string) => { generatePatientId.value = value } }) const generateStatusModel = computed({ get: () => generateStatus.value, set: (value: CheckInStatus) => { generateStatus.value = value } }) return { generatePatientId: generatePatientIdModel, generateStatus: generateStatusModel, generatedQRData: readonly(generatedQRData), generateRandomId, generateQuickQR, generateQRCode, downloadQR, copyQRToClipboard, shareQR, } }