Files
blackcanyontickets/src/lib/qr-generator.ts
dzinesco 26a87d0d00 feat: Complete platform enhancement with multi-tenant architecture
Major additions:
- Territory manager system with application workflow
- Custom pricing and page builder with Craft.js
- Enhanced Stripe Connect onboarding
- CodeReadr QR scanning integration
- Kiosk mode for venue sales
- Super admin dashboard and analytics
- MCP integration for AI-powered operations

Infrastructure improvements:
- Centralized API client and routing system
- Enhanced authentication with organization context
- Comprehensive theme management system
- Advanced event management with custom tabs
- Performance monitoring and accessibility features

Database schema updates:
- Territory management tables
- Custom pages and pricing structures
- Kiosk PIN system
- Enhanced organization profiles
- CodeReadr integration tables

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-12 18:21:40 -06:00

147 lines
3.7 KiB
TypeScript

import QRCode from 'qrcode';
interface QRCodeOptions {
size?: number;
margin?: number;
color?: {
dark?: string;
light?: string;
};
errorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H';
}
interface QRCodeResult {
dataUrl: string;
svg: string;
size: number;
}
export class QRCodeGenerator {
private defaultOptions: QRCodeOptions = {
size: 256,
margin: 2,
color: {
dark: '#000000',
light: '#FFFFFF'
},
errorCorrectionLevel: 'M'
};
/**
* Generate QR code for event ticket URL
*/
async generateEventQR(eventSlug: string, options: QRCodeOptions = {}): Promise<QRCodeResult> {
const ticketUrl = `${import.meta.env.PUBLIC_SITE_URL || 'https://portal.blackcanyontickets.com'}/e/${eventSlug}`;
return this.generateQRCode(ticketUrl, options);
}
/**
* Generate QR code for any URL
*/
async generateQRCode(url: string, options: QRCodeOptions = {}): Promise<QRCodeResult> {
const mergedOptions = { ...this.defaultOptions, ...options };
try {
// Generate data URL (base64 PNG)
const dataUrl = await QRCode.toDataURL(url, {
width: mergedOptions.size,
margin: mergedOptions.margin,
color: mergedOptions.color,
errorCorrectionLevel: mergedOptions.errorCorrectionLevel
});
// Generate SVG
const svg = await QRCode.toString(url, {
type: 'svg',
width: mergedOptions.size,
margin: mergedOptions.margin,
color: mergedOptions.color,
errorCorrectionLevel: mergedOptions.errorCorrectionLevel
});
return {
dataUrl,
svg,
size: mergedOptions.size || this.defaultOptions.size!
};
} catch (error) {
throw new Error('Failed to generate QR code');
}
}
/**
* Generate QR code with custom branding/logo overlay
*/
async generateBrandedQR(
url: string,
logoDataUrl?: string,
options: QRCodeOptions = {}
): Promise<QRCodeResult> {
const qrResult = await this.generateQRCode(url, {
...options,
errorCorrectionLevel: 'H' // Higher error correction for logo overlay
});
if (!logoDataUrl) {
return qrResult;
}
// If logo is provided, we'll need to composite it onto the QR code
// This would typically be done server-side with canvas or image processing
// For now, we'll return the base QR code and handle logo overlay in the image generation
return qrResult;
}
/**
* Validate URL before QR generation
*/
private validateUrl(url: string): boolean {
try {
new URL(url);
return true;
} catch {
return false;
}
}
/**
* Get optimal QR code size for different use cases
*/
getRecommendedSize(useCase: 'social' | 'flyer' | 'email' | 'print'): number {
switch (useCase) {
case 'social':
return 200;
case 'flyer':
return 300;
case 'email':
return 150;
case 'print':
return 600;
default:
return 256;
}
}
/**
* Generate multiple QR code formats for different use cases
*/
async generateMultiFormat(url: string): Promise<{
social: QRCodeResult;
flyer: QRCodeResult;
email: QRCodeResult;
print: QRCodeResult;
}> {
const [social, flyer, email, print] = await Promise.all([
this.generateQRCode(url, { size: this.getRecommendedSize('social') }),
this.generateQRCode(url, { size: this.getRecommendedSize('flyer') }),
this.generateQRCode(url, { size: this.getRecommendedSize('email') }),
this.generateQRCode(url, { size: this.getRecommendedSize('print') })
]);
return { social, flyer, email, print };
}
}
// Export singleton instance
export const qrGenerator = new QRCodeGenerator();