import React, { useState, useEffect, useContext, useRef } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import { Duration } from 'luxon' import { I18nContext } from '../../../contexts/i18n' import InfoTooltip from '../../../components/ui/info-tooltip' const TIMER_BASE = 60000 // Return the mm:ss start time of the countdown timer. // If time has elapsed between `timeStarted` the time current time, // then that elapsed time will be subtracted from the timer before // rendering function getNewTimer (currentTime, timeStarted, timeBaseStart) { const timeAlreadyElapsed = currentTime - timeStarted return timeBaseStart - timeAlreadyElapsed } function decreaseTimerByOne (timer) { return Math.max(timer - 1000, 0) } function timeBelowWarningTime (timer, warningTime) { const [warningTimeMinutes, warningTimeSeconds] = warningTime.split(':') return timer <= ((Number(warningTimeMinutes) * 60) + Number(warningTimeSeconds)) * 1000 } export default function CountdownTimer ({ timeStarted, timeOnly, timerBase = TIMER_BASE, warningTime, labelKey, infoTooltipLabelKey, }) { const t = useContext(I18nContext) const intervalRef = useRef() const initialTimeStartedRef = useRef() const [currentTime, setCurrentTime] = useState(() => Date.now()) const [timer, setTimer] = useState(() => getNewTimer(currentTime, timeStarted, timerBase)) useEffect(() => { if (intervalRef.current === undefined) { intervalRef.current = setInterval(() => { setTimer(decreaseTimerByOne) }, 1000) } return function cleanup () { clearInterval(intervalRef.current) } }, []) // Reset the timer that timer has hit '0:00' and the timeStarted prop has changed useEffect(() => { if (!initialTimeStartedRef.current) { initialTimeStartedRef.current = timeStarted || Date.now() } if (timer === 0 && timeStarted !== initialTimeStartedRef.current) { initialTimeStartedRef.current = timeStarted const newCurrentTime = Date.now() setCurrentTime(newCurrentTime) setTimer(getNewTimer(newCurrentTime, timeStarted, timerBase)) clearInterval(intervalRef.current) intervalRef.current = setInterval(() => { setTimer(decreaseTimerByOne) }, 1000) } }, [timeStarted, timer, timerBase]) const formattedTimer = Duration.fromMillis(timer).toFormat('m:ss') let time if (timeOnly) { time =
{formattedTimer}
} else if (labelKey) { time = t(labelKey, [
{formattedTimer}
]) } return (
{time}
{ !timeOnly && infoTooltipLabelKey ? ( ) : null }
) } CountdownTimer.propTypes = { timeStarted: PropTypes.number, timeOnly: PropTypes.bool, timerBase: PropTypes.number, warningTime: PropTypes.string, labelKey: PropTypes.string, infoTooltipLabelKey: PropTypes.string, }