1+ import React , { useState , useEffect } from 'react' ;
2+ import { ethers } from 'ethers' ;
3+ import "./css/Winners.css"
4+
5+ const CONTRACT_ADDRESS = '0xeADD42c14c50397E64b4dc94a4beD91175c1E011' ;
6+ const ABI = [
7+ {
8+ "anonymous" : false ,
9+ "inputs" : [
10+ {
11+ "indexed" : true ,
12+ "internalType" : "address" ,
13+ "name" : "winner" ,
14+ "type" : "address"
15+ } ,
16+ {
17+ "indexed" : true ,
18+ "internalType" : "address" ,
19+ "name" : "token" ,
20+ "type" : "address"
21+ } ,
22+ {
23+ "indexed" : false ,
24+ "internalType" : "uint256" ,
25+ "name" : "prize" ,
26+ "type" : "uint256"
27+ }
28+ ] ,
29+ "name" : "WinnerSelected" ,
30+ "type" : "event"
31+ } ,
32+ {
33+ "inputs" : [ ] ,
34+ "name" : "getTokens" ,
35+ "outputs" : [
36+ {
37+ "internalType" : "address[]" ,
38+ "name" : "" ,
39+ "type" : "address[]"
40+ }
41+ ] ,
42+ "stateMutability" : "view" ,
43+ "type" : "function"
44+ } ,
45+ {
46+ "inputs" : [ ] ,
47+ "name" : "lotteryActive" ,
48+ "outputs" : [
49+ {
50+ "internalType" : "bool" ,
51+ "name" : "" ,
52+ "type" : "bool"
53+ }
54+ ] ,
55+ "stateMutability" : "view" ,
56+ "type" : "function"
57+ }
58+ ] ;
59+
60+ const generateBlockchainImage = ( seed ) => {
61+ const colors = [ '#1a237e' , '#ffd700' , '#4a90e2' , '#c2185b' , '#ffa726' ] ;
62+ const randomColor = colors [ Math . abs ( seed . charCodeAt ( 0 ) ) % colors . length ] ;
63+
64+ return `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
65+ <defs>
66+ <pattern id="grid" width="20" height="20" patternUnits="userSpaceOnUse">
67+ <path d="M 20 0 L 0 0 0 20" fill="none" stroke="${ randomColor } " strokeOpacity="0.2" strokeWidth="1"/>
68+ </pattern>
69+ <radialGradient id="glow" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
70+ <stop offset="0%" style="stop-color:${ randomColor } ;stop-opacity:0.5"/>
71+ <stop offset="100%" style="stop-color:${ randomColor } ;stop-opacity:0"/>
72+ </radialGradient>
73+ </defs>
74+ <rect width="200" height="200" fill="url(#grid)"/>
75+ <circle cx="100" cy="100" r="80" fill="url(#glow)"/>
76+ <polygon points="100,20 180,100 100,180 20,100" fill="${ randomColor } " fillOpacity="0.3" stroke="${ randomColor } " strokeWidth="2"/>
77+ </svg>` ;
78+ } ;
79+
80+ const WinnersPage = ( ) => {
81+ const [ winners , setWinners ] = useState ( [ ] ) ;
82+ const [ latestWinner , setLatestWinner ] = useState ( null ) ;
83+ const [ showNotification , setShowNotification ] = useState ( false ) ;
84+ const [ isConnected , setIsConnected ] = useState ( false ) ;
85+ const [ loading , setLoading ] = useState ( false ) ;
86+ const [ error , setError ] = useState ( '' ) ;
87+ const [ contract , setContract ] = useState ( null ) ;
88+ const [ account , setAccount ] = useState ( '' ) ;
89+
90+ const connectWallet = async ( ) => {
91+ try {
92+ if ( typeof window . ethereum === 'undefined' ) {
93+ throw new Error ( 'MetaMask is not installed' ) ;
94+ }
95+
96+ setLoading ( true ) ;
97+ const accounts = await window . ethereum . request ( {
98+ method : 'eth_requestAccounts'
99+ } ) ;
100+
101+ const provider = new ethers . BrowserProvider ( window . ethereum ) ;
102+ const signer = await provider . getSigner ( ) ;
103+ const newContract = new ethers . Contract ( CONTRACT_ADDRESS , ABI , signer ) ;
104+
105+ setContract ( newContract ) ;
106+ setAccount ( accounts [ 0 ] ) ;
107+ setIsConnected ( true ) ;
108+ setLoading ( false ) ;
109+
110+ } catch ( err ) {
111+ setError ( err . message || 'Failed to connect wallet' ) ;
112+ setLoading ( false ) ;
113+ console . error ( 'Connection error:' , err ) ;
114+ }
115+ } ;
116+
117+ useEffect ( ( ) => {
118+ if ( ! contract ) return ;
119+
120+ const handleWinnerSelected = ( winner , token , prize , event ) => {
121+ const newWinner = {
122+ address : winner ,
123+ token : token ,
124+ prize : ethers . formatUnits ( prize , 18 ) ,
125+ date : new Date ( ) . toLocaleDateString ( ) ,
126+ image : generateBlockchainImage ( winner ) ,
127+ transactionHash : event . transactionHash
128+ } ;
129+
130+ setWinners ( prev => [ newWinner , ...prev ] ) ;
131+ setLatestWinner ( newWinner ) ;
132+ setShowNotification ( true ) ;
133+ setTimeout ( ( ) => setShowNotification ( false ) , 5000 ) ;
134+ } ;
135+
136+ contract . on ( 'WinnerSelected' , handleWinnerSelected ) ;
137+
138+ return ( ) => {
139+ contract . off ( 'WinnerSelected' , handleWinnerSelected ) ;
140+ } ;
141+ } , [ contract ] ) ;
142+
143+ useEffect ( ( ) => {
144+ if ( window . ethereum ) {
145+ window . ethereum . on ( 'accountsChanged' , ( accounts ) => {
146+ if ( accounts . length > 0 ) {
147+ setAccount ( accounts [ 0 ] ) ;
148+ } else {
149+ setIsConnected ( false ) ;
150+ setAccount ( '' ) ;
151+ }
152+ } ) ;
153+ }
154+
155+ return ( ) => {
156+ if ( window . ethereum ) {
157+ window . ethereum . removeListener ( 'accountsChanged' , ( ) => { } ) ;
158+ }
159+ } ;
160+ } , [ ] ) ;
161+
162+ const NoWinnersDisplay = ( ) => (
163+ < div className = "no-winners-container" >
164+ < div className = "hologram-coin" > </ div >
165+ < h2 className = "future-text" > No Winners Yet... The Future Awaits!</ h2 >
166+ < p className = "scroll-text" > Be the first to make history in the lottery!</ p >
167+ < button className = "cyber-button" onClick = { connectWallet } disabled = { loading } >
168+ { loading ? 'Initializing...' : 'Enter Now & Win Big' }
169+ < span className = "cyber-button-glitch" > </ span >
170+ </ button >
171+ </ div >
172+ ) ;
173+
174+ return (
175+ < div className = "cyber-container" >
176+ < div className = "grid-overlays" > </ div >
177+ < div className = "node-animation" > </ div >
178+
179+ { ! isConnected && (
180+ < div className = "connect-section" >
181+ < NoWinnersDisplay />
182+ { error && < div className = "cyber-error" > { error } </ div > }
183+ </ div >
184+ ) }
185+
186+ { showNotification && latestWinner && (
187+ < div className = "winner-notification" >
188+ 🎉 New Winner: { latestWinner . address . substring ( 0 , 6 ) } ...{ latestWinner . address . substring ( 38 ) }
189+ won { latestWinner . prize } tokens!
190+ </ div >
191+ ) }
192+
193+ < h1 className = "cyber-title" > 🏆 Cyber Lottery Winners</ h1 >
194+
195+ { isConnected && loading && (
196+ < div className = "loading-container" >
197+ < div className = "cyber-loader" > </ div >
198+ < p > Initializing blockchain connection...</ p >
199+ </ div >
200+ ) }
201+
202+ { isConnected && ! loading && winners . length === 0 && < NoWinnersDisplay /> }
203+
204+ { isConnected && winners . length > 0 && (
205+ < div className = "winners-grid" >
206+ { winners . map ( ( winner , index ) => (
207+ < div key = { index } className = "winner-card" >
208+ < div className = "card-hologram" >
209+ < img
210+ src = { winner . image }
211+ alt = "Winner's blockchain pattern"
212+ className = "winner-image"
213+ />
214+ </ div >
215+ < div className = "winner-details" >
216+ < h2 className = "winner-address" >
217+ { winner . address . substring ( 0 , 6 ) } ...{ winner . address . substring ( 38 ) }
218+ </ h2 >
219+ < p className = "winner-prize" >
220+ { winner . prize }
221+ < span className = "token-address" >
222+ ({ winner . token . substring ( 0 , 6 ) } ...{ winner . token . substring ( 38 ) } )
223+ </ span >
224+ </ p >
225+ < p className = "winner-date" > { winner . date } </ p >
226+ < a
227+ href = { `https://etherscan.io/tx/${ winner . transactionHash } ` }
228+ target = "_blank"
229+ rel = "noopener noreferrer"
230+ className = "transaction-link"
231+ >
232+ View Transaction
233+ </ a >
234+ </ div >
235+ </ div >
236+ ) ) }
237+ </ div >
238+ ) }
239+ </ div >
240+ ) ;
241+ } ;
242+
243+ export default WinnersPage ;
0 commit comments