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

Commit 01d2a37

Browse files
authored
Merge pull request #4 from Yadro/features-v1.0.2v2
Features v1.0.2
2 parents 55cc7db + 9983ae8 commit 01d2a37

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1076
-353
lines changed

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
SENTRY_DSN='https://XXXX.ingest.sentry.io/00000000'
2+
GA_UACODE=UA-XXXXXXXXXX
3+
# DEBUG=universal-analytics
4+
# NODE_DEBUG=request # debug requests in analytics

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@
200200
"@ant-design/colors": "6.0.0",
201201
"@ant-design/icons": "4.6.2",
202202
"@sentry/electron": "2.5.0",
203-
"antd": "4.15.0",
203+
"antd": "4.16.7",
204204
"caniuse-lite": "1.0.30001214",
205205
"clsx": "^1.1.1",
206206
"date-fns": "2.20.1",
@@ -221,7 +221,8 @@
221221
"react-jss": "^10.6.0",
222222
"react-router-dom": "^5.2.0",
223223
"regenerator-runtime": "^0.13.5",
224-
"source-map-support": "^0.5.19"
224+
"source-map-support": "^0.5.19",
225+
"universal-analytics": "^0.4.23"
225226
},
226227
"devEngines": {
227228
"node": ">=10.x",

src/App.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
import React from 'react';
2-
import { BrowserRouter as Router } from 'react-router-dom';
3-
import { observer } from 'mobx-react';
2+
import { BrowserRouter } from 'react-router-dom';
43

54
import Main from './screens/Main';
65
import 'antd/dist/antd.less';
76
import './App.global.less';
87

9-
export default observer(() => {
8+
const App = () => {
9+
// useEffect(() => {
10+
// Sentry.captureException(new Error(`${process.env.NODE_ENV} exception`));
11+
// }, []);
12+
1013
return (
11-
<Router>
14+
<BrowserRouter>
1215
<Main />
13-
</Router>
16+
</BrowserRouter>
1417
);
15-
});
18+
};
19+
20+
export default App;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import AbstractFileRepository from './repositories/AbstractFileRepository';
2+
import IService from './IService';
3+
4+
export default abstract class AbstractServiceWithProfile<T>
5+
implements IService<T> {
6+
protected repository: AbstractFileRepository | undefined;
7+
8+
setProfile(profile: string) {
9+
this.repository?.setProfile(profile);
10+
}
11+
12+
abstract getAll(): T;
13+
14+
abstract save(data: T): void;
15+
}

src/base/TreeModelHelper.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { ITreeItem } from '../types/ITreeItem';
2+
3+
const TreeModelHelper = {
4+
modifyItemsWithIdsRecursive<T extends ITreeItem<any>>(
5+
treeItems: T[],
6+
ids: string[],
7+
fn: (treeItem: T, ids: string[]) => void
8+
) {
9+
treeItems.forEach((item) => {
10+
fn(item, ids);
11+
if (Array.isArray(item.children) && item.children.length) {
12+
TreeModelHelper.modifyItemsWithIdsRecursive(item.children, ids, fn);
13+
}
14+
});
15+
},
16+
17+
getItemRecursive<T extends ITreeItem<any>>(
18+
tasks: T[],
19+
condition: (task: T) => boolean
20+
): T | undefined {
21+
for (const task of tasks) {
22+
if (condition(task)) {
23+
return task;
24+
}
25+
if (Array.isArray(task.children)) {
26+
const found = this.getItemRecursive(task.children, condition);
27+
if (found) {
28+
return found;
29+
}
30+
}
31+
}
32+
return undefined;
33+
},
34+
35+
getFlatItemsRecursive<T extends ITreeItem<any>>(
36+
tree: T[],
37+
condition: (task: T) => boolean
38+
): T[] {
39+
const result: T[] = [];
40+
41+
this.getFlatItemsRecursiveBase(tree, condition, result);
42+
43+
return result;
44+
},
45+
46+
getFlatItemsRecursiveBase<T extends ITreeItem<any>>(
47+
treeItems: T[],
48+
condition: (item: T) => boolean,
49+
result: T[]
50+
): T[] {
51+
for (const item of treeItems) {
52+
if (condition(item)) {
53+
result.push(item);
54+
}
55+
if (Array.isArray(item.children)) {
56+
this.getFlatItemsRecursiveBase(item.children, condition, result);
57+
}
58+
}
59+
return result;
60+
},
61+
62+
deleteItems<T extends ITreeItem<any>>(
63+
treeItems: T[],
64+
condition: (task: T) => boolean
65+
): T[] {
66+
const result = treeItems.filter((t) => !condition(t));
67+
for (let i = 0; i < result.length; i++) {
68+
const task = treeItems[i];
69+
if (Array.isArray(task.children)) {
70+
treeItems[i].children = this.deleteItems(task.children, condition);
71+
}
72+
}
73+
return result;
74+
},
75+
};
76+
77+
export default TreeModelHelper;

src/base/TreeModelStoreHelper.ts

Lines changed: 0 additions & 62 deletions
This file was deleted.

src/base/repositories/AbstractFileRepository.ts

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,60 @@ const fs = require('fs');
22
const path = require('path');
33

44
import FsHelper from '../../helpers/FsHelper';
5+
import PromiseQueue from '../../helpers/PromiseQueueHellper';
56

6-
const APP_FOLDER = 'YadroTimeTracker';
7-
const PROFILE_FOLDER = 'profile1';
7+
const APP_DIR = 'YadroTimeTracker_test';
88

99
export default abstract class AbstractFileRepository<T = any> {
10-
folderWithProfile: string = 'profile1';
10+
dirWithProfileData: string = 'profile1';
1111
fileName: string = 'defaultFileName.json';
12+
saveInRoot: boolean = false;
13+
14+
writeFileQueue = new PromiseQueue();
15+
16+
private get logPrefix() {
17+
const filePath = !this.saveInRoot ? this.dirWithProfileData : '';
18+
return `FileRepository [${filePath}/${this.fileName}]:`;
19+
}
1220

1321
private static get appDataFolder() {
1422
return process.env.APPDATA || '';
1523
}
1624

17-
private static get profileFolder() {
18-
return path.join(
19-
AbstractFileRepository.appDataFolder,
20-
APP_FOLDER,
21-
PROFILE_FOLDER,
22-
);
25+
private get destFolder() {
26+
const pathItems = [AbstractFileRepository.appDataFolder, APP_DIR];
27+
if (!this.saveInRoot) {
28+
pathItems.push(this.dirWithProfileData);
29+
}
30+
return path.join(...pathItems);
2331
}
2432

2533
private get filePath() {
26-
return path.join(AbstractFileRepository.profileFolder, this.fileName);
34+
return path.join(this.destFolder, this.fileName);
35+
}
36+
37+
public setProfile(profile: string) {
38+
this.dirWithProfileData = profile;
2739
}
2840

2941
public restore(defaultValue: T): T {
42+
console.log(`${this.logPrefix} restore`);
3043
if (fs.existsSync(this.filePath)) {
31-
const data = fs.readFileSync(this.filePath);
44+
const data = fs.readFileSync(this.filePath, { encoding: 'utf-8' });
3245
// TODO handle parse error. Backup file with issues and return defaultValue
3346
return JSON.parse(data);
3447
}
3548
return defaultValue;
3649
}
3750

3851
public save(data: T) {
39-
FsHelper.mkdirIfNotExists(AbstractFileRepository.profileFolder);
40-
return FsHelper.writeFile(this.filePath, data);
52+
FsHelper.mkdirIfNotExists(this.destFolder);
53+
this.writeFileQueue.add(() => {
54+
console.log(`${this.logPrefix} save`);
55+
return FsHelper.writeFile(this.filePath, data).catch(() => {
56+
console.error(`${this.logPrefix} can't save file '${this.filePath}'`);
57+
});
58+
});
59+
this.writeFileQueue.execute();
4160
}
4261
}

src/components/PlayStopButton/PlayStopButton.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { createUseStyles } from 'react-jss';
66

77
import CircleButton from '../CircleButton/CircleButton';
88
import rootStore from '../../modules/RootStore';
9-
import TaskModel from '../../models/TaskModel';
9+
import TaskModel from '../../modules/tasks/models/TaskModel';
1010

1111
const { tasksStore } = rootStore;
1212

@@ -27,7 +27,7 @@ export default observer(function PlayStopButton({
2727
if (!task?.active) {
2828
tasksStore.startTimer(task);
2929
} else {
30-
tasksStore.stopTimer(task);
30+
tasksStore.stopTimer();
3131
}
3232
}
3333
}

src/components/Profile/Profile.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React from 'react';
2+
import { Space } from 'antd';
3+
import { SettingOutlined } from '@ant-design/icons';
4+
import { createUseStyles } from 'react-jss';
5+
6+
import rootStore from '../../modules/RootStore';
7+
import useModal from '../../hooks/ModalHook';
8+
import SettingsModal from '../SettingsModal/SettingsModal';
9+
10+
const { settingsStore } = rootStore;
11+
12+
const Profile: React.VFC = () => {
13+
const classes = useStyles();
14+
const { settings } = settingsStore;
15+
const { open, openModal, closeModal } = useModal();
16+
17+
return (
18+
<Space className={classes.root}>
19+
<span className={classes.white}>{settings.currentProfile}</span>
20+
<SettingOutlined className={classes.white} onClick={openModal} />
21+
<SettingsModal visible={open} onClose={closeModal} />
22+
</Space>
23+
);
24+
};
25+
26+
const useStyles = createUseStyles({
27+
root: {
28+
marginLeft: 16,
29+
},
30+
white: {
31+
color: 'white',
32+
},
33+
});
34+
35+
export default Profile;

0 commit comments

Comments
 (0)