@@ -10,7 +10,6 @@ import { useGlobalWallet } from '@/contexts/wallet/WalletContext';
1010import { useAuth } from '@/contexts/auth/AuthContext' ;
1111import html2canvas from 'html2canvas' ;
1212import Image from 'next/image' ;
13- import GIF from 'gif.js' ;
1413
1514interface PokemonReferralCardProps {
1615 account : Account | null ;
@@ -26,8 +25,6 @@ export const PokemonReferralCard: React.FC<PokemonReferralCardProps> = ({
2625 const { user } = useAuth ( ) ;
2726 const [ isGeneratingPng , setIsGeneratingPng ] = useState ( false ) ;
2827 const [ isSharing , setIsSharing ] = useState ( false ) ;
29- const [ isGeneratingGif , setIsGeneratingGif ] = useState ( false ) ;
30- const [ gifProgress , setGifProgress ] = useState ( 0 ) ;
3128 const [ selectedPhase , setSelectedPhase ] = useState ( 0 ) ; // 0: baby, 1: teen, 2: adult
3229 const [ selectedBackground , setSelectedBackground ] = useState ( 0 ) ; // 0: explorer, 1: mid-level, 2: expert
3330 const [ selectedForm , setSelectedForm ] = useState ( 0 ) ; // 0: initial, 1: mid, 2: final
@@ -54,23 +51,23 @@ export const PokemonReferralCard: React.FC<PokemonReferralCardProps> = ({
5451 const rankingThemes = {
5552 1 : {
5653 // Gold
57- // background: 'linear-gradient(135deg, #FFD700 0%, #FFA500 50%, #FF8C00 100%)',
54+ background : 'linear-gradient(135deg, #FFD700 0%, #FFA500 50%, #FF8C00 100%)' ,
5855 border : '#FFD700' ,
5956 text : '#000000' ,
6057 shadow : 'shadow-yellow-500/50' ,
6158 glow : 'from-yellow-400/50 to-orange-400/50' ,
6259 } ,
6360 2 : {
6461 // Silver
65- // background: 'linear-gradient(135deg, #C0C0C0 0%, #A8A8A8 50%, #808080 100%)',
62+ background : 'linear-gradient(135deg, #C0C0C0 0%, #A8A8A8 50%, #808080 100%)' ,
6663 border : '#C0C0C0' ,
6764 text : '#000000' ,
6865 shadow : 'shadow-gray-400/50' ,
6966 glow : 'from-gray-300/50 to-gray-500/50' ,
7067 } ,
7168 3 : {
7269 // Bronze
73- // background: 'linear-gradient(135deg, #CD7F32 0%, #B8860B 50%, #8B4513 100%)',
70+ background : 'linear-gradient(135deg, #CD7F32 0%, #B8860B 50%, #8B4513 100%)' ,
7471 border : '#CD7F32' ,
7572 text : '#FFFFFF' ,
7673 shadow : 'shadow-orange-600/50' ,
@@ -257,110 +254,6 @@ export const PokemonReferralCard: React.FC<PokemonReferralCardProps> = ({
257254 }
258255 } ;
259256
260- const handleDownloadGif = async ( ) => {
261- if ( ! cardRef . current ) return ;
262-
263- setIsGeneratingGif ( true ) ;
264- setGifProgress ( 0 ) ;
265-
266- try {
267- const frames = [ ] ;
268- const totalFrames = 12 ; // Number of frames for the GIF
269- const delay = 100 ; // Delay between frames in ms
270-
271- // Generate frames with slight variations for animation
272-
273- for ( let i = 0 ; i < totalFrames ; i ++ ) {
274- // Create a temporary clone of the card with slight modifications
275- const clonedCard = cardRef . current . cloneNode ( true ) as HTMLElement ;
276-
277- // Add slight rotation and glow effect for animation
278- clonedCard . style . transform = `rotate(${ Math . sin ( i * 0.5 ) * 2 } deg)` ;
279- clonedCard . style . boxShadow = `0 0 ${ 20 + Math . sin ( i * 0.8 ) * 10 } px rgba(255, 215, 0, 0.5)` ;
280-
281- // Temporarily add to DOM for capture
282- clonedCard . style . cssText += `
283- position: absolute;
284- top: -9999px;
285- left: -9999px;
286- visibility: hidden;
287- pointer-events: none;
288- ` ;
289- document . body . appendChild ( clonedCard ) ;
290-
291- try {
292- const canvas = await html2canvas ( clonedCard , {
293- width : 400 ,
294- height : 520 ,
295- background : 'transparent' ,
296- useCORS : true ,
297- allowTaint : true ,
298- } ) ;
299-
300- frames . push ( canvas ) ;
301- const progress = ( ( i + 1 ) / totalFrames ) * 100 ;
302- setGifProgress ( progress ) ;
303-
304- // Small delay to show progress
305- await new Promise ( resolve => setTimeout ( resolve , 50 ) ) ;
306- } finally {
307- document . body . removeChild ( clonedCard ) ;
308- }
309- }
310-
311- // Create GIF
312- const gif = new GIF ( {
313- workers : 2 ,
314- quality : 10 ,
315- width : 400 ,
316- height : 520 ,
317- workerScript : '/gif.worker.js' ,
318- } ) ;
319-
320- // Add frames to GIF
321- frames . forEach ( frame => {
322- gif . addFrame ( frame , { delay : delay } ) ;
323- } ) ;
324-
325- // Render GIF
326- gif . on ( 'finished' , ( blob : Blob ) => {
327- const url = URL . createObjectURL ( blob ) ;
328- const link = document . createElement ( 'a' ) ;
329- link . href = url ;
330- link . download = `nexus-card-${ account . displayName || 'anonymous' } -${ Date . now ( ) } .gif` ;
331- document . body . appendChild ( link ) ;
332- link . click ( ) ;
333- document . body . removeChild ( link ) ;
334- URL . revokeObjectURL ( url ) ;
335-
336- setIsGeneratingGif ( false ) ;
337- setGifProgress ( 0 ) ;
338- addToast ( {
339- type : 'success' ,
340- title : '🎭 GIF Downloaded!' ,
341- message : 'Your animated Nexus card is ready!' ,
342- duration : 3000 ,
343- } ) ;
344- } ) ;
345-
346- gif . on ( 'progress' , ( progress : number ) => {
347- setGifProgress ( progress * 100 ) ;
348- } ) ;
349-
350- gif . render ( ) ;
351-
352- } catch ( error ) {
353- console . error ( 'Error generating GIF:' , error ) ;
354- setIsGeneratingGif ( false ) ;
355- setGifProgress ( 0 ) ;
356- addToast ( {
357- type : 'error' ,
358- title : 'GIF Generation Failed' ,
359- message : 'Unable to create animated GIF. Please try again.' ,
360- duration : 3000 ,
361- } ) ;
362- }
363- } ;
364257
365258
366259
@@ -497,6 +390,8 @@ export const PokemonReferralCard: React.FC<PokemonReferralCardProps> = ({
497390 alt = { `${ currentBackground . name } Background` }
498391 className = 'w-full h-full object-cover'
499392 />
393+ { /* Background Overlay for Better Text Readability */ }
394+ < div className = 'absolute inset-0 bg-black/40' > </ div >
500395 </ div >
501396
502397 < br />
@@ -546,30 +441,84 @@ export const PokemonReferralCard: React.FC<PokemonReferralCardProps> = ({
546441 ) }
547442
548443 { currentLayout . id === 1 && (
549- /* Modern Layout - Centered Single Column */
550- < div className = 'flex flex-col items-center text-center space-y-4' >
551- < div className = 'text-sm font-bold' style = { { color : currentTheme . text } } >
552- NEXUS CARD
444+ /* Modern Layout - Profile Card Style */
445+ < div className = 'flex flex-col h-full' >
446+ { /* Top Section - Card Type and Icon */ }
447+ < div className = 'flex justify-between items-start mb-4' >
448+ < div className = 'text-sm font-bold text-white/90' >
449+ COMMON
450+ </ div >
451+ < div className = 'w-6 h-6 bg-blue-400 rounded-full flex items-center justify-center' >
452+ < div className = 'w-3 h-3 bg-white rounded-full' > </ div >
453+ </ div >
553454 </ div >
554-
555- { /* Avatar */ }
556- < div className = 'relative' >
557- < div className = 'scale-125' >
558- < UserAvatar size = 'lg' showStatus = { false } />
455+
456+ { /* Center Section - Avatar and Name */ }
457+ < div className = 'flex flex-col items-center mb-6' >
458+ { /* Avatar */ }
459+ < div className = 'relative mb-3' >
460+ < div className = 'scale-125' >
461+ < UserAvatar size = 'lg' showStatus = { false } />
462+ </ div >
463+ < div className = 'absolute -bottom-1 -right-1 bg-orange-500 rounded-full w-8 h-8 flex items-center justify-center' >
464+ < div className = 'text-sm font-bold text-white' >
465+ { userLevel }
466+ </ div >
467+ </ div >
559468 </ div >
560- < div className = 'absolute -bottom-1 -right-1 bg-white rounded-full px-1.5 py-0.5' >
561- < div className = 'text-xs font-bold' style = { { color : 'black' } } >
562- Lv.{ userLevel }
469+
470+ { /* Name and Title */ }
471+ < div className = 'text-center' >
472+ < div className = 'text-lg font-bold text-white mb-1' >
473+ { account . displayName || 'Nexus Explorer' }
474+ </ div >
475+ < div className = 'text-sm text-yellow-400 font-semibold' >
476+ TRUSTLESS WORKER
563477 </ div >
564478 </ div >
565479 </ div >
566480
567- < div className = 'text-lg font-bold' style = { { color : currentTheme . text } } >
568- { account . displayName || 'Nexus Explorer' }
569- </ div >
570- < div className = 'text-xs opacity-80' style = { { color : currentTheme . text } } >
571- { account . totalPoints || 0 } points
481+ { /* Stats Section */ }
482+ < div className = 'flex-1 mb-4' >
483+ < div className = 'grid grid-cols-2 gap-2 text-sm' >
484+ < div className = 'flex justify-between items-center' >
485+ < span className = 'text-yellow-400 font-semibold' > XP</ span >
486+ < span className = 'text-white font-bold' > { account . experience || 0 } </ span >
487+ </ div >
488+ < div className = 'flex justify-between items-center' >
489+ < span className = 'text-yellow-400 font-semibold' > POINTS</ span >
490+ < span className = 'text-white font-bold' > { account . totalPoints || 0 } </ span >
491+ </ div >
492+ < div className = 'flex justify-between items-center' >
493+ < span className = 'text-yellow-400 font-semibold' > REFERRALS</ span >
494+ < span className = 'text-white font-bold' > 0</ span >
495+ </ div >
496+ < div className = 'flex justify-between items-center' >
497+ < span className = 'text-yellow-400 font-semibold' > BADGES</ span >
498+ < span className = 'text-white font-bold' > { earnedBadges . length } / 13</ span >
499+ </ div >
500+ </ div >
572501 </ div >
502+
503+ { /* Badges Section */ }
504+ { earnedBadges . length > 0 && (
505+ < div className = 'flex flex-wrap justify-center gap-2' >
506+ { earnedBadges . slice ( 0 , 6 ) . map ( ( badgeId , index ) => (
507+ < div key = { index } className = 'w-6 h-6' >
508+ < BadgeEmblem
509+ id = { badgeId as string }
510+ size = 'sm'
511+ className = 'w-full h-full'
512+ />
513+ </ div >
514+ ) ) }
515+ { earnedBadges . length > 6 && (
516+ < div className = 'w-6 h-6 bg-blue-400 rounded-full flex items-center justify-center' >
517+ < span className = 'text-xs font-bold text-white' > +{ earnedBadges . length - 6 } </ span >
518+ </ div >
519+ ) }
520+ </ div >
521+ ) }
573522 </ div >
574523 ) }
575524
@@ -605,8 +554,8 @@ export const PokemonReferralCard: React.FC<PokemonReferralCardProps> = ({
605554 < br />
606555 < br />
607556
608- { /* Earned Badges */ }
609- { earnedBadges . length > 0 && (
557+ { /* Earned Badges - Only for Classic and Minimal layouts */ }
558+ { currentLayout . id !== 1 && earnedBadges . length > 0 && (
610559 < div className = 'relative z-10 px-6 mb-4' >
611560 < div className = 'bg-black/30 backdrop-blur-sm rounded-lg p-3 border border-white/30' >
612561 { /* <div
@@ -638,29 +587,31 @@ export const PokemonReferralCard: React.FC<PokemonReferralCardProps> = ({
638587 </ div >
639588 ) }
640589
641- { /* Stats and Referral Code */ }
642- < div className = 'relative z-10 px-6 mb-4 space-y-3' >
643- { /* Stats */ }
644- < div className = 'bg-black/30 backdrop-blur-sm rounded-lg p-3 border border-white/30' >
645- < div
646- className = 'grid grid-cols-3 gap-2 text-sm'
647- style = { { color : currentTheme . text } }
648- >
649- < div className = 'text-center' >
650- < div className = 'font-bold text-lg' > { account . totalPoints || 0 } </ div >
651- < div className = 'text-xs opacity-80' > Points</ div >
652- </ div >
653- < div className = 'text-center' >
654- < div className = 'font-bold text-lg' > { account . experience || 0 } </ div >
655- < div className = 'text-xs opacity-80' > Experience</ div >
656- </ div >
657- < div className = 'text-center' >
658- < div className = 'font-bold text-lg' > { earnedBadges . length } </ div >
659- < div className = 'text-xs opacity-80' > Badges</ div >
590+ { /* Stats and Referral Code - Only for Classic and Minimal layouts */ }
591+ { currentLayout . id !== 1 && (
592+ < div className = 'relative z-10 px-6 mb-4 space-y-3' >
593+ { /* Stats */ }
594+ < div className = 'bg-black/30 backdrop-blur-sm rounded-lg p-3 border border-white/30' >
595+ < div
596+ className = 'grid grid-cols-3 gap-2 text-sm'
597+ style = { { color : currentTheme . text } }
598+ >
599+ < div className = 'text-center' >
600+ < div className = 'font-bold text-lg' > { account . totalPoints || 0 } </ div >
601+ < div className = 'text-xs opacity-80' > Points</ div >
602+ </ div >
603+ < div className = 'text-center' >
604+ < div className = 'font-bold text-lg' > { account . experience || 0 } </ div >
605+ < div className = 'text-xs opacity-80' > Experience</ div >
606+ </ div >
607+ < div className = 'text-center' >
608+ < div className = 'font-bold text-lg' > { earnedBadges . length } </ div >
609+ < div className = 'text-xs opacity-80' > Badges</ div >
610+ </ div >
660611 </ div >
661612 </ div >
662613 </ div >
663- </ div >
614+ ) }
664615
665616 < br />
666617
@@ -904,37 +855,6 @@ export const PokemonReferralCard: React.FC<PokemonReferralCardProps> = ({
904855 ) }
905856 </ button >
906857
907- { /* Download GIF Button */ }
908- < button
909- onClick = { handleDownloadGif }
910- disabled = { isGeneratingGif }
911- className = 'bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white font-bold py-3 px-6 rounded-xl transition-all duration-300 transform hover:scale-105 shadow-lg hover:shadow-xl disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none flex items-center justify-center space-x-2 w-full'
912- >
913- { isGeneratingGif ? (
914- < >
915- < div className = 'animate-spin rounded-full h-4 w-4 border-b-2 border-white' > </ div >
916- < span > Creating GIF...</ span >
917- < div className = 'animate-pulse text-xs ml-2' >
918- ({ Math . round ( gifProgress ) } %)
919- </ div >
920- </ >
921- ) : (
922- < >
923- < span > 🎭</ span >
924- < span > Download GIF</ span >
925- </ >
926- ) }
927- </ button >
928-
929- { /* GIF Progress Bar */ }
930- { isGeneratingGif && (
931- < div className = 'w-full bg-gray-700 rounded-full h-2 overflow-hidden' >
932- < div
933- className = 'bg-gradient-to-r from-purple-500 to-pink-500 h-2 rounded-full transition-all duration-300 ease-out'
934- style = { { width : `${ gifProgress } %` } }
935- />
936- </ div >
937- ) }
938858 </ div >
939859 </ div >
940860 ) ;
0 commit comments