1- import { useEffect } from "react" ;
1+ import { useEffect , useRef } from "react" ;
2+ import confetti from "canvas-confetti" ;
3+ import { useWalletContext } from "../providers/WalletProvider" ;
24import { useParams , useSearchParams } from "react-router-dom" ;
35import { toast } from "sonner" ;
46import { useRaffle } from "../hooks/useRaffles" ;
@@ -16,6 +18,8 @@ const RaffleDetails = () => {
1618 const [ searchParams ] = useSearchParams ( ) ;
1719 const raffleId = id ?? searchParams . get ( "raffle" ) ;
1820 const parsedRaffleId = raffleId ? parseInt ( raffleId , 10 ) : 0 ;
21+ const { address } = useWalletContext ( ) ;
22+ const hasCelebrated = useRef ( false ) ;
1923
2024 const { raffle, error, isLoading, refetch } = useRaffle ( parsedRaffleId ) ;
2125
@@ -25,6 +29,30 @@ const RaffleDetails = () => {
2529 return ( ) => window . removeEventListener ( "focus" , handleFocus ) ;
2630 } , [ refetch ] ) ;
2731
32+ useEffect ( ( ) => {
33+ if ( raffle ?. winner && address === raffle . winner && ! hasCelebrated . current ) {
34+ const duration = 3 * 1000 ;
35+ const animationEnd = Date . now ( ) + duration ;
36+ const defaults = { startVelocity : 30 , spread : 360 , ticks : 60 , zIndex : 0 } ;
37+
38+ const randomInRange = ( min : number , max : number ) => Math . random ( ) * ( max - min ) + min ;
39+
40+ const interval : any = setInterval ( function ( ) {
41+ const timeLeft = animationEnd - Date . now ( ) ;
42+
43+ if ( timeLeft <= 0 ) {
44+ return clearInterval ( interval ) ;
45+ }
46+
47+ const particleCount = 50 * ( timeLeft / duration ) ;
48+ confetti ( { ...defaults , particleCount, origin : { x : randomInRange ( 0.1 , 0.3 ) , y : Math . random ( ) - 0.2 } } ) ;
49+ confetti ( { ...defaults , particleCount, origin : { x : randomInRange ( 0.7 , 0.9 ) , y : Math . random ( ) - 0.2 } } ) ;
50+ } , 250 ) ;
51+
52+ hasCelebrated . current = true ;
53+ }
54+ } , [ raffle ?. winner , address ] ) ;
55+
2856 const statusLabel = raffle ?. status ?. toUpperCase ( ) || "UNKNOWN" ;
2957 const lowerStatus = raffle ?. status ?. toLowerCase ( ) || "" ;
3058 const isFinalized = lowerStatus === "closed" || lowerStatus === "finalized" || lowerStatus === "cancelled" ;
@@ -81,6 +109,20 @@ const RaffleDetails = () => {
81109 />
82110 </ div >
83111
112+ { raffle ?. winner && address === raffle . winner && (
113+ < div className = "bg-gradient-to-r from-yellow-400 via-pink-500 to-purple-600 p-1 rounded-3xl mb-6 animate-pulse" >
114+ < div className = "bg-white dark:bg-[#11172E] rounded-[22px] p-8 text-center shadow-2xl" >
115+ < div className = "text-5xl mb-4" > 🏆</ div >
116+ < h2 className = "text-3xl md:text-4xl font-black text-gray-900 dark:text-white mb-2 tracking-tight" >
117+ CONGRATULATIONS!
118+ </ h2 >
119+ < p className = "text-lg text-gray-600 dark:text-pink-200 font-medium" >
120+ You are the winner of this raffle! 🎉
121+ </ p >
122+ </ div >
123+ </ div >
124+ ) }
125+
84126 < RaffleDetailsCard
85127 image = { raffle . image || detailimage }
86128 images = { raffle . metadata ?. images }
0 commit comments