@@ -188,11 +188,34 @@ const Certificate: React.FC<CertificateProps> = ({ user, courseName }) => {
188188
189189 document . body . removeChild ( clone ) ;
190190
191- const image = canvas . toDataURL ( "image/png" , 1.0 ) ;
192- const link = document . createElement ( "a" ) ;
193- link . href = image ;
194- link . download = `Cipher_Certificate_${ user . username } .png` ;
195- link . click ( ) ;
191+ // --- MOBILE FRIENDLY DOWNLOAD/SHARE ---
192+ // Android WebViews often block 'a.download'. We use the Share API if available.
193+ const blob = await new Promise < Blob | null > ( resolve => canvas . toBlob ( resolve , 'image/png' ) ) ;
194+
195+ if ( blob && navigator . share ) {
196+ try {
197+ const file = new File ( [ blob ] , `Cipher_Certificate_${ user . username } .png` , { type : 'image/png' } ) ;
198+ await navigator . share ( {
199+ title : 'Cipher Academy Certificate' ,
200+ text : `I just got certified in Ethical Hacking by Cipher Academy!` ,
201+ files : [ file ]
202+ } ) ;
203+ } catch ( err ) {
204+ // If share fails (e.g. user cancelled), fallback to simple download
205+ const image = canvas . toDataURL ( "image/png" , 1.0 ) ;
206+ const link = document . createElement ( "a" ) ;
207+ link . href = image ;
208+ link . download = `Cipher_Certificate_${ user . username } .png` ;
209+ link . click ( ) ;
210+ }
211+ } else {
212+ // Desktop fallback
213+ const image = canvas . toDataURL ( "image/png" , 1.0 ) ;
214+ const link = document . createElement ( "a" ) ;
215+ link . href = image ;
216+ link . download = `Cipher_Certificate_${ user . username } .png` ;
217+ link . click ( ) ;
218+ }
196219
197220 } catch ( e ) {
198221 console . error ( "Certificate generation failed" , e ) ;
@@ -225,12 +248,12 @@ const Certificate: React.FC<CertificateProps> = ({ user, courseName }) => {
225248 className = "w-full flex items-center justify-center gap-3 bg-[#C5A059] text-black px-6 py-4 rounded-xl font-bold hover:bg-[#b08d4a] transition-all shadow-[0_4px_20px_rgba(197,160,89,0.3)] hover:shadow-[0_6px_25px_rgba(197,160,89,0.5)] hover:-translate-y-1 disabled:opacity-70 disabled:cursor-not-allowed tracking-wide uppercase text-sm"
226249 >
227250 { isGenerating ? < Loader2 className = "animate-spin" size = { 20 } /> : < Download size = { 20 } /> }
228- { isGenerating ? "Engraving..." : "Download Certificate " }
251+ { isGenerating ? "Engraving..." : "Download / Share " }
229252 </ button >
230253
231254 < div className = "flex items-center gap-2 text-gray-500 text-xs" >
232255 < Share2 size = { 12 } />
233- < span > Ready for LinkedIn & Portfolio </ span >
256+ < span > Save to Gallery or Share </ span >
234257 </ div >
235258 </ div >
236259
0 commit comments