1- import React , { useEffect , useState , useRef } from "react" ;
1+ import React , { useEffect , useState , useRef , useCallback } from "react" ;
22import { MapContainer , TileLayer , Marker , Popup } from "react-leaflet" ;
33import { LatLng , DivIcon } from "leaflet" ;
44import "leaflet/dist/leaflet.css" ;
@@ -75,13 +75,6 @@ const initializeLogoAnimations = () => {
7575const App : React . FC = ( ) => {
7676 const [ views , setViews ] = useState < ViewData [ ] > ( [ ] ) ;
7777 const [ lastObservedView , setLastObservedView ] = useState < number | null > ( null ) ;
78- const [ statsData , setStatsData ] = useState ( {
79- totalViews : 0 ,
80- finalized : 0 ,
81- notarized : 0 ,
82- growing : 0 ,
83- timedOut : 0
84- } ) ;
8578 const [ isMobile , setIsMobile ] = useState < boolean > ( false ) ;
8679 const currentTimeRef = useRef ( Date . now ( ) ) ;
8780 const wsRef = useRef < WebSocket | null > ( null ) ;
@@ -108,85 +101,7 @@ const App: React.FC = () => {
108101 } ;
109102 } , [ ] ) ;
110103
111- // Update current time every 100ms to force re-render for growing bars
112- useEffect ( ( ) => {
113- const interval = setInterval ( ( ) => {
114- currentTimeRef . current = Date . now ( ) ;
115- // Force re-render without relying on state updates
116- setViews ( views => [ ...views ] ) ;
117- } , 100 ) ;
118- return ( ) => clearInterval ( interval ) ;
119- } , [ ] ) ;
120-
121- // Update stats whenever views change
122- useEffect ( ( ) => {
123- const stats = {
124- totalViews : views . length ,
125- finalized : views . filter ( ( v : ViewData ) => v . status === "finalized" ) . length ,
126- notarized : views . filter ( ( v : ViewData ) => v . status === "notarized" ) . length ,
127- growing : views . filter ( ( v : ViewData ) => v . status === "growing" ) . length ,
128- timedOut : views . filter ( ( v : ViewData ) => v . status === "timed_out" ) . length
129- } ;
130- setStatsData ( stats ) ;
131- } , [ views ] ) ;
132-
133- // Initialize WebSocket
134- useEffect ( ( ) => {
135- const setup = async ( ) => {
136- await init ( ) ;
137- connectWebSocket ( ) ;
138- } ;
139-
140- const connectWebSocket = ( ) => {
141- const ws = new WebSocket ( WS_URL ) ;
142- wsRef . current = ws ;
143- ws . binaryType = "arraybuffer" ;
144-
145- ws . onopen = ( ) => {
146- console . log ( "WebSocket connected" ) ;
147- } ;
148-
149- ws . onmessage = ( event ) => {
150- const data = new Uint8Array ( event . data ) ;
151- const kind = data [ 0 ] ;
152- const payload = data . slice ( 1 ) ;
153-
154- switch ( kind ) {
155- case 0 : // Seed
156- const seed = parse_seed ( PUBLIC_KEY , payload ) ;
157- if ( seed ) handleSeed ( seed ) ;
158- break ;
159- case 1 : // Notarization
160- const notarized = parse_notarized ( PUBLIC_KEY , payload ) ;
161- if ( notarized ) handleNotarization ( notarized ) ;
162- break ;
163- case 3 : // Finalization
164- const finalized = parse_finalized ( PUBLIC_KEY , payload ) ;
165- if ( finalized ) handleFinalization ( finalized ) ;
166- break ;
167- }
168- } ;
169-
170- ws . onerror = ( error ) => {
171- console . error ( "WebSocket error:" , error ) ;
172- } ;
173-
174- ws . onclose = ( ) => {
175- console . log ( "WebSocket closed, trying to reconnect in 5 seconds" ) ;
176- setTimeout ( connectWebSocket , 5000 ) ;
177- } ;
178- } ;
179-
180- setup ( ) ;
181-
182- return ( ) => {
183- if ( wsRef . current ) {
184- wsRef . current . close ( ) ;
185- }
186- } ;
187- } , [ ] ) ;
188-
189- const handleSeed = ( seed : SeedJs ) => {
104+ const handleSeed = useCallback ( ( seed : SeedJs ) => {
190105 const view = seed . view + 1 ; // Next view is determined by seed - 1
191106
192107 setViews ( ( prevViews ) => {
@@ -280,9 +195,9 @@ const App: React.FC = () => {
280195
281196 return newViews ;
282197 } ) ;
283- } ;
198+ } , [ lastObservedView ] ) ;
284199
285- const handleNotarization = ( notarized : NotarizedJs ) => {
200+ const handleNotarization = useCallback ( ( notarized : NotarizedJs ) => {
286201 const view = notarized . proof . view ;
287202 setViews ( ( prevViews ) => {
288203 const index = prevViews . findIndex ( ( v ) => v . view === view ) ;
@@ -324,9 +239,9 @@ const App: React.FC = () => {
324239 block : notarized . block ,
325240 } , ...prevViews ] ;
326241 } ) ;
327- } ;
242+ } , [ ] ) ;
328243
329- const handleFinalization = ( finalized : FinalizedJs ) => {
244+ const handleFinalization = useCallback ( ( finalized : FinalizedJs ) => {
330245 const view = finalized . proof . view ;
331246 setViews ( ( prevViews ) => {
332247 const index = prevViews . findIndex ( ( v ) => v . view === view ) ;
@@ -368,7 +283,74 @@ const App: React.FC = () => {
368283 block : finalized . block ,
369284 } , ...prevViews ] ;
370285 } ) ;
371- } ;
286+ } , [ ] ) ;
287+
288+
289+ // Update current time every 100ms to force re-render for growing bars
290+ useEffect ( ( ) => {
291+ const interval = setInterval ( ( ) => {
292+ currentTimeRef . current = Date . now ( ) ;
293+ // Force re-render without relying on state updates
294+ setViews ( views => [ ...views ] ) ;
295+ } , 100 ) ;
296+ return ( ) => clearInterval ( interval ) ;
297+ } , [ ] ) ;
298+
299+ // Initialize WebSocket
300+ useEffect ( ( ) => {
301+ const setup = async ( ) => {
302+ await init ( ) ;
303+ connectWebSocket ( ) ;
304+ } ;
305+
306+ const connectWebSocket = ( ) => {
307+ const ws = new WebSocket ( WS_URL ) ;
308+ wsRef . current = ws ;
309+ ws . binaryType = "arraybuffer" ;
310+
311+ ws . onopen = ( ) => {
312+ console . log ( "WebSocket connected" ) ;
313+ } ;
314+
315+ ws . onmessage = ( event ) => {
316+ const data = new Uint8Array ( event . data ) ;
317+ const kind = data [ 0 ] ;
318+ const payload = data . slice ( 1 ) ;
319+
320+ switch ( kind ) {
321+ case 0 : // Seed
322+ const seed = parse_seed ( PUBLIC_KEY , payload ) ;
323+ if ( seed ) handleSeed ( seed ) ;
324+ break ;
325+ case 1 : // Notarization
326+ const notarized = parse_notarized ( PUBLIC_KEY , payload ) ;
327+ if ( notarized ) handleNotarization ( notarized ) ;
328+ break ;
329+ case 3 : // Finalization
330+ const finalized = parse_finalized ( PUBLIC_KEY , payload ) ;
331+ if ( finalized ) handleFinalization ( finalized ) ;
332+ break ;
333+ }
334+ } ;
335+
336+ ws . onerror = ( error ) => {
337+ console . error ( "WebSocket error:" , error ) ;
338+ } ;
339+
340+ ws . onclose = ( ) => {
341+ console . log ( "WebSocket closed, trying to reconnect in 5 seconds" ) ;
342+ setTimeout ( connectWebSocket , 5000 ) ;
343+ } ;
344+ } ;
345+
346+ setup ( ) ;
347+
348+ return ( ) => {
349+ if ( wsRef . current ) {
350+ wsRef . current . close ( ) ;
351+ }
352+ } ;
353+ } , [ handleSeed , handleNotarization , handleFinalization ] ) ;
372354
373355 // Define center using LatLng
374356 const center = new LatLng ( 20 , 0 ) ;
0 commit comments