import { screenReaderDebounceDelaySeconds } from 'config' import { useI18n } from 'domains/i18n/hooks' import { useAppDispatch } from 'domains/store' import { clearIdleDetachCountdown, decrementIdleDetachCountdownCounter, initIdleDetachCountdown, stopIdleDetachCountdownCounter, } from 'domains/store/slice' import { useVisibility } from 'domains/visibility/hooks' import { useCallback, useRef } from 'preact/hooks' import { getTimeFromSeconds, millisecondsToSeconds, } from 'ui/utils/general-utils' import { actionTypes } from 'ui/utils/seamly-utils' import { useLiveRegion } from './live-region-hooks' import { useSeamlyStateContext } from './seamly-state-hooks' import useSeamlyCommands from './use-seamly-commands' const useSeamlyIdleDetachCountdown = () => { const dispatch = useAppDispatch() const { idleDetachCountdown: { hasCountdown, isActive, count, remaining, timer, wasStopped, }, } = useSeamlyStateContext() const { isOpen } = useVisibility() // We create a ref here, and explicitly overwrite the current values, because the // `endCountdown` call initiated by the server has a different lifecycle from the // `IdleDetachWarning` component. const countdownState = useRef({ hasCountdown: false, wasStopped: false, }) countdownState.current = { hasCountdown, wasStopped: wasStopped || false, } const { emitEvent, sendAction } = useSeamlyCommands() const { t } = useI18n() const { sendAssertive, sendPolite } = useLiveRegion() const sendAssertiveIfOpen = useCallback( (text) => { if (isOpen) { sendAssertive(text) } }, [isOpen, sendAssertive], ) const sendPoliteIfOpen = useCallback( (text) => { if (isOpen) { sendPolite(text) } }, [isOpen, sendPolite], ) const initCountdown = useCallback( (milliseconds) => { const delaySeconds = millisecondsToSeconds(milliseconds) const delayTime = getTimeFromSeconds(delaySeconds) dispatch( initIdleDetachCountdown({ delaySeconds, delayTime, }), ) emitEvent('idleTimer.start') sendAssertiveIfOpen( `${t('idleDetachWarning.countdownTitle')} ${t( 'idleDetachWarning.countdownText', )} ${t('idleDetachWarning.countdownTimer', delayTime)}`, ) }, [dispatch, emitEvent, sendAssertiveIfOpen, t], ) const endCountdown = useCallback< (_continueChat?: boolean | undefined, _isServerAction?: boolean) => void >( (continueChat = undefined, isServerAction = false) => { const { hasCountdown, wasStopped } = countdownState.current if (!hasCountdown) { return } if (!continueChat) { if (!isServerAction) { sendAction({ type: actionTypes.detachService }) } sendAssertiveIfOpen(t('idleDetachWarning.notifyTransferText')) } if (!wasStopped) { emitEvent('idleTimer.stop') } dispatch(clearIdleDetachCountdown()) }, [dispatch, emitEvent, sendAction, sendAssertiveIfOpen, t], ) const decrementCountdown = useCallback(() => { if (!remaining || remaining <= 0) { return } const newRemaining = remaining - 1 if (newRemaining % screenReaderDebounceDelaySeconds === 0) { sendAssertiveIfOpen( `${t('idleDetachWarning.countdownText')} ${t( 'idleDetachWarning.countdownTimer', getTimeFromSeconds(newRemaining), )}`, ) } dispatch(decrementIdleDetachCountdownCounter()) }, [dispatch, remaining, sendAssertiveIfOpen, t]) const stopCountdown = useCallback(() => { if (!isActive) { return } dispatch(stopIdleDetachCountdownCounter()) if (remaining) { emitEvent('idleTimer.stop') sendPoliteIfOpen(t('idleDetachWarning.srCountDownStoppedText')) } }, [dispatch, emitEvent, isActive, remaining, sendPoliteIfOpen, t]) return { hasCountdown, isActive, count, remaining, timer, wasStopped, initCountdown, endCountdown, decrementCountdown, stopCountdown, } } export default useSeamlyIdleDetachCountdown