import QRCode from 'qrcode'; /** * QR Code generation and printing utilities */ export interface QRCodeOptions { width?: number; margin?: number; color?: { dark?: string; light?: string; }; errorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H'; } const defaultOptions: QRCodeOptions = { width: 200, margin: 2, color: { dark: '#000000', light: '#ffffff', }, errorCorrectionLevel: 'M', }; /** * Generate QR code as data URL (PNG image) */ export async function generateQRCode(data: string, options: QRCodeOptions = {}): Promise { const opts = { ...defaultOptions, ...options }; try { return await QRCode.toDataURL(data, { width: opts.width, margin: opts.margin, color: opts.color, errorCorrectionLevel: opts.errorCorrectionLevel, }); } catch (error) { console.error('QR Code generation failed:', error); throw error; } } /** * Generate QR code as SVG string */ export async function generateQRCodeSVG(data: string, options: QRCodeOptions = {}): Promise { const opts = { ...defaultOptions, ...options }; try { return await QRCode.toString(data, { type: 'svg', width: opts.width, margin: opts.margin, color: opts.color, errorCorrectionLevel: opts.errorCorrectionLevel, }); } catch (error) { console.error('QR Code SVG generation failed:', error); throw error; } } /** * Generate batch QR code data */ export function generateBatchQRData(batchId: string, batchName?: string): string { const baseUrl = window.location.origin; return JSON.stringify({ type: 'batch', id: batchId, name: batchName, url: `${baseUrl}/batches/${batchId}`, ts: Date.now(), }); } /** * Generate plant QR code data */ export function generatePlantQRData(plantId: string, tagNumber: string, address: string): string { const baseUrl = window.location.origin; return JSON.stringify({ type: 'plant', id: plantId, tag: tagNumber, address, url: `${baseUrl}/plants/${plantId}`, ts: Date.now(), }); } /** * Generate visitor badge QR code data */ export function generateVisitorQRData(visitorId: string, badgeNumber: string, name: string): string { return JSON.stringify({ type: 'visitor', id: visitorId, badge: badgeNumber, name, ts: Date.now(), }); } /** * Generate room/zone QR code data */ export function generateRoomQRData(roomId: string, roomName: string): string { const baseUrl = window.location.origin; return JSON.stringify({ type: 'room', id: roomId, name: roomName, url: `${baseUrl}/rooms/${roomId}`, ts: Date.now(), }); } /** * Parse scanned QR code data */ export function parseQRData(data: string): { type: 'batch' | 'plant' | 'visitor' | 'room' | 'unknown'; id?: string; url?: string; [key: string]: any; } { try { const parsed = JSON.parse(data); return { type: parsed.type || 'unknown', ...parsed, }; } catch { // If not JSON, try to extract URL if (data.startsWith('http')) { return { type: 'unknown', url: data }; } return { type: 'unknown', raw: data }; } } /** * Generate printable label HTML with QR code */ export async function generatePrintableLabel(params: { type: 'batch' | 'plant' | 'visitor' | 'room'; title: string; subtitle?: string; details?: string[]; qrData: string; size?: 'small' | 'medium' | 'large'; }): Promise { const { type, title, subtitle, details = [], qrData, size = 'medium' } = params; const qrCodeDataUrl = await generateQRCode(qrData, { width: size === 'small' ? 100 : size === 'large' ? 300 : 200, }); const sizes = { small: { width: '2in', fontSize: '8pt', qrSize: '1in' }, medium: { width: '3in', fontSize: '10pt', qrSize: '1.5in' }, large: { width: '4in', fontSize: '12pt', qrSize: '2in' }, }; const sizeConfig = sizes[size]; return `
${title}
${subtitle ? `
${subtitle}
` : ''} ${details.map(d => `
${d}
`).join('')}
${type.toUpperCase()} • ${new Date().toLocaleDateString()}
`; } /** * Print label(s) using browser print dialog */ export function printLabels(labelsHtml: string[], title: string = 'Print Labels') { const printWindow = window.open('', '_blank'); if (!printWindow) { alert('Please allow popups to print labels'); return; } printWindow.document.write(` ${title} ${labelsHtml.map(html => `
${html}
`).join('')} `); printWindow.document.close(); }