Skip to content

Commit a9d1ce3

Browse files
authored
Merge pull request #22 from amrlabib/enhancement/distance
Enhancement/distance
2 parents e47dfc5 + 4b099c1 commit a9d1ce3

File tree

6 files changed

+125
-195
lines changed

6 files changed

+125
-195
lines changed

src/useStopwatch.js

Lines changed: 13 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,22 @@
11
import { useState, useEffect, useRef } from 'react';
2+
import { Time } from './utils';
23

34
export default function useStopwatch(settings) {
45
const { autoStart } = settings || {};
56

67
const [seconds, setSeconds] = useState(0);
7-
const [minutes, setMinutes] = useState(0);
8-
const [hours, setHours] = useState(0);
9-
const [days, setDays] = useState(0);
108
const intervalRef = useRef();
119

12-
function addDay() {
13-
setDays((prevDays) => (prevDays + 1));
14-
}
15-
16-
function addHour() {
17-
setHours((prevHours) => {
18-
if (prevHours === 23) {
19-
addDay();
20-
return 0;
21-
}
22-
return prevHours + 1;
23-
});
24-
}
25-
26-
function addMinute() {
27-
setMinutes((prevMinutes) => {
28-
if (prevMinutes === 59) {
29-
addHour();
30-
return 0;
31-
}
32-
return prevMinutes + 1;
33-
});
34-
}
35-
36-
function addSecond() {
37-
setSeconds((prevSeconds) => {
38-
if (prevSeconds === 59) {
39-
addMinute();
40-
return 0;
41-
}
42-
return prevSeconds + 1;
43-
});
10+
function clearIntervalRef() {
11+
if (intervalRef.current) {
12+
clearInterval(intervalRef.current);
13+
intervalRef.current = undefined;
14+
}
4415
}
4516

4617
function start() {
4718
if (!intervalRef.current) {
48-
intervalRef.current = setInterval(() => addSecond(), 1000);
19+
intervalRef.current = setInterval(() => setSeconds((prevSeconds) => (prevSeconds + 1)), 1000);
4920
}
5021
}
5122

@@ -57,25 +28,22 @@ export default function useStopwatch(settings) {
5728
}
5829

5930
function reset() {
60-
if (intervalRef.current) {
61-
clearInterval(intervalRef.current);
62-
intervalRef.current = undefined;
63-
}
31+
clearIntervalRef();
6432
setSeconds(0);
65-
setMinutes(0);
66-
setHours(0);
67-
setDays(0);
33+
if (autoStart) {
34+
start();
35+
}
6836
}
6937

7038
// didMount effect
7139
useEffect(() => {
7240
if (autoStart) {
7341
start();
7442
}
75-
return reset;
43+
return clearIntervalRef;
7644
}, []);
7745

7846
return {
79-
seconds, minutes, hours, days, start, pause, reset,
47+
...Time.getTimeFromSeconds(seconds), start, pause, reset,
8048
};
8149
}

src/useTime.js

Lines changed: 9 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,33 @@
11
import { useState, useEffect, useRef } from 'react';
2+
import { Time } from './utils';
23

34
export default function useTime(settings) {
45
const { format } = settings || {};
56

6-
const [seconds, setSeconds] = useState(0);
7-
const [minutes, setMinutes] = useState(0);
8-
const [hours, setHours] = useState(0);
9-
const [ampm, setAmPm] = useState('');
7+
const [seconds, setSeconds] = useState(Time.getSecondsFromTimeNow());
108
const intervalRef = useRef();
119

12-
function formatHours(hoursValue) {
13-
if (format === '12-hour') {
14-
const ampmValue = hoursValue >= 12 ? 'pm' : 'am';
15-
let formattedHours = hoursValue % 12;
16-
formattedHours = formattedHours || 12;
17-
return { hoursValue: formattedHours, ampmValue };
10+
function clearIntervalRef() {
11+
if (intervalRef.current) {
12+
clearInterval(intervalRef.current);
13+
intervalRef.current = undefined;
1814
}
19-
return { hoursValue, ampmValue: '' };
2015
}
2116

22-
function setCurrentTime() {
23-
const now = new Date();
24-
const secondsValue = now.getSeconds();
25-
const minutesValue = now.getMinutes();
26-
const { hoursValue, ampmValue } = formatHours(now.getHours());
27-
28-
setSeconds(secondsValue);
29-
setMinutes(minutesValue);
30-
setHours(hoursValue);
31-
setAmPm(ampmValue);
32-
}
33-
34-
3517
function start() {
3618
if (!intervalRef.current) {
37-
setCurrentTime();
38-
intervalRef.current = setInterval(() => setCurrentTime(), 1000);
39-
}
40-
}
41-
42-
function reset() {
43-
if (intervalRef.current) {
44-
clearInterval(intervalRef.current);
45-
intervalRef.current = undefined;
19+
intervalRef.current = setInterval(() => setSeconds(Time.getSecondsFromTimeNow()), 1000);
4620
}
47-
setSeconds(0);
48-
setMinutes(0);
49-
setHours(0);
50-
setAmPm('');
5121
}
5222

5323
// didMount effect
5424
useEffect(() => {
5525
start();
56-
return reset;
26+
return clearIntervalRef;
5727
}, []);
5828

5929

6030
return {
61-
seconds, minutes, hours, ampm,
31+
...Time.getFormattedTimeFromSeconds(seconds, format),
6232
};
6333
}

src/useTimer.js

Lines changed: 30 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,148 +1,67 @@
11
import { useState, useEffect, useRef } from 'react';
2-
3-
4-
function isValidExpiryTimestamp(expiryTimestamp) {
5-
const isValid = (new Date(expiryTimestamp)).getTime() > 0;
6-
if (!isValid) {
7-
console.warn('react-timer-hook: { useTimer } Invalid expiryTimestamp settings', expiryTimestamp);
8-
}
9-
return isValid;
10-
}
11-
12-
function isValidOnExpire(onExpire) {
13-
const isValid = onExpire && typeof onExpire === 'function';
14-
if (onExpire && !isValid) {
15-
console.warn('react-timer-hook: { useTimer } Invalid onExpire settings function', onExpire);
16-
}
17-
return isValid;
18-
}
2+
import { Time, Validate } from './utils';
193

204
export default function useTimer(settings) {
215
const { expiryTimestamp: expiry, onExpire } = settings || {};
226
const [expiryTimestamp, setExpiryTimestamp] = useState(expiry);
23-
24-
const [seconds, setSeconds] = useState(0);
25-
const [minutes, setMinutes] = useState(0);
26-
const [hours, setHours] = useState(0);
27-
const [days, setDays] = useState(0);
7+
const [seconds, setSeconds] = useState(Time.getSecondsFromExpiry(expiryTimestamp));
288
const intervalRef = useRef();
299

30-
function reset() {
10+
function clearIntervalRef() {
3111
if (intervalRef.current) {
3212
clearInterval(intervalRef.current);
3313
intervalRef.current = undefined;
3414
}
35-
setSeconds(0);
36-
setMinutes(0);
37-
setHours(0);
38-
setDays(0);
39-
}
40-
41-
function subtractDay() {
42-
setDays((prevDays) => {
43-
if (prevDays > 0) {
44-
return prevDays - 1;
45-
}
46-
reset();
47-
isValidOnExpire(onExpire) && onExpire();
48-
return 0;
49-
});
5015
}
5116

52-
function subtractHour() {
53-
setHours((prevHours) => {
54-
if (prevHours === 0) {
55-
subtractDay();
56-
return 23;
57-
}
58-
59-
if (prevHours > 0) {
60-
return prevHours - 1;
61-
}
62-
return 0;
63-
});
64-
}
65-
66-
function subtractMinute() {
67-
setMinutes((prevMinutes) => {
68-
if (prevMinutes === 0) {
69-
subtractHour();
70-
return 59;
71-
}
72-
73-
if (prevMinutes > 0) {
74-
return prevMinutes - 1;
75-
}
76-
return 0;
77-
});
78-
}
79-
80-
function subtractSecond() {
81-
setSeconds((prevSeconds) => {
82-
if (prevSeconds === 0) {
83-
subtractMinute();
84-
return 59;
85-
}
86-
87-
if (prevSeconds > 0) {
88-
return prevSeconds - 1;
89-
}
90-
return 0;
91-
});
92-
}
93-
94-
// Timer expiry date calculation
95-
function calculateExpiryDate() {
96-
const now = new Date().getTime();
97-
const distance = expiryTimestamp - now;
98-
const daysValue = Math.floor(distance / (1000 * 60 * 60 * 24));
99-
const hoursValue = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
100-
const minutesValue = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
101-
const secondsValue = Math.floor((distance % (1000 * 60)) / 1000);
102-
if (secondsValue < 0) {
103-
reset();
104-
isValidOnExpire(onExpire) && onExpire();
105-
} else {
106-
setSeconds(secondsValue);
107-
setMinutes(minutesValue);
108-
setHours(hoursValue);
109-
setDays(daysValue);
110-
}
17+
function handleExpire() {
18+
clearIntervalRef();
19+
Validate.onExpire(onExpire) && onExpire();
11120
}
11221

11322
function start() {
114-
if (isValidExpiryTimestamp(expiryTimestamp) && !intervalRef.current) {
115-
calculateExpiryDate();
116-
intervalRef.current = setInterval(() => calculateExpiryDate(), 1000);
23+
if (!intervalRef.current) {
24+
intervalRef.current = setInterval(() => {
25+
const secondsValue = Time.getSecondsFromExpiry(expiryTimestamp);
26+
if (secondsValue <= 0) {
27+
handleExpire();
28+
}
29+
setSeconds(secondsValue);
30+
}, 1000);
11731
}
11832
}
11933

12034
function pause() {
121-
if (intervalRef.current) {
122-
clearInterval(intervalRef.current);
123-
intervalRef.current = undefined;
124-
}
35+
clearIntervalRef();
12536
}
12637

12738
function resume() {
128-
if (isValidExpiryTimestamp(expiryTimestamp) && !intervalRef.current) {
129-
intervalRef.current = setInterval(() => subtractSecond(), 1000);
39+
if (!intervalRef.current) {
40+
intervalRef.current = setInterval(() => setSeconds((prevSeconds) => {
41+
const secondsValue = prevSeconds - 1;
42+
if (secondsValue <= 0) {
43+
handleExpire();
44+
}
45+
return secondsValue;
46+
}), 1000);
13047
}
13148
}
13249

13350
function restart(newExpiryTimestamp) {
134-
reset();
51+
clearIntervalRef();
13552
setExpiryTimestamp(newExpiryTimestamp);
13653
}
13754

138-
// didMount effect
13955
useEffect(() => {
140-
start();
141-
return reset;
56+
if (Validate.expiryTimestamp(expiryTimestamp)) {
57+
setSeconds(Time.getSecondsFromExpiry(expiryTimestamp));
58+
start();
59+
}
60+
return clearIntervalRef;
14261
}, [expiryTimestamp]);
14362

14463

14564
return {
146-
seconds, minutes, hours, days, start, pause, resume, restart,
65+
...Time.getTimeFromSeconds(seconds), start, pause, resume, restart,
14766
};
14867
}

src/utils/Time.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
export default class Time {
2+
static getTimeFromSeconds(totalSeconds) {
3+
const days = Math.floor(totalSeconds / (60 * 60 * 24));
4+
const hours = Math.floor((totalSeconds % (60 * 60 * 24)) / (60 * 60));
5+
const minutes = Math.floor((totalSeconds % (60 * 60)) / 60);
6+
const seconds = Math.floor(totalSeconds % 60);
7+
8+
return {
9+
seconds,
10+
minutes,
11+
hours,
12+
days,
13+
};
14+
}
15+
16+
static getSecondsFromExpiry(expiry) {
17+
const now = new Date().getTime();
18+
const milliSecondsDistance = expiry - now;
19+
if (milliSecondsDistance > 0) {
20+
return Math.floor(milliSecondsDistance / 1000);
21+
}
22+
return 0;
23+
}
24+
25+
static getSecondsFromTimeNow() {
26+
const now = new Date();
27+
const currentTimestamp = now.getTime();
28+
const offset = (now.getTimezoneOffset() * 60);
29+
return (currentTimestamp / 1000) - offset;
30+
}
31+
32+
static getFormattedTimeFromSeconds(totalSeconds, format) {
33+
const { seconds: secondsValue, minutes, hours } = Time.getTimeFromSeconds(totalSeconds);
34+
let ampm = '';
35+
let hoursValue = hours;
36+
37+
if (format === '12-hour') {
38+
ampm = hours >= 12 ? 'pm' : 'am';
39+
hoursValue = hours % 12;
40+
}
41+
42+
return {
43+
seconds: secondsValue,
44+
minutes,
45+
hours: hoursValue,
46+
ampm,
47+
};
48+
}
49+
}

0 commit comments

Comments
 (0)