import React, { useState, useEffect, useRef } from 'react';
import { QrCode, Link, MessageSquare, User, Download, Copy, Check } from 'lucide-react';
const TRANSLATIONS = {
"en-US": {
"appTitle": "Easy QR Code Generator",
"appDescription": "Generate QR codes for URLs, text, and contact information",
"urlTab": "URL",
"textTab": "Text",
"contactTab": "Contact",
"enterUrl": "Enter URL",
"enterText": "Enter Text",
"contactInformation": "Contact Information",
"websiteUrl": "Website URL",
"urlPlaceholder": "example.com or https://example.com",
"urlHelp": "Enter a website URL. If you don't include http://, we'll add https:// automatically.",
"textContent": "Text Content",
"textPlaceholder": "Enter any text to generate QR code...",
"firstName": "First Name",
"firstNamePlaceholder": "John",
"lastName": "Last Name",
"lastNamePlaceholder": "Doe",
"phoneNumber": "Phone Number",
"phonePlaceholder": "+1 (555) 123-4567",
"emailAddress": "Email Address",
"emailPlaceholder": "john.doe@example.com",
"organization": "Organization",
"organizationPlaceholder": "Company Name",
"website": "Website",
"websitePlaceholder": "https://example.com",
"clearAllFields": "Clear All Fields",
"generatedQrCode": "Generated QR Code",
"scanQrCode": "Scan this QR code with your device",
"fillFormPrompt": "Fill in the form to generate your QR code",
"download": "Download",
"copyData": "Copy Data",
"copied": "Copied!",
"qrCodeData": "QR Code Data:",
"footerText": "Generate QR codes instantly • No data stored • Free to use",
"qrCodeAlt": "Generated QR Code"
},
"es-ES": {
"appTitle": "Generador de Códigos QR",
"appDescription": "Genera códigos QR para URLs, texto e información de contacto",
"urlTab": "URL",
"textTab": "Texto",
"contactTab": "Contacto",
"enterUrl": "Ingresa URL",
"enterText": "Ingresa Texto",
"contactInformation": "Información de Contacto",
"websiteUrl": "URL del Sitio Web",
"urlPlaceholder": "ejemplo.com o https://ejemplo.com",
"urlHelp": "Ingresa una URL de sitio web. Si no incluyes http://, agregaremos https:// automáticamente.",
"textContent": "Contenido de Texto",
"textPlaceholder": "Ingresa cualquier texto para generar código QR...",
"firstName": "Nombre",
"firstNamePlaceholder": "Juan",
"lastName": "Apellido",
"lastNamePlaceholder": "Pérez",
"phoneNumber": "Número de Teléfono",
"phonePlaceholder": "+1 (555) 123-4567",
"emailAddress": "Dirección de Correo",
"emailPlaceholder": "juan.perez@ejemplo.com",
"organization": "Organización",
"organizationPlaceholder": "Nombre de la Empresa",
"website": "Sitio Web",
"websitePlaceholder": "https://ejemplo.com",
"clearAllFields": "Limpiar Todos los Campos",
"generatedQrCode": "Código QR Generado",
"scanQrCode": "Escanea este código QR con tu dispositivo",
"fillFormPrompt": "Completa el formulario para generar tu código QR",
"download": "Descargar",
"copyData": "Copiar Datos",
"copied": "¡Copiado!",
"qrCodeData": "Datos del Código QR:",
"footerText": "Genera códigos QR al instante • No se almacenan datos • Gratis",
"qrCodeAlt": "Código QR Generado"
}
};
const appLocale = '{{APP_LOCALE}}';
const browserLocale = navigator.languages?.[0] || navigator.language || 'en-US';
const findMatchingLocale = (locale) => {
if (TRANSLATIONS[locale]) return locale;
const lang = locale.split('-')[0];
const match = Object.keys(TRANSLATIONS).find(key => key.startsWith(lang + '-'));
return match || 'en-US';
};
const locale = (appLocale !== '{{APP_LOCALE}}') ? findMatchingLocale(appLocale) : findMatchingLocale(browserLocale);
const t = (key) => TRANSLATIONS[locale]?.[key] || TRANSLATIONS['en-US'][key] || key;
const QRCodeGenerator = () => {
const [activeTab, setActiveTab] = useState('url');
const [qrData, setQrData] = useState('');
const [copied, setCopied] = useState(false);
const qrContainerRef = useRef(null);
// Form states for different types
const [urlInput, setUrlInput] = useState('');
const [textInput, setTextInput] = useState('');
const [contactInfo, setContactInfo] = useState({
firstName: '',
lastName: '',
phone: '',
email: '',
organization: '',
url: ''
});
// QR Code generation using QRious library via CDN
const generateQRCode = async (text) => {
if (!text.trim()) {
if (qrContainerRef.current) {
qrContainerRef.current.innerHTML = '';
}
return;
}
try {
// Load QRious library dynamically
if (!window.QRious) {
const script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/qrious/4.0.2/qrious.min.js';
script.onload = () => {
createQR(text);
};
document.head.appendChild(script);
} else {
createQR(text);
}
} catch (error) {
console.error('Error loading QR library:', error);
// Fallback to Google Charts API
generateFallbackQR(text);
}
};
const createQR = (text) => {
if (!qrContainerRef.current) return;
try {
// Clear previous QR code
qrContainerRef.current.innerHTML = '';
// Create canvas element
const canvas = document.createElement('canvas');
qrContainerRef.current.appendChild(canvas);
// Generate QR code
const qr = new window.QRious({
element: canvas,
value: text,
size: 300,
background: 'white',
foreground: 'black',
level: 'M'
});
// Style the canvas
canvas.className = 'w-full h-auto rounded-xl shadow-lg bg-white';
canvas.style.maxWidth = '300px';
canvas.style.height = 'auto';
} catch (error) {
console.error('Error creating QR code:', error);
generateFallbackQR(text);
}
};
const generateFallbackQR = (text) => {
if (!qrContainerRef.current) return;
// Clear previous content
qrContainerRef.current.innerHTML = '';
// Create img element for fallback
const img = document.createElement('img');
const encodedData = encodeURIComponent(text);
img.src = `https://chart.googleapis.com/chart?chs=300x300&cht=qr&chl=${encodedData}&choe=UTF-8`;
img.alt = t('qrCodeAlt');
img.className = 'w-full h-auto rounded-xl shadow-lg bg-white p-4';
img.style.maxWidth = '300px';
img.style.height = 'auto';
// Add error handling for the fallback image
img.onerror = () => {
// If Google Charts also fails, try QR Server API
img.src = `https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=${encodedData}&format=png&margin=10`;
};
qrContainerRef.current.appendChild(img);
};
const formatUrl = (url) => {
if (!url.trim()) return '';
// Add protocol if missing
if (!url.startsWith('http://') && !url.startsWith('https://')) {
return 'https://' + url;
}
return url;
};
const generateVCard = (contact) => {
const vcard = `BEGIN:VCARD
VERSION:3.0
FN:${contact.firstName} ${contact.lastName}
N:${contact.lastName};${contact.firstName};;;
ORG:${contact.organization}
TEL:${contact.phone}
EMAIL:${contact.email}
URL:${contact.url}
END:VCARD`;
return vcard;
};
useEffect(() => {
let data = '';
switch (activeTab) {
case 'url':
data = formatUrl(urlInput);
break;
case 'text':
data = textInput;
break;
case 'contact':
if (contactInfo.firstName || contactInfo.lastName || contactInfo.phone || contactInfo.email) {
data = generateVCard(contactInfo);
}
break;
default:
data = '';
}
setQrData(data);
generateQRCode(data);
}, [activeTab, urlInput, textInput, contactInfo]);
const downloadQRCode = () => {
if (!qrData) return;
const canvas = qrContainerRef.current?.querySelector('canvas');
const img = qrContainerRef.current?.querySelector('img');
if (canvas) {
// Download from canvas
const link = document.createElement('a');
link.download = `qr-code-${activeTab}.png`;
link.href = canvas.toDataURL();
link.click();
} else if (img) {
// Download from image
const link = document.createElement('a');
link.download = `qr-code-${activeTab}.png`;
link.href = img.src;
link.click();
}
};
const copyToClipboard = async () => {
if (qrData) {
try {
await navigator.clipboard.writeText(qrData);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch (err) {
console.error('Failed to copy text: ', err);
}
}
};
const resetForm = () => {
setUrlInput('');
setTextInput('');
setContactInfo({
firstName: '',
lastName: '',
phone: '',
email: '',
organization: '',
url: ''
});
setQrData('');
if (qrContainerRef.current) {
qrContainerRef.current.innerHTML = '';
}
};
const tabs = [
{ id: 'url', label: t('urlTab'), icon: Link },
{ id: 'text', label: t('textTab'), icon: MessageSquare },
{ id: 'contact', label: t('contactTab'), icon: User }
];
return (
);
};
export default QRCodeGenerator;
{t('appTitle')}
{t('appDescription')}
{/* Tab Navigation */}
{/* Input Section */}
)}
{/* Contact Input */}
{activeTab === 'contact' && (
)}
{/* QR Code Display Section */}
)}
{qrData && (
)}
{activeTab === 'url' && t('enterUrl')} {activeTab === 'text' && t('enterText')} {activeTab === 'contact' && t('contactInformation')}
{/* URL Input */} {activeTab === 'url' && (
setUrlInput(e.target.value)}
placeholder={t('urlPlaceholder')}
className="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-all duration-200"
/>
)}
{/* Text Input */}
{activeTab === 'text' && (
{t('urlHelp')}
setContactInfo({...contactInfo, firstName: e.target.value})}
placeholder={t('firstNamePlaceholder')}
className="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-all duration-200"
/>
setContactInfo({...contactInfo, lastName: e.target.value})}
placeholder={t('lastNamePlaceholder')}
className="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-all duration-200"
/>
setContactInfo({...contactInfo, phone: e.target.value})}
placeholder={t('phonePlaceholder')}
className="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-all duration-200"
/>
setContactInfo({...contactInfo, email: e.target.value})}
placeholder={t('emailPlaceholder')}
className="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-all duration-200"
/>
setContactInfo({...contactInfo, organization: e.target.value})}
placeholder={t('organizationPlaceholder')}
className="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-all duration-200"
/>
setContactInfo({...contactInfo, url: e.target.value})}
placeholder={t('websitePlaceholder')}
className="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-all duration-200"
/>
{t('generatedQrCode')}
{qrData ? (
) : (
)}
{qrData && (
{/* QR code will be dynamically inserted here */}
{t('scanQrCode')}
{t('fillFormPrompt')}
{t('qrCodeData')}
{qrData}
{t('footerText')}