import { createContext, useCallback, useEffect, useMemo, useState } from 'react'; import { Outlet, useOutletContext } from 'react-router-dom'; import { BREAKPOINTS, STREAM_ACTION_NAME } from '../constants'; import { useChannel } from './Channel'; import { useResponsiveDevice } from './ResponsiveDevice'; import useContextHook from './useContextHook'; import useCountdown from '../hooks/useCountdown'; const TIME_BASED_VIEWER_ACTIONS = [ STREAM_ACTION_NAME.CELEBRATION, STREAM_ACTION_NAME.NOTICE, STREAM_ACTION_NAME.QUIZ ]; const Context = createContext(null); Context.displayName = 'ViewerStreamActions'; export const Provider = () => { const { channelData } = useChannel(); const { color, isLive } = channelData || {}; const { currentBreakpoint } = useResponsiveDevice(); const [currentViewerAction, setCurrentViewerAction] = useState(); const outletCtx = useOutletContext(); const isChannelPageStackedView = currentBreakpoint < BREAKPOINTS.lg; const currentViewerStreamActionData = currentViewerAction?.data; const currentViewerStreamActionStartTime = currentViewerAction?.startTime; const currentViewerStreamActionName = currentViewerAction?.name; const currentViewerStreamActionTitle = `${currentViewerStreamActionName ?.charAt(0) ?.toUpperCase()}${currentViewerStreamActionName ?.slice(1) ?.replace(/_/g, ' ')}`; const augmentedCurrentViewerStreamActionData = useMemo( () => ({ ...currentViewerStreamActionData, color, startTime: currentViewerStreamActionStartTime }), [color, currentViewerStreamActionData, currentViewerStreamActionStartTime] ); const { duration: viewerActionDuration, startTime: viewerActionStartTime } = augmentedCurrentViewerStreamActionData; const viewerActionExpiry = typeof viewerActionDuration === 'number' && typeof viewerActionStartTime === 'number' ? viewerActionStartTime + viewerActionDuration * 1000 : null; const clearCurrentViewerAction = useCallback( () => setCurrentViewerAction(null), [] ); const clearCurrentViewerActionWithDelay = useCallback(() => { setTimeout( () => setCurrentViewerAction((prev) => { if (prev?.name === STREAM_ACTION_NAME.QUIZ) return null; // Don't cancel the current action if it changed to something other than a quiz return prev; }), 2000 ); }, [setCurrentViewerAction]); useCountdown({ expiry: viewerActionExpiry, isEnabled: TIME_BASED_VIEWER_ACTIONS.includes(currentViewerStreamActionName) && viewerActionExpiry, onExpiry: currentViewerStreamActionName === STREAM_ACTION_NAME.QUIZ ? clearCurrentViewerActionWithDelay : clearCurrentViewerAction }); useEffect(() => { if (!isLive) clearCurrentViewerAction(); }, [clearCurrentViewerAction, isLive]); const shouldRenderActionInTab = useMemo( () => [ STREAM_ACTION_NAME.QUIZ, STREAM_ACTION_NAME.PRODUCT, STREAM_ACTION_NAME.AMAZON_PRODUCT ].includes(currentViewerStreamActionName) && isChannelPageStackedView, [currentViewerStreamActionName, isChannelPageStackedView] ); const value = useMemo( () => ({ clearCurrentViewerAction, currentViewerStreamActionData: augmentedCurrentViewerStreamActionData, currentViewerStreamActionName, currentViewerStreamActionTitle, setCurrentViewerAction, shouldRenderActionInTab, isChannelPageStackedView }), [ augmentedCurrentViewerStreamActionData, clearCurrentViewerAction, currentViewerStreamActionName, currentViewerStreamActionTitle, shouldRenderActionInTab, isChannelPageStackedView ] ); return ( ); }; export const useViewerStreamActions = () => useContextHook(Context);