bookwiz.io / lib / hooks / usePageLifecycle.ts
usePageLifecycle.ts
Raw
import { useEffect, useRef, useState } from 'react'

interface PageLifecycleState {
  isVisible: boolean
  wasEverHidden: boolean
  timeHidden: number
  timeVisible: number
}

export function usePageLifecycle() {
  const [state, setState] = useState<PageLifecycleState>({
    isVisible: true,
    wasEverHidden: false,
    timeHidden: 0,
    timeVisible: Date.now()
  })
  
  const hiddenTimeRef = useRef<number>(0)
  const wasFreezingRef = useRef<boolean>(false)

  useEffect(() => {
    const handleVisibilityChange = () => {
      const now = Date.now()
      const isVisible = !document.hidden
      
      if (isVisible) {
        // Page became visible
        const timeHidden = hiddenTimeRef.current > 0 ? now - hiddenTimeRef.current : 0
        
        setState(prev => ({
          ...prev,
          isVisible: true,
          timeVisible: now,
          timeHidden
        }))
        
        hiddenTimeRef.current = 0
      } else {
        // Page became hidden
        hiddenTimeRef.current = now
        setState(prev => ({
          ...prev,
          isVisible: false,
          wasEverHidden: true
        }))
      }
    }

    const handleFreeze = () => {
      wasFreezingRef.current = true
    }

    const handleResume = () => {
      if (wasFreezingRef.current) {
        wasFreezingRef.current = false
        
        // Page was suspended, treat as significant event
        setState(prev => ({
          ...prev,
          wasEverHidden: true,
          timeVisible: Date.now()
        }))
      }
    }

    const handlePageShow = () => {
      // Page show event (possibly from cache)
    }

    const handlePageHide = () => {
      // Page hide event (possibly being cached)
    }

    // Add all the event listeners
    document.addEventListener('visibilitychange', handleVisibilityChange)
    document.addEventListener('freeze', handleFreeze)
    document.addEventListener('resume', handleResume)
    window.addEventListener('pageshow', handlePageShow)
    window.addEventListener('pagehide', handlePageHide)
    
    // Initial state
    handleVisibilityChange()

    return () => {
      document.removeEventListener('visibilitychange', handleVisibilityChange)
      document.removeEventListener('freeze', handleFreeze)
      document.removeEventListener('resume', handleResume)
      window.removeEventListener('pageshow', handlePageShow)
      window.removeEventListener('pagehide', handlePageHide)
    }
  }, [])

  const shouldRefreshData = (thresholdMs: number = 30000) => {
    return state.timeHidden > thresholdMs || wasFreezingRef.current
  }

  const shouldPreserveState = () => {
    // Preserve state if user just switched tabs briefly
    return state.wasEverHidden && state.timeHidden < 30000
  }

  return {
    ...state,
    shouldRefreshData,
    shouldPreserveState,
    wasRecentlyHidden: state.timeHidden > 0 && state.timeHidden < 5000
  }
}