import { useEffect, useState } from 'react'; export interface ICountDown { m: number; s: number; } /** * * @param minutes how many minutes. * @param autoplay by default true. if you want play coundDown after an action, you can set it to false and manually play it. * @param onEnd you can pass a callback function that will trigger at the END. * @returns */ export function useCountDown(minutes: number, autoplay = true, onEnd = () => {}) { const [countDown, setCountDown] = useState({m: minutes, s: 0}); const [stop, setStop] = useState(!autoplay); useEffect(() => { const handler = setTimeout(() => { if (countDown.m !== 0 || countDown.s !== 0) { setCountDown(calculateCountDown(countDown)); } else { onEnd(); } }, 1000); return () => { clearTimeout(handler); }; }, [countDown]); const reset = () => { setCountDown({m: minutes, s: 0}); }; const pause = () => { setStop(true); }; const play = () => { setStop(false); setCountDown({...countDown}); }; const calculateCountDown = (st: ICountDown): ICountDown => { if (stop) { return countDown; } const timeLeft = { m: 0, s: 0 }; const remain = st.m * 60 + st.s - 1; if (remain > 0) { timeLeft.m = Math.floor((remain) / 60); timeLeft.s = remain - timeLeft.m * 60; return timeLeft; } else { if (remain === 0 && countDown.s === 1) { return timeLeft; } else { return countDown; } } }; return { value: `${countDown.m > 9 ? countDown.m : '0' + countDown.m}:${countDown.s > 9 ? countDown.s : '0' + countDown.s}`, reset, pause, play }; }