1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
import React, { useState, useEffect } from 'react';
import convertTimeToString from '../utils/convertTimeToString';
interface PropTypes {
registerResult: (result: string) => void;
maxCountdown?: number;
}
enum Mode {
'idle',
'countdown',
'running' ,
'over',
};
const helperTextMap = {
[Mode.idle]: (
<>
<span>Hold </span>
<code>SPACE</code>
<span> to start countdown</span>
</>
),
[Mode.countdown]: (
<>
<span>Release </span>
<code>SPACE</code>
<span> to begin</span>
</>
),
[Mode.running]: 'Go fast!',
[Mode.over]: 'You are too late!',
};
const KEY_CODE = 32; // Space key
const Timer: React.FC<PropTypes> = ({ registerResult, maxCountdown = 15000 }) => {
const [mode, setMode] = useState<Mode>(Mode.idle);
const [displayTime, setDisplayTime] = useState<string>('00:00:00');
useEffect(() => {
const timestamp = Date.now();
if (mode === Mode.countdown) {
const repeater = setInterval(() => {
const timeDelta = maxCountdown - (Date.now() - timestamp);
if (timeDelta <= 0) setMode(Mode.over);
setDisplayTime(convertTimeToString(timeDelta));
}, 10);
return (): void => clearInterval(repeater);
}
if (mode === Mode.running) {
const repeater = setInterval(() => {
setDisplayTime(convertTimeToString(Date.now() - timestamp));
}, 10);
return (): void => clearInterval(repeater);
}
if (mode === Mode.over) {
setDisplayTime('00:00:00');
}
}, [mode, maxCountdown]);
const handleKeyPress = (event: KeyboardEvent): void => {
if (event.keyCode === KEY_CODE && mode === Mode.idle) {
event.preventDefault();
setMode(Mode.countdown);
}
};
const handleKeyUp = (event: KeyboardEvent): void => {
if (event.keyCode === KEY_CODE) {
if (mode === Mode.running) {
registerResult(displayTime);
setMode(Mode.idle);
} else if (mode === Mode.over) {
setMode(Mode.idle);
} else {
setMode(Mode.running);
}
}
};
useEffect(() => {
window.addEventListener('keyup', handleKeyUp);
window.addEventListener('keypress', handleKeyPress);
return () => {
window.removeEventListener('keyup', handleKeyUp);
window.removeEventListener('keypress', handleKeyPress);
};
});
return (
<>
<b>{ displayTime }</b>
<p>{ helperTextMap[mode] }</p>
</>
);
};
export default Timer;
|