qr 5

import React, { useState, useEffect, useRef } from 'react'; import QRCodeStyling, { DrawType, TypeNumber, Mode, ErrorCorrectionLevel, DotType, CornerSquareType, CornerDotType, FileExtension } from 'qr-code-styling'; import { CONTENT_TYPES, ContentType, QRStyleOptions, cn } from '../lib/utils'; import { InputForm } from './InputForms'; import { StyleCustomizer } from './StyleCustomizer'; import { Download, RefreshCw, CheckCircle2, AlertCircle } from 'lucide-react'; import { motion, AnimatePresence } from 'motion/react'; import jsPDF from 'jspdf'; export const QRGenerator: React.FC = () => { const [contentType, setContentType] = useState('url'); const [contentData, setContentData] = useState({}); const [styleOptions, setStyleOptions] = useState({ dotType: 'square', cornerSquareType: 'square', cornerDotType: 'square', dotColor: '#000000', bgColor: '#ffffff', margin: 2, showTitle: false, }); const [downloadFormat, setDownloadFormat] = useState('svg'); const [qrCode, setQrCode] = useState(null); const [isGenerated, setIsGenerated] = useState(false); const [isGenerating, setIsGenerating] = useState(false); const qrRef = useRef(null); // Initialize QR code object useEffect(() => { const newQrCode = new QRCodeStyling({ width: 300, height: 300, type: 'svg' as DrawType, data: '', dotsOptions: { color: '#000000', type: 'square' as DotType, }, backgroundOptions: { color: '#ffffff', }, imageOptions: { crossOrigin: 'anonymous', margin: 5, } }); setQrCode(newQrCode); }, []); // Update QR code when styles change (if already generated) useEffect(() => { if (qrCode && isGenerated) { updateQRCode(); } }, [styleOptions]); const getQRData = () => { switch (contentType) { case 'url': return contentData.url || ''; case 'text': return contentData.text || ''; case 'email': return `mailto:${contentData.email || ''}?subject=${encodeURIComponent(contentData.subject || '')}&body=${encodeURIComponent(contentData.body || '')}`; case 'phone': return `tel:${contentData.phone || ''}`; case 'sms': return `sms:${contentData.phone || ''}?body=${encodeURIComponent(contentData.message || '')}`; case 'wifi': return `WIFI:S:${contentData.ssid || ''};T:${contentData.encryption || 'WPA'};P:${contentData.password || ''};H:${contentData.hidden ? 'true' : 'false'};;`; case 'social': { const val = contentData.value || ''; switch (contentData.platform) { case 'facebook': return `https://facebook.com/${val}`; case 'instagram': return `https://instagram.com/${val}`; case 'whatsapp': return `https://wa.me/${val}`; case 'youtube': return `https://youtube.com/@${val}`; case 'twitter_url': return `https://twitter.com/${val}`; case 'twitter_tweet': return `https://twitter.com/intent/tweet?text=${encodeURIComponent(val)}`; default: return val; } } case 'location': return `geo:${contentData.lat || 0},${contentData.lng || 0}`; case 'event': return `BEGIN:VEVENT\nSUMMARY:${contentData.title || ''}\nLOCATION:${contentData.location || ''}\nDTSTART:${contentData.start?.replace(/[-:]/g, '') || ''}\nDTEND:${contentData.end?.replace(/[-:]/g, '') || ''}\nEND:VEVENT`; case 'pdf': return contentData.url || ''; case 'contact': case 'vcard': return `BEGIN:VCARD\nVERSION:3.0\nN:${contentData.lastName || ''};${contentData.firstName || ''};;${contentData.prefix || ''};\nFN:${contentData.prefix || ''} ${contentData.firstName || ''} ${contentData.lastName || ''}\nORG:${contentData.organization || ''}\nTITLE:${contentData.title || ''}\nTEL;TYPE=CELL:${contentData.phone || ''}\nEMAIL:${contentData.email || ''}\nEND:VCARD`; case 'mecard': return `MECARD:N:${contentData.lastName || ''},${contentData.firstName || ''};TEL:${contentData.phone || ''};EMAIL:${contentData.email || ''};;`; default: return ''; } }; const isFormValid = () => { const data = getQRData(); return data.trim().length > 0; }; const updateQRCode = () => { if (!qrCode) return; qrCode.update({ data: getQRData(), dotsOptions: { color: styleOptions.dotColor, type: styleOptions.dotType as DotType, }, backgroundOptions: { color: styleOptions.bgColor, }, cornersSquareOptions: { color: styleOptions.dotColor, type: styleOptions.cornerSquareType as CornerSquareType, }, cornersDotOptions: { color: styleOptions.dotColor, type: styleOptions.cornerDotType as CornerDotType, }, margin: styleOptions.margin, image: styleOptions.logo, }); }; const handleGenerate = () => { if (!qrCode || !isFormValid()) return; setIsGenerating(true); setTimeout(() => { updateQRCode(); if (qrRef.current) { qrRef.current.innerHTML = ''; qrCode.append(qrRef.current); } setIsGenerated(true); setIsGenerating(false); // Scroll to result qrRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' }); }, 800); }; const handleDownload = async () => { if (!qrCode) return; if (downloadFormat === 'pdf') { const blob = await qrCode.getRawData('png'); if (blob) { const reader = new FileReader(); reader.onloadend = () => { const base64data = reader.result as string; const pdf = new jsPDF(); pdf.addImage(base64data, 'PNG', 10, 10, 100, 100); pdf.save(`qr-code-${Date.now()}.pdf`); }; reader.readAsDataURL(blob); } } else { qrCode.download({ name: `qr-code-${Date.now()}`, extension: downloadFormat as FileExtension }); } }; return (
{/* Left Column: Inputs & Customization */}
{/* Content Type Selection */}
{CONTENT_TYPES.map((type) => ( ))}
{/* Dynamic Input Form */}
{/* Style Customization */}
{/* Generate Button */}
{/* Right Column: Preview & Download */}
{isGenerated ? (
QR Code Ready
{/* QR Preview Container */}
{styleOptions.showTitle && styleOptions.title && (
{styleOptions.title}
)}
{/* Download Controls */}

By default SVG is selected. You can choose other formats from the dropdown.

) : (

No QR Code Generated

Fill in the information on the left and click "Generate" to see your QR code here.

)} {/* Tips Card */}

Pro Tips

  • Use high contrast colors for better scanning.
  • SVG format is best for high-quality printing.
  • Adding a logo makes your QR code look professional.
); };