<div id="app"></div>
.container {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
.wrapper {
height: 80%;
width: 80%;
display: flex;
flex-flow: column wrap;
justify-content: center;
align-items: center;
border: 1px solid transparent;
border-radius: 15px;
background-color: #FFD5D4;
}
.wrapper > * {
margin-bottom: 1rem;
}
.timer {
display: flex;
flex-direction: column;
align-items: center;
}
.clock {
margin-bottom: 1rem;
}
.clock > input {
padding: 1rem;
margin: 0 5px;
width: 3rem;
text-align: center;
}
.time {
text-align: center;
}
.buttons {
display: flex;
flex-flow: row wrap;
justify-content: space-around;
align-items: center;
width: 70%;
}
button {
background-color: white;
padding: 16px 24px;
cursor: pointer;
border-radius: 5px;
border: 1px solid transparent;
font-weight: 600;
color: #FAF9F6;
}
button:hover {
opacity: 0.9;
}
.green {
background-color: #77DD76;
}
.blue {
background-color: #A7C7E7;
}
.red {
background-color: #FF6962;
}
/*
* https://frontendeval.com/questions/countdown-timer
*
* Create a countdown timer that notifies the user
*/
const Button = ({ color, text, onClick }) => {
return <button class={ color } onClick={ (e) => onClick(e, text) }>{ text }</button>
}
const App = () => {
const [hours, setHours] = React.useState(null);
const [minutes, setMinutes] = React.useState(null);
const [seconds, setSeconds] = React.useState(null);
const [totalTime, setTotalTime] = React.useState(0);
const [counting, setCounting] = React.useState(false);
let timerId;
React.useEffect(() => {
if (totalTime == 0 && counting) {
resetTimer();
alertUser();
}
}, [totalTime])
startTimer = () => {
if (!hours && !minutes && !seconds) {
alertUser();
return;
}
setCounting(true);
setTotalTime(calculateTime());
this.interval = setInterval(() => {
decrementByOneSecond();
}, 1000)
}
pauseTimer = () => {
clearInterval(this.interval);
setCounting(false);
}
resetTimer = () => {
clearInterval(this.interval);
setHours('');
setMinutes('');
setSeconds('');
setCounting(false);
setTotalTime(0);
}
decrementByOneSecond = () => {
const newTime = totalTime - 1;
const newHours = Math.floor(newTime / 3600);
const newMinutes = Math.floor((newTime - (newHours * 3600)) / 60);
const newSeconds = newTime - (newHours * 3600) - (newMinutes * 60);
setHours((''+newHours).padStart(2, '0'));
setMinutes((''+newMinutes).padStart(2, '0'));
setSeconds((''+newSeconds).padStart(2, '0'));
setTotalTime(time => newTime)
}
alertUser = () => {
alert('Timer finished');
}
calculateTime = () => {
const time = (+hours) * 60 * 60 + (+minutes) * 60 + (+seconds)
return time;
}
return (
<div class='container'>
<div class='wrapper'>
<div class='timer'>
<h1>Countdown Timer</h1>
<div class='clock'>
<input
type='number'
class='timer__hours'
placeholder='HH'
maxLength={2}
onChange={(e) => setHours(e.target.value)}
value={ hours }
aria-label="Hours"
></input>
<span>:</span>
<input
type='number'
class='timer__minutes'
placeholder='MM'
maxLength={2}
onChange={(e) => setMinutes(e.target.value)}
value={ minutes }
aria-label="Minutes"
></input>
<span>:</span>
<input
type='number'
class='timer__seconds'
placeholder='SS'
maxLength={2}
onChange={(e) => setSeconds(e.target.value)}
value={ seconds }
aria-label="Seconds"
></input>
</div>
<div class='buttons'>
{ !counting && <Button color='green' text='Start' onClick={ startTimer }/> }
{ counting && (
<>
<Button color='blue' text='Pause' onClick={ pauseTimer }/>
<Button color='red' text='Reset' onClick={ resetTimer }/>
</>
)}
</div>
</div>
<div class='time'><b>{totalTime}</b> seconds left</div>
</div>
</div>
)
}
ReactDOM.render(<App />, document.getElementById('app'));
View Compiled
This Pen doesn't use any external CSS resources.