Skip to content

Commit 5c9c19a

Browse files
author
Dmitry Yadrikhinsky
committed
[TaskList, Timer] Render custom title, Timer functionality
1 parent b6789f5 commit 5c9c19a

File tree

12 files changed

+112
-13
lines changed

12 files changed

+112
-13
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@
249249
"yarn-deduplicate": "^3.1.0"
250250
},
251251
"dependencies": {
252+
"@ant-design/icons": "4.6.2",
252253
"antd": "4.15.0",
253254
"electron-debug": "^3.1.0",
254255
"electron-log": "^4.2.4",

src/base/repositories/AbstractFileRepository.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
const fs = require('fs');
22

3-
type RecordUnknown = unknown | unknown[];
4-
5-
export default abstract class AbstractFileRepository<
6-
T extends RecordUnknown = RecordUnknown
7-
> {
3+
export default abstract class AbstractFileRepository<T = any> {
84
folder: string = 'profile1';
95
fileName: string = 'defaultFileName.json';
106

src/models/TaskModel.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import AbstractModel from '../base/AbstractModel';
22
import { ITreeItem } from '../types/ITreeItem';
3+
import { computed, makeObservable, observable } from 'mobx';
34

45
interface ITaskModel extends ITreeItem<ITaskModel> {
56
projectId: string;
67
checked: boolean;
8+
time: number[][];
9+
active: boolean;
710
}
811

912
export default class TaskModel extends AbstractModel implements ITaskModel {
@@ -12,9 +15,31 @@ export default class TaskModel extends AbstractModel implements ITaskModel {
1215
children: TaskModel[] = [];
1316
projectId: string = '';
1417
checked: boolean = false;
18+
active: boolean = false;
19+
time: number[][] = [];
1520

1621
constructor(props: ITaskModel) {
1722
super();
1823
this.load(props);
24+
makeObservable(this, {
25+
key: observable,
26+
title: observable,
27+
children: observable,
28+
projectId: observable,
29+
checked: observable,
30+
active: observable,
31+
time: observable,
32+
duration: computed,
33+
});
34+
}
35+
36+
get duration() {
37+
return this.time.reduce((prev: number, range: number[]) => {
38+
if (range.length > 0) {
39+
const duration = (range[1] ? range[1] : Date.now()) - range[0];
40+
return prev + duration;
41+
}
42+
return 0;
43+
}, 0);
1944
}
2045
}

src/screens/projects/Projects.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import React, { useState } from 'react';
22
import { Button, Layout, Space } from 'antd';
33
import { observer } from 'mobx-react';
4-
import { useHistory } from 'react-router-dom';
4+
import { Key } from 'rc-tree/lib/interface';
5+
6+
import './Projects.less';
57

68
import TaskInput from './components/TaskInput';
79
import rootStore from '../../services/RootStore';
810
import TreeList from './components/TreeList';
911
import TaskModel from '../../models/TaskModel';
1012
import ProjectModel from '../../models/ProjectModel';
1113
import ProjectModal from './components/ProjectModal';
12-
import { Key } from 'rc-tree/lib/interface';
13-
import './Projects.less';
14+
import TaskNode from './components/TaskNode/TaskNode';
1415

1516
const { Sider } = Layout;
1617

@@ -29,6 +30,9 @@ const TaskList = TreeList(
2930
getCheckedKeys() {
3031
return tasksStore.getCheckedKeys(projectStore.activeProject);
3132
},
33+
titleRender(node: TaskModel) {
34+
return <TaskNode model={node} />;
35+
},
3236
}
3337
);
3438

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.task-node {
2+
display: flex;
3+
}
4+
5+
.task-title {
6+
flex: 1;
7+
}
8+
9+
.task-node__actions {
10+
display: none;
11+
}
12+
13+
.task-node:hover .task-node__actions {
14+
display: inline;
15+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import React from 'react';
2+
import { CaretRightFilled, DeleteOutlined } from '@ant-design/icons';
3+
import TaskModel from '../../../../models/TaskModel';
4+
import './TaskNode.less';
5+
6+
interface TaskNodeProps {
7+
model: TaskModel;
8+
}
9+
10+
export default function TaskNode({ model }: TaskNodeProps) {
11+
return (
12+
<div className="task-node">
13+
<span className="task-title">{model.title}</span>
14+
<span className="task-node__actions">
15+
<CaretRightFilled />
16+
<DeleteOutlined />
17+
</span>
18+
</div>
19+
);
20+
}

src/screens/projects/components/TreeList.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ export default function TreeList<T extends ITreeItem>(
1515
updateData: (items: T[]) => void,
1616
options?: {
1717
checkable?: boolean;
18+
selectable?: boolean;
1819
onCheck?: (checkedKeys: React.Key[]) => void;
1920
getCheckedKeys?: () => React.Key[];
21+
titleRender?: (nodeData: T) => React.ReactNode;
2022
}
2123
) {
2224
return observer(function TreeList({ onSelect }: TreeListProps) {
@@ -95,11 +97,13 @@ export default function TreeList<T extends ITreeItem>(
9597
checkedKeys={options?.getCheckedKeys?.()}
9698
checkable={options?.checkable}
9799
draggable
100+
selectable={options?.selectable}
98101
blockNode
99102
onDrop={onDrop}
100103
treeData={data}
101104
onSelect={onSelect}
102105
onCheck={options?.checkable ? options?.onCheck : undefined}
106+
titleRender={options?.titleRender}
103107
/>
104108
);
105109
});

src/services/tasks/TaskFactory.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
11
import AbstractFactory from '../../base/AbstractFactory';
2+
import TaskRecordModel from '../../models/TaskRecordModel';
3+
import TaskModel from '../../models/TaskModel';
24

3-
export default class TaskFactory extends AbstractFactory {}
5+
export default class TaskFactory extends AbstractFactory {
6+
createTasks(data: TaskRecordModel): TaskRecordModel {
7+
const newData: TaskRecordModel = {};
8+
Object.keys(data).forEach((projectId) => {
9+
newData[projectId] = this.createList(TaskModel, data[projectId]);
10+
});
11+
return newData;
12+
}
13+
}
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import AbstractFileRepository from '../../base/repositories/AbstractFileRepository';
2+
import TaskRecordModel from '../../models/TaskRecordModel';
23

3-
export default class TaskRepository extends AbstractFileRepository {
4+
export default class TaskRepository extends AbstractFileRepository<
5+
TaskRecordModel
6+
> {
47
fileName = 'tasks.json';
58
}

src/services/tasks/TaskService.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ export default class TaskService implements IService<TaskRecordModel> {
88
taskFactory: TaskFactory = new TaskFactory();
99

1010
getAll(): TaskRecordModel {
11-
const tasks = this.taskRepository.restore({});
12-
return tasks as TaskRecordModel;
11+
const data: TaskRecordModel = this.taskRepository.restore({});
12+
return this.taskFactory.createTasks(data);
1313
}
1414

1515
save(data: TaskRecordModel) {

0 commit comments

Comments
 (0)