index.js (3076B)
1 /** 2 * WordPress dependencies 3 */ 4 import {__} from '@wordpress/i18n' 5 import './style.scss' 6 import config from '../config'; 7 import helper from '../helper'; 8 import classnames from 'classnames'; 9 const {compose} = wp.compose; 10 const {withSelect, withDispatch} = wp.data; 11 const {useState, useEffect, useRef} = wp.element; 12 13 function useInterval(callback, delay) { 14 const savedCallback = useRef(); 15 16 // Remember the latest callback. 17 useEffect(() => { 18 savedCallback.current = callback; 19 }, [callback]); 20 21 // Set up the interval. 22 useEffect(() => { 23 function tick() { 24 savedCallback.current(); 25 } 26 if (delay !== null) { 27 let id = setInterval(tick, delay); 28 return () => clearInterval(id); 29 } 30 }, [delay]); 31 } 32 33 function ChallengeTimer(props) { 34 const {started, expanded, setChallengeListExpanded, isChallengeOpen, finalStatus} = props; 35 const [secondsLeft, setSecondsLeft] = useState(helper.getSecondsLeft()); 36 const [paused, setPaused] = useState(false); 37 38 // only timer 39 useEffect(() => { 40 window.addEventListener('focus', resume); 41 window.addEventListener('blur', pause); 42 return () => { 43 window.removeEventListener('focus', resume); 44 window.removeEventListener('blur', pause); 45 }; 46 }); 47 48 // setup timer 49 useEffect(() => { 50 setSecondsLeft(helper.getSecondsLeft()); 51 if (helper.loadStep() === -1) { 52 setSecondsLeft(config.initialSecondsLeft); 53 } 54 }, [isChallengeOpen]); 55 56 // run timer 57 useInterval(() => { 58 setSecondsLeft(secondsLeft < 0 ? 0 : secondsLeft - 1); 59 helper.saveSecondsLeft(secondsLeft < 0 ? 0 : secondsLeft - 1); 60 }, (started && (paused === false) && secondsLeft >= 0 && finalStatus === '') ? 1000 : null); 61 62 63 // Pause the timer. 64 const pause = () => { 65 setPaused(true); 66 } 67 68 // Resume the timer. 69 const resume = () => { 70 setPaused(false); 71 } 72 73 return ( 74 <div className='block-timer'> 75 <div> 76 <h3>{__('Redux Challenge', redux_templates.i18n)}</h3> 77 <p><span>{helper.getFormatted(secondsLeft)}</span>{__(' remaining', redux_templates.i18n)}</p> 78 </div> 79 <div className={classnames('caret-icon', {'closed': expanded})} onClick={() => setChallengeListExpanded(!expanded)}> 80 <i className="fa fa-caret-down"></i> 81 </div> 82 </div> 83 ); 84 85 } 86 87 88 export default compose([ 89 withDispatch((dispatch) => { 90 const {setChallengeListExpanded} = dispatch('redux-templates/sectionslist'); 91 return { 92 setChallengeListExpanded 93 }; 94 }), 95 withSelect((select) => { 96 const {getChallengeOpen, getChallengeFinalStatus, getChallengeListExpanded} = select('redux-templates/sectionslist'); 97 return { 98 isChallengeOpen: getChallengeOpen(), 99 finalStatus: getChallengeFinalStatus(), 100 expanded: getChallengeListExpanded() 101 }; 102 }) 103 ])(ChallengeTimer);