@@ -27,6 +27,7 @@ import { cn } from '@/lib/utils';
2727const CUSTOM_QR_ENDPOINT = 'https://refhub-qr.netlify.app/api/generate-qr' ;
2828const CUSTOM_QR_FREEDOM = 0 ;
2929const QR_DOWNLOAD_BACKGROUND = '#0d0d0f' ;
30+ const QR_DOWNLOAD_SIZE = 2048 ;
3031
3132interface QRCodeDialogProps {
3233 vault : Vault ;
@@ -182,23 +183,58 @@ export function QRCodeDialog({ vault, onVaultUpdate }: QRCodeDialogProps) {
182183 return svg . replace ( / ( < s v g \b [ ^ > ] * > ) / , `$1${ background } ` ) ;
183184 } ;
184185
185- const downloadQR = ( ) => {
186+ const downloadPngFromSvg = async ( svg : string ) => {
187+ const canvas = document . createElement ( 'canvas' ) ;
188+ canvas . width = QR_DOWNLOAD_SIZE ;
189+ canvas . height = QR_DOWNLOAD_SIZE ;
190+
191+ const context = canvas . getContext ( '2d' ) ;
192+ if ( ! context ) throw new Error ( 'unable to prepare qr download' ) ;
193+
194+ const svgForDownload = getDownloadableSvg ( svg ) ;
195+ const blobUrl = URL . createObjectURL ( new Blob ( [ svgForDownload ] , { type : 'image/svg+xml' } ) ) ;
196+
197+ try {
198+ await new Promise < void > ( ( resolve , reject ) => {
199+ const image = new Image ( ) ;
200+ image . onload = ( ) => {
201+ context . clearRect ( 0 , 0 , QR_DOWNLOAD_SIZE , QR_DOWNLOAD_SIZE ) ;
202+ context . drawImage ( image , 0 , 0 , QR_DOWNLOAD_SIZE , QR_DOWNLOAD_SIZE ) ;
203+ resolve ( ) ;
204+ } ;
205+ image . onerror = ( ) => reject ( new Error ( 'unable to render qr download' ) ) ;
206+ image . src = blobUrl ;
207+ } ) ;
208+ } finally {
209+ URL . revokeObjectURL ( blobUrl ) ;
210+ }
211+
212+ const pngUrl = canvas . toDataURL ( 'image/png' ) ;
186213 const link = document . createElement ( 'a' ) ;
214+ link . download = `${ vault . name || 'vault' } -qr.png` ;
215+ link . href = pngUrl ;
216+ link . click ( ) ;
217+ } ;
187218
219+ const downloadQR = async ( ) => {
188220 if ( customQrSvg ) {
189- const svgForDownload = getDownloadableSvg ( customQrSvg ) ;
190- const blobUrl = URL . createObjectURL ( new Blob ( [ svgForDownload ] , { type : 'image/svg+xml' } ) ) ;
191- link . download = `${ vault . name || 'vault' } -qr.svg` ;
192- link . href = blobUrl ;
193- link . click ( ) ;
194- URL . revokeObjectURL ( blobUrl ) ;
195- toast ( { title : 'qr_code_downloaded' } ) ;
221+ try {
222+ await downloadPngFromSvg ( customQrSvg ) ;
223+ toast ( { title : 'qr_code_downloaded' } ) ;
224+ } catch ( error ) {
225+ toast ( {
226+ title : 'error_downloading_qr_code' ,
227+ description : ( error as Error ) . message ,
228+ variant : 'destructive' ,
229+ } ) ;
230+ }
196231 return ;
197232 }
198233
199234 const canvas = qrRef . current ?. querySelector ( 'canvas' ) ;
200235 if ( ! canvas ) return ;
201236
237+ const link = document . createElement ( 'a' ) ;
202238 link . download = `${ vault . name || 'vault' } -qr.png` ;
203239 link . href = canvas . toDataURL ( 'image/png' ) ;
204240 link . click ( ) ;
0 commit comments