diff --git a/Views/Home/Index.cshtml b/Views/Home/Index.cshtml index 0406913..f06d1ca 100644 --- a/Views/Home/Index.cshtml +++ b/Views/Home/Index.cshtml @@ -103,7 +103,7 @@ -
+
@@ -250,15 +250,186 @@
BEGIN:VCARD
-VERSION:3.0
-CHARSET=UTF-8
-Preencha os campos acima para ver o preview...
-END:VCARD
+ VERSION:3.0 + CHARSET=UTF-8 + Preencha os campos acima para ver o preview... + END:VCARD +
+ + + + + + + + + + + +
diff --git a/wwwroot/js/qr-speed-generator.js b/wwwroot/js/qr-speed-generator.js index 71fc512..a47de8c 100644 --- a/wwwroot/js/qr-speed-generator.js +++ b/wwwroot/js/qr-speed-generator.js @@ -106,16 +106,21 @@ class QRRapidoGenerator { }); }); - // VCard fields validation - const vcardFields = ['vcard-name', 'vcard-mobile', 'vcard-email']; - vcardFields.forEach(fieldId => { - const field = document.getElementById(fieldId); - if (field) { - field.addEventListener('input', () => { - this.updateGenerateButton(); - }); + // Add listeners to all relevant fields to update button state + const fieldsToWatch = [ + 'qr-content', 'vcard-name', 'vcard-mobile', 'vcard-email', + 'wifi-ssid', 'wifi-password', 'sms-number', 'sms-message', + 'email-to', 'email-subject', 'email-body' + ]; + fieldsToWatch.forEach(id => { + const el = document.getElementById(id); + if (el) { + el.addEventListener('input', () => this.updateGenerateButton()); } }); + document.querySelectorAll('input[name="wifi-security"]').forEach(radio => { + radio.addEventListener('change', () => this.updateGenerateButton()); + }); // Language selector document.querySelectorAll('[data-lang]').forEach(link => { @@ -431,6 +436,27 @@ class QRRapidoGenerator { this.showError('Erro na validação do VCard: ' + error.message); return false; } + } else if (qrType === 'wifi') { + const errors = window.wifiGenerator.validateWiFiData(); + if (errors.length > 0) { + this.showError(errors.join('
')); + return false; + } + return true; + } else if (qrType === 'sms') { + const errors = window.smsGenerator.validateSMSData(); + if (errors.length > 0) { + this.showError(errors.join('
')); + return false; + } + return true; + } else if (qrType === 'email') { + const errors = window.emailGenerator.validateEmailData(); + if (errors.length > 0) { + this.showError(errors.join('
')); + return false; + } + return true; } // Normal validation for other types @@ -454,6 +480,62 @@ class QRRapidoGenerator { const quickStyle = document.querySelector('input[name="quick-style"]:checked')?.value || 'classic'; const styleSettings = this.getStyleSettings(quickStyle); + 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' + }; + } 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' + }; + } 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) { @@ -729,7 +811,7 @@ class QRRapidoGenerator { 'wifi': 'Nombre de red;Contraseña;Tipo de seguridad (WPA/WEP)', 'vcard': 'Nombre;Teléfono;Email;Empresa', 'sms': 'Número;Mensaje', - 'email': 'email@ejemplo.com;Asunto;Mensaje' + 'email': 'email@ejemplo.com;Asunto;Mensagem' } }; @@ -1207,29 +1289,51 @@ class QRRapidoGenerator { } enableContentFields(type) { - const qrContent = document.getElementById('qr-content'); + const contentGroup = document.getElementById('content-group'); const vcardInterface = document.getElementById('vcard-interface'); - + const wifiInterface = document.getElementById('wifi-interface'); + const smsInterface = document.getElementById('sms-interface'); + const emailInterface = document.getElementById('email-interface'); + + // Hide all interfaces by default + if (vcardInterface) vcardInterface.style.display = 'none'; + if (wifiInterface) wifiInterface.style.display = 'none'; + if (smsInterface) smsInterface.style.display = 'none'; + if (emailInterface) emailInterface.style.display = 'none'; + if (contentGroup) contentGroup.style.display = 'block'; + if (type === 'vcard') { // Para vCard, ocultar textarea e mostrar interface específica - if (qrContent) { - qrContent.style.display = 'none'; - qrContent.removeAttribute('required'); - } + if (contentGroup) contentGroup.style.display = 'none'; if (vcardInterface) { vcardInterface.style.display = 'block'; this.enableVCardFields(); } + } else if (type === 'wifi') { + // Para WiFi, ocultar textarea e mostrar interface específica + if (contentGroup) contentGroup.style.display = 'none'; + if (wifiInterface) { + wifiInterface.style.display = 'block'; + } + } else if (type === 'sms') { + // Para SMS, ocultar textarea e mostrar interface específica + if (contentGroup) contentGroup.style.display = 'none'; + if (smsInterface) { + smsInterface.style.display = 'block'; + } + } else if (type === 'email') { + // Para Email, ocultar textarea e mostrar interface específica + if (contentGroup) contentGroup.style.display = 'none'; + if (emailInterface) { + emailInterface.style.display = 'block'; + } } else { // Para outros tipos, mostrar textarea - if (qrContent) { - qrContent.style.display = 'block'; - qrContent.setAttribute('required', 'required'); + if (contentGroup) contentGroup.style.display = 'block'; + const qrContent = document.getElementById('qr-content'); + if(qrContent) { qrContent.disabled = false; } - if (vcardInterface) { - vcardInterface.style.display = 'none'; - } } } @@ -1323,30 +1427,37 @@ class QRRapidoGenerator { updateGenerateButton() { const generateBtn = document.getElementById('generate-btn'); if (!generateBtn) return; - - let shouldEnable = false; - - // Verificar se tem tipo selecionado - if (this.selectedType) { - if (this.selectedType === 'vcard') { - // Para vCard, validar campos obrigatórios - shouldEnable = this.validateVCardFields(); - } else { - // Para outros tipos, validar conteúdo - const content = document.getElementById('qr-content')?.value || ''; - shouldEnable = this.validateContent(content); + + let isValid = false; + const type = this.selectedType; + + if (type === 'url' || type === 'text') { + const content = document.getElementById('qr-content')?.value || ''; + isValid = content.trim().length >= 3; + } else if (type === 'vcard') { + isValid = this.validateVCardFields(); + } else if (type === 'wifi') { + const data = window.wifiGenerator.collectWiFiData(); + isValid = data.ssid.trim() !== ''; + if (data.security !== 'nopass' && !data.password.trim()) { + isValid = false; } + } else if (type === 'sms') { + const data = window.smsGenerator.collectSMSData(); + isValid = data.number.trim() !== '' && data.message.trim() !== ''; + } else if (type === 'email') { + const data = window.emailGenerator.collectEmailData(); + isValid = data.to.trim() !== '' && data.subject.trim() !== ''; } - - generateBtn.disabled = !shouldEnable; - - // Feedback visual - if (shouldEnable) { - generateBtn.classList.remove('btn-secondary'); + + generateBtn.disabled = !isValid; + + if (isValid) { + generateBtn.classList.remove('btn-secondary', 'disabled'); generateBtn.classList.add('btn-primary'); } else { generateBtn.classList.remove('btn-primary'); - generateBtn.classList.add('btn-secondary'); + generateBtn.classList.add('btn-secondary', 'disabled'); } } @@ -1369,7 +1480,7 @@ class QRRapidoGenerator { // Garantir que o conteúdo seja tratado como UTF-8 try { // Verificar se há caracteres especiais - const hasSpecialChars = /[^\x00-\x7F]/.test(content); + const hasSpecialChars = /[^-]/.test(content); if (hasSpecialChars) { console.log('Caracteres especiais detectados, aplicando codificação UTF-8'); @@ -1441,6 +1552,9 @@ class QRRapidoGenerator { document.addEventListener('DOMContentLoaded', () => { window.qrGenerator = new QRRapidoGenerator(); window.vcardGenerator = new VCardGenerator(); + window.wifiGenerator = new WiFiQRGenerator(); + window.smsGenerator = new SMSQRGenerator(); + window.emailGenerator = new EmailQRGenerator(); // Initialize AdSense if necessary if (window.adsbygoogle && document.querySelector('.adsbygoogle')) { @@ -1448,7 +1562,312 @@ document.addEventListener('DOMContentLoaded', () => { } }); +class SMSQRGenerator { + constructor() { + this.initializeSMSInterface(); + } + + initializeSMSInterface() { + // Atualizar preview em tempo real + const fieldsToWatch = ['sms-number', 'sms-message']; + fieldsToWatch.forEach(fieldId => { + const element = document.getElementById(fieldId); + if (element) { + element.addEventListener('input', () => this.updatePreview()); + element.addEventListener('change', () => this.updatePreview()); + } + }); + + // Inicializar preview + this.updatePreview(); + } + + updatePreview() { + const smsString = this.generateSMSString(); + const previewElement = document.getElementById('sms-preview-text'); + if (previewElement) { + previewElement.textContent = smsString; + } + } + + generateSMSString() { + const data = this.collectSMSData(); + + if (!data.number || !data.message) { + return 'SMSTO::'; + } + + return `SMSTO:${data.number}:${data.message}`; + } + + collectSMSData() { + return { + number: document.getElementById('sms-number')?.value || '', + message: document.getElementById('sms-message')?.value || '' + }; + } + + validateSMSData() { + const data = this.collectSMSData(); + const errors = []; + + if (!data.number.trim()) { + errors.push('Número do celular é obrigatório'); + } + + if (!data.message.trim()) { + errors.push('Mensagem é obrigatória'); + } + + // Validação de telefone brasileiro básica + const phoneRegex = /^\d{10,11}$/; + if (data.number && !phoneRegex.test(data.number.replace(/\D/g, ''))) { + errors.push('Número deve ter 10 ou 11 dígitos (DDD + número)'); + } + + return errors; + } +} + +class EmailQRGenerator { + constructor() { + this.initializeEmailInterface(); + } + + initializeEmailInterface() { + // Atualizar preview em tempo real + const fieldsToWatch = ['email-to', 'email-subject', 'email-body']; + fieldsToWatch.forEach(fieldId => { + const element = document.getElementById(fieldId); + if (element) { + element.addEventListener('input', () => this.updatePreview()); + element.addEventListener('change', () => this.updatePreview()); + } + }); + + // Inicializar preview + this.updatePreview(); + } + + updatePreview() { + const emailString = this.generateEmailString(); + const previewElement = document.getElementById('email-preview-text'); + if (previewElement) { + previewElement.textContent = emailString; + } + } + + generateEmailString() { + const data = this.collectEmailData(); + + if (!data.to) { + return 'mailto:?subject=&body='; + } + + let emailString = `mailto:${data.to}`; + const params = []; + + if (data.subject) { + params.push(`subject=${encodeURIComponent(data.subject)}`); + } + + if (data.body) { + params.push(`body=${encodeURIComponent(data.body)}`); + } + + if (params.length > 0) { + emailString += '?' + params.join('&'); + } + + return emailString; + } + + collectEmailData() { + return { + to: document.getElementById('email-to')?.value || '', + subject: document.getElementById('email-subject')?.value || '', + body: document.getElementById('email-body')?.value || '' + }; + } + + validateEmailData() { + const data = this.collectEmailData(); + const errors = []; + + if (!data.to.trim()) { + errors.push('Email destinatário é obrigatório'); + } + + if (!data.subject.trim()) { + errors.push('Assunto é obrigatório'); + } + + // Validação básica de email + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (data.to && !emailRegex.test(data.to)) { + errors.push('Email destinatário inválido'); + } + + return errors; + } +} + +class WiFiQRGenerator { + constructor() { + this.initializeWiFiInterface(); + } + + initializeWiFiInterface() { + // Radio buttons: usar name para group + document.querySelectorAll('input[name="wifi-security"]').forEach(radio => { + radio.addEventListener('change', () => { + this.togglePasswordField(); + this.updatePreview(); + }); + }); + + // Campos individuais: usar IDs únicos + const fieldsToWatch = ['wifi-ssid', 'wifi-password', 'wifi-hidden']; + fieldsToWatch.forEach(fieldId => { + const element = document.getElementById(fieldId); + if (element) { + element.addEventListener('input', () => this.updatePreview()); + element.addEventListener('change', () => this.updatePreview()); + } + }); + + const togglePassword = document.getElementById('toggle-password'); + if (togglePassword) { + togglePassword.addEventListener('click', () => { + this.togglePasswordVisibility(); + }); + } + + // Inicializar estado + this.togglePasswordField(); + this.updatePreview(); + } + + togglePasswordField() { + const selectedRadio = document.querySelector('input[name="wifi-security"]:checked'); + const securityType = selectedRadio ? selectedRadio.value : 'WPA'; + + const passwordGroup = document.getElementById('wifi-password-group'); + const passwordInput = document.getElementById('wifi-password'); + + if (securityType === 'nopass') { + passwordGroup.style.display = 'none'; + passwordInput.removeAttribute('required'); + passwordInput.value = ''; + } else { + passwordGroup.style.display = 'block'; + passwordInput.setAttribute('required', 'required'); + } + } + + togglePasswordVisibility() { + const passwordInput = document.getElementById('wifi-password'); + const toggleIcon = document.getElementById('toggle-password'); + + if (passwordInput.type === 'password') { + passwordInput.type = 'text'; + toggleIcon.className = 'fas fa-eye-slash'; + } else { + passwordInput.type = 'password'; + toggleIcon.className = 'fas fa-eye'; + } + } + + updatePreview() { + const wifiString = this.generateWiFiString(); + const previewText = document.getElementById('wifi-preview-text'); + if(previewText) { + previewText.textContent = wifiString; + } + } + + generateWiFiString() { + const data = this.collectWiFiData(); + + // Validar dados mínimos + if (!data.ssid) { + return 'WIFI:T:WPA;S:;P:;H:false;;'; + } + + // Escapar caracteres especiais + const ssid = this.escapeWiFiString(data.ssid); + const password = this.escapeWiFiString(data.password); + + // Construir string WiFi + return `WIFI:T:${data.security};S:${ssid};P:${password};H:${data.hidden};;`; + } + + collectWiFiData() { + return { + ssid: document.getElementById('wifi-ssid').value, + security: document.querySelector('input[name="wifi-security"]:checked')?.value || 'WPA', + password: document.getElementById('wifi-password').value, + hidden: document.getElementById('wifi-hidden').checked.toString() + }; + } + + escapeWiFiString(str) { + if (!str) return ''; + // Escapar caracteres especiais do formato WiFi + return str.replace(/[\\;,:"]/g, '\\escapeWiFiString(str) { if (!str) return; }'); + + // Escapar caracteres especiais do formato WiFi + //return str.replace(/[\\;,:""]/g, '\\document.addEventListener('DOMContentLoaded', () => { + // window.qrGenerator = new QRRapidoGenerator(); + // window.vcardGenerator = new VCardGenerator(); + + // // Initialize AdSense if necessary + // if (window.adsbygoogle && document.querySelector('.adsbygoogle')) { + // (adsbygoogle = window.adsbygoogle || []).push({}); + // } + //}); + return str.replace(/[\\;,:"']/g, '\\$&'); + + // VCard Generator Class'); + } + + validateWiFiData() { + const data = this.collectWiFiData(); + const errors = []; + + // Validações obrigatórias + if (!data.ssid.trim()) { + errors.push('Nome da rede (SSID) é obrigatório'); + } + + // Validação de senha conforme tipo de segurança + if ((data.security === 'WPA' || data.security === 'WEP') && !data.password.trim()) { + errors.push('Senha é obrigatória para redes protegidas'); + } + + // Validação de comprimento + if (data.ssid.length > 32) { + errors.push('Nome da rede deve ter no máximo 32 caracteres'); + } + + if (data.password.length > 63) { + errors.push('Senha deve ter no máximo 63 caracteres'); + } + + // Validação WEP específica + if (data.security === 'WEP' && data.password) { + const validWEPLengths = [5, 10, 13, 26]; // WEP 64/128 bit + if (!validWEPLengths.includes(data.password.length)) { + errors.push('Senha WEP deve ter 5, 10, 13 ou 26 caracteres'); + } + } + + return errors; + } +} + // VCard Generator Class + class VCardGenerator { constructor() { this.initializeVCardInterface(); @@ -1458,7 +1877,7 @@ class VCardGenerator { encodeQuotedPrintable(text) { if (!text) return ''; - return text.replace(/[^\x20-\x7E]/g, (char) => { + return text.replace(/[^\u0020-\u007E]/g, (char) => { // Para caracteres especiais comuns do português, usar codificação UTF-8 const utf8Bytes = new TextEncoder().encode(char); return Array.from(utf8Bytes) @@ -1475,7 +1894,7 @@ class VCardGenerator { if (!needsEncoding) return trimmedText; // Verifica se há caracteres especiais que precisam de codificação - const hasSpecialChars = /[^\x20-\x7E]/.test(trimmedText); + const hasSpecialChars = /[^\u0020-\u007E]/.test(trimmedText); if (hasSpecialChars) { return `CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:${this.encodeQuotedPrintable(trimmedText)}`; @@ -1674,7 +2093,7 @@ class VCardGenerator { } isValidEmail(email) { - return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); + return /^[^ @]+@[^ @]+\.[^ @]+$/.test(email); } isValidURL(url) { @@ -1717,4 +2136,22 @@ window.QRApp = { ad.style.display = 'none'; }); } +}; + +// Google Analytics 4 Event Tracking +window.trackLanguageChange = function(from, to) { + if (typeof gtag !== 'undefined') { + gtag('event', 'language_change', { + 'from_language': from, + 'to_language': to + }); + } +}; + +window.trackUpgradeClick = function(location) { + if (typeof gtag !== 'undefined') { + gtag('event', 'upgrade_click', { + 'click_location': location + }); + } }; \ No newline at end of file