Skip to content
This repository was archived by the owner on Dec 26, 2022. It is now read-only.

Commit 58490fd

Browse files
committed
Dashboard
1 parent 7d55268 commit 58490fd

File tree

8 files changed

+151
-13
lines changed

8 files changed

+151
-13
lines changed
File renamed without changes.
Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,21 @@ import isSameDay from 'date-fns/isSameDay';
33
import TaskModel from '../models/TaskModel';
44
import TaskTimeItemModel from '../models/TaskTimeItemModel';
55
import compareAsc from 'date-fns/compareAsc';
6+
import TaskWithDurationModel from '../models/TaskWithDurationModel';
67

7-
export default function getTimeItems(
8+
/**
9+
* Returns TaskTimeItemModel contains time range
10+
* return {
11+
* task,
12+
* time: {
13+
* start: Date,
14+
* end: Date,
15+
* description
16+
* },
17+
* index,
18+
* }
19+
*/
20+
export function getTimeItems(
821
tasks: TaskModel[],
922
date: Date
1023
): TaskTimeItemModel[] {
@@ -25,3 +38,17 @@ export default function getTimeItems(
2538
taskTime = taskTime.sort((a, b) => compareAsc(a.time.start, b.time.start));
2639
return taskTime;
2740
}
41+
42+
/**
43+
* Return tasks with total time for selected day
44+
* @param tasks
45+
* @param date
46+
*/
47+
export function getTasksWithTotalTimeForDay(
48+
tasks: TaskModel[],
49+
date: Date
50+
): TaskWithDurationModel[] {
51+
return tasks.map(
52+
(task) => new TaskWithDurationModel(task, task.getDurationByDate(date))
53+
);
54+
}

src/models/TaskModel.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import isSameDay from 'date-fns/isSameDay';
33

44
import AbstractModel from '../base/AbstractModel';
55
import { ITreeItem } from '../types/ITreeItem';
6+
import { startOfDay } from 'date-fns';
67

78
export interface IJsonTimeRangeModel {
89
start: string;
@@ -11,7 +12,7 @@ export interface IJsonTimeRangeModel {
1112
}
1213

1314
export interface ITimeRangeModel {
14-
start?: Date;
15+
start: Date;
1516
end?: Date;
1617
description?: string;
1718
}
@@ -36,7 +37,6 @@ export default class TaskModel extends AbstractModel {
3637
time: ITimeRangeModel[] = [];
3738
datesInProgress: Date[] = [];
3839
details: string = '';
39-
deleted: boolean = false;
4040

4141
constructor(props: IJsonTaskModel) {
4242
super();
@@ -82,10 +82,21 @@ export default class TaskModel extends AbstractModel {
8282
}
8383

8484
get duration() {
85-
return this.time.reduce((prev: number, range: ITimeRangeModel) => {
85+
return this.time.reduce((acc: number, range: ITimeRangeModel) => {
8686
const { start, end } = range;
8787
const duration = (end ? end.getTime() : Date.now()) - start.getTime();
88-
return prev + duration;
88+
return acc + duration;
89+
}, 0);
90+
}
91+
92+
getDurationByDate(date: Date) {
93+
return this.time.reduce((acc: number, range: ITimeRangeModel) => {
94+
const { start, end } = range;
95+
let duration = 0;
96+
if (isSameDay(start, date)) {
97+
duration = (end ? end.getTime() : Date.now()) - start.getTime();
98+
}
99+
return acc + duration;
89100
}, 0);
90101
}
91102

@@ -101,10 +112,6 @@ export default class TaskModel extends AbstractModel {
101112
this.checked = checked;
102113
}
103114

104-
setDeleted() {
105-
this.deleted = true;
106-
}
107-
108115
start() {
109116
this.active = true;
110117
this.addDateWhenWasInProgress(new Date());
@@ -128,9 +135,10 @@ export default class TaskModel extends AbstractModel {
128135
}
129136

130137
private addDateWhenWasInProgress(date: Date) {
131-
const found = this.datesInProgress.find((d) => isSameDay(d, date));
138+
const normalDate = startOfDay(date);
139+
const found = this.datesInProgress.find((d) => isSameDay(d, normalDate));
132140
if (!found) {
133-
this.datesInProgress.push(date);
141+
this.datesInProgress.push(normalDate);
134142
}
135143
}
136144
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import TaskModel from './TaskModel';
2+
3+
export default class TaskWithDurationModel {
4+
constructor(
5+
public task: TaskModel,
6+
public duration: number // milliseconds
7+
) {}
8+
}

src/screens/Main.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Projects from './projects/Projects';
77
import TaskControl from '../components/TaskControl/TaskControl';
88
import HeaderMenu from '../components/HeaderMenu/HeaderMenu';
99
import HoursView from './hours/HoursView';
10+
import Dashboard from './dashboard/Dashboard';
1011

1112
const { Header } = Layout;
1213

@@ -20,6 +21,9 @@ export default observer(function Main() {
2021
<HeaderMenu>
2122
<Link to="/projects">Projects</Link>
2223
</HeaderMenu>
24+
<HeaderMenu>
25+
<Link to="/dashboard">Dashboard</Link>
26+
</HeaderMenu>
2327
<span className="flex-1" />
2428
<TaskControl />
2529
</Header>
@@ -33,6 +37,9 @@ export default observer(function Main() {
3337
<Route path="/projects">
3438
<Projects />
3539
</Route>
40+
<Route path="/dashboard">
41+
<Dashboard />
42+
</Route>
3643
</Switch>
3744
</Layout>
3845
);
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import React, { useMemo, useState } from 'react';
2+
import { createUseStyles } from 'react-jss';
3+
import { Layout, Space } from 'antd';
4+
import { observer } from 'mobx-react';
5+
6+
import SelectDate from '../../components/SelectDate/SelectDate';
7+
import rootStore from '../../services/RootStore';
8+
import { getTasksWithTotalTimeForDay } from '../../helpers/TaskHelper';
9+
import HoursWithDuration from './components/HoursWithDuration';
10+
11+
const { tasksStore } = rootStore;
12+
13+
const Dashboard: React.FC = observer(() => {
14+
const classes = useStyles();
15+
16+
const [date, setDate] = useState<Date>(new Date());
17+
const tasks = useMemo(() => tasksStore.getTasksByDate(date), [date]);
18+
const tasksWithDuration = useMemo(
19+
() => getTasksWithTotalTimeForDay(tasks, date),
20+
[tasks, date]
21+
);
22+
23+
return (
24+
<Layout className={classes.root}>
25+
<Space direction="vertical">
26+
<div className={classes.selectDate}>
27+
<SelectDate date={date} onChange={setDate} />
28+
</div>
29+
{tasksWithDuration.map((tasksWithDuration) => (
30+
<HoursWithDuration
31+
key={tasksWithDuration.task.key}
32+
taskWithDuration={tasksWithDuration}
33+
/>
34+
))}
35+
</Space>
36+
</Layout>
37+
);
38+
});
39+
40+
const useStyles = createUseStyles({
41+
root: {
42+
display: 'flex',
43+
flexDirection: 'row',
44+
justifyContent: 'center',
45+
overflowY: 'auto',
46+
padding: 12,
47+
},
48+
selectDate: {
49+
display: 'flex',
50+
justifyContent: 'center',
51+
},
52+
});
53+
54+
export default Dashboard;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React from 'react';
2+
import { Card } from 'antd';
3+
import { createUseStyles } from 'react-jss';
4+
5+
import TaskWithDurationModel from '../../../models/TaskWithDurationModel';
6+
import { msToTime } from '../../../helpers/DateTime';
7+
8+
interface IHoursWithDurationProps {
9+
taskWithDuration: TaskWithDurationModel;
10+
}
11+
12+
const HoursWithDuration: React.FC<IHoursWithDurationProps> = ({
13+
taskWithDuration,
14+
}: IHoursWithDurationProps) => {
15+
const classes = useStyles();
16+
17+
return (
18+
<Card className={classes.root}>
19+
<div>{taskWithDuration.task.title}</div>
20+
<div>{msToTime(taskWithDuration.duration)}</div>
21+
</Card>
22+
);
23+
};
24+
25+
const useStyles = createUseStyles({
26+
root: {
27+
width: 300,
28+
'& .ant-card-body': {
29+
padding: 8,
30+
},
31+
},
32+
});
33+
34+
export default HoursWithDuration;

src/screens/hours/HoursView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { observer } from 'mobx-react';
44

55
import rootStore from '../../services/RootStore';
66
import HoursCard from './components/HoursCard/HoursCard';
7-
import getTimeItems from '../../services/TaskTimeItem';
8-
import SelectDate from './components/SelectDate/SelectDate';
7+
import { getTimeItems } from '../../helpers/TaskHelper';
8+
import SelectDate from '../../components/SelectDate/SelectDate';
99
import TimeRangeModal from '../../components/TimeRangeModal/TimeRangeModal';
1010
import TaskTimeItemModel from '../../models/TaskTimeItemModel';
1111
import { Undefined } from '../../types/CommonTypes';

0 commit comments

Comments
 (0)