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