Adicione sua marca aos QR Codes! Upgrade para Premium e personalize com seu logo.
+Adicione sua marca aos QR Codes! Agora com tamanho configurável (10-25%) e colorização automática.
Fazer Upgrade @@ -869,4 +959,66 @@ -@await Html.PartialAsync("_AdSpace", new { position = "footer" }) \ No newline at end of file +@await Html.PartialAsync("_AdSpace", new { position = "footer" }) + + + \ No newline at end of file diff --git a/wwwroot/js/qr-speed-generator.js b/wwwroot/js/qr-speed-generator.js index 8dbeaab..3395c28 100644 --- a/wwwroot/js/qr-speed-generator.js +++ b/wwwroot/js/qr-speed-generator.js @@ -373,6 +373,12 @@ class QRRapidoGenerator { }; } + console.log('🚀 Enviando requisição:', { + endpoint: requestData.endpoint, + isMultipart: requestData.isMultipart, + hasLogo: requestData.isMultipart + }); + const response = await fetch(requestData.endpoint, fetchOptions); if (!response.ok) { @@ -403,12 +409,19 @@ class QRRapidoGenerator { const generationTime = ((performance.now() - this.startTime) / 1000).toFixed(1); + console.log('✅ QR code recebido do backend:', { + success: result.success, + hasBase64: !!result.qrCodeBase64, + base64Length: result.qrCodeBase64?.length || 0, + generationTime: generationTime + 's' + }); + this.displayQRResult(result, generationTime); this.updateSpeedStats(generationTime); this.trackGenerationEvent(requestData.data.type || requestData.data.get('type'), generationTime); } catch (error) { - console.error('Erro ao gerar QR:', error); + console.error('❌ Erro ao gerar QR:', error); this.showError(this.languageStrings[this.currentLang].error); } finally { this.hideGenerationLoading(); @@ -485,198 +498,145 @@ class QRRapidoGenerator { const quickStyle = document.querySelector('input[name="quick-style"]:checked')?.value || 'classic'; const styleSettings = this.getStyleSettings(quickStyle); + // Check if logo is selected FIRST - this determines the endpoint + const logoUpload = document.getElementById('logo-upload'); + const hasLogo = logoUpload && logoUpload.files && logoUpload.files[0]; + + // Get content based on type + let content, actualType; + if (type === 'url') { const dynamicData = window.dynamicQRManager.getDynamicQRData(); if (dynamicData.requiresPremium) { throw new Error('QR Dinâmico é exclusivo para usuários Premium. Faça upgrade para usar analytics.'); } - return { - data: { - type: 'url', - content: dynamicData.originalUrl, - isDynamic: dynamicData.isDynamic, - quickStyle: quickStyle, - primaryColor: document.getElementById('primary-color').value || (styleSettings.primaryColor || '#000000'), - backgroundColor: document.getElementById('bg-color').value || (styleSettings.backgroundColor || '#FFFFFF'), - 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 - }, - isMultipart: false, - endpoint: '/api/QR/GenerateRapid' - }; - } - - if (type === 'wifi') { - const wifiContent = window.wifiGenerator.generateWiFiString(); - return { - data: { - type: 'text', // WiFi is treated as text in the backend - content: wifiContent, - quickStyle: quickStyle, - primaryColor: document.getElementById('primary-color').value || (styleSettings.primaryColor || '#000000'), - backgroundColor: document.getElementById('bg-color').value || (styleSettings.backgroundColor || '#FFFFFF'), - 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 - }, - isMultipart: false, - endpoint: '/api/QR/GenerateRapid' - }; + content = dynamicData.originalUrl; + actualType = 'url'; + } else if (type === 'wifi') { + content = window.wifiGenerator.generateWiFiString(); + actualType = 'text'; // WiFi is treated as text in the backend } else if (type === 'sms') { - const smsContent = window.smsGenerator.generateSMSString(); - return { - data: { - type: 'text', - content: smsContent, - quickStyle: quickStyle, - primaryColor: document.getElementById('primary-color').value || (styleSettings.primaryColor || '#000000'), - backgroundColor: document.getElementById('bg-color').value || (styleSettings.backgroundColor || '#FFFFFF'), - 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 - }, - isMultipart: false, - endpoint: '/api/QR/GenerateRapid' - }; + content = window.smsGenerator.generateSMSString(); + actualType = 'text'; } else if (type === 'email') { - const emailContent = window.emailGenerator.generateEmailString(); - return { - data: { - type: 'text', - content: emailContent, - quickStyle: quickStyle, - primaryColor: document.getElementById('primary-color').value || (styleSettings.primaryColor || '#000000'), - backgroundColor: document.getElementById('bg-color').value || (styleSettings.backgroundColor || '#FFFFFF'), - 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 - }, - isMultipart: false, - endpoint: '/api/QR/GenerateRapid' - }; - } - - // Handle VCard type - if (type === 'vcard') { - if (window.vcardGenerator) { - const vcardContent = window.vcardGenerator.getVCardContent(); - const encodedContent = this.prepareContentForQR(vcardContent, 'vcard'); - return { - data: { - type: 'vcard', // Keep as vcard type for tracking - content: encodedContent, - quickStyle: quickStyle, - primaryColor: document.getElementById('primary-color').value || (styleSettings.primaryColor || '#000000'), - backgroundColor: document.getElementById('bg-color').value || (styleSettings.backgroundColor || '#FFFFFF'), - 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 - }, - isMultipart: false, - endpoint: '/api/QR/GenerateRapid' - }; - } else { + content = window.emailGenerator.generateEmailString(); + actualType = 'text'; + } else if (type === 'vcard') { + if (!window.vcardGenerator) { throw new Error('VCard generator não está disponível'); } + content = window.vcardGenerator.getVCardContent(); + actualType = 'vcard'; // Keep as vcard type for tracking + } else { + // Default case - get content from input + content = document.getElementById('qr-content').value; + actualType = type; + } + + // Prepare final content + const encodedContent = this.prepareContentForQR(content, actualType); + + // Get colors + const userPrimaryColor = document.getElementById('primary-color').value; + const userBackgroundColor = document.getElementById('bg-color').value; + const finalPrimaryColor = userPrimaryColor || (styleSettings.primaryColor || '#000000'); + const finalBackgroundColor = userBackgroundColor || (styleSettings.backgroundColor || '#FFFFFF'); + + // Common data for both endpoints + const commonData = { + type: actualType, + content: encodedContent, + quickStyle: quickStyle, + primaryColor: finalPrimaryColor, + backgroundColor: finalBackgroundColor, + 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 + }; + + // Add dynamic QR data if it's a URL type + if (type === 'url') { + const dynamicData = window.dynamicQRManager.getDynamicQRData(); + commonData.isDynamic = dynamicData.isDynamic; } - // Check if logo is selected for premium users - const logoUpload = document.getElementById('logo-upload'); - const hasLogo = logoUpload && logoUpload.files && logoUpload.files[0]; - if (hasLogo) { - // Use FormData for premium users with logo + // Use FormData for requests with logo const formData = new FormData(); - // Get user-selected colors with proper priority - const userPrimaryColor = document.getElementById('primary-color').value; - const userBackgroundColor = document.getElementById('bg-color').value; + // Add all common data to FormData + Object.keys(commonData).forEach(key => { + formData.append(key, commonData[key]); + }); - // Priority: User selection > Style defaults > Fallback - // Always use user selection if it exists, regardless of what color it is - const finalPrimaryColor = userPrimaryColor || (styleSettings.primaryColor || '#000000'); - const finalBackgroundColor = userBackgroundColor || (styleSettings.backgroundColor || '#FFFFFF'); - - // Debug logging for color selection - console.log('🎨 Color Selection Debug (FormData):'); - console.log(' Style:', quickStyle); - console.log(' Style Default Primary:', styleSettings.primaryColor); - console.log(' User Selected Primary:', userPrimaryColor); - console.log(' Final Primary Color:', finalPrimaryColor); - console.log(' Final Background Color:', finalBackgroundColor); - - // Add basic form fields with UTF-8 encoding - const rawContent = document.getElementById('qr-content').value; - const encodedContent = this.prepareContentForQR(rawContent, type); - - formData.append('type', document.getElementById('qr-type').value); - formData.append('content', encodedContent); - formData.append('quickStyle', quickStyle); - formData.append('primaryColor', finalPrimaryColor); - formData.append('backgroundColor', finalBackgroundColor); - formData.append('size', parseInt(document.getElementById('qr-size').value)); - formData.append('margin', parseInt(document.getElementById('qr-margin').value)); - formData.append('cornerStyle', document.getElementById('corner-style')?.value || 'square'); - formData.append('optimizeForSpeed', 'true'); - formData.append('language', this.currentLang); + // NOVOS PARÂMETROS DE LOGO APRIMORADO + const logoSettings = this.getLogoSettings(); + formData.append('logoSizePercent', logoSettings.logoSizePercent.toString()); + formData.append('applyLogoColorization', logoSettings.applyColorization.toString()); // Add logo file formData.append('logo', logoUpload.files[0]); - console.log('Logo file added to form data:', logoUpload.files[0].name, logoUpload.files[0].size + ' bytes'); - return { data: formData, isMultipart: true, endpoint: '/api/QR/GenerateRapidWithLogo' }; + // CORREÇÃO: Log detalhado antes de enviar + const logoSizeSlider = document.getElementById('logo-size-slider'); + const logoColorizeToggle = document.getElementById('logo-colorize-toggle'); + + console.log('🎨 Preparando FormData com logo:', { + logoFile: logoUpload.files[0].name, + logoSize: logoUpload.files[0].size + ' bytes', + logoSizePercent: logoSizeSlider?.value || logoSettings.logoSizePercent || '20', + colorization: logoColorizeToggle?.checked || logoSettings.applyColorization || false, + endpoint: '/api/QR/GenerateRapidWithLogo' + }); + + return { + data: formData, + isMultipart: true, + endpoint: '/api/QR/GenerateRapidWithLogo' + }; } else { - // Use JSON for basic QR generation (original working method) - // Get user-selected colors - const userPrimaryColor = document.getElementById('primary-color').value; - const userBackgroundColor = document.getElementById('bg-color').value; - - // Priority: User selection > Style defaults > Fallback - // Always use user selection if it exists, regardless of what color it is - const finalPrimaryColor = userPrimaryColor || (styleSettings.primaryColor || '#000000'); - const finalBackgroundColor = userBackgroundColor || (styleSettings.backgroundColor || '#FFFFFF'); - - // Debug logging for color selection - console.log('🎨 Color Selection Debug (JSON):'); - console.log(' Style:', quickStyle); - console.log(' Style Default Primary:', styleSettings.primaryColor); - console.log(' User Selected Primary:', userPrimaryColor); - console.log(' Final Primary Color:', finalPrimaryColor); - console.log(' Final Background Color:', finalBackgroundColor); - - const rawContent = document.getElementById('qr-content').value; - const encodedContent = this.prepareContentForQR(rawContent, type); + // Usar JSON para QR sem logo (método original) + console.log('📝 Preparando JSON sem logo - endpoint: /api/QR/GenerateRapid'); return { - data: { - type: document.getElementById('qr-type').value, - content: encodedContent, - quickStyle: quickStyle, - primaryColor: finalPrimaryColor, - backgroundColor: finalBackgroundColor, - 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 - }, + data: commonData, isMultipart: false, endpoint: '/api/QR/GenerateRapid' }; } } + // Nova função para coletar configurações de logo + getLogoSettings() { + const logoSizeSlider = document.getElementById('logo-size-slider'); + const logoColorizeToggle = document.getElementById('logo-colorize-toggle'); + + return { + logoSizePercent: parseInt(logoSizeSlider?.value || '20'), + applyColorization: logoColorizeToggle?.checked || false + }; + } + + // Função auxiliar para obter conteúdo baseado no tipo + getContentForType(type) { + if (type === 'url') { + const dynamicData = window.dynamicQRManager?.getDynamicQRData(); + return dynamicData?.originalUrl || document.getElementById('qr-content').value; + } else if (type === 'wifi') { + return window.wifiGenerator?.generateWiFiString() || ''; + } else if (type === 'vcard') { + return window.vcardGenerator?.getVCardContent() || ''; + } else if (type === 'sms') { + return window.smsGenerator?.generateSMSString() || ''; + } else if (type === 'email') { + return window.emailGenerator?.generateEmailString() || ''; + } else { + return document.getElementById('qr-content').value || ''; + } + } + getStyleSettings(style) { const styles = { classic: { primaryColor: '#000000', backgroundColor: '#FFFFFF' }, @@ -690,12 +650,26 @@ class QRRapidoGenerator { const previewDiv = document.getElementById('qr-preview'); if (!previewDiv) return; + // CORREÇÃO SIMPLES: Remover cache buster que quebrava a imagem e adicionar debug + const imageUrl = `data:image/png;base64,${result.qrCodeBase64}`; + previewDiv.innerHTML = ` -