11'use client' ;
22
3- import React , { useEffect , useState , useCallback } from 'react' ;
3+ import React , { useEffect , useState , useCallback , useMemo , useRef } from 'react' ;
44import { format } from 'date-fns' ;
55import { ThemeProvider } from 'styled-components' ;
66
@@ -23,7 +23,6 @@ import {
2323 processData ,
2424 handleResponseExport ,
2525 copyDataToClipboard ,
26- clearIntervals ,
2726 register ,
2827} from '@/lib' ;
2928import { notifyTelegram , notifySlack , notifyDiscord } from '@/lib/notify' ;
@@ -32,7 +31,7 @@ import { StoredData } from '@/lib/types/storedData';
3231import { Tab } from '@/lib/types/tab' ;
3332import { View } from '@/lib/types/view' ;
3433import { ThemeName , getTheme } from '@/theme' ;
35- import { writeStoredData , getStoredData , defaultStoredData } from '@/lib/localStorage' ;
34+ import { writeStoredData , getStoredData , defaultStoredData , flushStoredData } from '@/lib/localStorage' ;
3635import RequestDetailsWrapper from './components/requestDetailsWrapper' ;
3736import RequestsTableWrapper from './components/requestsTableWrapper' ;
3837import './styles.scss' ;
@@ -50,11 +49,15 @@ const HomePage = () => {
5049 const [ storedData , setStoredData ] = useState < StoredData > ( defaultStoredData ) ;
5150 const [ isCustomHostDialogVisible , setIsCustomHostDialogVisible ] = useState ( false ) ;
5251 const [ isClient , setIsClient ] = useState ( false ) ;
52+ const hasLoadedInitialData = useRef ( false ) ;
53+ const filteredDataRef = useRef < Array < Data > > ( [ ] ) ;
5354
5455 // Initialize stored data on client side
5556 useEffect ( ( ) => {
5657 setIsClient ( true ) ;
57- setStoredData ( getStoredData ( ) ) ;
58+ const loadedData = getStoredData ( ) ;
59+ setStoredData ( loadedData ) ;
60+ hasLoadedInitialData . current = true ;
5861 } , [ ] ) ;
5962
6063 const handleResetPopupDialogVisibility = useCallback ( ( ) => {
@@ -123,11 +126,13 @@ const HomePage = () => {
123126 } ) ;
124127 } ;
125128
126- const handleRowClick = ( id : string ) => {
129+ const handleRowClick = useCallback ( ( id : string ) => {
127130 setSelectedInteraction ( id ) ;
128- const reqDetails = filteredData && filteredData [ filteredData . findIndex ( ( item ) => item . id === id ) ] ;
129- setSelectedInteractionData ( reqDetails ) ;
130- } ;
131+ const reqDetails = filteredDataRef . current . find ( ( item ) => item . id === id ) ;
132+ if ( reqDetails ) {
133+ setSelectedInteractionData ( reqDetails ) ;
134+ }
135+ } , [ ] ) ;
131136
132137 const handleDeleteTab = ( tab : Tab ) => {
133138 const { tabs } = storedData ;
@@ -179,6 +184,7 @@ const HomePage = () => {
179184 ...storedData ,
180185 data : tempData ,
181186 } ) ;
187+ filteredDataRef . current = [ ] ;
182188 setFilteredData ( [ ] ) ;
183189 } ;
184190
@@ -199,7 +205,8 @@ const HomePage = () => {
199205 ) ;
200206
201207 setIsRegistered ( true ) ;
202- if ( pollData ?. data ?. length !== 0 && ! pollData . error ) {
208+
209+ if ( pollData ?. data ?. length > 0 && ! pollData . error ) {
203210 if ( pollData . aes_key ) {
204211 decryptedAESKey = decryptAESKey ( privateKey , pollData . aes_key ) ;
205212 }
@@ -236,9 +243,9 @@ const HomePage = () => {
236243 } ) ;
237244
238245 const newData = combinedData
239- . filter ( ( item ) => item [ 'unique-id' ] === dataFromLocalStorage . selectedTab [ 'unique-id' ] )
240- . map ( ( item ) => item ) ;
241- setFilteredData ( [ ... newData ] ) ;
246+ . filter ( ( item ) => item [ 'unique-id' ] === dataFromLocalStorage . selectedTab [ 'unique-id' ] ) ;
247+ filteredDataRef . current = newData ;
248+ setFilteredData ( newData ) ;
242249 }
243250 } catch ( error ) {
244251 console . error ( error ) ;
@@ -248,7 +255,9 @@ const HomePage = () => {
248255 } , [ handleResetPopupDialogVisibility , handleCustomHostDialogVisibility ] ) ;
249256
250257 useEffect ( ( ) => {
251- writeStoredData ( storedData ) ;
258+ if ( hasLoadedInitialData . current ) {
259+ writeStoredData ( storedData ) ;
260+ }
252261 } , [ storedData ] ) ;
253262
254263 useEffect ( ( ) => {
@@ -261,18 +270,16 @@ const HomePage = () => {
261270 window . addEventListener ( 'storage' , handleStorageChange ) ;
262271 setIsRegistered ( true ) ;
263272
273+ let registrationIntervalId : number | undefined ;
274+
264275 if ( storedData . correlationId === '' ) {
265276 setLoaderAnimationMode ( 'loading' ) ;
266277 setIsRegistered ( false ) ;
267- setTimeout ( ( ) => {
278+ const timeoutId = setTimeout ( ( ) => {
268279 register ( storedData . host , storedData . token , false , false )
269280 . then ( ( data ) => {
270281 setStoredData ( data ) ;
271- const intervalId = window . setInterval ( ( ) => {
272- processPolledData ( ) ;
273- } , 4000 ) ;
274282 setIsRegistered ( true ) ;
275- return intervalId ;
276283 } )
277284 . catch ( ( ) => {
278285 localStorage . clear ( ) ;
@@ -281,42 +288,96 @@ const HomePage = () => {
281288 setIsRegistered ( false ) ;
282289 } ) ;
283290 } , 1500 ) ;
291+
292+ return ( ) => {
293+ clearTimeout ( timeoutId ) ;
294+ window . removeEventListener ( 'storage' , handleStorageChange ) ;
295+ if ( registrationIntervalId ) {
296+ window . clearInterval ( registrationIntervalId ) ;
297+ }
298+ } ;
284299 }
285300
286301 return ( ) => {
287302 window . removeEventListener ( 'storage' , handleStorageChange ) ;
288303 } ;
289304 } , [ isClient ] ) ;
290305
306+ const pollingIntervalRef = useRef < number | undefined > ( undefined ) ;
307+ const isPageVisibleRef = useRef ( true ) ;
308+
309+ useEffect ( ( ) => {
310+ const handleVisibilityChange = ( ) => {
311+ isPageVisibleRef . current = ! document . hidden ;
312+
313+ if ( document . hidden ) {
314+ if ( pollingIntervalRef . current ) {
315+ window . clearInterval ( pollingIntervalRef . current ) ;
316+ pollingIntervalRef . current = undefined ;
317+ }
318+ flushStoredData ( ) ;
319+ } else if ( isClient && storedData . tabs . length > 0 ) {
320+ if ( ! pollingIntervalRef . current ) {
321+ processPolledData ( ) ; // Immediate poll on return
322+ pollingIntervalRef . current = window . setInterval ( ( ) => {
323+ processPolledData ( ) ;
324+ } , 4000 ) ;
325+ }
326+ }
327+ } ;
328+
329+ document . addEventListener ( 'visibilitychange' , handleVisibilityChange ) ;
330+
331+ const handleBeforeUnload = ( ) => {
332+ flushStoredData ( ) ;
333+ } ;
334+ window . addEventListener ( 'beforeunload' , handleBeforeUnload ) ;
335+
336+ return ( ) => {
337+ document . removeEventListener ( 'visibilitychange' , handleVisibilityChange ) ;
338+ window . removeEventListener ( 'beforeunload' , handleBeforeUnload ) ;
339+ } ;
340+ } , [ isClient , storedData . tabs . length , processPolledData ] ) ;
341+
291342 useEffect ( ( ) => {
292343 if ( ! isClient || storedData . tabs . length === 0 ) return ;
293344
294- clearIntervals ( ) ;
295- const intervalId = window . setInterval ( ( ) => {
296- processPolledData ( ) ;
297- } , 4000 ) ;
345+ if ( pollingIntervalRef . current ) {
346+ window . clearInterval ( pollingIntervalRef . current ) ;
347+ }
348+
349+ if ( isPageVisibleRef . current ) {
350+ pollingIntervalRef . current = window . setInterval ( ( ) => {
351+ processPolledData ( ) ;
352+ } , 4000 ) ;
353+ }
298354
299355 const tempFilteredData = storedData . data
300- . filter ( ( item ) => item [ 'unique-id' ] === storedData . selectedTab [ 'unique-id' ] )
301- . map ( ( item ) => item ) ;
356+ . filter ( ( item ) => item [ 'unique-id' ] === storedData . selectedTab [ 'unique-id' ] ) ;
357+ filteredDataRef . current = tempFilteredData ;
302358 setFilteredData ( tempFilteredData ) ;
303359
304360 return ( ) => {
305- window . clearInterval ( intervalId ) ;
361+ if ( pollingIntervalRef . current ) {
362+ window . clearInterval ( pollingIntervalRef . current ) ;
363+ pollingIntervalRef . current = undefined ;
364+ }
306365 } ;
307366 } , [ storedData . selectedTab , isClient , processPolledData ] ) ;
308367
309368 const selectedTabsIndex = storedData . tabs . findIndex ( ( item ) =>
310369 item === storedData . selectedTab
311370 ) ;
312371
372+ const theme = useMemo ( ( ) => getTheme ( storedData . theme ) , [ storedData . theme ] ) ;
373+
313374 if ( ! isClient ) {
314375 return null ;
315376 }
316377
317378 return (
318- < ThemeProvider theme = { getTheme ( storedData . theme ) } >
319- < GlobalStyles theme = { getTheme ( storedData . theme ) } />
379+ < ThemeProvider theme = { theme } >
380+ < GlobalStyles theme = { theme } />
320381 < div className = "main" >
321382 < AppLoader isRegistered = { isRegistered } mode = { loaderAnimationMode } />
322383 { aboutPopupVisibility && (
@@ -365,7 +426,7 @@ const HomePage = () => {
365426 < TabSwitcher
366427 handleTabButtonClick = { handleTabButtonClick }
367428 selectedTab = { storedData . selectedTab }
368- data = { [ ... storedData . tabs ] }
429+ data = { storedData . tabs }
369430 handleAddNewTab = { handleAddNewTab }
370431 handleDeleteTab = { handleDeleteTab }
371432 handleTabRename = { handleTabRename }
@@ -391,7 +452,7 @@ const HomePage = () => {
391452 />
392453 </ div >
393454 < RequestsTableWrapper
394- data = { [ ... filteredData ] }
455+ data = { filteredData }
395456 selectedInteraction = { selectedInteraction || '' }
396457 handleRowClick = { handleRowClick }
397458 filter = { storedData . filter }
0 commit comments