'use client'; import React from 'react'; import { QRCodeSVG } from 'qrcode.react'; import { Card, CardContent } from '@/components/ui/Card'; import { Badge } from '@/components/ui/Badge'; import { Dropdown, DropdownItem } from '@/components/ui/Dropdown'; import { formatDate } from '@/lib/utils'; interface QRCodeCardProps { qr: { id: string; title: string; type: 'STATIC' | 'DYNAMIC'; contentType: string; content?: any; slug: string; createdAt: string; scans?: number; style?: any; }; onEdit: (id: string) => void; onDelete: (id: string) => void; } export const QRCodeCard: React.FC = ({ qr, onEdit, onDelete, }) => { // For dynamic QR codes, use the redirect URL for tracking // For static QR codes, use the direct URL from content const baseUrl = process.env.NEXT_PUBLIC_APP_URL || (typeof window !== 'undefined' ? window.location.origin : 'http://localhost:3050'); // Get the QR URL based on type let qrUrl = ''; // SIMPLE FIX: For STATIC QR codes, ALWAYS use the direct content if (qr.type === 'STATIC') { // Extract the actual URL/content based on contentType if (qr.contentType === 'URL' && qr.content?.url) { qrUrl = qr.content.url; } else if (qr.contentType === 'PHONE' && qr.content?.phone) { qrUrl = `tel:${qr.content.phone}`; } else if (qr.contentType === 'VCARD') { // VCARD content needs to be formatted properly qrUrl = `BEGIN:VCARD VERSION:3.0 FN:${qr.content.firstName || ''} ${qr.content.lastName || ''} N:${qr.content.lastName || ''};${qr.content.firstName || ''};;; ${qr.content.organization ? `ORG:${qr.content.organization}` : ''} ${qr.content.title ? `TITLE:${qr.content.title}` : ''} ${qr.content.email ? `EMAIL:${qr.content.email}` : ''} ${qr.content.phone ? `TEL:${qr.content.phone}` : ''} END:VCARD`; } else if (qr.contentType === 'GEO' && qr.content) { const lat = qr.content.latitude || 0; const lon = qr.content.longitude || 0; const label = qr.content.label ? `?q=${encodeURIComponent(qr.content.label)}` : ''; qrUrl = `geo:${lat},${lon}${label}`; } else if (qr.contentType === 'TEXT' && qr.content?.text) { qrUrl = qr.content.text; } else if (qr.content?.qrContent) { // Fallback to qrContent if it exists qrUrl = qr.content.qrContent; } else { // Last resort fallback qrUrl = `${baseUrl}/r/${qr.slug}`; } console.log(`STATIC QR [${qr.title}]: ${qrUrl}`); } else { // DYNAMIC QR codes always use redirect for tracking qrUrl = `${baseUrl}/r/${qr.slug}`; console.log(`DYNAMIC QR [${qr.title}]: ${qrUrl}`); } const downloadQR = (format: 'png' | 'svg') => { const svg = document.querySelector(`#qr-${qr.id} svg`); if (!svg) return; if (format === 'svg') { let svgData = new XMLSerializer().serializeToString(svg); // If rounded corners, wrap in a clipped SVG if (qr.style?.cornerStyle === 'rounded') { const width = svg.getAttribute('width') || '96'; const height = svg.getAttribute('height') || '96'; const borderRadius = 10; // Smaller radius for dashboard svgData = ` ${svgData} `; } const blob = new Blob([svgData], { type: 'image/svg+xml' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${qr.title.replace(/\s+/g, '-').toLowerCase()}.svg`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } else { // Convert SVG to PNG const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); if (!ctx) return; const img = new Image(); const svgData = new XMLSerializer().serializeToString(svg); const blob = new Blob([svgData], { type: 'image/svg+xml' }); const url = URL.createObjectURL(blob); img.onload = () => { canvas.width = 300; canvas.height = 300; // Apply rounded corners if needed if (qr.style?.cornerStyle === 'rounded') { const borderRadius = 30; // Scale up for 300px canvas ctx.beginPath(); ctx.moveTo(borderRadius, 0); ctx.lineTo(300 - borderRadius, 0); ctx.quadraticCurveTo(300, 0, 300, borderRadius); ctx.lineTo(300, 300 - borderRadius); ctx.quadraticCurveTo(300, 300, 300 - borderRadius, 300); ctx.lineTo(borderRadius, 300); ctx.quadraticCurveTo(0, 300, 0, 300 - borderRadius); ctx.lineTo(0, borderRadius); ctx.quadraticCurveTo(0, 0, borderRadius, 0); ctx.closePath(); ctx.clip(); } ctx.drawImage(img, 0, 0, 300, 300); canvas.toBlob((blob) => { if (blob) { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${qr.title.replace(/\s+/g, '-').toLowerCase()}.png`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } }); URL.revokeObjectURL(url); }; img.src = url; } }; return (

{qr.title}

{qr.type}
} > downloadQR('png')}>Download PNG downloadQR('svg')}>Download SVG {qr.type === 'DYNAMIC' && ( onEdit(qr.id)}>Edit )} onDelete(qr.id)} className="text-red-600"> Delete
Type: {qr.contentType}
{qr.type === 'DYNAMIC' && (
Scans: {qr.scans || 0}
)}
Created: {formatDate(qr.createdAt)}
{qr.type === 'DYNAMIC' && (

📊 Dynamic QR: Tracks scans via {baseUrl}/r/{qr.slug}

)}
); };