Skip to content

Commit c97875a

Browse files
author
Dmitry Yadrikhinsky
committed
[Timer] Start/stop timers
1 parent fe31732 commit c97875a

File tree

4 files changed

+59
-5
lines changed

4 files changed

+59
-5
lines changed

src/helpers/DateTime.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
function timePad(time: number): string {
2+
return String(time).padStart(2, '0');
3+
}
4+
5+
export function msToTime(s: number) {
6+
const ms = s % 1000;
7+
s = (s - ms) / 1000;
8+
const secs = s % 60;
9+
s = (s - secs) / 60;
10+
const mins = s % 60;
11+
const hrs = (s - mins) / 60;
12+
13+
return `${timePad(hrs)}:${timePad(mins)}:${timePad(secs)}`;
14+
}

src/models/TaskModel.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ export default class TaskModel extends AbstractModel implements ITaskModel {
3636
get duration() {
3737
return this.time.reduce((prev: number, range: number[]) => {
3838
if (range.length > 0) {
39-
const duration = (range[1] ? range[1] : Date.now()) - range[0];
39+
const duration =
40+
(range.length === 2 ? range[1] : Date.now()) - range[0];
4041
return prev + duration;
4142
}
4243
return 0;

src/screens/projects/components/TaskNode/TaskNode.tsx

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,53 @@
1-
import React from 'react';
2-
import { CaretRightFilled, DeleteOutlined } from '@ant-design/icons';
3-
import TaskModel from '../../../../models/TaskModel';
1+
import React, { useEffect, useRef, useState } from 'react';
2+
import {
3+
CaretRightFilled,
4+
DeleteOutlined,
5+
PauseOutlined,
6+
} from '@ant-design/icons';
7+
48
import './TaskNode.less';
59

10+
import TaskModel from '../../../../models/TaskModel';
11+
import rootStore from '../../../../services/RootStore';
12+
import { msToTime } from '../../../../helpers/DateTime';
13+
14+
const { tasksStore } = rootStore;
15+
616
interface TaskNodeProps {
717
model: TaskModel;
818
}
919

1020
export default function TaskNode({ model }: TaskNodeProps) {
21+
const intervalRef = useRef<NodeJS.Timeout>();
22+
const [duration, setDuration] = useState<string>('');
23+
24+
useEffect(() => {
25+
const duration = model.duration;
26+
if (duration !== 0) {
27+
setDuration(msToTime(duration));
28+
}
29+
if (model.active) {
30+
intervalRef.current = setInterval(() => {
31+
setDuration(msToTime(model.duration));
32+
}, 1000);
33+
}
34+
return () => {
35+
if (intervalRef.current) {
36+
clearInterval(intervalRef.current);
37+
}
38+
};
39+
}, [model.active]);
40+
1141
return (
1242
<div className="task-node">
1343
<span className="task-title">{model.title}</span>
44+
<span>{duration}</span>
1445
<span className="task-node__actions">
15-
<CaretRightFilled />
46+
{!model.active ? (
47+
<CaretRightFilled onClick={() => tasksStore.startTimer(model)} />
48+
) : (
49+
<PauseOutlined onClick={() => tasksStore.endTimer(model)} />
50+
)}
1651
<DeleteOutlined />
1752
</span>
1853
</div>

src/services/tasks/TaskStore.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,16 @@ export default class TaskStore {
4444
}
4545
});
4646
task.time.push([Date.now()]);
47+
task.active = true;
48+
this.tasksService.save(this.tasks);
4749
}
4850

4951
endTimer(task: TaskModel) {
5052
this.activeTask = undefined;
5153
task.active = false;
5254
const range = task.time[task.time.length - 1];
5355
range.push(Date.now());
56+
this.tasksService.save(this.tasks);
5457
}
5558

5659
restore() {
@@ -70,6 +73,7 @@ export default class TaskStore {
7073
if (Array.isArray(this.tasks[projectId])) {
7174
this.checkTasksRecursive(this.tasks[projectId], taskIds);
7275
}
76+
this.tasksService.save(this.tasks);
7377
}
7478

7579
private getCheckedKeysRecursive(tasks: TaskModel[], checkedIds: string[]) {

0 commit comments

Comments
 (0)