import { Localized } from "@fluent/react/compat" ; import React , { FunctionComponent , useCallback , useEffect , useState , } from "react" ; import { graphql } from "react-relay" ; import { useLive , useVisibilityState } from "coral-framework/hooks" ; import { useCoralContext } from "coral-framework/lib/bootstrap/CoralContext" ; import { globalErrorReporter } from "coral-framework/lib/errors" ; import { useInView } from "coral-framework/lib/intersection" ; import { useFetch , withFragmentContainer } from "coral-framework/lib/relay" ; import { Icon } from "coral-ui/components/v2" ; import { CallOut } from "coral-ui/components/v3" ; import { ViewersWatchingContainer_settings } from "coral-stream/__generated__/ViewersWatchingContainer_settings.graphql" ; import { ViewersWatchingContainer_story } from "coral-stream/__generated__/ViewersWatchingContainer_story.graphql" ; import RefreshStoryViewerCount from "./RefreshStoryViewerCount" ; import styles from "./ViewersWatchingContainer.css" ; interface Props { story : ViewersWatchingContainer_story ; settings : ViewersWatchingContainer_settings ; } const TIMEOUT = 20000 ; const TIMEOUT_JITTER = TIMEOUT / 2 ; const MAX_TIMEOUT = TIMEOUT + TIMEOUT_JITTER ; const ViewersWatchingContainer = ( { story , settings , } ) => { const { window } = useCoralContext ( ) ; const { inView , intersectionRef } = useInView ( ) ; const [ lastRefreshed , setLastRefreshed ] = useState < number > ( Date . now ( ) ) ; const [ refreshed , setRefreshed ] = useState ( false ) ; const live = useLive ( { story , settings } ) ; const visible = useVisibilityState ( ) ; const refreshStoryViewerCount = useFetch ( RefreshStoryViewerCount ) ; const refresh = useCallback ( async ( ) => { try { await refreshStoryViewerCount ( { storyID : story . id } ) ; setRefreshed ( true ) ; setLastRefreshed ( Date . now ( ) ) ; } catch ( err ) { globalErrorReporter . report ( err ) ; } } , [ refreshStoryViewerCount , story . id ] ) ; const available = story . viewerCount !== null ; useEffect ( ( ) => { if ( ! live || ! available || ! visible || ! inView ) { return ; } const lastRefreshedDiff = Date . now ( ) - lastRefreshed ; if ( lastRefreshedDiff >= MAX_TIMEOUT ) { void refresh ( ) ; return ; } const timeout = window . setTimeout ( refresh , MAX_TIMEOUT - lastRefreshedDiff + Math . floor ( Math . random ( ) * TIMEOUT_JITTER ) ) ; return ( ) => { window . clearTimeout ( timeout ) ; } ; } , [ live , story . id , refreshStoryViewerCount , visible , available , inView , lastRefreshed , refresh , ] ) ; if ( ! live || story . viewerCount === null ) { return null ; } const viewerCount = refreshed ? story . viewerCount || 1 : story . viewerCount + 1 ; return ( < div ref = { intersectionRef } > < CallOut classes = { { icon : styles . icon , title : styles . title , container : styles . container , } } icon = { < Icon size = "md" > people_alt < /Icon>} color="primary" title={<Localized id="comments-watchers" $count={viewerCount}> < span > { viewerCount } online < /span> < /Localized>} titleWeight="semiBold"/ > < /div>); } ; const enhanced = withFragmentContainer < Props > ( { story : graphql `
    fragment ViewersWatchingContainer_story on Story {
      id
      viewerCount
      isClosed
      settings {
        live {
          enabled
        }
      }
    }
  ` , settings : graphql `
    fragment ViewersWatchingContainer_settings on Settings {
      disableCommenting {
        enabled
      }
    }
  ` , } ) ( ViewersWatchingContainer ) ; export default enhanced ;