// QR Rapido Speed Generator
class QRRapidoGenerator {
constructor() {
this.startTime = 0;
this.currentQR = null;
this.timerInterval = null;
this.languageStrings = {
'pt-BR': {
tagline: 'Gere QR codes em segundos!',
generating: 'Gerando...',
generated: 'Gerado em',
seconds: 's',
ultraFast: 'Geração ultra rápida!',
fast: 'Geração rápida!',
normal: 'Geração normal',
error: 'Erro na geração. Tente novamente.',
success: 'QR Code salvo no histórico!'
},
'es': {
tagline: '¡Genera códigos QR en segundos!',
generating: 'Generando...',
generated: 'Generado en',
seconds: 's',
ultraFast: '¡Generación ultra rápida!',
fast: '¡Generación rápida!',
normal: 'Generación normal',
error: 'Error en la generación. Inténtalo de nuevo.',
success: '¡Código QR guardado en el historial!'
},
'en': {
tagline: 'Generate QR codes in seconds!',
generating: 'Generating...',
generated: 'Generated in',
seconds: 's',
ultraFast: 'Ultra fast generation!',
fast: 'Fast generation!',
normal: 'Normal generation',
error: 'Generation error. Please try again.',
success: 'QR Code saved to history!'
}
};
this.currentLang = localStorage.getItem('qrrapido-lang') || 'pt-BR';
this.initializeEvents();
this.checkAdFreeStatus();
this.updateLanguage();
this.updateStatsCounters();
}
initializeEvents() {
// Form submission with timer
const form = document.getElementById('qr-speed-form');
if (form) {
form.addEventListener('submit', this.generateQRWithTimer.bind(this));
}
// Quick style selection
document.querySelectorAll('input[name="quick-style"]').forEach(radio => {
radio.addEventListener('change', this.applyQuickStyle.bind(this));
});
// QR type change with hints
const qrType = document.getElementById('qr-type');
if (qrType) {
qrType.addEventListener('change', this.updateContentHints.bind(this));
}
// Language selector
document.querySelectorAll('[data-lang]').forEach(link => {
link.addEventListener('click', this.changeLanguage.bind(this));
});
// Real-time preview for premium users
if (this.isPremiumUser()) {
this.setupRealTimePreview();
}
// Download buttons
this.setupDownloadButtons();
// Share functionality
this.setupShareButtons();
// Save to history
const saveBtn = document.getElementById('save-to-history');
if (saveBtn) {
saveBtn.addEventListener('click', this.saveToHistory.bind(this));
}
}
setupDownloadButtons() {
const pngBtn = document.getElementById('download-png');
const svgBtn = document.getElementById('download-svg');
const pdfBtn = document.getElementById('download-pdf');
if (pngBtn) pngBtn.addEventListener('click', () => this.downloadQR('png'));
if (svgBtn) svgBtn.addEventListener('click', () => this.downloadQR('svg'));
if (pdfBtn) pdfBtn.addEventListener('click', () => this.downloadQR('pdf'));
}
setupShareButtons() {
// Check if Web Share API is supported and show/hide native share option
if (navigator.share && this.isMobileDevice()) {
const nativeShareOption = document.getElementById('native-share-option');
if (nativeShareOption) {
nativeShareOption.classList.remove('d-none');
}
}
// Show save to gallery option on mobile
if (this.isMobileDevice()) {
const saveGalleryOption = document.getElementById('save-gallery-option');
if (saveGalleryOption) {
saveGalleryOption.classList.remove('d-none');
}
}
// Add event listeners to share buttons
const shareButtons = {
'native-share': () => this.shareNative(),
'share-whatsapp': () => this.shareWhatsApp(),
'share-telegram': () => this.shareTelegram(),
'share-email': () => this.shareEmail(),
'copy-qr-link': () => this.copyToClipboard(),
'save-to-gallery': () => this.saveToGallery()
};
Object.entries(shareButtons).forEach(([id, handler]) => {
const button = document.getElementById(id);
if (button) {
button.addEventListener('click', (e) => {
e.preventDefault();
handler();
});
}
});
}
isMobileDevice() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||
(navigator.maxTouchPoints && navigator.maxTouchPoints > 2 && /MacIntel/.test(navigator.platform));
}
async shareNative() {
if (!this.currentQR || !navigator.share) return;
try {
// Create a blob from the base64 image
const base64Response = await fetch(`data:image/png;base64,${this.currentQR.base64}`);
const blob = await base64Response.blob();
const file = new File([blob], 'qrcode.png', { type: 'image/png' });
const shareData = {
title: 'QR Code - QR Rapido',
text: 'QR Code gerado com QR Rapido - o gerador mais rápido do Brasil!',
url: window.location.origin,
files: [file]
};
// Check if files can be shared
if (navigator.canShare && navigator.canShare(shareData)) {
await navigator.share(shareData);
} else {
// Fallback without files
await navigator.share({
title: shareData.title,
text: shareData.text,
url: shareData.url
});
}
this.trackShareEvent('native');
} catch (error) {
console.error('Error sharing:', error);
if (error.name !== 'AbortError') {
this.showError('Erro ao compartilhar. Tente outro método.');
}
}
}
shareWhatsApp() {
if (!this.currentQR) return;
const text = encodeURIComponent('QR Code gerado com QR Rapido - o gerador mais rápido do Brasil! ' + window.location.origin);
const url = `https://wa.me/?text=${text}`;
if (this.isMobileDevice()) {
window.open(url, '_blank');
} else {
window.open(`https://web.whatsapp.com/send?text=${text}`, '_blank');
}
this.trackShareEvent('whatsapp');
}
shareTelegram() {
if (!this.currentQR) return;
const text = encodeURIComponent('QR Code gerado com QR Rapido - o gerador mais rápido do Brasil!');
const url = encodeURIComponent(window.location.origin);
const telegramUrl = `https://t.me/share/url?url=${url}&text=${text}`;
window.open(telegramUrl, '_blank');
this.trackShareEvent('telegram');
}
shareEmail() {
if (!this.currentQR) return;
const subject = encodeURIComponent('QR Code - QR Rapido');
const body = encodeURIComponent(`Olá!\n\nCompartilho com você este QR Code gerado no QR Rapido, o gerador mais rápido do Brasil!\n\nAcesse: ${window.location.origin}\n\nAbraços!`);
const mailtoUrl = `mailto:?subject=${subject}&body=${body}`;
window.location.href = mailtoUrl;
this.trackShareEvent('email');
}
async copyToClipboard() {
if (!this.currentQR) return;
try {
const shareText = `QR Code gerado com QR Rapido - ${window.location.origin}`;
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(shareText);
} else {
// Fallback for older browsers
const textArea = document.createElement('textarea');
textArea.value = shareText;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
textArea.style.top = '-999999px';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
document.execCommand('copy');
textArea.remove();
}
this.showSuccess('Link copiado para a área de transferência!');
this.trackShareEvent('copy');
} catch (error) {
console.error('Error copying to clipboard:', error);
this.showError('Erro ao copiar link. Tente novamente.');
}
}
async saveToGallery() {
if (!this.currentQR) return;
try {
// Create a blob from the base64 image
const base64Response = await fetch(`data:image/png;base64,${this.currentQR.base64}`);
const blob = await base64Response.blob();
// Create download link
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `qrrapido-${new Date().toISOString().slice(0,10)}-${Date.now()}.png`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
this.showSuccess('QR Code baixado! Verifique sua galeria/downloads.');
this.trackShareEvent('gallery');
} catch (error) {
console.error('Error saving to gallery:', error);
this.showError('Erro ao salvar na galeria. Tente novamente.');
}
}
trackShareEvent(method) {
// Google Analytics
if (typeof gtag !== 'undefined') {
gtag('event', 'qr_shared', {
'share_method': method,
'user_type': this.isPremiumUser() ? 'premium' : 'free',
'language': this.currentLang
});
}
// Internal tracking
console.log(`QR Code shared via ${method}`);
}
async generateQRWithTimer(e) {
e.preventDefault();
// Validation
if (!this.validateForm()) return;
// Start timer
this.startTime = performance.now();
this.showGenerationStarted();
const formData = this.collectFormData();
try {
const response = await fetch('/api/QR/GenerateRapid', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData)
});
if (!response.ok) {
if (response.status === 429) {
this.showUpgradeModal('Limite de QR codes atingido! Upgrade para QR Rapido Premium e gere códigos ilimitados.');
return;
}
throw new Error('Erro na geração');
}
const result = await response.json();
if (!result.success) {
throw new Error(result.error || 'Erro desconhecido');
}
const generationTime = ((performance.now() - this.startTime) / 1000).toFixed(1);
this.displayQRResult(result, generationTime);
this.updateSpeedStats(generationTime);
this.trackGenerationEvent(formData.type, generationTime);
} catch (error) {
console.error('Erro ao gerar QR:', error);
this.showError(this.languageStrings[this.currentLang].error);
} finally {
this.hideGenerationLoading();
}
}
validateForm() {
const qrType = document.getElementById('qr-type').value;
const qrContent = document.getElementById('qr-content').value.trim();
if (!qrType) {
this.showError('Selecione o tipo de QR code');
return false;
}
if (!qrContent) {
this.showError('Digite o conteúdo do QR code');
return false;
}
if (qrContent.length > 4000) {
this.showError('Conteúdo muito longo. Máximo 4000 caracteres.');
return false;
}
return true;
}
collectFormData() {
const quickStyle = document.querySelector('input[name="quick-style"]:checked')?.value || 'classic';
const styleSettings = this.getStyleSettings(quickStyle);
return {
type: document.getElementById('qr-type').value,
content: document.getElementById('qr-content').value,
quickStyle: quickStyle,
primaryColor: document.getElementById('primary-color').value,
backgroundColor: document.getElementById('bg-color').value,
size: parseInt(document.getElementById('qr-size').value),
margin: parseInt(document.getElementById('qr-margin').value),
cornerStyle: document.getElementById('corner-style')?.value || 'square',
optimizeForSpeed: true,
language: this.currentLang,
...styleSettings
};
}
getStyleSettings(style) {
const styles = {
classic: { primaryColor: '#000000', backgroundColor: '#FFFFFF' },
modern: { primaryColor: '#007BFF', backgroundColor: '#F8F9FA' },
colorful: { primaryColor: '#FF6B35', backgroundColor: '#FFF3E0' }
};
return styles[style] || styles.classic;
}
displayQRResult(result, generationTime) {
const previewDiv = document.getElementById('qr-preview');
if (!previewDiv) return;
previewDiv.innerHTML = `
`;
// Show generation statistics
this.showGenerationStats(generationTime);
// Show download buttons
const downloadSection = document.getElementById('download-section');
if (downloadSection) {
downloadSection.style.display = 'block';
}
// Save current data
this.currentQR = {
base64: result.qrCodeBase64,
id: result.qrId,
generationTime: generationTime
};
// Update counter for free users
if (result.remainingQRs !== undefined) {
this.updateRemainingCounter(result.remainingQRs);
}
}
showGenerationStarted() {
const button = document.getElementById('generate-btn');
const spinner = button?.querySelector('.spinner-border');
const timer = document.querySelector('.generation-timer');
if (button) button.disabled = true;
if (spinner) spinner.classList.remove('d-none');
if (timer) timer.classList.remove('d-none');
// Update timer in real time
this.timerInterval = setInterval(() => {
const elapsed = ((performance.now() - this.startTime) / 1000).toFixed(1);
const timerSpan = timer?.querySelector('span');
if (timerSpan) {
timerSpan.textContent = `${elapsed}s`;
}
}, 100);
// Preview loading
const preview = document.getElementById('qr-preview');
if (preview) {
preview.innerHTML = `
${this.languageStrings[this.currentLang].generating}