feat: add download option for QR codes in create and dashboard pages
This commit is contained in:
@@ -82,6 +82,17 @@ export default function CreateQRPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDownload = async () => {
|
||||||
|
try {
|
||||||
|
const QRCodeStyling = (await import('qr-code-styling')).default;
|
||||||
|
const qrCode = new QRCodeStyling(qrOptions);
|
||||||
|
qrCode.download({ name: qrName || 'QR-Code', extension: 'png' });
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Download failed', err);
|
||||||
|
alert('Failed to download QR code');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-8 max-w-7xl mx-auto h-full">
|
<div className="p-8 max-w-7xl mx-auto h-full">
|
||||||
<div className="flex justify-between items-center mb-8">
|
<div className="flex justify-between items-center mb-8">
|
||||||
@@ -89,13 +100,22 @@ export default function CreateQRPage() {
|
|||||||
<h1 className="text-3xl font-bold text-gray-800">Create QR Code</h1>
|
<h1 className="text-3xl font-bold text-gray-800">Create QR Code</h1>
|
||||||
<p className="text-gray-500 mt-1">Design a beautiful, dynamic QR code</p>
|
<p className="text-gray-500 mt-1">Design a beautiful, dynamic QR code</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<div className="flex gap-3">
|
||||||
onClick={handleGenerate}
|
<button
|
||||||
disabled={isGenerating}
|
onClick={handleDownload}
|
||||||
className="bg-indigo-600 text-white px-6 py-2.5 rounded-lg hover:bg-indigo-700 transition-colors font-semibold shadow-sm disabled:opacity-50"
|
className="bg-white border border-gray-300 text-gray-700 px-6 py-2.5 rounded-lg hover:bg-gray-50 transition-colors font-semibold shadow-sm flex items-center gap-2"
|
||||||
>
|
>
|
||||||
{isGenerating ? 'Saving...' : 'Save QR Code'}
|
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" /></svg>
|
||||||
</button>
|
Download
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleGenerate}
|
||||||
|
disabled={isGenerating}
|
||||||
|
className="bg-indigo-600 text-white px-6 py-2.5 rounded-lg hover:bg-indigo-700 transition-colors font-semibold shadow-sm disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{isGenerating ? 'Saving...' : 'Save QR Code'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 h-[calc(100vh-180px)]">
|
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 h-[calc(100vh-180px)]">
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ interface QRCode {
|
|||||||
short_url_id: string;
|
short_url_id: string;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
scans: number;
|
scans: number;
|
||||||
|
design_data: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function DashboardPage() {
|
export default function DashboardPage() {
|
||||||
@@ -79,6 +80,23 @@ export default function DashboardPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDownload = async (qr: QRCode) => {
|
||||||
|
try {
|
||||||
|
const QRCodeStyling = (await import('qr-code-styling')).default;
|
||||||
|
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://qr.houseofwebsites.ai';
|
||||||
|
const shortUrl = `${baseUrl}/l/${qr.short_url_id}`;
|
||||||
|
|
||||||
|
const qrCode = new QRCodeStyling({
|
||||||
|
...qr.design_data,
|
||||||
|
data: shortUrl
|
||||||
|
});
|
||||||
|
qrCode.download({ name: qr.name || 'QR-Code', extension: 'png' });
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to download QR code', err);
|
||||||
|
alert('Failed to download QR code');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const totalScans = qrs.reduce((sum, qr) => sum + Number(qr.scans), 0);
|
const totalScans = qrs.reduce((sum, qr) => sum + Number(qr.scans), 0);
|
||||||
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:4001';
|
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:4001';
|
||||||
|
|
||||||
@@ -169,7 +187,10 @@ export default function DashboardPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col gap-2 w-full sm:w-48">
|
<div className="flex flex-col gap-2 w-full sm:w-48">
|
||||||
<button className="w-full bg-green-500 hover:bg-green-600 text-white font-bold py-2.5 px-4 rounded-lg transition-colors flex justify-center items-center gap-2 shadow-sm border border-transparent">
|
<button
|
||||||
|
onClick={() => handleDownload(qr)}
|
||||||
|
className="w-full bg-green-500 hover:bg-green-600 text-white font-bold py-2.5 px-4 rounded-lg transition-colors flex justify-center items-center gap-2 shadow-sm border border-transparent"
|
||||||
|
>
|
||||||
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" /></svg>
|
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" /></svg>
|
||||||
Download
|
Download
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user